请有人以C风格伪代码展示如何编写一个函数(无论您喜欢哪种表示点的方式),该函数返回true,如果4个点(作为函数参数)形成一个矩形,否则返回false?
我想出了一种解决方案,首先尝试找到两个具有相等x值的不同点对,然后对y轴做同样处理。 但是代码相当冗长。 只是好奇看看别人会想出什么。
请有人以C风格伪代码展示如何编写一个函数(无论您喜欢哪种表示点的方式),该函数返回true,如果4个点(作为函数参数)形成一个矩形,否则返回false?
我想出了一种解决方案,首先尝试找到两个具有相等x值的不同点对,然后对y轴做同样处理。 但是代码相当冗长。 只是好奇看看别人会想出什么。
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;
}
(当然,在实践中,应该使用有限的精度来测试两个浮点数a和b的相等性:例如,abs(a-b) < 1E-6)sqr(x)==x*x
,这意味着ddi
实际上是从cx
到xi
的距离的平方。这应该非常快速。 - Brett Pontarellistruct 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);
}
如果事先不知道顺序,我们需要进行稍微复杂一些的检查:
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);
}
if (IsOrthogonal(a, b, c)) return IsRectangle(a, b, c, d); else if (IsOrthogonal(a, b, d)) return IsRectangle(a, b, d, c); else return false;
- Vladit is much more concise in code, though :-)
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);
}
(If you want to make it work with floating point values, please, do not just blindly replace the int declarations in the headers. It is bad practice. They are there for a reason. One should always work with some upper bound on the error when comparing floating point results.)
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.
从一个点到另一个点3的距离应该形成一个直角三角形:
| / /| | / / | | / / | |/___ /___|
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
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;
}
进一步推荐采用点积方法,检查由任意3个点组成的向量中是否有两个互相垂直,并查看它们的x和y是否与第四个点匹配。
如果你有点[Ax,Ay] [Bx,By] [Cx,Cy] [Dx,Dy]
向量v = B-A 向量u = C-A
v(dot)u/|v||u| == cos(theta)
所以如果(v.u == 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 (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}
这个问题中没有平方根,也没有可能出现除以零的情况。我注意到早些帖子中有人提到了这些问题,所以我想提供一个替代方案。
因此,在计算上,您需要四次减法来得到v和u,两次乘法,一次加法,并且您必须检查1到7个等式之间的某个位置。
也许我是在编造,但我模糊地记得在某个地方读到过减法和乘法是“更快”的计算。我假设声明变量/数组并设置它们的值也非常快?
抱歉,我对这种事情还很陌生,所以我希望能得到一些反馈。
编辑:基于我下面的评论,请尝试这个:
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}
我最近也遇到了类似的挑战,但是在Python中,我想出了以下方法,也许这个方法会有价值。这个想法是有六条线,如果把它们放到一个集合里,应该会剩下3个唯一的线距离 - 长度、宽度和对角线。
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
首先验证这四个点是否能够构成平行四边形,然后再找出是否存在一个直角。
1. 验证平行四边形
输入4个点A、B、C、D;
如果(A、B、C、D是同一个点),退出;// 不是矩形;
否则,形成3个向量AB、AC、AD,验证(AB=AC+AD || AC=AB+AD || AD=AB+AC),\\如果其中一个满足,则为平行四边形;
2.验证直角
通过上一步,我们可以找到哪两个点是A的相邻点;
我们需要找出角A是否为直角,如果是,则为矩形。
我不知道是否存在错误。请查找并纠正。