【问题标题】:Drawing holes in Google Maps Polygons with DrawingManager使用 DrawingManager 在 Google 地图多边形中绘制孔
【发布时间】:2021-02-21 10:23:49
【问题描述】:

到目前为止,我将绘制的对象列表保存到一个数组中

var overlayArr = [] //Store all completed objects
var formattedWithHoles = [] //Store converted collisions
google.maps.event.addListener(drawingManager, 'overlaycomplete', function(e) {
      overlayArr.push(e.overlay);
      overlayArr.forEach(isPolygonInsidePolygon) //Doesn't work right
});

包含所有对象,然后我需要生成一个 GeoJSON,但首先如果一个多边形内部有一个多边形——那么它必须被绘制为一个洞

//Helper function
function isPolygonInsidePolygon(innerPolygon, outerPolygon) {
  var points = innerPolygon.getPath().getArray();

  for( var i = 0; i < points.length; i++ ){
    if(!google.maps.geometry.poly.containsLocation( points[i], outerPolygon) ){ 
      return false; 
    }
  }
  //formattedWithHoles.push(...); //Use inner and outer polygon data class?
  return true; 
}

生成每个对象的 GeoJSON 而不检查碰撞:

google.maps.Polygon.prototype.getGeoJSON = function()  {
//GeoJSON format
let geoJSON = {
    type: 'Feature',
    geometry: {
        type: 'Polygon', //MultiPolygon for holes?
        coordinates: []
    },
    properties: {}
};

    let paths = this.getPaths().getArray();

    for (var path of paths)  {
        let pathArray = [];
        let points = path.getArray();
        let firstPoint = false;

        for (var point of points)  {
            if (firstPoint === false)  {
                firstPoint = point;
            }
            pathArray.push([point.lng(), point.lat()])
        }

        pathArray.push([firstPoint.lng(), firstPoint.lat()]);
        geoJSON.geometry.coordinates.push(pathArray);
    }
    //console.log(geoJSON);
    return geoJSON;
};

如何结合google.maps.event.addListener(drawingManager, 'overlaycomplete',...) 侦听器来检测碰撞并使其生成带孔的geoJSON?

我基本上是在地图上绘制农田,并想在无法耕种的障碍物上打洞,因此 1 个农场可能有多个我需要清除的障碍物。

【问题讨论】:

  • 你会只有一层包含的多边形吗?
  • 我基本上是在地图上绘制农田,并想在无法耕种的障碍物上打洞,所以 1 个农场可能有多个我需要消除的障碍

标签: javascript google-maps-api-3


【解决方案1】:

要打孔,如果外面的多边形是逆时针的,里面的多边形需要顺时针(缠绕方向),反之亦然。每the documentation

要在多边形内创建一个空白区域,您需要创建两条路径,一条在另一条内部。 要创建孔,定义内部路径的坐标必须与定义外部路径的坐标顺序相反。例如,如果外部路径的坐标是顺时针方向,那么内部路径必须是逆时针方向。

相关问题:

一个选项:

  1. 创建一个函数来控制缠绕方向。下面是来自https://github.com/mapbox/geojson-rewind/blob/main/index.jsrewindRing 的修改(获取google.maps.LatLng 对象的数组)版本
function rewindRing(ring, dir) {
    var area = 0;
    for (var i = 0, len = ring.length, j = len - 1; i < len; j = i++) {
      area += ((ring[i].lng() - ring[j].lng()) * (ring[j].lat() + ring[i].lat()));
    }
    console.log("area="+area+" dir="+dir);
    if (area >= 0 !== !dir) 
      ring.reverse();
    return ring;
  }
  1. 当您在另一个多边形中找到一个多边形时,反转它的缠绕方向:
var found = false;
for (var i = 0; i < overlayArr.length; i++) {
  if (isPolygonInsidePolygon(e.overlay, overlayArr[i])) {
    found = true;
    var path = e.overlay.getPath().getArray();
    path = rewindRing(path, false);
    overlayArr[i].getPaths().push(new google.maps.MVCArray(path));
    e.overlay.setMap(null);
    break;
  }
}
if (!found) {
  console.log("!found");
  overlayArr.push(e.overlay);
}

