我有一个 2D 平面,划分为 n 边凸多边形。我正在使用WRF 的 PNPOLY 算法进行多边形包含,以确保一个点属于一个且仅属于一个多边形。
是否有一种算法可以用来将线段PO剪裁到平面中的给定多边形,假设pnpoly(O) == true
, 这样pnpoly(P')将始终为真?
我当前的 clipToPoly 实现对线段和多边形的每个边缘进行线线相交测试,然后使用相交点(如本 SO 答案中所述),但这并不总是产生满足 PNPOLY 的点。
function clipPointToPoly(p, o, poly) {
var i, j, n = poly.length,
q, r = {}, s = {}, pq = {},
rxs, t, u;
function cross2(v, w) {
return v.x * w.y - v.y * w.x;
}
for (i = 0, j = n - 1; i < n; j = i++) {
q = poly[i];
s.x = poly[j].x - q.x;
s.y = poly[j].y - q.y;
r.x = o.x - p.x;
r.y = o.y - p.y;
rxs = cross2(r, s);
if (rxs !== 0) {
pq.x = q.x - p.x;
pq.y = q.y - p.y;
t = cross2(pq, s) / rxs;
u = cross2(pq, r) / rxs;
if (0 < u && u < 1 && 0 < t && t < 1) {
p.x = p.x + t * r.x;
p.y = p.y + t * r.y;
return true;
}
}
}
return false;
};
这是我对 PNPOLY 的实现:
function pnpoly(p, poly) {
var i, j, e0, e1,
n = polygon.length,
inside = false;
for (i = 0, j = n - 1; i < n; j = i++) {
e0 = poly[i];
e1 = poly[j];
if ( ((p0.y > p.y) !== (p1.y > p.y)) &&
((p.x < (p1.x - p0.x) * (p.y - p0.y) / (p1.y - p0.y) + p0.x)) ) {
inside = !inside;
}
}
return inside;
};
我认为我对 Simplicity 的模拟,或者在使用浮点数正确处理边缘情况时如何处理 PNPOLY 的半开集了解不够。
例如:
poly: [(1,1), (-1,1), (-1,-1), (1,-1)]
p: (5,5)
o: (0,0)
p' = (1,1)
这失败了,因为根据 PNPOLY 不包括 (1,1) (它位于集合的开放侧),但 clipToPoly 没有考虑到这一点。如果我知道它在集合的开放端,我想我可以用 epsilon 轻推它,但我更喜欢更稳定的解决方案。
另一个例子:
poly: [-995.9592341908675, -88.48705014724577
-1040.5031753180106, -176.53192722405026
-549.9211095905894, -330.8462151682281
-653.7143990581328, -211.59193148034612]
p: -1032.3773586525654, -208.3586379393678
o: -957.4172402148379, -202.6668958854324
在这种情况下,clipToPoly 失败,因为O非常靠近多边形的边缘,由于浮点不精确,它甚至没有检测到相交。
t: 1.0000000000000002 u: 0.8306380503739466
有没有办法让 clipToPoly 的浮点不精确度与 PNPOLY 相匹配,以便两者保持一致?