Ayant une liste de points, comment puis-je trouver s'ils sont dans le sens horaire?
Par exemple:
point[0] = (5,0)
point[1] = (6,4)
point[2] = (4,5)
point[3] = (1,5)
point[4] = (1,0)
dirait qu'il est anti-horaire (ou anti-horaire, pour certaines personnes).
Réponses:
Certaines des méthodes suggérées échoueront dans le cas d'un polygone non convexe, comme un croissant. En voici un simple qui fonctionnera avec des polygones non convexes (il fonctionnera même avec un polygone auto-intersecté comme un chiffre huit, vous indiquant s'il est principalement dans le sens horaire).
Somme sur les bords, (x 2 - x 1 ) (y 2 + y 1 ). Si le résultat est positif, la courbe est dans le sens horaire, s'il est négatif, la courbe est dans le sens antihoraire. (Le résultat est le double de la zone fermée, avec une convention +/-.)
la source
Sum( (x[(i+1) mod N] - x[i]) * (y[i] + y[(i+1) mod N]) )
pour i = 0 à N-1. C'est à dire, doit prendre l'index Modulo N (N ≡ 0
) La formule ne fonctionne que pour les polygones fermés . Les polygones n'ont pas de bords imaginaires.Le produit croisé mesure le degré de perpendiculaire de deux vecteurs. Imaginez que chaque arête de votre polygone soit un vecteur dans le plan xy d'un espace xyz tridimensionnel (3-D). Alors le produit croisé de deux bords successifs est un vecteur dans la direction z (direction z positive si le deuxième segment est dans le sens horaire, moins direction z si c'est dans le sens antihoraire). La magnitude de ce vecteur est proportionnelle au sinus de l'angle entre les deux bords d'origine, il atteint donc un maximum quand ils sont perpendiculaires, et diminue progressivement pour disparaître lorsque les bords sont colinéaires (parallèles).
Donc, pour chaque sommet (point) du polygone, calculez la magnitude du produit croisé des deux bords adjacents:
Étiquetez donc les bords consécutivement, de même que
edgeA
le segment depoint0
verspoint1
etedgeB
entrepoint1
àpoint2
...
edgeE
est entrepoint4
etpoint0
.Alors le sommet A (
point0
) est entreedgeE
[Depoint4
àpoint0
]edgeA
[Depoint0
à `point1 'Ces deux arêtes sont elles-mêmes vecteurs, dont les coordonnées x et y peuvent être déterminées en soustrayant les coordonnées de leurs points de début et de fin:
edgeE
=point0
-point4
=(1, 0) - (5, 0)
=(-4, 0)
etedgeA
=point1
-point0
=(6, 4) - (1, 0)
=(5, 4)
etEt le produit vectoriel de ces deux bords adjacents est calculée en utilisant le facteur déterminant de la matrice suivante, qui est réalisée en mettant les coordonnées des deux vecteurs ci - dessous les symboles représentant les trois axes de coordonnées (
i
,j
, etk
). La troisième coordonnée (zéro) est là parce que le concept de produit croisé est une construction 3D, et donc nous étendons ces vecteurs 2D en 3D afin d'appliquer le produit croisé:Étant donné que tous les produits croisés produisent un vecteur perpendiculaire au plan de deux vecteurs en cours de multiplication, le déterminant de la matrice ci-dessus n'a qu'une
k
composante, (ou axe z).La formule pour calculer la magnitude de la
k
composante de l'axe ou z esta1*b2 - a2*b1 = -4* 4 - 0* 1
=-16
La magnitude de cette valeur (
-16
), est une mesure du sinus de l'angle entre les 2 vecteurs d'origine, multipliée par le produit des magnitudes des 2 vecteurs.En fait, une autre formule pour sa valeur est
A X B (Cross Product) = |A| * |B| * sin(AB)
.Donc, pour revenir à une mesure de l'angle, vous devez diviser cette valeur, (
-16
), par le produit des grandeurs des deux vecteurs.|A| * |B|
=4 * Sqrt(17)
=16.4924...
Donc, la mesure du péché (AB) =
-16 / 16.4924
=-.97014...
Il s'agit de mesurer si le segment suivant après le sommet s'est courbé à gauche ou à droite, et de combien. Il n'est pas nécessaire de prendre l'arc sinus. Tout ce qui nous importera, c'est son ampleur, et bien sûr son signe (positif ou négatif)!
Faites cela pour chacun des 4 autres points autour du chemin fermé et additionnez les valeurs de ce calcul à chaque sommet.
Si la somme finale est positive, vous êtes allé dans le sens horaire, négatif, anti-horaire.
la source
Je suppose que c'est une assez vieille question, mais je vais quand même jeter une autre solution, car elle est simple et peu mathématique - elle utilise simplement l'algèbre de base. Calculez la zone signée du polygone. S'il est négatif, les points sont dans le sens horaire, s'il est positif, ils sont dans le sens antihoraire. (Ceci est très similaire à la solution Beta.)
Calculez la zone signée: A = 1/2 * (x 1 * y 2 - x 2 * y 1 + x 2 * y 3 - x 3 * y 2 + ... + x n * y 1 - x 1 * y n )
Ou en pseudo-code:
Notez que si vous ne faites que vérifier la commande, vous n'avez pas à vous soucier de diviser par 2.
Sources: http://mathworld.wolfram.com/PolygonArea.html
la source
previousPoint
pour la prochaine itération. Avant de démarrer la boucle, définissezpreviousPoint
le dernier point du tableau. Le compromis est une copie de variable locale supplémentaire mais moins d'accès au tableau. Et surtout, ne pas avoir à toucher le tableau d'entrée.Trouvez le sommet avec le plus petit y (et le plus grand x s'il y a des liens). Soit le sommet
A
et le sommet précédent de la listeB
et le sommet suivant de la listeC
. Calculez maintenant le signe du produit croisé deAB
etAC
.Références:
Comment trouver l'orientation d'un polygone simple? dans la foire aux questions: comp.graphics.algorithms .
Orientation des courbes sur Wikipedia.
la source
O(1)
solution. Toutes les autres réponses donnent desO(n)
solutions pourn
le nombre de points de polygone. Pour des optimisations encore plus approfondies, consultez la sous-section Considérations pratiques du fantastique article d' orientation sur les courbes de Wikipedia .O(1)
que si (A) ce polygone est convexe (auquel cas tout sommet arbitraire réside sur la coque convexe et suffit donc) ou (B) vous connaissez déjà le sommet avec la plus petite coordonnée Y. Si ce n'est pas le cas (c'est-à-dire que ce polygone n'est pas convexe et que vous n'en savez rien), uneO(n)
recherche est requise. Puisqu'aucune sommation n'est requise, cependant, c'est encore beaucoup plus rapide que toute autre solution pour les polygones simples.Voici une implémentation C # simple de l'algorithme basé sur cette réponse .
Supposons que nous avons un
Vector
type ayantX
et desY
propriétés de typedouble
.%
est l'opérateur modulo ou reste effectuant l'opération modulo qui ( selon Wikipedia ) trouve le reste après division d'un nombre par un autre.la source
Commencez à l'un des sommets et calculez l'angle sous-tendu par chaque côté.
Le premier et le dernier seront nuls (alors sautez-les); pour le reste, le sinus de l'angle sera donné par le produit croisé des normalisations à la longueur unitaire de (point [n] -point [0]) et (point [n-1] -point [0]).
Si la somme des valeurs est positive, votre polygone est dessiné dans le sens inverse des aiguilles d'une montre.
la source
Pour ce que cela vaut, j'ai utilisé ce mixin pour calculer l'ordre d'enroulement pour les applications Google Maps API v3.
Le code exploite l'effet secondaire des zones de polygones: un ordre d'enroulement dans le sens horaire des sommets donne une zone positive, tandis qu'un ordre d'enroulement dans le sens antihoraire des mêmes sommets produit la même zone qu'une valeur négative. Le code utilise également une sorte d'API privée dans la bibliothèque de géométrie de Google Maps. Je me sentais à l'aise de l'utiliser - à vos risques et périls.
Exemple d'utilisation:
Exemple complet avec tests unitaires @ http://jsfiddle.net/stevejansen/bq2ec/
la source
Une implémentation de la réponse de Sean en JavaScript:
Je suis sûr que c'est vrai. Cela semble fonctionner :-)
Ces polygones ressemblent à ceci, si vous vous demandez:
la source
Il s'agit de la fonction implémentée pour OpenLayers 2 . La condition pour avoir un polygone dans le sens horaire est
area < 0
, cela est confirmé par cette référence .la source
Si vous utilisez Matlab, la fonction
ispolycw
renvoie true si les sommets du polygone sont dans le sens des aiguilles d'une montre.la source
Comme expliqué également dans cet article de Wikipedia Orientation de la courbe , étant donné 3 points
p
,q
etr
sur le plan (c'est-à-dire avec les coordonnées x et y), vous pouvez calculer le signe du déterminant suivantSi le déterminant est négatif (c'est-à-dire
Orient(p, q, r) < 0
), alors le polygone est orienté dans le sens horaire (CW). Si le déterminant est positif (c'est-à-direOrient(p, q, r) > 0
), le polygone est orienté dans le sens antihoraire (CCW). Le déterminant est zéro (c'est-à-direOrient(p, q, r) == 0
) si pointsp
,q
etr
sont colinéaires .Dans la formule ci-dessus, nous ajoutons ceux devant les coordonnées de
p
,q
etr
parce que nous utilisons des coordonnées homogènes .la source
Code C # pour implémenter la réponse de lhf :
la source
Je pense que pour que certains points soient donnés dans le sens horaire, tous les bords doivent être positifs non seulement la somme des bords. Si un bord est négatif, au moins 3 points sont donnés dans le sens antihoraire.
la source
Ma solution C # / LINQ est basée sur les conseils produits croisés de @charlesbretana ci-dessous. Vous pouvez spécifier une normale de référence pour l'enroulement. Cela devrait fonctionner tant que la courbe est principalement dans le plan défini par le vecteur haut.
avec un test unitaire
la source
Voici ma solution en utilisant les explications des autres réponses:
la source
Une méthode beaucoup plus simple sur le plan informatique, si vous connaissez déjà un point à l'intérieur du polygone :
Choisissez n'importe quel segment de ligne dans le polygone d'origine, les points et leurs coordonnées dans cet ordre.
Ajoutez un point «intérieur» connu et formez un triangle.
Calculez CW ou CCW comme suggéré ici avec ces trois points.
la source
Après avoir testé plusieurs implémentations peu fiables, l'algorithme qui a fourni des résultats satisfaisants concernant l'orientation CW / CCW hors de la boîte était celui publié par OP dans ce fil (
shoelace_formula_3
).Comme toujours, un nombre positif représente une orientation CW, tandis qu'un nombre négatif CCW.
la source
Voici la solution swift 3.0 basée sur les réponses ci-dessus:
la source
Une autre solution pour cela;
Prenez tous les sommets comme un tableau comme celui-ci;
la source
Solution pour R pour déterminer la direction et inverser si dans le sens horaire (jugé nécessaire pour les objets propres):
la source
Bien que ces réponses soient correctes, elles sont plus mathématiquement intenses que nécessaires. Supposons les coordonnées de la carte, où le point le plus au nord est le point le plus élevé sur la carte. Trouvez le point le plus au nord, et si 2 points sont à égalité, c'est le plus au nord puis le plus à l'est (c'est le point que lhf utilise dans sa réponse). Dans vos points,
point [0] = (5,0)
point [1] = (6,4)
point [2] = (4,5)
point [3] = (1,5)
point [4] = (1,0)
Si nous supposons que P2 est le point le plus au nord puis à l'est, le point précédent ou suivant détermine dans le sens horaire, CW ou CCW. Puisque le point le plus au nord se trouve sur la face nord, si le P1 (précédent) vers P2 se déplace vers l'est, la direction est CW. Dans ce cas, il se déplace vers l'ouest, donc la direction est CCW comme le dit la réponse acceptée. Si le point précédent n'a pas de mouvement horizontal, alors le même système s'applique au point suivant, P3. Si P3 est à l'ouest de P2, c'est le cas, alors le mouvement est CCW. Si le mouvement P2 à P3 est à l'est, c'est à l'ouest dans ce cas, le mouvement est CW. Supposons que nte, P2 dans vos données, est le point le plus au nord puis à l'est et le prv est le point précédent, P1 dans vos données et nxt est le point suivant, P3 dans vos données et [0] est horizontal ou est / ouest où l'ouest est inférieur à l'est et [1] est vertical.
la source
.x
et.y
d'une structure, au lieu de[0]
et[1]
. Je ne savais pas ce que disait votre code, la première fois que je l'ai regardé.)Voici une implémentation Python 3 simple basée sur cette réponse (qui, à son tour, est basée sur la solution proposée dans la réponse acceptée )
la source
trouver le centre de masse de ces points.
supposons qu'il y ait des lignes de ce point à vos points.
trouver l'angle entre deux lignes pour line0 line1
que de le faire pour la ligne 1 et la ligne 2
...
...
si cet angle augmente de façon monotone que dans le sens antihoraire,
sinon si la diminution est monotone dans le sens horaire
sinon (ce n'est pas monotone)
vous ne pouvez pas décider, donc ce n'est pas sage
la source