简体   繁体   English

找到传单多边形的中心?

[英]Finding the center of Leaflet polygon?

I have a bunch of leaflet polygons on a map I created.我在创建的地图上有一堆传单多边形。 Each polygon represents something different.每个多边形代表不同的东西。 A specific set of information is displayed in a popup depending on the page the user is on.根据用户所在的页面,在弹出窗口中显示一组特定的信息。 I need to find a way to make the "popup" bubble open in the center of the polygon it represents.我需要找到一种方法来在它所代表的多边形的中心打开“弹出”气泡。

Each polygon is drawn using the following code:每个多边形都使用以下代码绘制:

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);

The popup is drawn using the following code:使用以下代码绘制弹出窗口:

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

So I need to find a way for .setLatLang to determin or be given the center of the polygon.所以我需要找到一种方法让.setLatLang确定或被赋予多边形的中心。

I came up with 3 solutions that may work, not sure how to go about it.我想出了 3 个可能有效的解决方案,但不知道如何去做。

  1. find a way to use the coordinates of a polygon to determine the center of the polygon where the popup will open.找到一种使用多边形坐标来确定弹出窗口将打开的多边形中心的方法。

  2. call one point of the polygon, then offset the position of the popup.调用多边形的一点,然后偏移弹出窗口的位置。

  3. Use an id for each polygon, so each popup knows the box area (polygon) it can be opened in.为每个多边形使用一个 id,因此每个弹出窗口都知道可以在其中打开的框区域(多边形)。

Can someone help me please?有人能帮助我吗?

一段时间以来,Leaflet 内置了getCenter()方法:

polygon.getBounds().getCenter();

There are a few ways to approximate the centroid of a polygon.有几种方法可以近似多边形的质心。

The easiest (but least accurate method) is to get the center of the bounding box that contains the polygon, as yarl suggested, using polygon.getBounds().getCenter();最简单(但最不准确的方法)是获取包含多边形的边界框的中心,正如 yarl 建议的那样,使用polygon.getBounds().getCenter();

I originally answered the question with the formula for finding the centroid of the points, which can be found by averaging the coordinates of its vertices.我最初用求点的质心的公式回答了这个问题,可以通过对其顶点坐标求平均值来找到。

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);

While the centroid of the points is a close enough approximation to trick me, a commenter pointed out that it is not the centroid of the polygon .虽然点的质心足够接近以欺骗我,但评论者指出它不是多边形的质心。

An implementation based on the formula for a centroid of a non-self-intersecting closed polygon gives the correct result:基于非自相交闭合多边形质心公式的实现给出了正确的结果:

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];        
}

The problem you are trying to solve is called the pole of inaccessibility problem.您试图解决的问题称为无法访问问题的极点 Finding the best place to put a label in a polygon isn't completely solved by finding the center of the bounding box.通过找到边界框的中心并不能完全解决在多边形中放置标签的最佳位置。 Consider a polygon in the shape of the letter U. The center of the bounding box puts the label outside of the polygon.考虑一个字母 U 形状的多边形。边界框的中心将标签放在多边形的外面。 It took me forever to find this outstanding library: https://github.com/mapbox/polylabel我花了很长时间才找到这个优秀的库: https : //github.com/mapbox/polylabel

From the README.MD:来自README.MD:

A fast algorithm for finding polygon pole of inaccessibility, the most distant internal point from the polygon outline (not to be confused with centroid), implemented as a JavaScript library.一种快速算法,用于查找无法访问的多边形极点,即距离多边形轮廓最远的内部点(不要与质心混淆),作为 JavaScript 库实现。 Useful for optimal placement of a text label on a polygon.用于在多边形上最佳放置文本标签。

It's an iterative grid algorithm, inspired by paper by Garcia-Castellanos & Lombardo, 2007. Unlike the one in the paper, this algorithm:这是一种迭代网格算法,灵感来自 Garcia-Castellanos & Lombardo,2007 年的论文。与论文中的不同,该算法:

  • guarantees finding global optimum within the given precision保证在给定精度内找到全局最优
  • is many times faster (10-40x)快很多倍(10-40 倍)

Usage:用法:

Given polygon coordinates in GeoJSON-like format and precision (1.0 by default), Polylabel returns the pole of inaccessibility coordinate in [x, y] format.给定类似 GeoJSON 格式的多边形坐标和精度(默认为 1.0),Polylabel 以 [x, y] 格式返回无法访问坐标的极点。

var p = polylabel(polygon, 1.0);

无法接近的极点

How the algorithm works:算法的工作原理:

This is an iterative grid-based algorithm, which starts by covering the polygon with big square cells and then iteratively splitting them in the order of the most promising ones, while aggressively pruning uninteresting cells.这是一种基于网格的迭代算法,它首先用大方形单元覆盖多边形,然后按照最有希望的顺序迭代拆分它们,同时积极修剪无趣的单元。

  1. Generate initial square cells that fully cover the polygon (with cell size equal to either width or height, whichever is lower).生成完全覆盖多边形的初始方形单元格(单元格大小等于宽度或高度,以较小者为准)。 Calculate distance from the center of each cell to the outer polygon, using negative value if the point is outside the polygon (detected by ray-casting).计算从每个单元格的中心到外部多边形的距离,如果点在多边形外部(通过光线投射检测到),则使用负值。
  2. Put the cells into a priority queue sorted by the maximum potential distance from a point inside a cell, defined as a sum of the distance from the center and the cell radius (equal to cell_size * sqrt(2) / 2).将单元格放入一个优先级队列,按照距单元格内一点的最大潜在距离排序,定义为距中心的距离和单元格半径的总和(等于 cell_size * sqrt(2) / 2)。
  3. Calculate the distance from the centroid of the polygon and pick it as the first "best so far".计算与多边形质心的距离并将其选为第一个“迄今为止最好的”。
  4. Pull out cells from the priority queue one by one.从优先级队列中一一拉出信元。 If a cell's distance is better than the current best, save it as such.如果一个单元格的距离比当前最好的要好,就这样保存它。 Then, if the cell potentially contains a better solution that the current best (cell_max - best_dist > precision), split it into 4 children cells and put them in the queue.然后,如果该单元格可能包含比当前最佳(cell_max - best_dist > precision)更好的解决方案,则将其拆分为 4 个子单元格并将它们放入队列中。
  5. Stop the algorithm when we have exhausted the queue and return the best cell's center as the pole of inaccessibility.当我们用尽队列并返回最佳单元的中心作为不可访问极点时停止算法。 It will be guaranteed to be a global optimum within the given precision.将保证在给定精度内是全局最优。

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

assuming each polygon has only 4 sides it is simple假设每个多边形只有 4 个边,这很简单

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

using this example get max and min lat: 74.03617 and 74.14008 respectively so same for long: -99.92615 and 99.33838 respectively使用这个例子得到最大和最小纬度:分别为 74.03617 和 74.14008 所以长的相同:-99.92615 和 99.33838

Then get the middle value for each: (max - min) / 2 = 0.051955 and -0.293885 then add them to the minimum amount然后得到每个的中间值:(max - min) / 2 = 0.051955 和 -0.293885 然后将它们添加到最小数量

gives you a centre of 74.088125, -99.632265给你一个74.088125, -99.632265的中心

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM