如何合并多个相交的多边形

How to merge multiple intersecting polygons

我正在尝试使用 turfjs 合并或分组多边形。

下图显示了合并前的样子以及合并后的样子。

我正在使用 Openlayers 和 Typescript,它们都有多边形,因此别名为 TurfPolygon 等。 我首先将我的 OpenLayers 多边形转换为 Turfjs 多边形,因此我可以使用 Turf 函数。

const mergedIds: number[] = [];
const t0 = performance.now();

    for (const object of arrayTurfObjects) {
        if (mergedIds.find(x => x === object.properties.mergedId)) {
            continue;
        }

        let mergeResultPolygon: TurfFeature<TurfPolygon> | null = null;

        for (let indexNested = 0; indexNested < arrayTurfObjects.length; indexNested++) {
            const nestedObject = arrayTurfObjects[indexNested];

            if(nestedObject === object){
                continue;
            }

            if(mergedIds.find(x => x === nestedObject.properties.mergedId)){
                continue;
            }

            if(mergeResultPolygon){
                if(booleanIntersects(mergeResultPolygon, nestedObject)){
                    mergeResultPolygon = TurfUnion(mergeResultPolygon, nestedObject) as TurfFeature<TurfPolygon, any>;
                    mergedIds.push(nestedObject.properties.mergedId);
                    indexNested = 0;
                }
            } else {
                if(booleanIntersects(object, nestedObject)){
                    mergeResultPolygon = TurfUnion(object, nestedObject) as TurfFeature<TurfPolygon, any>;
                    mergedIds.push(nestedObject.properties.mergedId);
                    indexNested = 0;
                }
            }
        }

        if (mergeResultPolygon) {
            const polygon = new Polygon(mergeResultPolygon.geometry.coordinates);
            const feature = new Feature(polygon);
            feature.setStyle(new Style({
                stroke: new Stroke({
                    color: ColorCode.BLACK,
                    width: 5,
                }),
                fill: new Fill({
                    color: 'rgba(255,0,0, 0.6)',
                }),
            }));
            //Here is an function to add the mergeResultPolygon to the map to check if it's correct
        }
}

const t1 = performance.now();
console.log((t1 - t0) + ' milliseconds.');

我正在遍历同一个数组,该数组包含两次多边形。 首先我检查多边形是否已经合并,所以我可以跳过,然后我声明我的合并结果多边形。 然后是我跳过多边形的嵌套循环,如果它与我外循环中的多边形相同并且它已经合并。

为了开始我的合并过程,我正在寻找与当前外环多边形相交的第一个多边形,因此我可以为我的 mergeResultPolygon 设置一个值。 之后,我将更多多边形合并到该变量。

如您所见,我必须重置嵌套循环,以便再次迭代。 我这样做是因为我没有任何顺序,所以之前的多边形可能与合并结果多边形相交。

我的问题是我在客户端执行此操作,但性能不是很好。

这个问题有更好的解决方案吗?

从所有多边形的联合中获取合并多边形的演示

<!doctype html>
<html lang="en">
  <head>
    <link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/css/ol.css" type="text/css">
    <style>
      html, body, .map {
        margin: 0;
        padding: 0;
        width: 100%;
        height: 100%;
      }
    </style>
    <script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v6.5.0/build/ol.js"></script>
    <script src="https://unpkg.com/@turf/turf@6.3.0/turf.min.js"></script>
  </head>
  <body>
    <div id="map" class="map"></div>
    <script type="text/javascript">

      var count = 200;
      var features = new Array(count);
      var e = 4500000;
      for (var i = 0; i < count; ++i) {
        var coordinates = [2 * e * Math.random() - e, 2 * e * Math.random() - e];
        features[i] = new ol.Feature(new ol.geom.Polygon.fromExtent(ol.extent.buffer(coordinates.concat(coordinates), 200000)));
      }

      var source = new ol.source.Vector({
        features: features,
      });

      var map = new ol.Map({
        target: 'map',
        layers: [
          new ol.layer.Tile({
            source: new ol.source.OSM()
          }),
          new ol.layer.Vector({
            source: source
          })
        ],
        view: new ol.View({
          center: [0, 0],
          zoom: 2
        })
      });

      var result;
      format = new ol.format.GeoJSON();
      source.forEachFeature(function(feature) {
        var turfPolygon = format.writeFeatureObject(feature);
        if (!result) {
          result = turfPolygon;
        } else {
          result = turf.union(result, turfPolygon);
        }
      });

      var results = [];
      var olResult = format.readFeature(result);
      if (olResult.getGeometry().getType() === 'MultiPolygon') {
        olResult.getGeometry().getPolygons().forEach(function(polygon) {
          results.push(new ol.Feature(polygon));
        });
      } else {
        results.push(olResult);
      }

      map.addLayer(
        new ol.layer.Vector({
          source: new ol.source.Vector({
            features: results,
          }),
          style: new ol.style.Style({
            stroke: new ol.style.Stroke({
              color: 'red',
              width: 2
            })
          })
        })
      );

    </script>
  </body>
</html>