我需要旋转凹多边形以最小化其高度。我正在考虑找到一条直线,该直线是该多边形的最小直径,然后旋转它以使直线与Y轴平行。
我的问题是如何找到这样一条线?或者,是否有其他算法可以旋转多边形以使其高度最小化?
提前致谢。
答案 0 :(得分:3)
ARRAY points := {P1, P2, ..., PN};
points.delete(middle vertices of any collinear sequence of three points);
REAL p_a := index of vertex with minimum y-coordinate;
REAL p_b := index of vertex with maximum y-coordinate;
REAL rotated_angle := 0;
REAL min_width := INFINITY;
VECTOR caliper_a(1,0); // Caliper A points along the positive x-axis
VECTOR caliper_b(-1,0); // Caliper B points along the negative x-axis
WHILE rotated_angle < PI
// Determine the angle between each caliper and the next adjacent edge in the polygon
VECTOR edge_a(points[p_a + 1].x - points[p_a].x, points[p_a + 1].y - points[p_a].y);
VECTOR edge_b(points[p_b + 1].x - points[p_b].x, points[p_b + 1].y - points[p_b].y);
REAL angle_a := angle(edge_a, caliper_a);
REAL angle_b := angle(edge_b, caliper_b);
REAL width := 0;
// Rotate the calipers by the smaller of these angles
caliper_a.rotate(min(angle_a, angle_b));
caliper_b.rotate(min(angle_a, angle_b));
IF angle_a < angle_b
p_a++; // This index should wrap around to the beginning of the array once it hits the end
width = caliper_a.distance(points[p_b]);
ELSE
p_b++; // This index should wrap around to the beginning of the array once it hits the end
width = caliper_b.distance(points[p_a]);
END IF
rotated_angle = rotated_angle + min(angle_a, angle_b);
IF (width < min_width)
min_width = width;
END IF
END WHILE
RETURN min_width;
请参阅http://en.wikipedia.org/wiki/Rotating_calipers
注意:这两个问题都解决了凸的问题。要解决凹面的情况,您只需通过执行以下操作将输入从凸起转换为凸面:
1. Compute convex hull of your concave polygon.
2. Run algorithm above on convex polygon.
3. Once minimum height found, rotate.
4. Transform back to concave polygon.
凸包在Python中很常见。您可以使用:http://docs.scipy.org/doc/scipy-dev/reference/generated/scipy.spatial.ConvexHull.html
如果你不习惯使用这个库,你可以使用这个算法将凹形转换为凸形:(这并不意味着使用,只是非常糟糕的伪代码,你可以理解如何计算凸包)
Traverse vertices of concave polygon in clockwise order
_prev = starting vertex of traversal
_middle = second vertex in traversal
FOR _next vertex in traversal:
IF _prev -> _middle -> _next make right turn (i.e. concave part)
Connect _prev and _next and set _middle = _next
ELSE
Shift _prev to _middle and _middle to _next.
换句话说,你只需删除凹陷部分:)