【问题标题】:Find centerpoint of polygon in JavaScript在 JavaScript 中查找多边形的中心点
【发布时间】:2013-04-23 08:04:51
【问题描述】:

我有一个来自谷歌地图的“地点”对象,它有一组坐标,代表给定位置的边界框,比如伦敦。每组坐标都有一个纬度和经度。

我已经编写了以下代码来查找中心点,但我不确定它是否确实产生了中心点。如果多边形有 5 个点而不是 4 个呢?此外,这是否可以以更有效的方式完成,操作更少?

function average(array) {
  // Add together and then divide by the length
  return _.reduce(array, function (sum, num) {
    return sum + num;
  }, 0) / array.length;
}

// I have a two-dimensional array that I want to get the average of

var coords = [
  [ -1.2, 5.1 ],
  [ -1.3, 5.2 ],
  [ -1.8, 5.9 ],
  [ -1.9, 5.8 ]
]

// So I get the first column

var lats = coords.map(function (coord) {
  return coord[0];
})

// Then the second

var longs = coords.map(function (coord) {
  return coord[1];
})

// And average each column out

console.log([average(lats), average(longs)])

Example.

【问题讨论】:

  • 你在使用Google Maps Javascript API v3吗?
  • 我建议获取多边形的边界,然后使用边界的中心。
  • @geocodezip 这就是我所拥有的,我相信? “边界框”。

标签: javascript google-maps math geolocation geometry


【解决方案1】:

这应该得到任何polygonareacentroid

/*jslint sub: true, maxerr: 50, indent: 4, browser: true */
/*global console */

(function () {
    "use strict";

    function Point(x, y) {
        this.x = x;
        this.y = y;
    }

    function Region(points) {
        this.points = points || [];
        this.length = points.length;
    }

    Region.prototype.area = function () {
        var area = 0,
            i,
            j,
            point1,
            point2;

        for (i = 0, j = this.length - 1; i < this.length; j=i,i++) {
            point1 = this.points[i];
            point2 = this.points[j];
            area += point1.x * point2.y;
            area -= point1.y * point2.x;
        }
        area /= 2;

        return area;
    };

    Region.prototype.centroid = function () {
        var x = 0,
            y = 0,
            i,
            j,
            f,
            point1,
            point2;

        for (i = 0, j = this.length - 1; i < this.length; j=i,i++) {
            point1 = this.points[i];
            point2 = this.points[j];
            f = point1.x * point2.y - point2.x * point1.y;
            x += (point1.x + point2.x) * f;
            y += (point1.y + point2.y) * f;
        }

        f = this.area() * 6;

        return new Point(x / f, y / f);
    };

    var polygon = [
            {"x": -1.2, "y": 5.1},
            {"x": -1.3, "y": 5.2},
            {"x": -1.8, "y": 5.9},
            {"x": -1.9, "y": 5.8}
        ],
        region = new Region(polygon);

    console.log(region.centroid());
}());

开启jsfiddle

【讨论】:

  • 我接受这个答案是因为它明确回答了我的问题,尽管我在我的应用程序中使用了@razzak 的 Google Maps API 答案。
  • 除非你找到一些信息表明它不是。
  • 我的线性代数不是最新的。计算质心,f是什么,f = this.area() * 6背后的魔力是什么?
【解决方案2】:

这将获取任何形状的中心点作为数组 [centerX, centerY]:

var center = function (arr)
{
    var minX, maxX, minY, maxY;
    for (var i = 0; i < arr.length; i++)
    {
        minX = (arr[i][0] < minX || minX == null) ? arr[i][0] : minX;
        maxX = (arr[i][0] > maxX || maxX == null) ? arr[i][0] : maxX;
        minY = (arr[i][1] < minY || minY == null) ? arr[i][1] : minY;
        maxY = (arr[i][1] > maxY || maxY == null) ? arr[i][1] : maxY;
    }
    return [(minX + maxX) / 2, (minY + maxY) / 2];
}

另一种方式:

var center = function (arr)
{
    var x = arr.map (function (a){ return a[0] });
    var y = arr.map (function (a){ return a[1] });
    var minX = Math.min.apply (null, x);
    var maxX = Math.max.apply (null, x);
    var minY = Math.min.apply (null, y);
    var maxY = Math.max.apply (null, y);
    return [(minX + maxX) / 2, (minY + maxY) / 2];
}
getCenter (coords);

或者,如果您的浏览器支持 ECMAScript 6,那么您可以使用 Arrow functionsSpread syntax,如下所示:

var center = function (arr)
{
    var x = arr.map (xy => xy[0]);
    var y = arr.map (xy => xy[1]);
    var cx = (Math.min (...x) + Math.max (...x)) / 2;
    var cy = (Math.min (...y) + Math.max (...y)) / 2;
    return [cx, cy];
}

jsfiddle

