如何检查4个点是否形成正方形?


36

假设我有4个点(它们是2维),它们彼此不同,并且我想知道它们是否形成正方形。怎么做?(让过程尽可能简单。)


3
我认为您需要考虑旋转正方形?
马丁·彼得

您是否完全了解点的顺序?即,您能否说出两个点是相邻的还是对角的?(此信息可用于简化流程)
Daniel B

1
@DanielB没有其他信息。就像我有一张白皮书,并随机在其上绘制4个点一样。然后我想知道它们是否形成正方形。
MarshalSHI 2012年

5
特别是如果将这些点表示为浮点数,则在以下建议的任何比较中包括“容忍”感是很有用的。对于浮点运算的结果,精确的相等性检查可能会失败,即使我们人类认为它们“足够接近”。
Stephan A. Terre 2012年

这闻起来像一个作业问题。并不是说这有什么问题。:/ whathaveyoutried.com
吉姆·

Answers:


65

假设正方形可以相对于已有的坐标系旋转,则不能依赖于四个点中X和Y值的重复。

您可以做的是计算四个点之间的距离。如果您发现以下情况成立,那么您将得到一个正方形:

  1. 有两个点,比如说A和C,它们彼此之间的距离为x;还有另外两个点,比如说B和D,它们之间也是彼此的距离x

  2. 每个点{A,B,C,D}与未x的两个点之间的距离相等。即:如果A 与C距离x,那么它将与B和D距离z

顺便说一句,距离z必须为SQRT((x ^ 2)/ 2),但是您无需确认这一点。如果条件1和2为真,则您有一个正方形。 注意:有些人担心平方根的效率低下。我并不是说您应该进行此计算,我只是说,如果您进行了计算,您将得到可预测的结果!

平方规则的插图

您要做的最起码的工作是选择一个点(例如A)并计算到其他三个点的距离。如果您发现一个点的A是x,另外两个点的z是z,那么您只需要检查其他两个点是否相对即可。如果它们彼此也是x,则您有一个正方形。即:

  • AB = z
  • AC = x
  • AD = z

由于AB = AD,请检查BD:

  • BD = x

只是要确保,您需要检查另一面:BC和CD。

  • BC = z
  • CD = z

由于AC = BD,并且AB = AD = BC = CD,因此,这是一个正方形。

在此过程中,如果找到两个以上的不同边距,则该图形不能是正方形,因此可以停止查找。


工作示例实施

我已经在jsfiddle上创建了一个工作示例(请参阅此处)。在对算法的解释中,我使用了任意点A,B,C和D。为了遍历示例,这些任意点碰巧是按一定顺序排列的。即使这些点的顺序不同,该算法也可以工作,但是,如果这些点的顺序不同,则该示例不一定有效。


感谢: meshuai,Blrfl,MSalters和Bart van Ingen Schenau提出的有益意见,以改善此答案。


19
您可以缩短此过程,而不必担心点的顺序,方法是测量它们之间的距离并跟踪找到的唯一距离的数量。一旦超过两个(乔尔的xz),该图就不是正方形。
Blrfl 2012年

3
另一个优化将是比较平方距离而不是距离。
vaughandroid 2012年

3
@Blrfl:您的测试无效。假设ABCD是菱形,AB = BC = CD = DA = 1,AC = 1(对角线短),那么AD〜1.7(对角线长)/您只有x和z的两个长度,但该图不是正方形。
MSalters 2012年

2
@JoelBrown:可以创建对角线形状,对角线AC = BD = x,边AB = BC = AD = z,最后边CD = y!= z。
Bart van Ingen Schenau 2012年

2
足够公平,但是请注意,OP明确表示了二维。
乔尔·布朗

24

选择四个点中的三个。

通过检查点之间的三个向量之一是否等于旋转90度的另一个向量,找出它是否为等腰三角形。

如果是这样,则通过向量相加来计算第四点,并将其与给定的第四点进行比较。

请注意,这不需要昂贵的平方根,甚至不需要乘法。


两个好答案之一。sqrt除非至关重要,否则不要使用!您无需将整数计算降级为FP ...更不用说降低FP计算的精度了。
K.Steff

谢谢。好人
MarshalSHI 2012年

