web-dev-qa-db-fra.com

trouver si 4 points sur un plan forment un rectangle?

Quelqu'un peut-il me montrer, s'il vous plaît, dans un pseudo-code de style C, comment écrire une fonction (représenter les points comme vous le souhaitez) qui renvoie true si 4 points (arguments de la fonction) forment un rectangle et false sinon?

Je suis venu avec une solution qui essaie d'abord de trouver 2 paires distinctes de points avec une valeur x égale, puis le fait pour l'axe des ordonnées. Mais le code est plutôt long. Juste curieux de voir ce que les autres proposent.

46
pete
  • trouver le centre de gravité des angles: cx = (x1 + x2 + x3 + x4)/4, cy = (y1 + y2 + y3 + y4)/4
  • vérifier si les carrés des distances du centre de masse aux 4 coins sont égaux
bool isRectangle(double x1, double y1,
                 double x2, double y2,
                 double x3, double y3,
                 double x4, double y4)
{
  double cx,cy;
  double dd1,dd2,dd3,dd4;

  cx=(x1+x2+x3+x4)/4;
  cy=(y1+y2+y3+y4)/4;

  dd1=sqr(cx-x1)+sqr(cy-y1);
  dd2=sqr(cx-x2)+sqr(cy-y2);
  dd3=sqr(cx-x3)+sqr(cy-y3);
  dd4=sqr(cx-x4)+sqr(cy-y4);
  return dd1==dd2 && dd1==dd3 && dd1==dd4;
}

(Bien sûr, dans la pratique, le test d'égalité de deux nombres à virgule flottante a et b doit être effectué avec une précision finie: par exemple, abs (a-b) <1E-6) 

55
Curd
struct point
{
    int x, y;
}

// tests if angle abc is a right angle
int IsOrthogonal(point a, point b, point c)
{
    return (b.x - a.x) * (b.x - c.x) + (b.y - a.y) * (b.y - c.y) == 0;
}

int IsRectangle(point a, point b, point c, point d)
{
    return
        IsOrthogonal(a, b, c) &&
        IsOrthogonal(b, c, d) &&
        IsOrthogonal(c, d, a);
}

Si la commande n'est pas connue à l'avance, nous avons besoin d'un contrôle légèrement plus compliqué:

int IsRectangleAnyOrder(point a, point b, point c, point d)
{
    return IsRectangle(a, b, c, d) ||
           IsRectangle(b, c, a, d) ||
           IsRectangle(c, a, b, d);
}
36
Vlad
  • traduire le quadrilatère de sorte qu'un de ses sommets se trouve maintenant à l'origine 
  • les trois points restants forment trois vecteurs de l'origine
  • l'un d'eux doit représenter la diagonale
  • les deux autres doivent représenter les côtés
  • par la règle du parallélogramme si les côtés forment la diagonale, nous avons un parallélogramme
  • si les côtés forment un angle droit, il s'agit d'un parallélogramme à angle droit
  • les angles opposés d'un parallélogramme sont égaux
  • les angles consécutifs d'un parallélogramme sont complémentaires
  • donc tous les angles sont des angles droits
  • c'est un rectangle
  • c'est beaucoup plus concis dans le code, cependant :-)

    static bool IsRectangle(
       int x1, int y1, int x2, int y2, 
       int x3, int y3, int x4, int y4)
    {
        x2 -= x1; x3 -= x1; x4 -= x1; y2 -= y1; y3 -= y1; y4 -= y1;
        return
            (x2 + x3 == x4 && y2 + y3 == y4 && x2 * x3 == -y2 * y3) ||
            (x2 + x4 == x3 && y2 + y4 == y3 && x2 * x4 == -y2 * y4) ||
            (x3 + x4 == x2 && y3 + y4 == y2 && x3 * x4 == -y3 * y4);
    }
    
  • (Si vous voulez que cela fonctionne avec des valeurs à virgule flottante, veuillez ne pas simplement remplacer aveuglément les déclarations int dans les en-têtes. C'est une mauvaise pratique. Elles sont là pour une raison. On devrait toujours travailler avec des lié à l'erreur lors de la comparaison des résultats en virgule flottante.)

5
Andras Vass

La distance d'un point à l'autre 3 devrait former un triangle rectangle:

// | 
 |// | 
 |// | 
 |/___ /___|
d1 = sqrt( (x2-x1)^2 + (y2-y1)^2 ) 
d2 = sqrt( (x3-x1)^2 + (y3-y1)^2 ) 
d3 = sqrt( (x4-x1)^2 + (y4-y1)^2 ) 
if d1^2 == d2^2 + d3^2 then it's a rectangle

Simplifier:

d1 = (x2-x1)^2 + (y2-y1)^2
d2 = (x3-x1)^2 + (y3-y1)^2
d3 = (x4-x1)^2 + (y4-y1)^2
if d1 == d2+d3 or d2 == d1+d3 or d3 == d1+d2 then return true
4
Carlos Gutiérrez

Si les points sont A, B, C & D et que vous connaissez l'ordre, vous calculez les vecteurs:

x = B-A, y = C-B, z = D-C et w = A-D

Ensuite, prenez les produits de points (x point y), (y point z), (z point w) et (w point x). S'ils sont tous nuls, vous avez un rectangle.

3
Axel Gneiting

Nous savons que deux droites verticales sont perpendiculaires si le produit de leurs pentes est -1, puisqu'un avion est donné, nous pouvons trouver les pentes de trois droites consécutives et les multiplier ensuite pour vérifier si elles sont vraiment perpendiculaires ou non. Supposons que nous ayons les lignes L1, L2, L3. Maintenant, si L1 est perpendiculaire à L2 et L2 perpendiculaire à L3, alors il s’agit d’un rectangle et d’une pente de m implique que c'est un rectangle. Le code est comme suit

bool isRectangle(double x1,double y1,
        double x2,double y2,
        double x3,double y3,
        double x4,double y4){
    double m1,m2,m3;
    m1 = (y2-y1)/(x2-x1);
    m2 = (y2-y3)/(x2-x3);
    m3 = (y4-y3)/(x4-x3);

    if((m1*m2)==-1 && (m2*m3)==-1)
        return true;
    else
        return false;
}
1
manugupt1
1. Find all possible distances between given 4 points. (we will have 6 distances)
2. XOR all distances found in step #1
3. If the result after XORing is 0 then given 4 points are definitely vertices of a square or a rectangle otherwise, return false (given 4 points do not form a rectangle).
4. Now, to differentiate between square and rectangle 
   a. Find the largest distance out of 4 distances found in step #1. 
   b. Check if the largest distance / Math.sqrt (2) is equal to any other distance.
   c. If answer is No, then given four points form a rectangle otherwise they form a square.

Ici, nous utilisons les propriétés géométriques de rectangle/square et Bit Magic .

Propriétés du rectangle en jeu  

  1. Les côtés et les diagonales opposés d'un rectangle sont de même longueur.
  2. Si la longueur diagonale d'un rectangle est égale à sqrt (2) fois, le rectangle est alors un carré.

Bit Magic

  1. XORing nombres de valeur égale retournent 0. 

Étant donné que les distances entre 4 coins d’un rectangle forment toujours 3 paires, une pour la diagonale et deux pour chaque côté de longueur différente, XORing toutes les valeurs renverront 0 pour un rectangle.

1
vineet kapoor

pour aller encore plus loin dans la suggestion du produit scalaire, vérifiez si deux des vecteurs créés par l'un quelconque des 3 points des points sont perpendiculaires, puis vérifiez si x et y correspondent au quatrième point.

Si vous avez des points [Ax, Ay] [Bx, By] [Cx, Cy] [Dx, Dy]

vecteur v = B-A vecteur u = C-A

v(dot)u/|v||u| == cos(theta)

donc si (v.u == 0) il y a deux lignes perpendiculaires juste là.

En fait, je ne connais pas la programmation en C, mais voici une programmation "méta" pour vous: P

if (v==[0,0] || u==[0,0] || u==v || D==A) {not a rectangle, not even a quadrilateral}

var dot = (v1*u1 + v2*u2); //computes the "top half" of (v.u/|v||u|)
if (dot == 0) { //potentially a rectangle if true

    if (Dy==By && Dx==Cx){
     is a rectangle
    }

    else if (Dx==Bx && Dy==Cy){
     is a rectangle
    }
}
else {not a rectangle}

il n'y a pas de racines carrées dans cela, et pas de potentiel pour une division par zéro. J'ai remarqué que des personnes mentionnaient ces problèmes dans des publications antérieures et j'ai donc pensé proposer une alternative.

Donc, en calcul, vous avez besoin de quatre soustractions pour obtenir v et u, deux multiplications, une addition et vous devez vérifier entre 1 et 7 égalités.

je invente peut-être cela, mais je me souviens vaguement d'avoir lu quelque part que les soustractions et les multiplications sont des calculs "plus rapides". Je suppose que déclarer des variables/tableaux et définir leurs valeurs est également assez rapide?

Désolé, je suis assez novice dans ce genre de choses, alors j'aimerais avoir des retours sur ce que je viens d'écrire.

Edit: essayez ceci basé sur mon commentaire ci-dessous:

A = [a1,a2];
B = [b1,b2];
C = [c1,c2];
D = [d1,d2];

u = (b1-a1,b2-a2);
v = (c1-a1,c2-a2);

if ( u==0 || v==0 || A==D || u==v)
    {!rectangle} // get the obvious out of the way

var dot = u1*v1 + u2*v2;
var pgram = [a1+u1+v1,a2+u2+v2]
if (dot == 0 && pgram == D) {rectangle} // will be true 50% of the time if rectangle
else if (pgram == D) {
    w = [d1-a1,d2-a2];

    if (w1*u1 + w2*u2 == 0) {rectangle} //25% chance
    else if (w1*v1 + w2*v2 == 0) {rectangle} //25% chance

    else {!rectangle}
}
else {!rectangle}
1
David Meister

J'ai récemment fait face à un défi similaire, mais en Python, c'est ce que j'ai proposé en Python, peut-être que cette méthode pourrait être utile. L'idée est qu'il y a six lignes et que, si elles sont créées dans un ensemble, il doit rester 3 distances de lignes uniques: la longueur, la largeur et la diagonale.

def con_rec(a,b,c,d): 
        d1 = a.distanceFromPoint(b)
        d2 = b.distanceFromPoint(c)
        d3 = c.distanceFromPoint(d)
        d4 = d.distanceFromPoint(a)
        d5 = d.distanceFromPoint(b)
        d6 = a.distanceFromPoint(c)
        lst = [d1,d2,d3,d4,d5,d6] # list of all combinations 
        of point to point distances
        if min(lst) * math.sqrt(2) == max(lst): # this confirms a square, not a rectangle
            return False
        z = set(lst) # set of unique values in ck
        if len(lst) == 3: # there should be three values, length, width, diagonal, if a 
        4th, it's not a rectangle
            return True
        else: # not a rectangle
            return False
0
Mike M.