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.
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)
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);
}
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.)
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
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.
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. 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
Bit Magic
É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.
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}
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