Trouver si un point se trouve à l'intérieur d'un rectangle ou non

je veux savoir si un point se trouve à l'intérieur d'un rectangle ou non. Le rectangle peut être orienté de n'importe quelle manière, et n'a pas besoin d'être aligné sur l'axe.

une méthode à laquelle je pouvais penser était de faire pivoter le rectangle et les coordonnées de point pour faire l'axe du rectangle aligné et puis simplement en testant les coordonnées de point qu'elles se trouvent à l'intérieur de celle du rectangle ou non.

la méthode ci-dessus nécessite une rotation et donc des opérations en virgule flottante. Être il y a de toute autre manière efficace de faire cela?

66
demandé sur Peter O. 2010-05-02 11:08:15

9 réponses

comment le rectangle est-il représenté? Trois points? Quatre points? Point, côtés et angle? Deux points et un côté? Quelque chose d'autre? Sans le savoir, toute tentative de répondre à votre question n'aura qu'une valeur purement académique.

dans tous les cas, pour tout polygone convexe (y compris le rectangle) le test est très simple: vérifier chaque bord du polygone, en supposant que chaque bord est orienté dans le sens inverse des aiguilles d'une montre, et vérifier si le point se trouve à gauche du bord (dans le demi-plan gauche). Si tous les bords passent le test - le point est à l'intérieur. Si on échoue , le point est à l'extérieur.

pour vérifier si le point (xp, yp) se trouve du côté gauche du bord (x1, y1) - (x2, y2) , vous devez construire l'équation de ligne pour la ligne contenant le bord. L'équation est la suivante

A * x + B * y + C = 0

A = -(y2 - y1)
B = x2 - x1
C = -(A * x1 + B * y1)

Maintenant, tout ce que vous devez faire est de calculer

D = A * xp + B * yp + C

si D > 0 , le point est à gauche. Si D < 0 , le point est sur la droite. Si D = 0 , le point est sur la ligne.

Cependant, ce test, encore une fois, fonctionne pour tout polygone convexe, ce qui signifie qu'il peut être trop générique pour un rectangle. Un rectangle pourrait permettre un test plus simple... Par exemple, dans un rectangle (ou dans tout autre parallélogramme) les valeurs de A et B ont la même grandeur mais des signes différents pour les bords opposés (c'est-à-dire parallèles), qui peuvent être exploités pour simplifier l'essai.

70
répondu AnT 2017-12-11 21:20:52

en supposant que le rectangle est représenté par trois points A, B, C, avec AB et BC perpendiculaire, vous n'avez qu'à vérifier les projections du point d'interrogation m sur AB et BC:

0 <= dot(AB,AM) <= dot(AB,AB) &&
0 <= dot(BC,BM) <= dot(BC,BC)

AB est un vecteur AB, avec des coordonnées (Bx-Ax,by-Ay), et dot(U,V) est le produit dot des vecteurs U et V: Ux*Vx+Uy*Vy .

mise à Jour . Prenons un exemple pour illustrer cela: Un(5,0) B(0,2) C(1,5) et D(6,3). À partir de la point de coordonnées, on obtient AB=(-5,2), BC=(1,3), le point(AB,AB)=29, point(BC,BC)=10.

pour le point d'interrogation M(4,2), nous avons AM=(-1,2), BM=(4,0), dot(AB,AM)=9, dot(BC,BM)=4. M est à l'intérieur du rectangle.

pour le point d'interrogation P(6,1), nous avons AP=(1,1), BP=(6,-1), dot(AB,AP)=-3, dot (BC,BP)=3. P n'est pas à l'intérieur du rectangle, parce que sa projection sur le côté AB n'est pas à l'intérieur du segment AB.

34
répondu Eric Bainville 2013-02-05 18:40:56
# Pseudo code
# Corners in ax,ay,bx,by,dx,dy
# Point in x, y

bax = bx - ax
bay = by - ay
dax = dx - ax
day = dy - ay

if ((x - ax) * bax + (y - ay) * bay < 0.0) return false
if ((x - bx) * bax + (y - by) * bay > 0.0) return false
if ((x - ax) * dax + (y - ay) * day < 0.0) return false
if ((x - dx) * dax + (y - dy) * day > 0.0) return false

return true
15
répondu Jonas Elfström 2013-12-10 19:55:11

j'ai emprunté à la réponse D'Eric Bainville:

0 <= dot(AB,AM) <= dot(AB,AB) && 0 <= dot(BC,BM) <= dot(BC,BC)

qui en javascript ressemble à ceci:

function pointInRectangle(m, r) {
    var AB = vector(r.A, r.B);
    var AM = vector(r.A, m);
    var BC = vector(r.B, r.C);
    var BM = vector(r.B, m);
    var dotABAM = dot(AB, AM);
    var dotABAB = dot(AB, AB);
    var dotBCBM = dot(BC, BM);
    var dotBCBC = dot(BC, BC);
    return 0 <= dotABAM && dotABAM <= dotABAB && 0 <= dotBCBM && dotBCBM <= dotBCBC;
}

function vector(p1, p2) {
    return {
            x: (p2.x - p1.x),
            y: (p2.y - p1.y)
    };
}

function dot(u, v) {
    return u.x * v.x + u.y * v.y; 
}

par exemple:

var r = {
    A: {x: 50, y: 0},
    B: {x: 0, y: 20},
    C: {x: 10, y: 50},
    D: {x: 60, y: 30}
};

var m = {x: 40, y: 20};

puis:

pointInRectangle(m, r); // returns true.

Voici un codepen pour dessiner la sortie comme un test visuel :) http://codepen.io/mattburns/pen/jrrprN

enter image description here

13
répondu matt burns 2016-06-16 17:03:50

je me rends compte que c'est un vieux fil, mais pour quiconque est intéressé à regarder cela d'une perspective purement mathématique, il ya un excellent fil sur l'échange de la pile de mathématiques, ici:

https://math.stackexchange.com/questions/190111/how-to-check-if-a-point-is-inside-a-rectangle

Edit: inspiré par ce fil, j'ai mis en place une méthode vectorielle simple pour déterminer rapidement où se trouve votre point.

supposons que vous ayez un rectangle avec des points à p1 = (x1, y1), p2 = (x2, y2), p3 = (x3, y3) et p4 = (x4, y4), allant dans le sens des aiguilles d'une montre. Si un point p = (x, y) se trouve à l'intérieur du rectangle, alors le produit de points (p - p1).(p2 - p1) sera comprise entre 0 et |p2 - p1|^2 et (p - p1).(p4-p1) se situera entre 0 et |p4 - p1|^2. Cela équivaut à prendre la projection du vecteur p - p1 sur la longueur et la largeur du rectangle, avec p1 comme origine.

Cela peut avoir plus de sens si je montre un code équivalent:

p21 = (x2 - x1, y2 - y1)
p41 = (x4 - x1, y4 - y1)

p21magnitude_squared = p21[0]^2 + p21[1]^2
p41magnitude_squared = p41[0]^2 + p41[1]^2

for x, y in list_of_points_to_test:

    p = (x - x1, y - y1)

    if 0 <= p[0] * p21[0] + p[1] * p21[1] <= p21magnitude_squared:
        if 0 <= p[0] * p41[0] + p[1] * p41[1]) <= p41magnitude_squared:
            return "Inside"
        else:
            return "Outside"
    else:
        return "Outside"

Et c'est tout. Il fonctionnera également pour les parallélogrammes.

10
répondu Matt Thompson 2017-04-13 12:19:15

si vous ne pouvez pas résoudre le problème pour le rectangle essayer de diviser le problème à des problèmes plus faciles. Diviser le rectangle en 2 triangles vérifier si le point est à l'intérieur de l'un d'eux comme ils l'expliquent dans ici

essentiellement, vous parcourez les bords sur deux paires de lignes à partir d'un point. Ensuite, en utilisant le produit croisé pour vérifier si le point est entre les deux lignes en utilisant le produit croisé. Si c'est vérifié pour les 3 points, puis le point est à l'intérieur du triangle. La bonne chose à propos de cette méthode est qu'elle ne crée pas d'erreurs de float-point qui se produit si vous vérifiez les angles.

6
répondu Cristian T 2010-05-02 07:22:15
bool pointInRectangle(Point A, Point B, Point C, Point D, Point m ) {
    Point AB = vect2d(A, B);  float C1 = -1 * (AB.y*A.x + AB.x*A.y); float  D1 = (AB.y*m.x + AB.x*m.y) + C1;
    Point AD = vect2d(A, D);  float C2 = -1 * (AD.y*A.x + AD.x*A.y); float D2 = (AD.y*m.x + AD.x*m.y) + C2;
    Point BC = vect2d(B, C);  float C3 = -1 * (BC.y*B.x + BC.x*B.y); float D3 = (BC.y*m.x + BC.x*m.y) + C3;
    Point CD = vect2d(C, D);  float C4 = -1 * (CD.y*C.x + CD.x*C.y); float D4 = (CD.y*m.x + CD.x*m.y) + C4;
    return     0 >= D1 && 0 >= D4 && 0 <= D2 && 0 >= D3;}





Point vect2d(Point p1, Point p2) {
    Point temp;
    temp.x = (p2.x - p1.x);
    temp.y = -1 * (p2.y - p1.y);
    return temp;}

Points inside polygon

je viens d'implémenter la réponse de AnT en utilisant c++. J'ai utilisé ce code pour vérifier si la coordination du pixel(X,Y) se trouve à l'intérieur de la forme ou non.

