web-dev-qa-db-fra.com

Comment combiner des polygones complexes?

Étant donné deux polygones:

POLYGON((1 0, 1 8, 6 4, 1 0))
POLYGON((4 1, 3 5, 4 9, 9 5, 4 1),(4 5, 5 7, 6 7, 4 4, 4 5))

Comment puis-je calculer l'union (polygone combiné)?

 enter image description here

Exemple de Dave utilise SQL Server pour produire l'union, mais je dois accomplir la même chose dans le code. Je cherche une formule mathématique ou un exemple de code dans n'importe quelle langue qui expose les mathématiques réelles. Je tente de produire des cartes qui combinent les pays de manière dynamique en régions. J'ai posé une question connexe ici: Regroupement des formes géographiques

67
grenade

C'est une très bonne question. J'ai implémenté le même algorithme sur c # il y a quelque temps. L’algorithme construit un contour commun de deux polygones (c’est-à-dire construit une union sans trous). C'est ici.


Goal

Étape 1. Créez un graphique décrivant les polygones.

Entrée: premier polygone (n points), deuxième polygone (m points). Sortie: graphique. Sommet - polygone du point d'intersection. 

Nous devrions trouver des intersections. Parcourez tous les côtés des polygones des deux polygones [O (n * m)] et recherchez les intersections. 

  • Si aucune intersection n’est trouvée, ajoutez simplement des sommets et connectez-les. 

  • Si des intersections sont trouvées, classez-les par longueur en fonction de leur point de départ, ajoutez tous les sommets (Début, fin et intersections) et connectez-les (déjà dans Ordre trié) au bord .Graph

Étape 2. Vérifier le graphique construit

Si nous n'avons trouvé aucun point d'intersection lors de la création du graphique, l'une des conditions suivantes est remplie:

  1. Polygon1 contient polygone2 - retourne polygone1
  2. Polygon2 contient polygone1 - retourne polygone2
  3. Polygon1 et polygon2 ne se croisent pas. Renvoie polygon1 ET polygone2. 

Étape 3. Recherchez le sommet inférieur gauche.

Trouvez les coordonnées x et y minimales (minx, miny). Trouvez ensuite la distance minimale entre (minx, miny) et les points du polygone. Ce point sera le point en bas à gauche. 

Left-bottom point

Étape 4. Construire un contour commun.

Nous commençons à parcourir le graphique à partir du point inférieur gauche et continuons jusqu'à ce que nous y revenions. Au début, nous marquons tous les bords comme non visités. À chaque itération, vous devez sélectionner le point suivant et le marquer comme visité. 

Pour choisir le point suivant, choisissez un bord avec un angle interne maximal dans le sens anti-horaire.

Je calcule deux vecteurs: vector1 pour Edge actuel et vector2 pour chaque prochain Edge non visité (comme présenté dans l'image).

Pour les vecteurs, je calcule:

  1. Produit scalaire (produit scalaire). Il retourne une valeur liée à un angle entre vecteurs. 
  2. Produit vectoriel (produit croisé). Il retourne un nouveau vecteur. Si la coordonnée z de ce vecteur Est positive, le produit scalaire me donne un angle droit en sens antihoraire. Sinon (la coordonnée z est négative), I calculer un angle entre les vecteurs comme étant un angle de 360 ​​à partir du scalaire produit.

En conséquence, je reçois un bord (et un sommet suivant correspondant) avec l'angle maximum. 

J'ajoute à la liste des résultats chaque sommet passé. La liste de résultats est le polygone d'union .Vectors

Remarques

  1. Cet algorithme nous permet de fusionner plusieurs polygones - pour appliquer de manière itérative des paires de polygones.
  2. Si vous avez un chemin composé de nombreuses courbes et lignes de Bézier, vous devez d'abord l'aplatir.
53
xtmq

Vous devez déterminer quels points se trouvent à l’intérieur . Après avoir supprimé ces points, vous pouvez insérer un ensemble de points "extérieurs" dans l'autre. Vos points d’insertion (par exemple, où la flèche dans l’image est à droite) sont ceux où vous avez dû supprimer des points des jeux d’entrée.

6
Benjamin Bannier

Bonne question! Je n'ai jamais tenté cela auparavant, mais je vais tenter le coup maintenant.

Premièrement: vous devez savoir où ces deux formes se chevauchent. Pour ce faire, vous pouvez examiner chaque bord du polygone A et voir où il se croise, ainsi que le contour du polygone B. Dans cet exemple, il devrait y avoir deux points d'intersection.

Ensuite: Créez la forme de l'union. Vous pouvez prendre tous les sommets dans A et B, ainsi que les points d'intersection, puis exclure les sommets contenus dans la forme finale. Pour trouver ces points, il semble que vous puissiez trouver n'importe quel sommet de A situé à l'intérieur de B et tout sommet de B situé à l'intérieur de A.

Essayez gpc .

3
lhf

Une solution que j'ai vue en utilisant des arbres BSP est décrite ici .

Fondamentalement, il décrit l'intersection en termes d'une union des arêtes du polygone A qui sont à l'intérieur du polygone B (y compris les arêtes partielles et calculées à l'aide de BSP tree ). Ensuite, vous pouvez définir A/B comme ~ (~UNE/\~B), où ~ désigne l’inversion du polygone,/indique l’union et/\ désigne l’intersection.

