65 const VirtualRobot::MathTools::ConvexHull2D& hull)
67 const auto& vertices = hull.vertices;
72 bool anyPositive =
false;
73 bool anyNegative =
false;
75 float minEdgeDistance = std::numeric_limits<float>::max();
77 for (std::size_t i = 0; i < vertices.size(); i++)
79 const Eigen::Vector2f& a = vertices[i];
80 const Eigen::Vector2f& b = vertices[(i + 1) % vertices.size()];
82 const Eigen::Vector2f edge = b - a;
83 const Eigen::Vector2f toPt = pt - a;
84 const float cross = edge.x() * toPt.y() - edge.y() * toPt.x();
86 anyPositive |=
cross > 0;
87 anyNegative |=
cross < 0;
89 minEdgeDistance = std::min(minEdgeDistance, distanceToSegment(pt, a, b));
92 const bool inside = not(anyPositive and anyNegative);
93 return inside ? 0.F : minEdgeDistance;
112 if (clusterPoints.empty())
117 const float cosHalfWindowAngle = std::cos(params.windowAngle / 2);
119 for (
const Eigen::Vector2f& pt : clusterPoints)
121 if (angularTestValid)
123 const Eigen::Vector2f fromPlug = pt - params.plugPosition;
124 const float distanceToPlug = fromPlug.norm();
127 if (distanceToPlug > 1.F
128 and fromPlug.dot(outward) / distanceToPlug < cosHalfWindowAngle)
134 if (distanceToHull(pt) > params.maxDistanceToHull)
140 return thickness(clusterPoints) <= params.maxThickness;
146 if (points.size() < 2)
151 Eigen::Vector2f
mean = Eigen::Vector2f::Zero();
152 for (
const Eigen::Vector2f& pt : points)
156 mean /=
static_cast<float>(points.size());
158 Eigen::Matrix2f covariance = Eigen::Matrix2f::Zero();
159 for (
const Eigen::Vector2f& pt : points)
161 const Eigen::Vector2f centered = pt -
mean;
162 covariance += centered * centered.transpose();
164 covariance /=
static_cast<float>(points.size());
167 const Eigen::SelfAdjointEigenSolver<Eigen::Matrix2f> solver(covariance);
168 const Eigen::Vector2f minorAxis = solver.eigenvectors().col(0);
170 float minProjection = std::numeric_limits<float>::max();
171 float maxProjection = std::numeric_limits<float>::lowest();
172 for (
const Eigen::Vector2f& pt : points)
174 const float projection = (pt -
mean).
dot(minorAxis);
175 minProjection = std::min(minProjection, projection);
176 maxProjection = std::max(maxProjection, projection);
179 return maxProjection - minProjection;
187 std::vector<Eigen::Vector2f> polygon;
189 if (not angularTestValid)
194 polygon.reserve(2 * numArcSamples);
196 const float centerAngle = std::atan2(outward.y(), outward.x());
200 const float maxRadius = 4 * (params.plugPosition.norm() + params.maxDistanceToHull);
206 const auto boundaryRadius =
207 [
this, maxRadius](
const Eigen::Vector2f& direction,
float maxAllowedDistance)
210 float hi = maxRadius;
211 for (
int iteration = 0; iteration < 32; iteration++)
213 const float mid = (
lo +
hi) / 2;
214 if (distanceToHull(params.plugPosition + mid * direction) <= maxAllowedDistance)
226 const auto windowDirection = [
this, centerAngle](std::size_t i, std::size_t n)
229 centerAngle - params.windowAngle / 2 +
230 params.windowAngle *
static_cast<float>(i) /
static_cast<float>(n - 1);
231 return Eigen::Vector2f(std::cos(
angle), std::sin(
angle));
235 for (std::size_t i = 0; i < numArcSamples; i++)
237 const Eigen::Vector2f direction = windowDirection(i, numArcSamples);
238 polygon.push_back(params.plugPosition +
239 boundaryRadius(direction, params.maxDistanceToHull) * direction);
243 for (std::size_t i = 0; i < numArcSamples; i++)
245 const Eigen::Vector2f direction =
246 windowDirection(numArcSamples - 1 - i, numArcSamples);
247 polygon.push_back(params.plugPosition + boundaryRadius(direction, 0.F) * direction);