求助:如何判断Marker是否位于KML绘制的嵌套多边形内部?
嘿,我来帮你搞定嵌套多边形里Marker的位置判断问题!
嵌套多边形内Marker位置判断方案
核心逻辑:区分内外层的环绕数规则
嵌套多边形(带洞的那种)的点-in-polygon判断,核心是搞清楚外层多边形和内层洞的顶点排列方向——KML里默认遵循的是外层顺时针、内层逆时针(反过来也能行,关键是内外方向必须相反)。
这里用非零环绕数规则比奇偶规则更靠谱,因为它能准确识别“洞”的区域,不会在边界情况出现误判。
具体实现步骤
1. 从KML里提取坐标数据
首先得把KML里的多边形坐标解析出来,你的KML代码里应该有<Polygon>标签,其中:
<outerBoundaryIs>下面的<LinearRing>是外层多边形的坐标<innerBoundaryIs>下面的是内层洞的坐标
解析后你会得到两个(或多个,多洞情况)坐标数组:
outerCoords: 外层的经纬度数组,格式比如[[经度1, 纬度1], [经度2, 纬度2], ...]innerCoords: 内层洞的经纬度数组,格式同上
2. 写一个基础的点-in-polygon判断函数
下面是基于非零环绕数规则的函数示例(用JavaScript写的,你可以改成你用的开发语言):
// 判断点是否在单个多边形内部(非零环绕数规则) function pointInPolygon(point, polygonCoords) { let isInside = false; const [pointX, pointY] = point; const coordCount = polygonCoords.length; // 遍历多边形的每条边 for (let i = 0, j = coordCount - 1; i < coordCount; j = i++) { const [x1, y1] = polygonCoords[i]; const [x2, y2] = polygonCoords[j]; // 先判断点的y坐标是否在当前边的y范围内 const isYCrossing = ((y1 > pointY) !== (y2 > pointY)); if (isYCrossing) { // 计算边与点水平线的交点x坐标 const intersectX = ((pointY - y1) * (x2 - x1)) / (y2 - y1) + x1; // 根据边的方向调整环绕数,判断是否进入/离开多边形 if (x1 < x2) { if (pointX < intersectX) isInside = !isInside; } else { if (pointX > intersectX) isInside = !isInside; } } } return isInside; }
3. 处理嵌套多边形的判断逻辑
对于带洞的多边形,判断规则很简单:Marker必须在外层多边形内部,同时不在任何内层洞的内部。
所以最终的判断函数可以这么写:
// 判断点是否在嵌套多边形内(支持多个内层洞) function pointInNestedPolygon(point, outerCoords, innerCoordsList) { // 第一步:先确认点在外层里面 const isInOuter = pointInPolygon(point, outerCoords); if (!isInOuter) return false; // 第二步:检查点是否在任何一个内层洞里 for (const innerCoords of innerCoordsList) { const isInHole = pointInPolygon(point, innerCoords); // 因为内层是逆时针方向,返回true就表示点在洞里,直接排除 if (isInHole) return false; } return true; }
4. 适配KML的顶点顺序
如果你的KML里内层洞的顶点顺序和外层一样(比如都是顺时针),那上面的函数会把洞当成另一个外层,这时候你需要反转内层的坐标数组,让内外方向相反:
// 反转坐标数组,改变顶点排列方向 function reverseCoordinateOrder(coords) { return [...coords].reverse(); } // 修正内层洞的坐标顺序 const correctedInnerCoords = reverseCoordinateOrder(innerCoords);
几个要注意的细节
- 确保KML里的
<LinearRing>坐标是闭合的——第一个点和最后一个点要相同 - 如果是多个内层洞,把所有内层坐标数组放到
innerCoordsList数组里就行 - KML的坐标格式是
经度,纬度,海拔,解析的时候记得只取前两个值就行
内容的提问来源于stack exchange,提问作者Khan
相关产品推荐
相关产品推荐

