Le polygone est donné comme une liste d'objets Vector2i (coordonnées entier 2 dimensions et entier). Comment puis-je tester si un point donné est à l'intérieur? Toutes les implémentations que j'ai trouvées sur le Web échouent pour un contre-exemple trivial. Il semble vraiment être difficile d'écrire une mise en œuvre correcte. La langue n'a pas d'importance car je vais le porter moi-même.
S'il est convexe, un moyen trivial de vérifier est que le point est positionné du même côté de tous les segments (si ils sont traversés dans le même ordre).
Vous pouvez vérifier cela facilement avec le produit croisé (car il est proportionnel au cosinus de l'angle formé entre le segment et le point, celles dont le signe positif poserait sur le côté droit et ceux ayant une panneau négatif sur le côté gauche).
Voici le code en Python:
RIGHT = "RIGHT"
LEFT = "LEFT"
def inside_convex_polygon(point, vertices):
previous_side = None
n_vertices = len(vertices)
for n in xrange(n_vertices):
a, b = vertices[n], vertices[(n+1)%n_vertices]
affine_segment = v_sub(b, a)
affine_point = v_sub(point, a)
current_side = get_side(affine_segment, affine_point)
if current_side is None:
return False #outside or over an Edge
Elif previous_side is None: #first segment
previous_side = current_side
Elif previous_side != current_side:
return False
return True
def get_side(a, b):
x = x_product(a, b)
if x < 0:
return LEFT
Elif x > 0:
return RIGHT
else:
return None
def v_sub(a, b):
return (a[0]-b[0], a[1]-b[1])
def x_product(a, b):
return a[0]*b[1]-a[1]*b[0]
Si le polygone est convexe, alors en C #, ce qui suit implémente le " TEST TEST SI TOUJOURS de la même manière " méthode et fonctionne au plus à O (N de points de polygone):
public static bool IsInConvexPolygon(Point testPoint, List<Point> polygon)
{
//Check if a triangle or higher n-gon
Debug.Assert(polygon.Length >= 3);
//n>2 Keep track of cross product sign changes
var pos = 0;
var neg = 0;
for (var i = 0; i < polygon.Count; i++)
{
//If point is in the polygon
if (polygon[i] == testPoint)
return true;
//Form a segment between the i'th point
var x1 = polygon[i].X;
var y1 = polygon[i].Y;
//And the i+1'th, or if i is the last, with the first point
var i2 = i < polygon.Count - 1 ? i + 1 : 0;
var x2 = polygon[i2].X;
var y2 = polygon[i2].Y;
var x = testPoint.X;
var y = testPoint.Y;
//Compute the cross product
var d = (x - x1)*(y2 - y1) - (y - y1)*(x2 - x1);
if (d > 0) pos++;
if (d < 0) neg++;
//If the sign changes, then point is outside
if (pos > 0 && neg > 0)
return false;
}
//If no change in direction, then on same side of all segments, and thus inside
return true;
}
la réponse de Fortran a presque travaillé pour moi, sauf que j'ai trouvé que je devais traduire le polygone afin que le point que vous testez soit identique à l'origine. Voici le JavaScript que j'ai écrit pour faire ce travail:
function Vec2(x, y) {
return [x, y]
}
Vec2.nsub = function (v1, v2) {
return Vec2(v1[0]-v2[0], v1[1]-v2[1])
}
// aka the "scalar cross product"
Vec2.perpdot = function (v1, v2) {
return v1[0]*v2[1] - v1[1]*v2[0]
}
// Determine if a point is inside a polygon.
//
// point - A Vec2 (2-element Array).
// polyVerts - Array of Vec2's (2-element Arrays). The vertices that make
// up the polygon, in clockwise order around the polygon.
//
function coordsAreInside(point, polyVerts) {
var i, len, v1, v2, Edge, x
// First translate the polygon so that `point` is the Origin. Then, for each
// Edge, get the angle between two vectors: 1) the Edge vector and 2) the
// vector of the first vertex of the Edge. If all of the angles are the same
// sign (which is negative since they will be counter-clockwise) then the
// point is inside the polygon; otherwise, the point is outside.
for (i = 0, len = polyVerts.length; i < len; i++) {
v1 = Vec2.nsub(polyVerts[i], point)
v2 = Vec2.nsub(polyVerts[i+1 > len-1 ? 0 : i+1], point)
Edge = Vec2.nsub(v1, v2)
// Note that we could also do this by using the normal + dot product
x = Vec2.perpdot(Edge, v1)
// If the point lies directly on an Edge then count it as in the polygon
if (x < 0) { return false }
}
return true
}
La fonction pointupolygontest dans OpenCV "détermine si le point est à l'intérieur d'un contour, à l'extérieur ou réside sur un bord": http://docs.opencv.org/modules/imgproc/doc/tructural_analysis_and_shape_descriptors.html?highlight= pointpolygontest # pointupolygontest
la façon dont je sais est quelque chose comme ça.
vous choisissez un point quelque part en dehors du polygon, il peut être éloigné de la géométrie. Ensuite, vous dessinez une ligne de ce point. Je veux dire que vous créez une équation de ligne avec ces deux points.
ensuite, pour chaque ligne de ce polygone, vous vérifiez si elles se croisent.
la somme de nombre de lignes intersectées vous donne-vous qu'il est à l'intérieur ou non.
si c'est impair: à l'intérieur
si c'est même: à l'extérieur
Ou de l'homme qui a écrit le livre, voir - page géométrique
Spécifiquement Cette page , il discute pourquoi la règle d'enroulement est généralement meilleure que la traversée de rayons.
edit - Désolé, ce n'est pas Jospeh o'Rourke qui a écrit l'excellent livre géométrie informatique en C , c'est Paul Bourke mais toujours une très très bonne source d'algorithmes de géométrie.