点-in-多边形算法适配带孔洞多面体误判问题排查(.NET)
带孔洞多面体的点内判断逻辑修复
你的代码问题出在没有区分多面体中的外环和孔洞内环。OGC标准里,MultiPolygon的每个Polygon结构是[外环坐标数组, 孔洞1坐标数组, 孔洞2坐标数组,...]:外环用来标记核心包含区域,而孔洞是要从包含区域中排除的部分。原代码把所有环都当成外环处理,导致孔洞的环错误地翻转判断状态,最终对处于「外环包含但不在任何孔洞内」的点误判为不在区域中。
修复后的代码
private static bool CheckIfCoordinatesContainPoint(double[][][][] coordinates, double x, double y) { bool isInsideTotal = false; foreach (var polygon in coordinates) { bool isInsidePolygon = false; // 先判断点是否在外环内部 var outerRing = polygon[0]; isInsidePolygon = IsPointInRing(outerRing, x, y); // 遍历所有内环(孔洞),如果点在任意孔洞内,就排除该点 for (int i = 1; i < polygon.Length; i++) { var innerRing = polygon[i]; if (IsPointInRing(innerRing, x, y)) { isInsidePolygon = false; break; // 只要在一个孔洞里,无需检查其他孔洞 } } isInsideTotal = isInsideTotal || isInsidePolygon; } return isInsideTotal; } // 提取单个环的点内判断逻辑,复用奇偶校验法 private static bool IsPointInRing(double[][] ring, double x, double y) { bool isInside = false; int count = ring.Length; for (int i = 0, j = count - 1; i < count; j = i++) { var vertexI = ring[i]; var vertexJ = ring[j]; double xi = vertexI[0]; double yi = vertexI[1]; double xj = vertexJ[0]; double yj = vertexJ[1]; bool intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); if (intersect) { isInside = !isInside; } } return isInside; }
修复逻辑说明
- 拆分环的处理逻辑:把单个环的点内判断提取成独立方法,让代码更易维护。
- 明确外环与内环的作用:
- 先通过外环判断点是否处于多边形的核心包含区域。
- 再遍历所有内环(孔洞),如果点在任意孔洞内,就将该多边形的包含状态置为
false(因为孔洞是要排除的区域)。
- 多面体的最终判断:只要有一个多边形包含该点,整体结果就为
true。
你的测试点x=721649.31 y=6190955.51正好处于某个带孔洞多边形的外环内部,但原代码把孔洞的环也当作外环多次翻转状态,最终返回false。修复后的代码会正确识别点在外环内且不在孔洞中,返回true。
如果业务需要严格处理「点正好在环边上」的情况,可以在IsPointInRing方法中添加额外的边界判断逻辑。
内容的提问来源于stack exchange,提问作者Gyuude
相关产品推荐
相关产品推荐

