【问题标题】:Check if polygon is in viewport检查多边形是否在视口中
【发布时间】:2016-01-26 07:22:11
【问题描述】:

我有 250 个多边形,每个多边形有 100-300 个点。 如何检查视口中有哪些多边形?

逻辑上的做法是检查每个多边形的每个点是否在视口中,但这似乎非常昂贵和愚蠢。 我还有其他选择吗?如果有,有哪些选择?

我的其他想法:

  • 使用边界框 - 缺点是它只有 4 个点,可能会给出假阴性
  • 用更少的点制作不可见的简化多边形 - 过多的额外工作、数据和资源使用

以下代码遍历所有 250 个多边形和每个多边形的 100-300 个点,并检查它是否在视口中。我认为自己是编程的初学者,但这似乎不是一个好主意,特别是如果我需要在每次更改边界/拖动地图时都发生这种情况。

google.maps.event.addListener( map, 'bounds_changed', function( ) {

    var viewport = map.getBounds();

    var polygons = [array of polygons];
    var polygonsCount = polygons.length;

    // Polygons
    for(a = 0; a < polygonsCount; a++) {

        var polygonPoints = polygons[a].getPath(); // Array of points
        var inBounds = false;

        var pointsCount = polygonPoints.length;

        // Points
        for(b = 0; b < pointsCount; b++) {

            if(viewport.contains(polygonPoints[b])) { 

                inBounds = true; 
                return false;  // No need to continue loop if we found one 
            } 
        } 
    }
});

【问题讨论】:

  • 您可以跟踪最接近边界边缘但不在地图每一侧边界内的多边形点,然后当边界发生变化时,您只需要更新地图内的多边形IFF 您跟踪的 4 个点中的任何一个现在都在里面,而不是每次边界更新时检查所有 250*n 个点。对内部最近的点执行相同操作,以防它们缩小边界。
  • 您也可以只检查每个多边形上的 1 个点,看看它是否在边界边缘的“n”范围内,其中 n 是外接多边形的圆的直径,IFF 这是真的然后迭代所有点,否则继续下一个多边形
  • 这两种策略应该会大大减少你的计算时间,比如原来的 1%。祝你好运!
  • 对不起,我不知道 javascript 或 google maps API

标签: javascript google-maps google-maps-api-3


【解决方案1】:

您可以使用以下函数来确定多边形是否位于地图视口内:

function containsPolygon(map,polygon) {
    return polygon.getPaths().getArray().every(function (path) {
        return path.getArray().every(function(coord) {
            return map.getBounds().contains(coord);
        });
    });
}

示例

var g_polygongs = [];
function initMap() {
    var map = new google.maps.Map(document.getElementById('map'), {
        zoom: 3,
        center: { lat: 24.886, lng: -70.268 },
        mapTypeId: google.maps.MapTypeId.TERRAIN
    });

    //generate polygons
    for (var i = 0; i < 100; i++) {
        var startLng = getRandomArbitrary(-90.0, 0.0);
        var startLat = getRandomArbitrary(0.0, 60.0);
        var coords = [
            { lat: startLat, lng: startLng },
            { lat: startLat - 6.0, lng: startLng + 4.0 },
            { lat: startLat + 6.0, lng: startLng + 8.0 },
            { lat: startLat, lng: startLng }
        ];
        g_polygongs.push(createPolygon(map,coords));
    }


    google.maps.event.addListener(map, 'bounds_changed', function () {

      g_polygongs.forEach(function(p) {
          if (containsPolygon(map, p)) {
              p.setOptions({ strokeWeight: 2.0, fillColor: 'green' });
          } else {
              p.setOptions({ fillColor: 'orange' });
          }

      });
    });

}


function containsPolygon(map,polygon) {
    return polygon.getPaths().getArray().every(function (path) {
        return path.getArray().every(function(coord) {
            return map.getBounds().contains(coord);
        });
    });
}





function createPolygon(map,coords) {
    // Construct the polygon.
    var poly = new google.maps.Polygon({
        paths: coords,
        strokeColor: '#FF0000',
        strokeOpacity: 0.8,
        strokeWeight: 2,
        fillColor: '#FF0000',
        fillOpacity: 0.35
    });
    poly.setMap(map);
    return poly;
}


function getRandomArbitrary(min, max) {
    return Math.random() * (max - min) + min;
}
html, body {
    height: 100%;
    margin: 0;
    padding: 0;
}

#map {
    height: 100%;
}
<div id="map"></div>
<script async defer
            src="https://maps.googleapis.com/maps/api/js?callback=initMap"></script>

JSFiddle

【讨论】:

  • 这似乎检查了每个点,当我的多边形包含数百个点时可能会导致一些性能问题,或者我误解了你的代码?另外,有没有办法添加 padding,这样即使是靠近边界和稍微超出边界的多边形也会被计为 visible
  • 没错,它可能会影响性能,因为在map.getBounds().contains函数中我们会验证地图是否包含多边形每个顶点的坐标
【解决方案2】:

使用边界框应该是一个简单的过程,并且可以很好地减少比较。如果通过了,那么您仍然可以检查每个点以获得明确的结果。

google.maps.LatLngBounds 有一个可以使用的相交函数。

您可能希望预先计算每个多边形的边界,但这只需要发生一次或在它们更新时发生。 Google 地图不提供边界功能,但您可以创建它。

获取多边形的边界

if (!google.maps.Polygon.prototype.getBounds) {

    google.maps.Polygon.prototype.getBounds=function(){
        var bounds = new google.maps.LatLngBounds()
        this.getPath().forEach(function(element,index)  {bounds.extend(element)})
        return bounds
    }
}

预先计算每个边界;

function calcBounds(){
    for(a = 0; a < polygonsCount; a++) {
            polygons[a].bounds = polygons[a].getBounds(); //precalculated
    }
}

在您的事件处理程序中添加额外的测试。

google.maps.event.addListener( map, 'bounds_changed', function( ) {

    var viewport = map.getBounds();

    var polygons = [array of polygons];
    var polygonsCount = polygons.length;

    // Polygons
    for(a = 0; a < polygonsCount; a++) {
        var bounds = polygons[a].bounds; //precalculated
        if(viewport.intersects(bounds)){ //only continue if basic test passes
            var polygonPoints = polygons[a].getPath(); // Array of points
            var inBounds = false;

            var pointsCount = polygonPoints.length;

            // Points
            for(b = 0; b < pointsCount; b++) {

                if(viewport.contains(polygonPoints[b])) { 

                    inBounds = true; 
                    return false;  // No need to continue loop if we     found one 
                } 
            }
        } 
    }
});

【讨论】:

  • 好的..但是如何解决地图放大并且我们在在多边形的中间在中间或边界框边框的问题?没有显示任何点,如何仍然知道 this 多边形是否显示?
  • 那么初始边界框相交测试应该适用于此。您只需要将多边形相交函数改进为比简单的点比较更高级的东西。应该是周围的资源。看这个答案stackoverflow.com/a/10838831/1522857
猜你喜欢
  • 2011-06-17
  • 2014-08-26
  • 2018-02-15
  • 2014-04-26
  • 2011-08-18
  • 2021-07-11
  • 1970-01-01
相关资源
最近更新 更多