现在,这是正确的方法。确实在这里不需要乘法。

您如何查找两个向量是否相互垂直,而它们的点积不涉及乘法?
Pavan Manjunath '18 -4-2

1
直角旋转的(x,y)分别是(-y,x)或(y,-x),具体取决于您是沿正方向还是负方向旋转。
starblue '18 -4-3

15

我认为最简单的解决方案如下:

  • 首先,计算这四个点的中心: center = (A + B + C + D)/4

  • 然后计算向量A - center。让它成为v := (x,y)

  • v2向量v旋转90度:v2 := (-y, x)

  • 现在,其他的点应该是center - vcenter + v2center - v2

此解决方案的优点是您根本不必使用平方根。


2
是的 这是最容易理解的,也可能是最容易实现的。
埃里克G

似乎段的向量相等。任何人都可以详细说明或证明其工作原理吗?
vCillusion

它专门针对情况(0,0),(2,1),(3,-1),(1,-2)失败–正方形未与轴对齐
vCillusion '16

1
它适用于这种情况。中心点是(1.5,-0.5),第一个点是(0,0),其他三个点是(1.5,-0.5)+(1.5,-0.5)=(3,-1); (1.5,-0.5)+(0.5,1.5)=(2,1)和(1.5,-0.5)-(0.5,1.5)=(1,-2)这意味着它是一个正方形。证明是..对称吗?
aragaer

“距离解决方案”需要平方根,但是有“平方距离解决方案”,不需要。您的效率可能更高……
maaartinus

5

抱歉,某些答案不适用。

对于这种情况,您测量了3条边(假设AB,AC和AD),发现两条边具有相同的大小(例如AC和AD),而一条边更大(例如AB)。然后,您将测量CD以查看其大小是否与AB相同,然后您会发现它的大小。可能没有正方形,而是下面的图片,这使它成为错误的解决方案。

不是正方形...

然后尝试其他解决方案:至少测量一次所有距离:AB,AC,AD,BC,BD,CD。然后,您发现那时的4个相等,而其他2个也相等。但是您可能只有下面的图片:

那也不是正方形...

因此,尽管获得了很高的评价,但这些答案还是不正确的。

一种可能的解决方案:如果两个相等的度量未连接同一点。因此:如果AB和CD长度相同,则所有其他组合(AC,AD,BC,BD)也相等,那么您就有一个平方。如果同一点的长度最大(AB和AC最大,其他所有都相等),则上面的图片之一。


不,他的算法表示距离x的2个边不共享点。但您只共享C。因此,假设AC为x,则BD应该为另一个x,而不是BC。
MarshalSHI 2012年

3

令这四个点具有坐标向量a,b,c,d。

然后让我们称它们的差异为w =(ad),x =(ba),y =(cb),z =(dc)。

