简体   繁体   English

在X1 y1 X2 y2形式的10,000个点的文件中,如何检测至少四个正方形? 爪哇

[英]In a file of 10,000 points of the form X1 y1 X2 y2 ,,, How to detect at least 4 which form a square ? java

I tried this example with only 4 points, it works with: 我只用了4点尝试了这个示例,它适用于:

-1 -1 -1 -1
2 1 2 1
4 -2 4 -2
1 -4 1 -4

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class CarreSimple {
    static int distance(Point point1, Point point2) {
        int dist = (int) (Math.pow(point1.getX() - point2.getX(), 2) + Math.pow(point1.getY() - point2.getY(), 2));
        dist = (int) Math.sqrt(dist);
        return dist;
    }

    public static void main(String[] args) {
        boolean EstCarre = false;
        Point[] tb = new Point[10000];
        int i = 0;
        BufferedReader br = null;
        try {
            br = new BufferedReader(new FileReader("C:/Users/walid/Downloads/points.txt"));
            String line;
            while ((line = br.readLine()) != null) {
                String[] parts = line.split(" ");
                int part1 = Integer.parseInt(parts[0]);
                int part2 = Integer.parseInt(parts[1]);

                Point p = new Point(part1, part2);
                tb[i] = p;
                System.out.println("X " + tb[i].getX() + " y " + tb[i].getY());
                i++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (br != null) {
                    br.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

        int[] distances = new int[3];
        distances[0] = distance(tb[0], tb[1]);
        distances[1] = distance(tb[0], tb[2]);
        distances[2] = distance(tb[0], tb[3]);
        System.out.println(distances[0]);

        int CoteEgal1 = -1;
        int CoteEgal2 = -1;
        int CotePasEgal = -1;


        if (distances[0] == distances[1]) {
            if (distances[0] != distances[2]) {
                CoteEgal1 = 0;
                CoteEgal2 = 1;
                CotePasEgal = 2;
            }
        } else if (distances[1] == distances[2]) {
            if (distances[1] != distances[0]) {
                CoteEgal1 = 1;
                CoteEgal2 = 2;
                CotePasEgal = 0;
            }
        } else if (distances[0] == distances[2]) {
            if (distances[0] != distances[1]) {
                CoteEgal1 = 0;
                CoteEgal2 = 2;
                CotePasEgal = 1;
            }
        }
        if (CoteEgal1 != -1) {
            int coinOpposÈ = 0;
            switch (CotePasEgal) {
                case 0:
                    coinOpposÈ = distance(tb[2], tb[3]);
                    break;
                case 1:
                    coinOpposÈ = distance(tb[1], tb[3]);
                    break;
                case 2:
                    coinOpposÈ = distance(tb[1], tb[2]);
                    break;
                default:
                    break;
            }

            if (coinOpposÈ == distances[CotePasEgal]) {
                int diagonal = coinOpposÈ;
                int adjacent = distances[CoteEgal1];
                boolean stillOK = true;
                for (int a = 0; a < 4; a++) {
                    int diagonalCount = 0;
                    int adjacentCount = 0;
                    for (int b = 0; b < 4; b++) {
                        if (a != b) {
                            int dist = distance(tb[a], tb[b]);
                            if (dist == diagonal) {
                                diagonalCount++;
                            } else if (dist == adjacent) {
                                adjacentCount++;
                            }
                        }
                    }
                    // est ce que on a 1 diagonal et 2 adjacents
                    if (!(diagonalCount == 1 && adjacentCount == 2)) {
                        stillOK = false;
                        break;
                    }
                }
                if (stillOK) {
                    EstCarre = true;
                }
            }
        }
        if (EstCarre) {
            System.out.println("C'est un carre");
        } else {
            System.out.println("Ce n'est pas un carre");
        }
    }
}

To make a loop on a file of 10,000 points and test on each combination of 4 I found too much difficult. 要在10,000点的文件上循环并对4个点的每种组合进行测试,我发现太难了。

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class Square {
    static int distance(Point point1, Point point2) {
        int dist = (int) (Math.pow(point1.getX() - point2.getX(), 2) + Math.pow(point1.getY() - point2.getY(), 2));
        dist = (int) Math.sqrt(dist);
        return dist;
    }

    public static void main(String[] args) {
        boolean EstCarre = false;
        Point[] tb = new Point[10000];
        int i = 0;
        BufferedReader br = null;
        try {
            br = new BufferedReader(new FileReader("C:/Users/walid/Downloads/exercice.txt"));
            String line;
            while ((line = br.readLine()) != null) {
                String[] parts = line.split(" ");
                int part1 = Integer.parseInt(parts[0]);
                int part2 = Integer.parseInt(parts[1]);

                Point p = new Point(part1, part2);
                tb[i] = p;
                System.out.println("X " + tb[i].getX() + " y " + tb[i].getY());
                i++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (br != null) {
                    br.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
        for (int i2 = 0; i2 < 10000; i2++) {
            for (int j = 0; j < 10000; j++) {
                for (int k = 0; k < 10000; k++) {
                    for (int l = 0; l < 10000; l++) {
                        if (i2 != j && i2 != k && i2 != l && j != k && j != l && k != l) {
                            int[] distances = new int[10000000];
                            distances[i2] = distance(tb[i2], tb[j]);
                            distances[j] = distance(tb[i2], tb[k]);
                            distances[k] = distance(tb[i2], tb[l]);

                            int CoteEgal1 = -1;
                            int CoteEgal2 = -1;
                            int CotePasEgal = -1;

                            if (distances[i2] == distances[j]) {
                                if (distances[i2] != distances[k]) {
                                    CoteEgal1 = i2;
                                    CoteEgal2 = j;
                                    CotePasEgal = k;
                                }
                            } else if (distances[i2] == distances[k]) {
                                if (distances[j] != distances[i2]) {
                                    CoteEgal1 = j;
                                    CoteEgal2 = k;
                                    CotePasEgal = i2;
                                }
                            } else if (distances[i2] == distances[k]) {
                                if (distances[i2] != distances[j]) {
                                    CoteEgal1 = i2;
                                    CoteEgal2 = k;
                                    CotePasEgal = j;
                                }
                            }

                            int coinOpposÈ = 0;
                            if (CoteEgal1 != -1) {
                                if (CotePasEgal == i2) {
                                    coinOpposÈ = distance(tb[k], tb[l]);
                                } else if (CotePasEgal == j) {
                                    coinOpposÈ = distance(tb[j], tb[l]);
                                } else if (CotePasEgal == k) {
                                    coinOpposÈ = distance(tb[j], tb[k]);
                                }

                                if (coinOpposÈ == distances[CotePasEgal]) {
                                    int diagonal = coinOpposÈ;
                                    int adjacent = distances[CoteEgal1];
                                    boolean stillOK = true;
                                    for (int a = 0; a < 10000000; a++) {
                                        int diagonalCount = 0;
                                        int adjacentCount = 0;
                                        for (int b = 0; b < 10000000; b++) {
                                            if (a != b) {
                                                int dist = distance(tb[a], tb[b]);
                                                if (dist == diagonal) {
                                                    diagonalCount++;
                                                } else if (dist == adjacent) {
                                                    adjacentCount++;
                                                }
                                            }
                                        }
                                        // est ce que on a 1 diagonal et 2 adjacents
                                        if (!(diagonalCount == 1 && adjacentCount == 2)) {
                                            stillOK = false;
                                            break;
                                        }
                                    }
                                    if (stillOK) {
                                        EstCarre = true;
                                    }
                                }
                            }
                        }
                        if (EstCarre) {
                            System.out.println("square found");
                        }
                    }
                }
            }
        }
    }
}

code 2: couple is a class that takes two points 代码2:一对是需要两分的课程

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.HashMap;
import java.util.Set;

public class CarreP {
    public static void main(String[] args) {
        Point[] tb = new Point[10000];
        int i = 0;
        BufferedReader br = null;
        try {
            br = new BufferedReader(new FileReader("C:/Users/walid/Downloads/exercice.txt"));
            String line;
            while ((line = br.readLine()) != null) {
                String[] parts = line.split(" ");
                int part1 = Integer.parseInt(parts[0]);
                int part2 = Integer.parseInt(parts[1]);

                Point p = new Point(part1, part2);
                tb[i] = p;
                i++;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (br != null) {
                    br.close();
                }
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

        HashMap<Couple, Integer> hmap = new HashMap<Couple, Integer>();
        int j = 0;
        while (j < tb.length) {
            for (int k = 0; k < tb.length; k++) {
                int xcarre = (int) Math.pow(tb[j].getX() - tb[k].getX(), 2);
                int ycarre = (int) Math.pow(tb[j].getY() - tb[k].getY(), 2);

                int distance = (int) Math.sqrt(xcarre + ycarre);
                Couple c = new Couple(tb[k], tb[k]);
                hmap.put(c, distance);
                Set set = hmap.entrySet();
                Iterator iterator = set.iterator();
                Iterator iterator2 = set.iterator();
                int[] distances = new int[hmap.size()];
                int s = 0;
                while (iterator.hasNext()) {
                    Map.Entry mentry = (Map.Entry) iterator.next();
                    distances[s] = (int) mentry.getValue();
                    System.out.println(distances[s]);
                    s++;
                }
                int CoteEgal1 = -1;
                int CoteEgal2 = -1;
                int CoteInegal = -1;
                for (int i1 = 0; i1 < distances.length; i1++) {
                    for (int i2 = 0; i2 < distances.length; i2++) {
                        for (int i3 = 0; i3 < distances.length; i3++) {
                            if (distances[i1] == distances[i2]) {
                                if (distances[i1] != distances[i3]) {
                                    CoteEgal1 = i1;
                                    CoteEgal2 = i2;
                                    CoteInegal = i3;
                                }
                            } else if (distances[i2] == distances[i3]) {
                                if (distances[i2] != distances[i1]) {
                                    CoteEgal1 = i2;
                                    CoteEgal2 = i3;
                                    CoteInegal = i1;
                                }
                            } else if (distances[i1] == distances[i3]) {
                                if (distances[i1] != distances[i2]) {
                                    CoteEgal1 = i1;
                                    CoteEgal2 = i3;
                                    CoteInegal = i2;
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

General idea is the following: 总体思路如下:

Suppose, we have two points: A and B. There are only two ways to build a square with this points: ABCD and ABEF (see picture below). 假设我们有两个点:A和B。只有两种方法可以用此点构建一个正方形:ABCD和ABEF(请参见下图)。 Now, lets consider AB is a vector. 现在,让我们考虑AB是一个向量。 We can rotate it 90 degrees clockwise and we will get point D. If we move it to point B, then we will get point C. Similarly we can rotate AB 90 degrees counterclockwise and get F and E. 我们可以将其顺时针旋转90度,得到点D。如果将其移动到点B,则将得到点C。类似地,我们可以将AB逆时针旋转90度,得到F和E。

解释图片

Now we need only check if file contains points C and D, or E and F. If so, we have a square. 现在我们只需要检查文件是否包含C和D点,或E和F点。如果是,则有一个正方形。 We can do it quickly if we store all of points in hashmap. 如果我们将所有点存储在哈希图中,则可以快速完成。

Here is a sample implementation: 这是一个示例实现:

import java.util.HashSet;
import java.util.Set;

public class Main {
    public static Set<Point> pointsSet = new HashSet<>();

    public static void main(String[] args) {
        //Suppose, that points are already parsed from file
        Point[] points = new Point[]{
                new Point(-1, -1),
                new Point(2, 1),
                new Point(4, -2),
                new Point(1, -4)
        };

        //Fill hashset with points. Important: hashCode() and equals() methods are overrided in Point class
        for (Point point : points) {
            pointsSet.add(point);
        }

        Point point1;
        Point point2;
        Point suggested_point3;
        Point suggested_point4;

        //Consider every pair of points
        for (int i = 0; i < points.length - 1; i++) {
            point1 = points[i];
            for (int j = i + 1; j < points.length; j++) {
                point2 = points[j];

                //Calculate vector coordinates for pair of points
                Vector vector = new Vector(point2.getX() - point1.getX(), point2.getY() - point1.getY());

                //Rotate vector clockwise by 90 degrees and calculate coordinates,
                //where two more points should be to form a square with current pair of points
                Vector clockwise_rotated_vector = rotateVector(vector, 90);
                suggested_point3 = moveVectorToPoint(clockwise_rotated_vector, point1);
                suggested_point4 = moveVectorToPoint(clockwise_rotated_vector, point2);
                if (pointsSet.contains(suggested_point3) && pointsSet.contains(suggested_point4)) {
                    squareFound(point1, point2, suggested_point3, suggested_point4);
                }

                //Same for counterclockwise rotated vector
                Vector counterclockwise_rotated_vector = rotateVector(vector, -90);
                suggested_point3 = moveVectorToPoint(counterclockwise_rotated_vector, point1);
                suggested_point4 = moveVectorToPoint(counterclockwise_rotated_vector, point2);
                if (pointsSet.contains(suggested_point3) && pointsSet.contains(suggested_point4)) {
                    squareFound(point1, point2, suggested_point3, suggested_point4);
                }
            }
        }
    }

    private static void squareFound(Point point1, Point point2, Point point3, Point point4) {
        System.out.println(String.format("%s, %s, %s, %s", point1, point2, point3, point4));
    }

    private static Point moveVectorToPoint(Vector vector, Point point) {
        double x = point.getX() + vector.getX();
        double y = point.getY() + vector.getY();
        return new Point(x, y);
    }

    private static Vector rotateVector(Vector original_vector, double degrees) {
        double radians = Math.toRadians(degrees);
        double x = original_vector.getX() * Math.cos(radians) - original_vector.getY() * Math.sin(radians);
        double y = original_vector.getX() * Math.sin(radians) + original_vector.getY() * Math.cos(radians);
        return new Vector(x, y);
    }
}

Class Point : 课堂Point

import java.math.BigDecimal;
import java.util.Locale;

public class Point {
    public Point(double x, double y) {
        this.x = x;
        this.y = y;

        //Store decimal values with certain scale, which would later be used for hashCode() calculation
        this.decimalX = new BigDecimal(x).setScale(DECIMAL_SCALE, BigDecimal.ROUND_HALF_EVEN);
        this.decimalY = new BigDecimal(y).setScale(DECIMAL_SCALE, BigDecimal.ROUND_HALF_EVEN);
    }

    private static final int DECIMAL_SCALE = 3;

    private double x;
    public double getX() {
        return x;
    }

    private double y;
    public double getY() {
        return y;
    }

    private BigDecimal decimalX;
    private BigDecimal decimalY;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Point point = (Point) o;

        if (!decimalX.equals(point.decimalX)) return false;
        return decimalY.equals(point.decimalY);
    }

    @Override
    public int hashCode() {
        //calculate for decimal values, so two very close enough points will have equal hash codes
        int result = decimalX.hashCode();
        result = 31 * result + decimalY.hashCode();
        return result;
    }

    @Override
    public String toString() {
        return String.format(Locale.ENGLISH, "(%2f,%2f)", x, y);
    }
}

Class Vector : Vector

public class Vector {
    public Vector(double x, double y) {
        this.x = x;
        this.y = y;
    }

    private double x;
    public double getX() {
        return x;
    }

    private double y;
    public double getY() {
        return y;
    }
}

UPDATE: As mentioned in comments, there were few moments to improve, so I updated my code. 更新:正如评论中所提到的,有一些地方需要改进,因此我更新了代码。

Finding all possible combinations of squares from 10000 points would be too much work doing it brute-force. 要从10000个点中找到所有可能的正方形组合,将很难完成。

So, you need a way to find points that can be combined to form a square, ie points that share X or Y coordinate. 因此,您需要一种方法来查找可以组合成正方形的点,即共享X或Y坐标的点。

So, load all points into memory, "indexing" them by building a Map<Integer, Set<Integer>> , mapping X coordinates to collection of Y coordinates. 因此,将所有点加载到内存中,通过构建Map<Integer, Set<Integer>> ,将X坐标映射到Y坐标的集合来“索引”它们。 The value is a Set so duplicate points are eliminated, and to improve performance of code below. 该值是一个Set因此消除了重复的点,并提高了下面代码的性能。

Now comes the more brute-force part, but it's greatly reduced, so shouldn't be too bad. 现在出现了更强力的部分,但是它大大减少了,因此应该不会太糟。 Search like this (pseudo-code so you have to do part of this too) : 像这样搜索(伪代码,因此您也必须做一部分)

for eRight in xMap:
    xRight = eKey.key
    continue if eRight.value.size() == 1
    for eLeft in xMap:
        xLeft = eLeft.key
        continue if xLeft >= xRight
        continue if eLeft.value.size() == 1
        // at this point we now have two distinct X coordinates
        // with their corresponding collection of Y coordinates
        for yTop : eLeft.value:
            continue if ! eRight.value.contains(yTop)
            for yBottom : eLeft.value:
                continue if yBottom >= yTop // assuming (0,0) is lower-left
                continue if ! eRight.value.contains(yBottom)
                // at this point we now have two distinct Y coordinates
                // that fit both X coordinates, i.e we have a rectangle
                new Rectangle(xLeft, yTop, xRight, yBottom)

The above code finds rectangles , not squares . 上面的代码查找矩形 ,而不是正方形 I'll leave it to you to changing it to find squares. 我将它留给您进行更改以找到正方形。
Hint : The yBottom (or yTop ) loop is replaced with a calculation. 提示yBottom (或yTop )循环被计算替换。

I have an answer that is similar to Marat Safin's above, except that I think we must be careful about the fact that floating point arithmetic is imprecise and we must be careful that after some steps of calculation, a floating point number like 3.1415926 may become 3.1415927 (just differ by 1E-7). 我有一个与上面的Marat Safin相似的答案,除了我认为我们必须注意以下事实:浮点算法不精确,并且必须小心,经过一些计算步骤,像3.1415926这样的浮点数可能会变成3.1415927 (只是相差1E-7)。 The solution to this is that we must also declare an argument epsilon (tolerance) that allows us to do "approximately equal" of two floating point numbers (such as double ). 解决方案是,我们还必须声明一个参数epsilon (公差),该参数允许我们对两个浮点数(例如double )“近似相等”。

My answer also has test input which you can use to verify your program. 我的答案还包含测试输入,可用于验证程序。

You can find my answer here in another SO post of Detect square in a List of Points 您可以在点列表中检测方的另一篇SO帖子中找到我的答案

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何确定百万数据点中的哪些点 (x,y) 位于矩形 (x1, x2, y1, y2) 所描述的区域内? - How to determine which points (x,y) out of million data points lie inside the area described by a rectangle (x1, x2, y1, y2)? 如何划分字符串(x1,y1)(x2,y2)格式 - How to divide string (x1,y1)(x2,y2) format 如何重新格式化 GetVertices 以返回 (x1,y1,0), (x2,y2,0), (x3,y3,0);? - How to re format GetVertices to return (x1,y1,0), (x2,y2,0), (x3,y3,0);? 在java中以给定速度以直线将对象从点(x1,y1)移动到点(x2,y2)的方法 - Method to move an object from point(x1,y1) to point(x2,y2) at a given speed in a straight line in java 按钮无法绘制具有坐标(x1,x2,y1,y2)的折线图 - Button not working to draw line graph having its coordinate (x1, x2, y1, y2) 如果我们知道距离x1,y1,y2,则计算x2 - Calculate x2 if we know distance, x1, y1, y2 如何使用Quartz库每天在XX:XX处安排从日期X1 / Y1 / Z1到日期X2 / Y2 / Z2的某些任务? - How can I use Quartz library to schedule some task from date X1/Y1/Z1 to date X2/Y2/Z2 at XX:XX every day? 给定两个点 A(x1,y1) &amp; B(x2,y2),我想在球面上找到第三点 C(x3,y3) 和线 AB 之间的距离和 AD 的长度 - Given two points A(x1,y1) & B(x2,y2), I want to find the distance between the third point C(x3,y3) and line AB and length of AD on spherical surface 为什么 x *= (y1*y2*y3)/z1 没有给出与 JAVA 中的 x = x * (y1*y2*y3)/z1 相同的答案 - Why is x *= (y1*y2*y3)/z1 not giving the same answer as x = x * (y1*y2*y3)/z1 in JAVA Java - setXY(x1, y1) 和新的 Object 有什么区别 - Java - What the difference of setXY(x1, y1) and new Object
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM