web-dev-qa-db-fra.com

Un algorithme simple pour l'intersection de polygones

Je cherche un algorithme très simple pour calculer l'intersection/le découpage des polygones . C'est-à-dire, étant donné les polygones P, Q, je souhaite trouver le polygone T qui est contenu dans P et dans Q et que je souhaite que T soit maximal parmi tous les polygones possibles.

Le temps d'exécution ne me dérange pas (j'ai quelques très petits polygones), je peux aussi me permettre d'obtenir une approximation de l'intersection des polygones (c'est-à-dire, un polygone avec moins de points, mais qui est toujours contenu dans l'intersection des polygones ).

Mais il est vraiment important pour moi que l’algorithme soit simple (tests moins coûteux) et de préférence court (moins de code).

edit: s'il vous plaît noter, je souhaite obtenir un polygone qui représente l'intersection. Je n'ai pas besoin que d'une réponse booléenne à la question de savoir si les deux polygones se croisent.

58
Elazar Leibovich

Je comprends que l’affiche originale cherchait une solution simple, mais malheureusement, il n’existe pas de solution simple. 

Néanmoins, j'ai récemment créé une bibliothèque de coupures de logiciels libres open-source (écrites en Delphi, C++ et C #) qui permet de clipser toutes sortes de polygones (y compris ceux qui se croisent automatiquement). Cette bibliothèque est assez simple à utiliser: http://sourceforge.net/projects/polyclipping/ .

50
Angus Johnson

Vous pouvez utiliser un algorithme Polygon Clipping pour rechercher l'intersection de deux polygones. Cependant, ces algorithmes ont tendance à être compliqués lorsque tous les cas Edge sont pris en compte.

Une implémentation de la coupure de polygone que vous pouvez utiliser avec votre moteur de recherche préféré est Weiler-Atherton. Article de wikipedia sur Weiler-Atherton

Alan Murta dispose d'une implémentation complète d'un clipper de polygones GPC .

Modifier:

Une autre approche consiste à diviser d’abord chaque polygone en un ensemble de triangles, plus faciles à gérer. Le théorème Deux-oreilles de Gary H. Meisters fait l'affaire. Cette page à McGill explique très bien la subdivision en triangle.

17
Doug Ferguson

Si vous utilisez C++ et que vous ne voulez pas créer l'algorithme vous-même, vous pouvez utiliser Boost.Geometry . Il utilise une version adaptée de l'algorithme de Weiler-Atherton mentionné ci-dessus.

12
Barend

Vous ne nous avez pas donné votre représentation d'un polygone. Donc, je choisis (plutôt de suggérer) un pour vous :)

Représentez chaque polygone comme un grand polygone convexe et une liste de polygones convexes plus petits qui doivent être «soustraits» de ce grand polygone convexe.

Maintenant, étant donné deux polygones dans cette représentation, vous pouvez calculer l'intersection comme suit: 

Calculez l'intersection des grands polygones convexes pour former le grand polygone de l'intersection. Puis «soustrayez» les intersections de toutes les plus petites des deux pour obtenir une liste des polygones sous-traités.

Vous obtenez un nouveau polygone suivant la même représentation. 

Étant donné que l'intersection de polygones convexes est facile, cette recherche d'intersection devrait l'être également.

Cela semble fonctionner, mais je n’y ai pas réfléchi plus en profondeur en ce qui concerne la complexité correct/temps/espace.

6
Aryabhatta

Voici une approche basée sur la triangulation qui est assez simple à mettre en œuvre et peut être exécutée en mode O (N).2). 

