web-dev-qa-db-fra.com

Trouver le centre du polygone Leaflet?

J'ai un groupe de polygones de tracts sur une carte que j'ai créée. Chaque polygone représente quelque chose de différent. Un ensemble d'informations spécifiques est affiché dans une fenêtre contextuelle en fonction de la page sur laquelle l'utilisateur se trouve. Je dois trouver un moyen de faire en sorte que la bulle "popup" s'ouvre au centre du polygone qu'elle représente.

Chaque polygone est dessiné en utilisant le code suivant:

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

La popup est dessinée en utilisant le code suivant:

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

Il me faut donc trouver un moyen pour que .setLatLang détermine ou reçoive le centre du polygone.

Je suis venu avec 3 solutions qui peuvent fonctionner, pas sûr de savoir comment s'y prendre.

  1. trouvez un moyen d'utiliser les coordonnées d'un polygone pour déterminer le centre du polygone où la fenêtre contextuelle va s'ouvrir.

  2. appelle un point du polygone, puis décale la position de la fenêtre contextuelle.

  3. Utilisez un identifiant pour chaque polygone, de sorte que chaque fenêtre contextuelle connaisse la zone de la boîte (polygone) dans laquelle elle peut être ouverte.

Quelqu'un peut m'aider s'il vous plaît?

15
Nxlevel

Il existe plusieurs façons d’approcher le centroïde d’un polygone.

La méthode la plus simple (mais la moins précise) consiste à obtenir le centre du cadre de sélection contenant le polygone, comme l'a suggéré yarl, à l'aide de polygon.getBounds().getCenter();.

J'ai initialement répondu à la question avec la formule pour trouver le centroïde des points, ce qui peut être trouvé en faisant la moyenne des coordonnées de ses sommets. 

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

Bien que le centroïde des points soit une approximation assez proche pour me piéger, un commentateur a souligné que ce n'était pas le centroïde du polygone

Une implémentation basée sur la formule pour a centroïde d'un polygone fermé non auto-intersectant donne le résultat correct: 

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];        
}
23
Steve Clanton

Depuis un certain temps, Leaflet a intégré getCenter () method:

polygon.getBounds().getCenter();
43
yarl

Le problème que vous essayez de résoudre s'appelle le pôle d'inaccessibilité problème. Trouver le meilleur endroit pour placer une étiquette dans un polygone n'est pas complètement résolu en trouvant le centre du cadre de sélection. Considérons un polygone ayant la forme de la lettre U. Le centre du cadre de sélection place l'étiquette en dehors du polygone. Il m'a fallu une éternité pour trouver cette bibliothèque exceptionnelle: https://github.com/mapbox/polylabel

À partir du README.MD:

Un algorithme rapide pour trouver le pôle d’inaccessibilité polygonal, le point interne le plus éloigné du contour du polygone (à ne pas confondre avec le centroïde), implémenté sous la forme d’une bibliothèque JavaScript. Utile pour le placement optimal d'une étiquette de texte sur un polygone.

C'est un algorithme de grille itératif, inspiré du papier de Garcia-Castellanos & Lombardo, 2007. Contrairement à celui de l'article, cet algorithme:

  • garantit la recherche de l’optimum global dans les limites de la précision donnée
  • est plusieurs fois plus rapide (10-40x)

Usage:

Étant donné les coordonnées de polygone au format et à la précision de type GeoJSON (1.0 par défaut), Polylabel renvoie la coordonnée du pôle d’inaccessibilité au format [x, y].

var p = polylabel(polygon, 1.0);

 Pole of Inaccessibility

Comment fonctionne l'algorithme:

Il s'agit d'un algorithme itératif basé sur une grille, qui commence par recouvrir le polygone de grandes cellules carrées, puis en les séparant de manière itérative dans l'ordre des plus prometteurs, tout en éliminant de manière agressive les cellules inintéressantes.

  1. Générez des cellules carrées initiales couvrant complètement le polygone (avec une taille de cellule égale à la largeur ou à la hauteur, selon la valeur la plus basse). Calculez la distance entre le centre de chaque cellule et le polygone extérieur, en utilisant une valeur négative si le point se trouve en dehors du polygone (détecté par projection de rayons).
  2. Placez les cellules dans une file d'attente prioritaire triée par la distance potentielle maximale d'un point à l'intérieur d'une cellule, définie comme la somme de la distance du centre et du rayon de la cellule (égal à cell_size * sqrt (2)/2).
  3. Calculez la distance entre le centroïde du polygone et sélectionnez-le comme premier "meilleur jusqu'ici".
  4. Extrayez les cellules de la file d'attente prioritaire une à une. Si la distance d'une cellule est meilleure que la meilleure actuelle, enregistrez-la en tant que telle. Ensuite, si la cellule contient potentiellement une meilleure solution que la meilleure actuelle (cell_max - best_dist> precision), divisez-la en 4 cellules enfants et placez-les dans la file d'attente.
  5. Arrêtez l'algorithme une fois la file d'attente épuisée et renvoyez le centre de la meilleure cellule en tant que pôle d'inaccessibilité. Il sera garanti d'être un optimum global dans les limites de la précision donnée.

 The most distant internal point from the polygon outline

12
Kristopher

en supposant que chaque polygone n'a que 4 côtés, c'est simple

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

en utilisant cet exemple, get max et min lat: 74.03617 et 74.14008 respectivement, donc pareil pour long: -99.92615 et 99.33838 respectivement

Ensuite, obtenez la valeur moyenne pour chacun: (max - min)/2 = 0.051955 et -0.293885, puis ajoutez-les au minimum

vous donne un centre de 74.088125, -99.632265

0
Graham Ritchie