如果可以从a旋转90度来创建w,则w与a正交。在数学上,二维空间中的90度旋转矩阵是((0,-1),(1,0)。因此,w是否为90度旋转的条件导致

(w_1 == -x_2和w_2 == x_1)

如果成立,则需要检查w == -y和x == -z,或者

((w_1 == -y_1和w_2 == -y_2)和(x_1 == -z_1和x_2 == -z_2))

如果这三个关系成立,则a,b,c,d会构成一个定向的正方形。


1
我认为矩形也可以满足您的条件。
MarshalSHI 2012年

不,正交条件不能满足第一个条件,但长度不能相等。
马克·萨尔泽

1
是的,我只是想念第一个。但是这4点没有顺序。因此,我认为,我们需要采取更多步骤以进行确认。
MarshalSHI 2012年

是的...如果没有更聪明的主意出现,那谁该循环。我认为,需要一个外部循环来根据a,b,c,d的每种可能的顺序来计算w,x,y,z,以及一个内部循环才能对w,x,y,z元组的每种可能的顺序进行计算。
Mark Salzer 2012年

2

类似于starblue的答案

选择四个点中的任何三个。

在其中寻找直角的顶点:通过检查三个向量中的任意两个的点积是否为零。如果找不到,就不是正方形。

检查与该角度相邻的顶点是否也成直角。如果不是,则不是正方形。

检查对角线是否垂直:如果第一和第四顶点与其他两个顶点(对角线)之间的矢量的点积为零,则其为正方形。


好主意,但您仍然需要检查第四个顶点与其他点的距离是否正确。您只需检查它是否在对角线上。
starblue

@starblue对!否则会形成风筝。更新。
最大

2

在此处输入图片说明

这里有一些很好的答案,但是这个问题要求最简单的方法。我快速思考了一下,这就是我会做的。

您可以判断四个点是否代表一个正方形(即使旋转),也可以找到四个点的平均值。

R = (A+B+C+D)/4

获得平均值后,所有四个点的每个点与平均值之间的距离必须相同。

if(dist(R,A) == dist(R,B) == dist(R,C) == dist(R,D) then
   print "Is Square"
else
   print "Is Not Square"

编辑:

我的错。那只会告诉您形状点是否在圆上。如果还检查点之间的距离,则它必须是正方形。

if(dist(R,A) == dist(R,B) == dist(R,C) == dist(R,D) AND
  (dist(A,B) == dist(B,C) == dist(C,D) == dist(A,D) then
   print "Is Square"
else
   print "Is Not Square"

这假定点A,B,C,D不交叉(因为具有有效的缠绕顺序)。


1

根据标准集,这不是一个答案,但是我希望这会有所帮助:

[从下面的链接复制,因此您不必打开链接] Python 76个字符

def S(A):c=sum(A)/4.0;return set(A)==set((A[0]-c)*1j**i+c for i in range(4))

函数S将复数列表作为其输入(A)。如果我们知道正方形的中心和一个角,则可以通过围绕中心点(c)旋转角90,180和270度来重建正方形。在复平面上,通过将点乘以i绕原点旋转90度。如果我们的原始形状和重建的正方形具有相同的点,那么它一定是正方形。

摘自: 确定4个点是否形成正方形

我说,如果您喜欢答案,请花点时间感谢此人,或在该页面上投票给他的答案。


1
您可以在这里总结算法。要链接到另一个SE网站,这是略好于指向另一个网站,但我们想要的答案是在这个页面,这个问题被问。现在人们必须再次单击以了解答案。
马丁·彼得

1

我认为您可以通过简单的加减运算来找到最小值/最大值。字词(与其他人的图匹配):

  • y值最高的点=> A
  • 最高x => B
  • 最低y => C
  • 最低x => D

如果4个点仅共享2个x值和2个y值,则您有一个水平平方。

否则,如果您的点满足以下条件,则您有一个正方形:

  • Ax + Cx = Bx + Dx
  • Ay + Cy = By + Dy
  • Ay-Cy = Bx-Dx

说明:线段AC和BD应该在它们的中点相交。因此(Ax + Cx)/ 2是AC的中点,而(Bx + Dx)/ 2是BD的中点。将此方程的每一边乘以2,得到我的第一个方程。对于Y值,第二个方程式是相同的。菱形(菱形)将满足这些属性,因此您需要检查边是否相等-宽度是否与高度相同。那是第三个方程式。


0

基本想法(这回答了我是否正在贡献新的东西的问题,当我单击以提供答案时,该问题被机器人问到了):

  • 对角线相等的菱形是一个正方形。
  • “尽可能简单”包括:
    • 没有分裂,
    • 没有平方根,
    • 没有分支
    • 没有搜索,
    • 没有角度检查或追逐,
    • 没有向量
    • 没有转变,
    • 没有复数,
    • 没有多行功能,并且
    • 不导入特殊软件包(仅使用内置的东西)。
    • (也没有帝王的纠缠!)

我在R中的解决方案如下所示。我假设恰好有四个点,并且根据问题陈述,已经确定了这些点是唯一的。

sumsq <- function(x) sum(x^2)

quadrances.xy <- function(xy) vapply(
    as.data.frame(t(diff(xy)), optional=T), sumsq, 1)

观看诺曼·怀德伯格(Norman Wildberger)的作品,尤其是他的YouTube视频(真实的鱼类,真实的数字,真实的工作等)和他的《神的比例》一书,其中讨论了“四面楚歌”。

xy指的是由R的接受一种基质的plotpointslines功能。

应用as.data.frame是使R按列进行操作的一种技巧。

optional=T子句消除了无论如何都不会使用的名称。

quadrances.xy..i2. <- function(xy, i2) vapply(
    as.data.frame(i2, optional=T),
    function(k) quadrances.xy(m[k,]),
    1)

此函数用于计算指定点之间的象限,其中点对由i2参数指定。该i2符号指的是一个索引矩阵,每个索引具有一列,每列具有2个元素(该combn函数返回的同类矩阵)。

quadrance.every.xy <- function(xy, .which=combn(nrow(xy), 2))
        quadrances.xy..i2.(xy, .which)

.which是作为一个参数只是将其暴露在formals并试图与之通信是怎么回事。

is.square.xy <- function(xy) {
    qq <- sort(quadrance.every.xy(xy))
    all(qq[2:4] == qq[1]) && # ALL SIDES (SHORT QUADRANCES) EQUAL
    qq[5] == qq[6] # ALL DIAGONALS (LONG QUADRANCES) EQUAL
}

我说“简单”不包含多行功能。您必须原谅此两行功能。

xy <- t(matrix(c(3,0,  7,3,  4,7,  0,4), ncol=4))
xy
#      [,1] [,2]
# [1,]    3    0
# [2,]    7    3
# [3,]    4    7
# [4,]    0    4
is.square.xy(xy)
# [1] TRUE

请注意,除了关于这四个要点的问题之外,前四个功能本身就很有用。


0

假设四个点A =(ax,ay),B =(bx,by),C =(cx,cy),D =(dx,dy),它们形成了一个逆时针方向的正方形点。通过将bx,cx和dx减去ax,然后将by,cy和dy减去ay,设置ax = ay = 0,移动点,使A处于(0,0)。

如果这些点按逆时针顺序恰好是正方形的角,则我们应具有(cx,cy)=(bx-by,bx + by)和(dx,dy)=(-by,bx)。因此,我们计算了从C和D到应到达的平方距离:errC =(cx-bx + by)^ 2 +(cy-bx-by)^ 2,而errD =(dx + by)^ 2 +(dy-bx)^ 2。我们将它们相加,然后除以(bx ^ 2 +除^ 2),得到err =(errC + errD)/(bx ^ 2 +除^ 2)。如果是完美的正方形,则结果err将为0;如果几乎是正方形,则结果为err;如果我们平移,缩放或旋转正方形的点,则该数字将保持不变,但舍入误差除外。

但是我们不知道顺序。我们可以找出哪个点是C,因为它离A远:计算distB = bx ^ 2 + by ^ 2,distD = dx ^ 2 + dy ^ 2。如果distD≥1.5 distB,则交换C和D;如果distB≥1.5 distD,则我们交换C和B。现在C是正确的。我们还可以找出哪些点是B和D:如果我们猜错了哪一个是B而哪一个是D,则我们的计算会将D放到完全错误的位置。所以如果errD≥(bx ^ 2 + by ^ 2),那么我们交换B和D。

摘要:

  1. 从bx,cx,dx中减去ax。用cy,dy减去ay。
  2. 令distB = bx ^ 2 + by ^ 2,distD = dx ^ 2 + dy ^ 2。
  3. 如果distD≥1.5 * distB,则交换C和D并再次计算distD
  4. 否则,如果distB≥1.5 * distD,则交换B和C并再次计算distB。
  5. 令errD =(dx + by)^ 2 +(dy-bx)^ 2。
  6. 如果errD≥distB,则交换B和D,交换distB和distD,再次计算errD。
  7. 令errC =(cx-bx + by)^ 2 +(cy-bx-by)^ 2。
  8. 令err =(errC + errD)/ distB。
  9. 根据err的值确定是正方形还是近似正方形。

如果我们知道点的顺序,显然可以简化。


-3

解决方案类似于思考媒体。

第一步:

x = (A+B+C+D)/4
f=0
if(dist(x,A) == dist(x,B) == dist(x,C) == dist(x,D) 
   f=1
else
   f=0

此属性后跟正方形,因为它是循环的。现在是跟随此属性的圈子。所以,现在只需检查

if(A.B==B.C==C.D==D.A==0)
  f=1
else 
  f=0

if (f==1)
  square
else 
  not square

在这里AB表示A和B的点积

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.