找到传单多边形的中心?

2022-08-30 13:44:49

我在我创建的地图上有一堆小叶多边形。每个多边形表示不同的东西。一组特定信息显示在弹出窗口中,具体取决于用户所在的页面。我需要找到一种方法来使“弹出”气泡在其所代表的多边形的中心打开。

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

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,以便每个弹出窗口都知道可以在其中打开它的框区域(多边形)。

有人可以帮我吗?


答案 1

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

polygon.getBounds().getCenter();

答案 2

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

最简单(但最不准确的方法)是获取包含多边形的边界框的中心,如 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);

虽然点的质心是一个足够接近的近似值来欺骗我,但一位评论者指出它不是多边形的质心。

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

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