BTW, O (N2) est optimale pour ce problème. Imaginez deux polygones en forme de lames de fourche se coupant à angle droit. Chacun a un nombre de segments proportionnel au nombre de dents; le nombre de polygones dans l'intersection est proportionnel au carré du nombre de dents.

  1. D'abord, triangulez chaque polygone.

  2. Comparez tous les triangles de P par paire avec tous les triangles de Q pour détecter les intersections. Toute paire de triangles qui se croisent peut être divisée en triangles plus petits, chacun d'eux étant en P, en Q ou à l'intersection. (Ce que vous avez utilisé à l'étape 1 peut être réutilisé pour vous aider.) Ne conservez que les triangles qui se trouvent à l'intersection.

  3. Calculez les voisins de chaque triangle en les comparant par paires et construisez un graphique de contiguïté. Ce graphique contiendra un sous-graphe connecté pour chaque polygone dans l'intersection de P et de Q.

  4. Pour chacun de ces sous-graphes, choisissez un triangle, dirigez-vous vers Edge, puis contournez-le en produisant les segments délimitant le polygone de sortie correspondant.

5
Eric

Voici une approche simple et stupide: en entrée, discrétisez vos polygones en bitmap. Pour se croiser, ET les bitmaps ensemble. Pour produire des polygones en sortie, tracez les bords irréguliers du bitmap et lissez-les à l'aide d'un algorithme d'approximation de polygone . (Je ne me souviens pas si ce lien fournit les algorithmes les plus appropriés, il ne s'agit que du premier hit de Google. Vous pouvez essayer l'un des outils permettant de convertir des images bitmap en représentations vectorielles. Vous pourriez peut-être y faire appel sans réimplémenter l'algorithme. ?)

La partie la plus complexe serait traçant les frontières }, je pense.

Au début des années 90, je rencontrais d'ailleurs un problème de ce type au travail. Je l'ai étouffé: j'ai mis au point un algorithme (complètement différent) qui fonctionnerait avec les coordonnées d'un nombre réel, mais qui semblait se heurter à une pléthore de cas dégénérés complètement irréversible face aux réalités de la virgule flottante . Peut-être qu'avec l'aide d'Internet, j'aurais mieux fait!

4
Darius Bacon

La façon dont j'ai travaillé sur le même problème

  1. briser le polygone en segments de ligne
  2. trouver la ligne d'intersection en utilisant IntervalTrees ou LineSweepAlgo
  3. trouver un chemin fermé en utilisant GrahamScanAlgo pour trouver un chemin fermé avec des sommets adjacents
  4. Renvoi 3. avec DinicAlgo pour les dissoudre

note: mon scénario était différent étant donné que les polygones avaient un sommet commun. Mais espérons que cela peut aider

0
Ansh David

Je n'ai pas de solution très simple, mais voici les principales étapes pour l'algorithme real:

  1. Créez une double liste chaînée personnalisée pour les sommets des polygones et les arêtes Utiliser std::list ne suffira pas, car vous devez permuter vous-même les pointeurs/décaleurs précédents et précédents .__ pour une opération spéciale sur les nœuds C’est le seul moyen d’avoir un code simple et cela donnera de bonnes performances.
  2. Trouvez les points d'intersection en comparant chaque paire d'arêtes. Note Que comparer chaque paire d’Edge donnera O (N²) temps, mais améliorer L’algorithme en O (N · logN) sera facile par la suite. Pour certaines paires d'arêtes .__ (disons a → b et c → d), le point d'intersection est trouvé en utilisant Le paramètre (de 0 à 1) sur l'arête a → b, qui est donné par tₐ = d₀/(d₀-d₁), où d₀ est (ca) × (ba) et d₁ est (da) × (ba). × est Le produit transversal 2D tel que p × q = pₓ · qᵧ-pᵧ · qₓ. Après avoir trouvé tₐ, Trouver le point d'intersection, c'est l'utiliser comme paramètre d'interpolation linéaire Sur le segment a → b: P = a + tₐ (b-a)
  3. Séparez chaque bord en ajoutant des sommets (et des nœuds dans votre liste liée) Où les segments se croisent.
  4. Ensuite, vous devez traverser les nœuds aux points d'intersection. Il s’agit de L’opération pour laquelle vous deviez créer une liste personnalisée avec double lien Vous devez échanger une paire de pointeurs next (et mettre à jour les pointeurs previous en conséquence).

Ensuite, vous avez le résultat brut de l'algorithme de résolution d'intersection de polygones. Normalement, vous souhaiterez sélectionner une région en fonction du nombre d'enroulement de chaque région. Recherchez numéro de polygone pour une explication à ce sujet.

Si vous souhaitez créer un algorithme O (N · logN) à partir de celui-ci, vous devez faire exactement la même chose, sauf que vous le faites dans un algorithme de balayage de ligne. Cherchez algorithme de Bentley Ottman. L'algorithme interne sera le même, avec la seule différence que vous aurez un nombre réduit d'arêtes à comparer, à l'intérieur de la boucle.

0
Dom