寻找Leaflet多边形的中心?

时间:2014-04-01 20:45:56

标签: javascript php html leaflet

我在我创建的地图上有一堆传单多边形。每个多边形代表不同的东西根据用户所在的页面,弹出窗口中会显示一组特定信息。我需要找到一种方法来制作" popup"气泡在它所代表的多边形的中心打开。

使用以下代码绘制每个多边形:

var L20 = [
    [74.0995, -99.92615],
    [74.14008, -99.4043],
    [74.07691, -99.33838],
    [74.03617, -99.86023]
];



var L19 = [
    [74.02559, -99.84924],
    [74.06636, -99.32739],
    [74.0029, -99.26147],
    [73.96197, -99.77783]
];

var L18 = [
    [73.95142, -99.76684],
    [73.99235, -99.25048],
    [73.92889, -99.18456],
    [73.8878, -99.69543]
];

var set1 = L.polygon([L20, L19, L18], {
    color: "#fff",
    weight: 1,
    stroke: true,
    opacity: 0.05,
    fillColor: "#346B1F",

}).addTo(map);

使用以下代码绘制弹出窗口:

var popup = L.popup({})
    .setLatLng([73.64017, -100.32715])
    .setContent(content).openOn(map);
    var popup = L.popup();

所以我需要找到一种方法让.setLatLang确定或给出多边形的中心。

我提出了3个可行的解决方案,但不确定如何解决这个问题。

  1. 找到一种方法来使用多边形的坐标来确定弹出窗口打开的多边形的中心。

  2. 调用多边形的一个点,然后偏移弹出窗口的位置。

  3. 为每个多边形使用id,因此每个弹出窗口都知道可以打开的框区域(多边形)。

  4. 有人能帮助我吗?

4 个答案:

答案 0 :(得分:44)

因为Leaflet有一段时间内置了getCenter()方法:

polygon.getBounds().getCenter();

答案 1 :(得分:23)

有几种方法可以近似多边形的质心。

最简单(但最不准确的方法)是使用polygon.getBounds().getCenter();

获取包含多边形的边界框的中心,如yarl所建议的那样

我最初用寻找点的质心的公式回答了这个问题,可以通过平均其顶点坐标找到。

var getCentroid = function (arr) { 
    return arr.reduce(function (x,y) {
        return [x[0] + y[0]/arr.length, x[1] + y[1]/arr.length] 
    }, [0,0]) 
}

centerL20 = getCentroid(L20);

虽然点的质心非常接近于欺骗我,但是一位评论者指出它不是多边形的质心

基于centroid of a non-self-intersecting closed polygon公式的实现给出了正确的结果:

var getCentroid2 = function (arr) {
    var twoTimesSignedArea = 0;
    var cxTimes6SignedArea = 0;
    var cyTimes6SignedArea = 0;

    var length = arr.length

    var x = function (i) { return arr[i % length][0] };
    var y = function (i) { return arr[i % length][1] };

    for ( var i = 0; i < arr.length; i++) {
        var twoSA = x(i)*y(i+1) - x(i+1)*y(i);
        twoTimesSignedArea += twoSA;
        cxTimes6SignedArea += (x(i) + x(i+1)) * twoSA;
        cyTimes6SignedArea += (y(i) + y(i+1)) * twoSA;
    }
    var sixSignedArea = 3 * twoTimesSignedArea;
    return [ cxTimes6SignedArea / sixSignedArea, cyTimes6SignedArea / sixSignedArea];        
}

答案 2 :(得分:13)

您尝试解决的问题称为无法访问的极点问题。通过找到边界框的中心,找不到将标签放在多边形中的最佳位置。考虑字母U形状的多边形。边界框的中心将标签放在多边形之外。我花了很长时间才找到这个杰出的图书馆:https://github.com/mapbox/polylabel

来自 README.MD:

  

一种快速算法,用于查找不可访问性的多边形极点,即多边形轮廓中最远的内部点(不要与质心混淆),实现为JavaScript库。用于在多边形上最佳放置文本标签。

     

这是一种迭代网格算法,受Garcia-Castellanos&amp; Lombardo,2007。与论文中的不同,这个算法:

     
      
  • 保证在给定精度内找到全局最优
  •   
  • 快了很多倍(10-40x)
  •   
     

用法:

     

给定GeoJSON格式和精度的多边形坐标(默认为1.0),Polylabel以[x,y]格式返回不可访问坐标的极点。

var p = polylabel(polygon, 1.0);

Pole of Inaccessibility

  

算法的工作原理:

     

这是一种迭代的基于网格的算法,首先用大方块覆盖多边形,然后按照最有希望的单元的顺序迭代分割它们,同时积极地修剪不感兴趣的单元格。

     
      
  1. 生成完全覆盖多边形的初始方形单元格(单元格大小等于宽度或高度,以较低者为准)。计算从每个像元的中心到外多边形的距离,如果该点在多边形之外(通过光线投射检测),则使用负值。
  2.   
  3. 将单元格放入优先级队列,该队列按单元格内点的最大潜在距离排序,定义为距中心的距离和单元格半径之和(等于cell_size * sqrt(2)/ 2)。
  4.   
  5. 计算距离多边形质心的距离,并选择它作为第一个“迄今为止最好的”。
  6.   
  7. 逐个从优先级队列中拉出单元格。如果单元格的距离优于当前最佳距离,请将其保存。然后,如果单元格可能包含当前最佳的解决方案(cell_max - best_dist&gt; precision),则将其拆分为4个子单元格并将它们放入队列中。
  8.   
  9. 当我们耗尽队列并将最佳小区的中心作为不可访问的极点返回时停止算法。它将保证在给定精度范围内成为全局最优。
  10.   

The most distant internal point from the polygon outline

答案 3 :(得分:0)

假设每个多边形只有4个边,这很简单

var L20 = [
[74.0995, -99.92615],
[74.14008, -99.4043],
[74.07691, -99.33838],
[74.03617, -99.86023]
];

使用这个例子得到max和min lat:74.03617和74.14008分别如此相同:-99.92615和99.33838

然后得到每个的中间值:(max - min)/ 2 = 0.051955和-0.293885然后将它们添加到最小量

为您提供74.088125, -99.632265

的中心