给定四个坐标检查它是否形成正方形

时间:2013-08-01 23:32:09

标签: java algorithm complexity-theory

所以我试着写一个简单的方法,它接受一组四个坐标并决定它们是否形成正方形。我的方法是从一个点开始并计算其他三个点和基点之间的距离。由此我们可以得到具有相同值的两边和一个对角线的两边。然后我用毕达哥拉斯定理来找出边平方是否等于对角线。如果是isSquare方法则返回true,否则为false。我想知道是否有一些案例我可能会错过,或者如果方法有问题。谢谢所有的帮助。

public class CoordinatesSquare {

public static boolean isSquare(List<Point> listPoints) {
    if (listPoints != null && listPoints.size() == 4) {
        int distance1 = distance(listPoints.get(0), listPoints.get(1));
        int distance2 = distance(listPoints.get(0), listPoints.get(2));
        int distance3 = distance(listPoints.get(0), listPoints.get(3));

        if (distance1 == distance2) {
            // checking if the sides are equal to the diagonal
            if (distance3 == distance1 + distance2) {
                return true;
            }

        } else if (distance1 == distance3) {
            // checking if the sides are equal to the diagonal
            if (distance2 == distance1 + distance3) {
                return true;
            }

        }
    }
    return false;
}

private static int distance(Point point, Point point2) {
              //(x2-x1)^2+(y2-y1)^2
    return (int) (Math.pow(point2.x - point.x, 2) + (Math.pow(point2.y
            - point.y, 2)));
}

public static void main(String args[]) {
    List<Point> pointz = new ArrayList<Point>();
    pointz.add(new Point(2, 2));
    pointz.add(new Point(2, 4));
    pointz.add(new Point(4, 2));
    pointz.add(new Point(4, 4));
    System.out.println(CoordinatesSquare.isSquare(pointz));
}
}


//Point Class
 public class Point {
Integer x;
Integer y;
boolean isVisited;

public Point(Integer x, Integer y) {
    this.x = x;
    this.y = y;
}

@Override
public boolean equals(Object obj) {
    if(obj!=null && obj.getClass().equals(this.getClass())){
        return ((Point) obj).x.equals(this.x)&&((Point) obj).y.equals(this.y);
    }
    return false;

}
}

7 个答案:

答案 0 :(得分:6)

你知道,你可以更容易地做同样的检查。你只需要检查两件事: “四点制作平行四边形”和“其中一个角度是正确的”。

P3 = P1 + (P2-P1) + (P4-P1)

时首先是这样

第二次(P2-P1)*(P4-P1) = 0

其中A*B是点积(A.x * B.x + A.y * B.y)

这里唯一的问题是计算错误。您不能指望浮点数完全相等,因此您应该考虑使用A=B之类的abs(A-B) < E而不是E而不是{{1}}。

答案 1 :(得分:3)

这是一个角落案例:

如果dist1是方形的对角线距离怎么办? (我假设4点是任意顺序。)

您可能需要再次检查距离:

if(dist1 == dist2){
    //do stuff
}
else if(dist1 == dist3){
    //do stuff
}
else if(dist2 == dist3){
    //do stuff
}
else return false;

答案 2 :(得分:2)

您的功能并未考虑所有因素。你只是在检查一点与其他点。 jwpat7提到了这一点,所以这是一个例子:

bad square!

假设点按此顺序排列:(红色,黄色,绿色,蓝色),网格上的每个块都是一个。

您的distance1distance2都将等于4,所以您基本上说最后一点可以是任何distance3 = 8。这是蓝线。如果最后一个点在该行的任何位置,则您只是将其批准为正方形。

您可以通过执行相同检查轻松解决此问题,但使用下一个坐标作为“基础”,而不是0.如果您的检查通过了两个点,则绝对一个正方形。< / p>


替代:

你可以检查它是否不是一个正方形。在有效方格中,只有两个有效距离,边长(s)和对角线长度(d)。

由于您使用的是平方距离d = s * 2

如果任何距离(只有六个)不等于ds,则不能为正方形。如果所有六个必须为正方形。

优点是,如果您检查以确认正方形,则必须进行所有六次距离检查。如果你想证明它是一个正方形,你可以在找到一个坏的之后停下来。

所以,这取决于你的数据。如果您期望更多的正方形而不是非正方形,您可能需要检查方形度。如果您期望更多非方形,则应检查非方形。这样你可以获得更好的平均情况,即使最坏的情况更慢。