5
répondu Alghyaline 2017-02-23 13:21:14

si un point est à l'intérieur d'un rectangle. Sur un plan. Pour les coordonnées mathématiciennes ou géodésiques (GPS)

  • laisser le rectangle être réglé par les sommets A, B, C, D. le point est P. Les coordonnées sont rectangulaires: x, Y.
  • Permet de prolonger les côtés du rectangle. Nous avons donc 4 lignes droites l AB , l BC , l CD , l DA , ou, pour le souffle, l 1 , l 2 , l 3 , l 4 .
  • faites une équation pour chaque l i . L'équation sorte de:

    f je (P)=0.

P est un point. Pour les points, appartenant à l je , l'équation est vraie.

  • nous avons besoin des fonctions du côté gauche des équations. Il s'agit de f 1 , f 2 , f 3 , f 4 .
  • un Avis, que pour chaque point d'un côté de l je la fonction f je est supérieur à 0, pour les points de l'autre côté f je est inférieure à 0.
  • donc, si nous vérifions P étant dans le rectangle, nous avons seulement besoin pour le p pour être sur les côtés corrects des quatre lignes. Donc, nous devons vérifier quatre fonctions pour leurs signes.
  • mais quel côté de la ligne est le bon, auquel le rectangle appartient? C'est le côté où se trouvent les sommets d'un rectangle qui n'appartiennent pas à la ligne. Pour vérifier nous pouvons choisir n'importe qui de deux sommets n'appartenant pas.
  • nous devons donc vérifier ceci:

    f AB (P) f AB (c) >= 0

    f BC (P) f BC (D) >= 0

    f CD (P) f CD (a) >= 0

    f DA (P) f DA (B) >= 0

les inégalités ne sont pas strictes, car si un point est sur le border, il appartient au rectangle, aussi. Si vous n'avez pas besoin de points sur la frontière, vous pouvez modifier inequations strict. Mais pendant que vous travaillez dans les opérations à virgule flottante, le choix n'est pas pertinent.

  • pour un point, c'est-à-dire dans le rectangle, les quatre iniquités sont vraies. Notez que cela fonctionne aussi pour chaque polygone convexe, seul le nombre de lignes/équations différera.
  • La seule chose qui reste est d'obtenir une équation d'une droite passant par deux points. C'est une équation linéaire bien connue. Écrivons pour une ligne AB et point P:

    f AB (P)   (x Un -x B ) (y P -y B ) - (y Un -y B ) (x P -x B )

le vérifier pourrait être simplifié - allons le long du rectangle dans le sens des aiguilles d'une montre - A, B, C, D, A. Alors tous les côtés corrects seront à la droite des lignes. Donc, nous n'avons pas besoin de comparer avec le côté où un autre coin est. Et nous devons vérifier un ensemble d'injustices plus courtes:

F AB (P) >= 0

f BC (P) >= 0

f CD (P) >= 0

f DA (P) >= 0

mais c'est correct pour la normale, mathématicien (de l'école de mathématiques) ensemble de coordonnées, où X est à droite et Y au sommet. Et pour les coordonnées géodésie , comme sont utilisés dans le GPS, où X est au sommet, et Y est à droite, nous devons tourner les iniquités:

F AB (P) <= 0

f BC (P) <= 0

f CD (P) <= 0

f DA (P) <= 0

si vous n'êtes pas sûr avec les directions des axes, faites attention avec ce check - check simplifié pour un point avec le placement connu, si vous avez choisi les iniquités correctes.

4
répondu Gangnus 2018-01-08 15:24:13

la façon la plus facile que j'ai pensé était de projeter le point sur l'axe du rectangle. Laissez-moi vous expliquer:

si vous pouvez obtenir le vecteur du centre du rectangle au bord supérieur ou inférieur et au bord gauche ou droit. Et vous avez aussi un vecteur du centre du rectangle à votre point, vous pouvez projeter ce point sur vos Vecteurs de largeur et de hauteur.

P = vecteur point, H = vecteur hauteur, W =vecteur largeur

obtenir vecteur Unité W', H' en divisant les vecteurs par leur magnitude

proj_P, H = P - (P. H')H' proj_P, W=P - (P. W')W'

sauf erreur de ma part, ce que je ne pense pas être... (Corrigez - moi si je me trompe) mais si la magnitude de la projection de votre point sur le vecteur hauteur est inférieure alors la magnitude du vecteur hauteur (qui est la moitié de la hauteur du rectangle) et la magnitude de la projection de votre point sur le vecteur largeur est, ensuite, vous avez un point à l'intérieur de votre rectangle.

si vous avez un système de coordonnées universel, vous pourriez avoir à calculer la hauteur/largeur/point vecteurs en utilisant la soustraction vectorielle. Les projections vectorielles sont incroyables! rappelez-vous que.

0
répondu Matthew 2010-12-23 17:08:07