proof of concept fiddle

Live example

代码 sn-p:

// This example requires the Drawing library. Include the libraries=drawing
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyBIwzALxUPNbatRBj3Xi1Uhp0fFzwWNBkE&libraries=drawing">
function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    center: {
      lat: -34.397,
      lng: 150.644
    },
    zoom: 8,
  });
  const drawingManager = new google.maps.drawing.DrawingManager({
    drawingMode: google.maps.drawing.OverlayType.POLYGON,
    drawingControl: true,
    drawingControlOptions: {
      position: google.maps.ControlPosition.TOP_CENTER,
      drawingModes: [
        google.maps.drawing.OverlayType.POLYGON,
      ],
    },
  });
  drawingManager.setMap(map);
  var overlayArr = [] //Store all completed objects
  var formattedWithHoles = [] //Store converted collisions
  google.maps.event.addListener(drawingManager, 'overlaycomplete', function(e) {
    var path = e.overlay.getPath().getArray()
    path = rewindRing(path, true);
    var newPoly = new google.maps.Polygon({
      path: path,
    })
    var found = false;
    for (var i = 0; i < overlayArr.length; i++) {
      if (isPolygonInsidePolygon(e.overlay, overlayArr[i])) {
        found = true;
        var path = e.overlay.getPath().getArray();
        path = rewindRing(path, false);
        overlayArr[i].getPaths().push(new google.maps.MVCArray(path));
        e.overlay.setMap(null);
        break;
      }
    }
    if (!found) {
      overlayArr.push(e.overlay);
    }
  });

  //Helper function
  function isPolygonInsidePolygon(innerPolygon, outerPolygon) {
    var points = innerPolygon.getPath().getArray();

    for (var i = 0; i < points.length; i++) {
      if (!google.maps.geometry.poly.containsLocation(points[i], outerPolygon)) {
        return false;
      }
    }
    return true;
  }

  google.maps.Polygon.prototype.getGeoJSON = function() {
    //GeoJSON format
    let geoJSON = {
      type: 'Feature',
      geometry: {
        type: 'Polygon', //MultiPolygon for holes?
        coordinates: []
      },
      properties: {}
    };

    let paths = this.getPaths().getArray();

    for (var path of paths) {
      let pathArray = [];
      let points = path.getArray();
      let firstPoint = false;

      for (var point of points) {
        if (firstPoint === false) {
          firstPoint = point;
        }
        pathArray.push([point.lng(), point.lat()])
      }

      pathArray.push([firstPoint.lng(), firstPoint.lat()]);
      geoJSON.geometry.coordinates.push(pathArray);
    }
    //console.log(geoJSON);
    return geoJSON;
  };

  // from https://github.com/mapbox/geojson-rewind/blob/main/index.js
  function rewindRing(ring, dir) {
    var area = 0;
    for (var i = 0, len = ring.length, j = len - 1; i < len; j = i++) {
      area += ((ring[i].lng() - ring[j].lng()) * (ring[j].lat() + ring[i].lat()));
    }
    console.log("area=" + area + " dir=" + dir);
    if (area >= 0 !== !dir)
      ring.reverse();
    return ring;
  }
}
/* Always set the map height explicitly to define the size of the div
       * element that contains the map. */

#map {
  height: 100%;
}


/* Optional: Makes the sample page fill the window. */

html,
body {
  height: 100%;
  margin: 0;
  padding: 0;
}
<!DOCTYPE html>
<html>

<head>
  <title>Drawing Tools</title>
  <script src="https://polyfill.io/v3/polyfill.min.js?features=default"></script>
  <!-- jsFiddle will insert css and js -->
</head>

<body>
  <div id="map"></div>

  <!-- Async script executes immediately and must be after any DOM elements used in callback. -->
  <script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk&callback=initMap&libraries=drawing&v=weekly" async></script>
</body>

</html>

【讨论】:

    猜你喜欢
    • 2012-08-15
    • 2020-01-14
    • 1970-01-01
    • 2023-03-06
    • 2020-04-13
    • 2017-12-08
    • 2011-07-02
    • 1970-01-01
    相关资源
    最近更新 更多