public static boolean isSquare(List<Point> points){
    if(points == null || points.size() != 4)
        return false;
    int dist1 = sqDistance(points.get(0), points.get(1));
    int dist2 = sqDistance(points.get(0), points.get(2));
    if(dist1 == dist2){ //if neither are the diagonal
        dist2 = sqDistance(points.get(0), points.get(3));
    }
    int s = Math.min(dist1, dist2);
    int d = s * 2;

    for(int i=0;i<points.size;i++){
        for(int j=i+1;j<points.size();j++){
            int dist = sqDistance(points.get(i), points.get(j));
            if(dist != s && dist != d))
                return false;
        }
    }
    return true;
}

答案 3 :(得分:1)

如果您添加了else if(dist2 == dist3){...}替代方案(也在另一个答案中也有建议),那么当这四个点形成正方形时,您的isSquare方法确实会识别正方形。但是,您的代码也会将一些非正方形报告为正方形。例如,考虑点{(0,0),(1,1),(0,-1),( - 1,0)}的集合。那么您的distance1,2,3值分别为2,1,1,这将满足dist2 == dist3案例中的测试。

任何非退化四边形总共有六个角间距离。知道其中五个距离会将剩余距离限制为两个值中的任何一个;也就是说,它并没有唯一地约束它。因此,我认为基于角间距离的方形测试方法必须计算并测试其中的所有六个。

答案 4 :(得分:0)

你没有正确使用毕达哥拉斯定理。毕达哥拉斯定理指出,两条腿的平方和是对角线的平方,你正在解释它意味着两条腿的总和等于对角线。您应该将此用于毕达哥拉斯定理测试:

if (distance3 == Math.sqrt(distance1*distance1 + distance2*distance2)) {
    return true;
}

答案 5 :(得分:0)

这有意义吗?

<script>

function isSquare(p1,p2,p3,p4){
  if ((areACorner(p1,p2,p3) && areACorner(p4,p2,p3))
   || (areACorner(p1,p2,p4) && areACorner(p3,p2,p4))
   || (areACorner(p1,p3,p4) && areACorner(p2,p3,p4))) return true

  return false
}

function areACorner(p1,p2,p3){
  //pivot point is p1
  return Math.abs(p2.y - p1.y) == Math.abs(p3.x - p1.x) 
      && Math.abs(p2.x - p1.x) == Math.abs(p3.y - p1.y)
}

</script>

输出:

console.log(isSquare({x:0,y:0},{x:1,y:1},{x:0,y:1},{x:1,y:0}))
true

console.log(isSquare({x:0,y:0},{x:1,y:1},{x:-1,y:-1},{x:1,y:0}))
false

答案 6 :(得分:0)

如果您使用(我的C代码),我使用平方距离(以避免sqrt):

int sqDist(Point p1, Point p2) {
    int x = p1.x - p2.x;
    int y = p1.y - p2.y;
    return(x*x + y*y);
}

其中Point就是:

typedef struct {
    int x, y;
} Point;

`

在你的代码中,计算每个角落彼此的排列,找到最小/最大边缘(平方值),然后你可以检查你有4个边和2个对角线:

int squares[6];

squares[0] = sqDist(p[0], p[1]);
squares[1] = sqDist(p[0], p[2]);
squares[2] = sqDist(p[0], p[3]);
squares[3] = sqDist(p[1], p[2]);
squares[4] = sqDist(p[1], p[3]);
squares[5] = sqDist(p[2], p[3]);

int side = squares[0];
int diagonal = squares[0];
int i = 0;
while((++i <= 4) && (side >= diagonal)) {
    if(squares[i] < side) side = squares[i];
    if(squares[i] > diagonal) diagonal = squares[i];
}
int diagonal_cnt = 0;
int side_cnt = 0;
int error = 0;
for(int i = 0; i < 6; i++) {
   if(abs(side - squares[i]) <= error) side_cnt++;
   if(abs(diagonal - squares[i]) <= error) diagonal_cnt++;
}
printf("Square = %s\n", ((side_cnt == 4) && (diagonal_cnt == 2)) ? "true" : "false");

您可以更改error值来处理浮点错误 - 如果您想转换此例程来处理浮点值。

注意:如果所有点位于同一位置,我认为这是一个点(不是正方形)。