Point dans le Polygone de l'Algorithme
J'ai vu le dessous de fonctionnement de l'algorithme utilisé pour vérifier si un point est dans un polygone donné à partir de ce lien:
int pnpoly(int nvert, float *vertx, float *verty, float testx, float testy)
{
int i, j, c = 0;
for (i = 0, j = nvert-1; i < nvert; j = i++) {
if ( ((verty[i]>testy) != (verty[j]>testy)) &&
(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
c = !c;
}
return c;
}
J'ai essayé de cet algorithme et ça marche, tout simplement parfait. Mais, malheureusement, je ne comprends pas bien après avoir passé un certain temps à essayer pour se faire une idée de lui.
Donc si quelqu'un est en mesure de comprendre cet algorithme, pourriez-vous m'expliquer un peu.
Merci.
- La réponse vous lien contient un lien vers sa source, et la source a une longue explication de l'algorithme: ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html Avez-vous lu cela?
- J'ai trouvé erich.realtimerendering.com/ptinpoly pour être une excellente ressource pour la compréhension de "point dans le polygone" les stratégies.
Vous devez vous connecter pour publier un commentaire.
L'algorithme est ray-casting de la droite. Chaque itération de la boucle, le point de test est vérifié à l'encontre de l'un des bords du polygone. La première ligne de la si-test réussit si le point d'y coord est dans le bord du champ. La deuxième ligne vérifie si le point de test est à la gauche de la ligne (je pense - je n'ai pas tout morceau de papier à la main pour vérifier). Si c'est vrai que la ligne dessinée rightwards à partir du test de point de croix de pointe.
À plusieurs reprises par l'inversion de la valeur de
c
, l'algorithme compte combien de fois la droite ligne traverse le polygone. Si elle traverse un nombre impair de fois, alors le point est à l'intérieur; si un même numéro, le point est à l'extérieur.J'aurais des préoccupations avec a) l'exactitude de l'arithmétique à virgule flottante, et b) les effets de l'existence d'une arête horizontale, ou d'un point d'essai avec le même y-coord comme un sommet, si.
Chowlett est correct dans tous les cas, la forme, et la forme.
L'algorithme suppose que si ton point est sur la ligne du polygone, alors que c'est à l'extérieur - pour certains cas, c'est faux. Changer les deux "> "opérateurs" >=', et un changement de '<' de '<=' fixera.
(points[i].y) >= point.y
devrait être(points[i].y >= point.y)
Cela peut être aussi détaillée qu'il pourrait faire pour expliquer le ray-tracing de l'algorithme dans le code réel. Il pourrait ne pas être optimisé mais qui doit toujours venir après une compréhension complète du système.
Juste un mot à propos de l'optimisation: Il n'est pas vrai que le plus court (et/ou le tersest) du code est la manière la plus rapide de mise en œuvre. C'est un processus plus rapide pour lire et stocker un élément d'un tableau et de l'utiliser (peut-être) de nombreuses fois dans l'exécution du bloc de code que pour accéder au tableau à chaque fois que cela est nécessaire. Ceci est particulièrement important si le tableau est très grand. À mon avis, par le stockage de chaque terme d'un tableau dans une variable nommée, il est également plus facile d'évaluer son but et sont donc beaucoup plus lisible le code. Juste mes deux cents...
L'algorithme est dépouillé de la plupart des éléments nécessaires. Après qu'il a été développé et testé tous les trucs inutiles a été supprimé. Comme résultat, vous pouvez comprend pas facilement, mais il fait le travail et aussi dans de très bonnes performances.
J'ai pris la liberté de traduire à ActionScript-3:
Cet algorithme fonctionne dans n'importe quel polygone fermé tant que le du polygone à côtés ne traversent pas. Triangle, pentagone, carré, même un très sinueuse par morceaux-linéaire de la bande de caoutchouc qui n'est pas de la croix lui-même.
1) Définir votre polygone en tant que dirigé le groupe de vecteurs. Par c'est à dire que chaque côté du polygone est décrit par un vecteur qui va du sommet à un sommet d'un+1. Les vecteurs sont donc réalisé de sorte que la tête de l'un touche la queue de l'autre jusqu'à la dernière vecteur touche la queue de la première.
2) Sélectionnez le point de test à l'intérieur ou à l'extérieur du polygone.
3) Pour chaque vecteur Vn le long du périmètre du polygone trouver le vecteur Dn qui commence sur le point d'essai et se termine à la queue de Vn. Calculer le vecteur Cn défini comme DnXVn/DN*VN (X) indique la croix du produit; * indique un produit scalaire). Appel de l'ampleur de la Cn par le nom de Mn.
4) Ajouter tous les Mn et appelons cette quantité K.
5) Si K est égal à zéro, le point est à l'extérieur du polygone.
6) Si K n'est pas zéro, le point est à l'intérieur du polygone.
Théoriquement, un point qui se trouve SUR le bord du polygone va produire un résultat indéfini.
Géométriques sens de K est le total de l'angle que la puce est assis sur notre point de test "vu" la fourmi de marche au bord du polygone à pied vers la gauche, moins l'angle se dirigea vers la droite. Dans un circuit fermé, la fourmi se termine là où elle a commencé.
À l'extérieur du polygone, indépendamment de l'emplacement, la réponse est zéro.
À l'intérieur du polygone, indépendamment de l'emplacement, la réponse est "un temps autour du point".
J'ai changé le code d'origine pour le rendre un peu plus lisible (également cette utilise Eigen). L'algorithme est identique.
Cette méthode de vérifier si le rayon à partir du point (testx, hargneuse) à O (0,0) couper les côtés du polygone ou pas .
Il est bien connu conclusion ici: si un rayon de 1 point et coupez les côtés d'un polygone pour une drôle de temps, ce point appartient au polygone, sinon, ce point sera à l'extérieur du polygone.
Je pense que l'idée de base est de calculer les vecteurs à partir de ce point, un à chaque arête du polygone. Si le vecteur traverse une arête, alors le point est à l'intérieur du polygone. Par polygones concaves si elle traverse un nombre impair d'arêtes, il est aussi bien à l'intérieur (avertissement: bien que vous ne savez pas si il fonctionne pour tous les polygones concaves).
Étendre sur @chowlette de réponse où la deuxième ligne vérifie si le point est à gauche de la ligne,
Pas de dérivation est donné, mais c'est ce que j'ai:
D'abord il permet d'imaginer de base 2 cas:
. /
ou/.
Si notre point de tirer un rayon horizontalement, où serait-il grève le segment de ligne. Est notre point vers la gauche ou la droite? À l'intérieur ou à l'extérieur? Nous savons que sa coordonnée y parce que c'est par définition le même que le point. Quelle serait la coordonnée x de l'être?
Prendre votre ligne traditionnelle formule
y = mx + b
. m est la hausse au cours de l'exécution. Ici, au lieu de cela, nous essayons de trouver le coordonnée x du point sur ce segment de ligne qui a la même hauteur (y) en tant que notre point.Nous avons donc à résoudre pour x:
x = (y - b)/m
.m
est montée sur exécuter, de sorte que cela devient de courir sur la hausse ou la(yj - yi)/(xj - xi)
devient(xj - xi)/(yj - yi)
. b est le décalage de l'origine. Si nous supposonsyi
comme la base de notre système de coordonnées, b devient yi. De notre point detesty
est notre entrée, en soustrayantyi
transforme la totalité de la formule dans un décalage deyi
.Nous avons maintenant
(xj - xi)/(yj - yi)
ou1/m
temps y ou(testy - yi)
:(xj - xi)(testy - yi)/(yj - yi)
mais testx n'est pas fondée àyi
nous avons donc le rajouter dans le but de comparer les deux ( ou zéro testx ainsi )Voici une implémentation php de ce:
Test:
C'est l'algorithme que j'utilise, mais j'ai ajouté un peu de prétraitement, la ruse de l'accélérer. Mes polygones ont ~1000 bords et ils ne changent pas, mais j'ai besoin de regarder pour savoir si le curseur est à l'intérieur de l'un sur chaque déplacement de la souris.
En gros, j'ai divisé la hauteur du rectangle de délimitation de l'égalité de longueur des intervalles et pour chacun de ces intervalles que je compile la liste des bords qui se trouvent dans/intersection avec elle.
Quand j'ai besoin de regarder pour un point, je peux calculer en O(1) du temps - intervalle, il est, puis je l'ai seulement besoin de tester ces bords qui sont dans l'intervalle de la liste.
J'ai utilisé 256 intervalles et cela a réduit le nombre d'arêtes j'ai besoin de tester 2 à 10 au lieu de ~1000.
J'ai modifié le code pour vérifier si le point est dans un polygone, y compris le point est sur un bord.