要获得最佳性能,您应该根据自己的数据比较不同的算法。我比较了一些 Point-In-Polygon 算法,我发现 Ray-Casting 提供了最好的性能,here's 是一个比较。你可以找到一个写得很好的Ray-Casting算法实现here。
这是一个快速而简单的部分,在下一步你想要合并两个多边形。如果多边形是凸的,您可以连接两个更近的顶点,但是由于您说它们可能是凹的(甚至是凸多边形的边缘上有额外的顶点),因此更近的角将不起作用。例如:
您应该从每个多边形中选择一个顶点,使其连接线不与多边形的任何边相交。要找到两条线的交点,您可以这样做:
function Zero(const Value: Double): Boolean;
const
Epsilon = 1E-10;
begin
Result := Abs(Value) < Epsilon;
end;
function IntersectLines(const X11, Y11, X12, Y12, X21, Y21, X22, Y22: Double;
out X, Y: Double): Boolean;
var
A1, B1, C1, A2, B2, C2, D: Double;
begin
A1 := Y12 - Y11;
B1 := X11 - X12;
C1 := A1 * X11 + B1 * Y11;
A2 := Y22 - Y21;
B2 := X21 - X22;
C2 := A2 * X21 + B2 * Y21;
D := A1 * B2 - A2 * B1;
if Zero(D) then
Result := False // Lines are parallel
else
begin
X = (B2 * C1 - B1 * C2) / D;
Y = (A1 * C2 - A2 * C1) / D;
end;
end;
但请注意,仅找到交点并不意味着所选顶点不正确,因为我们正在处理线段,因此交点应该在线段内。要找出这一点,您可以检查该点是否在线段的边界框内。例如在这个插图中,1 和 2 是选定的顶点,3 是它们的交叉线与边的交点,但 3 不在 1 和 2 的覆盖边界框内。
您应该注意到,每对选定顶点的交叉线将至少穿过边界框内每个多边形的两条边(在选定顶点上相交的边),因此边界框不应包含它的边界。
之后,您应该将外部多边形与其选定的顶点分开,并在它们之间插入内部多边形的重定向顶点。
最后,我应该说:是的!有很多关于所有这些的理论,但你应该找到自己的。正如您所说,一个多边形都在另一个多边形内,这意味着它们是系统生成的,甚至是像字符边界一样预定义的。然后
您也许可以更改所有讨论过的算法,以针对您自己的情况获得更好的性能。