【讨论】:

    【解决方案3】:

    在 Google Maps API v3(未测试)中获取多边形的边界(使用您的数据):

    var coords = [
      [ -1.2, 5.1 ],
      [ -1.3, 5.2 ],
      [ -1.8, 5.9 ],
      [ -1.9, 5.8 ]
    ];
    
    var bounds = new google.maps.LatLngBounds();
    for (var i = 0; i<coords.length; i++) {
       bounds.extend(new google.maps.LatLng(coords[i][0], coords[i][1]));
    }
    var center = bounds.getCenter();
    
    var latitude = center.lat();           // latitude=-1.5499999999999998
    var longitude = center.lng();          // longitude=5.5
    var coordinates = center.toUrlValue(); // coordinates=-1.55,5.5
    

    var coords = [
      [-1.2, 5.1],
      [-1.3, 5.2],
      [-1.8, 5.9],
      [-1.9, 5.8]
    ];
    
    var bounds = new google.maps.LatLngBounds();
    for (var i = 0; i < coords.length; i++) {
      bounds.extend(new google.maps.LatLng(coords[i][0], coords[i][1]));
    }
    var center = bounds.getCenter();
    
    var latitude = center.lat();
    console.log("latitude=" + latitude);
    var longitude = center.lng();
    console.log("longitude=" + longitude);
    var coordinates = center.toUrlValue();
    console.log("coordinates=" + coordinates);
    &lt;script src="https://maps.googleapis.com/maps/api/js?key=AIzaSyCkUOdZ5y7hMm0yrcCQoCvLwzdM6M8s5qk"&gt;&lt;/script&gt;

    【讨论】:

      【解决方案4】:

      这是我的 es6 解决方案,用于平均一组纬度和经度。 平均值不是确切的中心点,但在我的情况下它可以完成工作。

      getLatLonCenterFromGeom = (coords) => {
          const arrAvg = arr => arr.reduce((a,b) => a + b, 0) / arr.length;
      
          const centerLat = arrAvg(coords.map(c=>c.latitude));
          const centerLon = arrAvg(coords.map(c=>c.longitude));
      
          if (isNaN(centerLat)|| isNaN(centerLon))
              return null;
          else return {latitude: centerLat, longitude:centerLon};
      }
      

      【讨论】:

        【解决方案5】:

        我知道这不是您正在寻找的,但如果没有其他人回答,它可能会有所帮助。这是一个 PHP 函数,我用它来为我的地图应用程序找到多边形的中心点。它应该很容易转换为 javascript 供您使用。

        function getCenter($coord_array){
            $i = 0;
            $center = $coord_array[0];
            unset($coord_array[0]);
            foreach($coord_array as $key => $coord){    
                $plat = $coord[0];
                $plng = $coord[1];
                $clat = $center[0];
                $clng = $center[1];
                $mlat = ($plat + ($clat * $i)) / ($i + 1);
                $mlng = ($plng + ($clng * $i)) / ($i + 1);
                $center = array($mlat, $mlng);
                $i++;
            }
            return array($mlat, $mlng);
        }
        

        注意,多边形必须是闭合的,这意味着数组中的第一个点和数组中的最后一个点是相同的。

        将坐标字符串转换为所需数组的函数:

        function coordStringToArray($coord_string)
        {
            $coord_array = explode("\n",$coord_string);
            foreach($coord_array as $key => $coord){
                $coord_array[$key] = explode(', ',$coord);
            }
            return $coord_array;
        }
        

        原始坐标字符串示例:

        42.390576, -71.074258
        42.385822, -71.077091
        42.382461, -71.079408
        42.382018, -71.081468
        42.380496, -71.080953
        42.380433, -71.076576
        42.373902, -71.073915
        42.373078, -71.069967
        42.369273, -71.064216
        42.368892, -71.062328
        42.369527, -71.056491
        42.370288, -71.050741
        42.371619, -71.047908
        42.376185, -71.046278
        42.383476, -71.045763
        42.386139, -71.050483
        42.386202, -71.057693
        42.387597, -71.066534
        42.390259, -71.072284
        42.391210, -71.073658
        

        【讨论】:

          【解决方案6】:
          //Pure JavaScript version
          
          function getCenterPoint(polygonId){
            var p=document.getElementById(polygonId).points;
            
            //Set initial min and max values
            var minX=p[0].x, maxX=p[0].x, minY=p[0].y, maxY=p[0].y;
          
            for(var i=0;i<p.length; i++){
              if(p[i].x < minX){minX=p[i].x;}
              if(p[i].x > maxX){maxX=p[i].x;}
              if(p[i].y < minY){minY=p[i].y;}
              if(p[i].y > maxY){maxY=p[i].y;}
            }
            return [(maxX + minX)/2, (maxY + minY)/2];
          }
          

          centerPoint = getCenterPoint("MyPolygonId");

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2011-07-01
            • 1970-01-01
            • 2018-01-23
            • 2017-08-19
            • 2023-03-17
            • 1970-01-01
            • 2014-05-12
            相关资源
            最近更新 更多