找到一个平面上的4个点是否形成一个矩形?

时间:2010-02-20 19:01:06

标签: c algorithm geometry

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

我提出了一个解决方案,首先尝试找到具有相同x值的2对不同点,然后对y轴进行此操作。但代码相当长。只是想知道其他人想出了什么。

11 个答案:

答案 0 :(得分:57)

  • 找到角点的质心:cx =(x1 + x2 + x3 + x4)/ 4,cy =(y1 + y2 + y3 + y4)/ 4
  • 测试从质心到所有4个角的距离的平方是否相等
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)

答案 1 :(得分:37)

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

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

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

答案 2 :(得分:5)

  • 翻译四边形,使其顶点之一现在位于原点
  • 其余三个点从原点
  • 形成三个向量
  • 其中一个必须代表对角线
  • 其他两个必须代表双方
  • parallelogram rule如果两边形成对角线,我们有一个平行四边形
  • 如果两侧形成直角,则它是具有直角的平行四边形
  • 平行四边形的相对角度相等
  • 平行四边形的连续角度是补充
  • 因此所有角度都是直角
  • 是一个矩形
  • 但代码更简洁: - )

    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);
    }
    
  • (如果你想让它与浮点值一起使用,请不要盲目地替换标题中的 int 声明。这是不好的做法。它们适用于在比较浮点结果时,应始终使用错误的某个上限。)

答案 3 :(得分:4)

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

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

答案 4 :(得分:3)

如果分数是A,B,C&amp; D你知道顺序然后计算向量:

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

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

答案 5 :(得分:3)

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.

在这里,我们使用的是矩形/正方形位魔术的几何属性。

正在播放的矩形属性

  1. 矩形的相对边和对角线的长度相等。
  2. 如果矩形的对角线长度是sqrt(2)乘以其任何长度,则矩形是正方形。

位魔术

  1. 对等号进行异或运算返回0。

由于矩形的4个角之间的距离将始终形成3对,其中一对用于对角线,而两个用于不同长度的每一侧,因此对所有值进行XOR运算将为矩形返回0。

答案 6 :(得分:1)

我们知道如果斜率的乘积为-1,则两条直线是垂直的,因为给定了一个平面,我们可以找到三条连续线的斜率,然后将它们相乘以检查它们是否真正垂直。假设我们有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;
}

答案 7 :(得分:1)

将点积建议更进一步,检查点中任意3点的两个矢量是否垂直,然后看x和y是否与第四点匹配。

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

向量v = B-A 向量u = C-A

V(点)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}

答案 8 :(得分:0)

如何验证这四个点首先可以形成平行四边形,然后找出是否存在一个直角
1. 验证平行四边形

input 4 points A, B, C, D;

if(A, B, C, D are the same points), exit;// not a rectangle;

else form 3 vectors, AB, AC, AD, verify(AB=AC+AD || AC=AB+AD || AD=AB+AC), \\if one of them satisfied, this is a parallelogram;

2. 验证直角

through the last step, we could find which two points are the adjacent points of A;

We need to find out if angle A is a right angle, if it is, then rectangle.

我不知道是否存在错误。请找出是否存在。

答案 9 :(得分:0)

我最近面临类似的挑战,但是在Python中,这就是我在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

答案 10 :(得分:0)

这是我的算法建议,用于轴对齐的矩形测试,但使用Python。

这个想法是要抓住第一个点作为枢轴,所有其他点必须符合相同的宽度和高度,并通过一组检查所有点是否不同,以解决诸如(1 ,2),(1、2),(10、30),(10、30)。

from collections import namedtuple

Point = namedtuple('Point', ('x', 'y'))

def is_rectangle(p1, p2, p3, p4) -> bool:
    width = None
    height = None

    # All must be distinct
    if (len(set((p1, p2, p3, p4))) < 4):
        return False

    pivot = p1

    for point in (p2, p3, p4):
        candidate_width = point.x - pivot.x
        candidate_height = point.y - pivot.y

        if (candidate_width != 0):
            if (width is None):
                width = candidate_width
            elif (width != candidate_width):
                return False

        if (candidate_height != 0):
            if (height is None):
                height = candidate_height
            elif (height != candidate_height):
                return False

    return width is not None and height is not None

# Some Examples
print(is_rectangle(Point(10, 50), Point(20, 50), Point(10, 40), Point(20, 40)))
print(is_rectangle(Point(100, 50), Point(20, 50), Point(10, 40), Point(20, 40)))
print(is_rectangle(Point(10, 10), Point(20, 50), Point(10, 40), Point(20, 40)))
print(is_rectangle(Point(10, 30), Point(20, 30), Point(10, 30), Point(20, 30)))
print(is_rectangle(Point(10, 30), Point(10, 30), Point(10, 30), Point(10, 30)))
print(is_rectangle(Point(1, 2), Point(10, 30), Point(1, 2), Point(10, 30)))
print(is_rectangle(Point(10, 50), Point(80, 50), Point(10, 40), Point(80, 40)))