2
nornagon

En regroupant les pays, j'espère qu'il n'y aura pas de chevauchement - vous pourriez utiliser un algorithme assez naïf qui recherche les sommets partagés - une vue simple consisterait à parcourir les points d'un polygone, en vérifiant s'il en existe un autre , et partage le même point suivant ou précédent pour voir s’il existe une correspondance. Ensuite, supprimez simplement le sommet partagé pour créer votre union.

1
Rowland Shaw

Il me fallait aujourd'hui résoudre le même problème et trouver la solution avec cette librairie: http://www.cs.man.ac.uk/~toby/alan/software/ .

Il a beaucoup d'implémentations de langage la liste ici incluant Java, Obj-C, C #, Lua, python et plus.

1
ademar111190

J'ai fait face au même problème et j'ai résolu le problème en utilisant la méthode suivante

Enveloppe Cython pour la traduction en C++ de la bibliothèque Clipper d’Angus Johnson (ver. 6.4.2) https://github.com/fonttools/pyclipper

pc = pyclipper.Pyclipper()
def get_poly_union(polygons):
    pc.AddPaths(polygons, pyclipper.PT_SUBJECT, True)
    solution = pc.Execute(pyclipper.CT_UNION, pyclipper.PFT_NONZERO, pyclipper.PFT_NONZERO)
    return solution[0]

print_image = image.copy()
solution = get_poly_union(polygons_array) 
#polygons_array=[polygon,polygon,polygon, ...,polygon] and polygon=[point,point,point...,point]

cv2.drawContours(print_image, [np.asarray(solution)], -1, (0, 255, 0), 2)

plt.imshow(print_image)
1

C'est une question très ancienne mais Union_ function de Boost a fonctionné pour moi.

Voir cet extrait ci-dessous:

#include <iostream>
#include <vector>

#include <boost/geometry.hpp>
#include <boost/geometry/geometries/point_xy.hpp>
#include <boost/geometry/geometries/polygon.hpp>

#include <boost/foreach.hpp>


int main()
{
    typedef boost::geometry::model::polygon<boost::geometry::model::d2::point_xy<double> > polygon;

    polygon green, blue;

    boost::geometry::read_wkt(
        "POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))", green);

    boost::geometry::read_wkt(
        "POLYGON((5 5, 5 15, 15 15, 15 5, 5 5))", blue);

    std::vector<polygon> output;
    boost::geometry::union_(green, blue, output);

    int i = 0;
    std::cout << "green || blue:" << std::endl;
    BOOST_FOREACH(polygon const& p, output)
    {
        std::cout << i++ << ": " << boost::geometry::area(p) << std::endl;

        for (int i = 0; i < p.outer().size(); i++)
        {
            std::cout << p.outer().at(i).x() << " " << p.outer().at(i).y() << std::endl;
        }
    }



    return 0;
}
0
Yonatan