寻找Leaflet多边形的中心?

Nxl*_*vel 19 html javascript php 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);
Run Code Online (Sandbox Code Playgroud)

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

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

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

我想出了3个可能有用的解决方案,不知道如何去做.

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

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

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

有谁可以帮助我吗?

yar*_*arl 46

由于Leaflet有一段时间内置了getCenter()方法:

polygon.getBounds().getCenter();
Run Code Online (Sandbox Code Playgroud)

  • 这应该是公认的答案.另请注意,您甚至不需要多边形对象(我愚蠢地试图获取一段时间).您可以在任何Bounds对象上运行它,因此同样的事情适用于图层,即layer.getBounds().getCenter(); (3认同)
  • 如果多边形的形状为U,则不起作用.边界框的中心将使其位于多边形之外. (3认同)
  • 对于大多数形状,边界框的中心将足够接近多边形的中心.直角三角形和L形区域是差异明显的例子,但对于大多数情况来说这要好得多,我同意. (2认同)

Ste*_*ton 29

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

最简单(但最不准确的方法)是获取包含多边形的边界框的中心,如yarl建议的那样, polygon.getBounds().getCenter();

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

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);
Run Code Online (Sandbox Code Playgroud)

虽然点的质心足够逼近我,但是一位评论者指出它并不是多边形的质心.

基于非自相交闭合多边形质心公式的实现给出了正确的结果:

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];        
}
Run Code Online (Sandbox Code Playgroud)

  • 这个答案是不正确的.想象一个右侧略微圆角的矩形.您的方法将质心放在右边缘,因为左侧的两个顶点在平均值中的表示不足,而在右侧则是任意大的数字.如果每个点"重量"相同,这是有效的,但如果每个单位区域"重量"相同,则不是这样,这实际上是每个人在谈论多边形的质心时的意思. (2认同)

Kri*_*her 14

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

来自README.MD:

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

这是一个迭代网格算法,受到Garcia-Castellanos&Lombardo,2007年的论文的启发.与论文中的不同,这个算法:

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

用法:

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

var p = polylabel(polygon, 1.0);

无法接触的极点

算法如何工作:

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

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

多边形轮廓中最远的内部点