如何获取自相交多边形的外壳(Outer Shell)?
提取自相交多边形的外壳(Turf.js及替代方案)
一、基于Turf.js的解决方案(优先推荐)
Turf.js提供了turf.unkinkPolygon方法,可直接将自相交/环绕的多边形拆分为多个不重叠的有效多边形。由于外壳的面积必然远大于内部交叉产生的小区域,只需筛选出面积最大的多边形即可得到目标外壳。
代码示例
import * as turf from '@turf/turf'; // 你的自相交多边形GeoJSON const selfIntersectingPoly = { type: 'Polygon', coordinates: [[/* 填入你的坐标数组 */]] }; // 拆分自相交多边形为多个有效多边形 const unkinkedMultiPoly = turf.unkinkPolygon(selfIntersectingPoly); // 筛选面积最大的多边形(即外壳) const outerShell = unkinkedMultiPoly.features.reduce((max, curr) => { return turf.area(curr) > turf.area(max) ? curr : max; }, unkinkedMultiPoly.features[0]); // 输出结果 console.log(outerShell);
说明
turf.unkinkPolygon会将自相交的Polygon转换为MultiPolygon,包含所有拆分后的有效子多边形。- 通过面积筛选的逻辑适用于绝大多数场景:内部交叉区域的面积远小于外壳,因此最大面积的多边形即为所需的无孔洞外壳。
二、替代方案:JSTS拓扑库
如果Turf.js的处理不符合需求,可使用JSTS(Java Topology Suite的JS端口),它在复杂拓扑处理上更强大。
代码示例
import jsts from 'jsts'; const geoJsonReader = new jsts.io.GeoJSONReader(); const geoJsonWriter = new jsts.io.GeoJSONWriter(); // 自相交多边形GeoJSON const selfIntersectingPoly = { type: 'Polygon', coordinates: [[/* 填入你的坐标数组 */]] }; // 转换为JSTS几何对象 const jstsGeometry = geoJsonReader.read(selfIntersectingPoly); // 修复自相交:buffer(0)会自动处理自相交,生成有效几何对象 const fixedGeometry = jstsGeometry.buffer(0); // 处理MultiPolygon情况,筛选面积最大的外壳 let outerShellJsts; if (fixedGeometry.getGeometryType() === 'MultiPolygon') { let maxArea = -1; for (let i = 0; i < fixedGeometry.getNumGeometries(); i++) { const currGeom = fixedGeometry.getGeometryN(i); const currArea = currGeom.getArea(); if (currArea > maxArea) { maxArea = currArea; outerShellJsts = currGeom; } } } else { outerShellJsts = fixedGeometry; } // 转换回GeoJSON格式 const outerShellGeoJSON = geoJsonWriter.write(outerShellJsts); console.log(outerShellGeoJSON);
三、手动实现思路(不推荐,复杂度高)
若需自行编写算法,核心步骤如下:
- 自相交检测与拆分:遍历多边形的所有边,检测相交点,将原多边形拆分为多个不相交的子多边形。
- 外层判断:选取一个明显在原多边形外部的点(比如所有坐标外接矩形的外部点),判断该点是否在子多边形内部——外层多边形会让该点处于外部,而内部交叉区域的子多边形会包含该点。
- 筛选结果:保留符合外层条件的多边形,即为目标外壳。
注:手动实现需处理大量边界情况(如多相交点、嵌套交叉等),开发成本高,建议优先使用成熟库。
内容的提问来源于stack exchange,提问作者Pelayo Martinez
相关产品推荐
相关产品推荐

