发现一个平面上的4个点是否构成一个矩形?

有人可以告诉我用C风格的伪代码如何编写一个函数(代表你喜欢的点),如果4点(参数函数)形成一个矩形,返回true,否则返回false?

我想出了一个解决scheme,首先尝试find两个不同的点的X值相等,然后做这个Y轴。 但是代码很长。 只是好奇,看看别人想出了什么。

  • findangular点的质心:cx =(x1 + x2 + x3 + x4)/ 4,cy =(y1 + y2 + y3 + y4)/ 4
  • testing从质心到全部四个angular的距离的平方是否相等
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; } 

(当然在实践中,testing两个浮点数a和b的相等应该用有限的精度来完成:例如abs(ab)<1E-6)

 struct point { int x, y; } // tests if angle abc is a right angle int IsOrthogonal(point a, point b, point c) { return (bx - ax) * (bx - cx) + (by - ay) * (by - cy) == 0; } int IsRectangle(point a, point b, point c, point d) { return IsOrthogonal(a, b, c) && IsOrthogonal(b, c, d) && IsOrthogonal(c, d, a); } 

如果事先不知道订单,我们需要稍微复杂一点的检查:

 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); } 
  • 平移四边形,使其顶点之一现在位于原点
  • 剩下的三点从原点形成三个向量
  • 其中一个必须代表对angular线
  • 另外两个必须代表双方
  • 通过平行四边形规则,如果边形成对angular线,我们有一个平行四边形
  • 如果两边形成直angular,则是一个直angular平行四边形
  • 平行四边形的对angular相等
  • 平行四边形的连续angular度是补充的
  • 因此所有angular度都是直angular
  • 这是一个矩形
  • 它在代码中更加简洁:-)

     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); } 
  • (如果你想使用浮点值,请不要盲目地replace头文件中的int声明,这是不好的做法,他们是有原因的,应该总是在错误的上限上工作当比较浮点结果。)

如果积分是A,B,C和D,并且你知道这个顺序,那么你可以计算这些vector:

x = BA,y = CB,z = DC,w = AD

然后取点产品(x dot y),(y dot z),(z dot w)和(w dot x)。 如果他们都是零,那么你有一个矩形。

从一点到另一点的距离应该形成一个直angular三angular形:

 |  / / |
 |  / / |
 |  / / |
 | / ___ / ___ |
 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 

简化:

 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 

我们知道,如果两条直线的积为-1,那么两条直线是垂直的,因为我们可以find一个连续的三条直线的斜率,然后把它们相乘来检查它们是否真的垂直。 假设我们有行L1,L2,L3。 现在如果L1垂直于L2,L2垂直于L3,那么它是一个矩形和m(L1)* m(L2)= – 1和m(L2)* m(L3)= – 1的斜率,意味着它是一个矩形。 代码如下

 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; } 

将点积build议进一步考虑,检查由点中的任意三点产生的两个向量是否垂直,然后查看x和y是否与第四点相匹配。

如果有[Ax,Ay] [Bx,By] [Cx,Cy] [Dx,Dy]

向量v = BA向量u = CA

V(点)U / | V || U | == cos(theta)

所以如果(vu == 0)那里有几条垂直线。

我其实不知道C编程,但是这里给你一些“元”编程: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 (vu/|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} 

这里没有平方根,没有零分的可能性。 我注意到人们在之前的post中提到这些问题,所以我想我会提供一个替代scheme。

所以,计算上,你需要四个减法来得到v和u,两个乘法,一个加法,你必须检查1到7之间的平等。

也许我正在做这个,但我依稀记得在某处读取减法和乘法是“更快”的计算。 我假设声明variables/数组并设置它们的值也相当快?

对不起,我对这类东西很陌生,所以我很想反馈一下我写的东西。

编辑:试试这个基于我的评论如下:

 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}