如何修改C#代码判断点是否在多环Polygon内(Azure CosmosDB场景)
支持多环Polygon的点-in-多边形判断实现
问题背景
在Azure CosmosDB中存储的Polygon数据结构如下(可能包含多个环,第一环为外环,其余为内部排除区域):
{ ... "Polygon": { "type": "Polygon", "coordinates": [ [ -72.2811341, 42.9275741 ], [ -72.2816062, 42.9256955 ], [ -72.2780764, 42.9261986 ], [ -72.2811341, 42.9275741 ] ] }, ... }
现有如下C#方法仅支持单环Polygon的点-in-多边形判断,需要修改以支持多环场景:
private bool IsPointInPolygon(Point p, Position[] polygon) { double minX = polygon[0].Latitude; double maxX = polygon[0].Latitude; double minY = polygon[0].Longitude; double maxY = polygon[0].Longitude; for (int i = 1; i < polygon.Length; i++) { Position q = polygon[i]; minX = Math.Min(q.Latitude, minX); maxX = Math.Max(q.Latitude, maxX); minY = Math.Min(q.Longitude, minY); maxY = Math.Max(q.Longitude, maxY); } if (p.Position.Latitude < minX || p.Position.Latitude > maxX || p.Position.Longitude < minY || p.Position.Longitude > maxY) { return false; } bool inside = false; for (int i = 0, j = polygon.Length - 1; i < polygon.Length; j = i++) { if ((polygon[i].Longitude > p.Position.Longitude) != (polygon[j].Longitude > p.Position.Longitude) && p.Position.Latitude < (polygon[j].Latitude - polygon[i].Latitude) * (p.Position.Longitude - polygon[i].Longitude) / (polygon[j].Longitude - polygon[i].Longitude) + polygon[i].Latitude) { inside = !inside; } } return inside; }
修改方案
核心逻辑:点必须在外环内部,同时不在任何一个内环(排除区)内部,才判定为在多环Polygon内。
修改后的代码
保留原单环判断逻辑作为基础方法,新增多环处理的外层方法:
// 原单环判断方法,改为私有辅助方法 private bool IsPointInSingleRing(Point p, Position[] ring) { if (ring == null || ring.Length < 3) return false; double minX = ring[0].Latitude; double maxX = ring[0].Latitude; double minY = ring[0].Longitude; double maxY = ring[0].Longitude; for (int i = 1; i < ring.Length; i++) { Position q = ring[i]; minX = Math.Min(q.Latitude, minX); maxX = Math.Max(q.Latitude, maxX); minY = Math.Min(q.Longitude, minY); maxY = Math.Max(q.Longitude, maxY); } // 边界盒快速排除,提升性能 if (p.Position.Latitude < minX || p.Position.Latitude > maxX || p.Position.Longitude < minY || p.Position.Longitude > maxY) { return false; } bool inside = false; for (int i = 0, j = ring.Length - 1; i < ring.Length; j = i++) { if ((ring[i].Longitude > p.Position.Longitude) != (ring[j].Longitude > p.Position.Longitude) && p.Position.Latitude < (ring[j].Latitude - ring[i].Latitude) * (p.Position.Longitude - ring[i].Longitude) / (ring[j].Longitude - ring[i].Longitude) + ring[i].Latitude) { inside = !inside; } } return inside; } // 多环Polygon判断方法 private bool IsPointInMultiRingPolygon(Point p, Position[][] polygonRings) { if (polygonRings == null || polygonRings.Length == 0) return false; // 第一步:判断是否在外环内(第一个环为外环) bool isInsideOuterRing = IsPointInSingleRing(p, polygonRings[0]); if (!isInsideOuterRing) return false; // 第二步:判断是否在任何一个内环内,若在则排除 for (int i = 1; i < polygonRings.Length; i++) { if (IsPointInSingleRing(p, polygonRings[i])) { return false; } } // 在外环内且不在任何内环内,返回true return true; }
关键说明
- 原方法重命名为
IsPointInSingleRing,作为复用单环判断逻辑的辅助方法。 - 多环方法
IsPointInMultiRingPolygon接收二维数组Position[][],对应Polygon的多环坐标结构。 - 先通过外环判断快速排除不在多边形范围内的点,再遍历所有内环,只要点落在任意内环中,就判定为不在目标区域内。
- 保留了原有的边界盒预判断,减少不必要的射线法计算,提升整体性能。
内容的提问来源于stack exchange,提问作者dasisderblyme
相关产品推荐
相关产品推荐

