Search code examples
javaandroidpoint

Detect Location of known Points in a Rectangle


I have a array of 4 PointF objects. Each point in this array is a Corner of a rectangle. Now I want to set the Points in that array in a certain order in dependence of their Location. e.g. PointF[0] shall be the topleft point and PointF[1] the bottomleft (and so on in clockwise direction).

I tried to check the coordinates e.g. if a points x and y coordinates are the lowest of every Point in the array it is the topleft one (Image Coordinate System). And if every coordinate is the biggest, it is the bottomright point.

The Problem with this solution is, that it is possible, that the Points in that Array could also represent a parallelogram or a trapezoid meaning, that the angle between the corners does not have to be 90 degree.

Here a Image where I try to visualize what I want to achieve:

Example


Solution

  • I found a good solution, which fits for my Problem.

    First I try to detect the top-left corner and the bottom-right corner of the Rectangle. To do that, I calculate the length of a two dimensional Vector from the source of the coordinate system. The shortest of the 4 vectors would be the top-left corner and the biggest the bottom-right corner. The other two points I try to detect through simple coordinate check with the two known points. To avoid a little bug, where the top-right-corner would come through the same check as the bottom-left, I sort the points through their x coordinates.

    Here is the code:

    private PointF[] checkPointLocation(PointF[] points){
    
        double minLength = 100000000;
        double maxLength = 0;
        int minPos = 0;
        int maxPos = 0;
    
        for(int i = 0; i < points.length; i++){
            double vLength = Math.abs(Math.sqrt((points[i].x * points[i].x) + (points[i].y * points[i].y)));
    
            if(vLength < minLength) {
                minLength = vLength;
                minPos = i;
            }
            if(vLength > maxLength) {
                maxLength = vLength;
                maxPos = i;
            }
        }
    
        PointF topLeft = points[minPos];
        PointF bottomRight = points[maxPos];
    
        Log.d(TAG, "TopLeft: " + topLeft);
        Log.d(TAG, "BottomRight: " + bottomRight);
    
        PointF topRight = null;
        PointF bottomLeft = null;
    
        Arrays.sort(points, (o1, o2) -> Float.compare(o1.x, o2.x));
    
        for(int i = 0; i < points.length; i++){
            PointF p = points[i];
            Log.d(TAG, "Point: " + p);
    
            if( p.equals(topLeft) || p.equals(bottomRight))
                continue;
    
            if(bottomLeft == null && p.x < bottomRight.x && p.y > topLeft.y)
                bottomLeft = p;
    
            if(topRight == null && p.x > topLeft.x && p.y < bottomRight.y)
                topRight = p;
        }
    
        if(topRight == null){
            throw new NullPointerException("topRight is null");
        }
        if(bottomLeft == null){
            throw new NullPointerException("BottomLeft is null");
        }
    
        Log.d(TAG, "BottomLeft = " + bottomLeft);
        Log.d(TAG, "TopRight = " + topRight);
    
        PointF[] ccwPoints = {topLeft, bottomLeft, bottomRight, topRight};
    
        return ccwPoints;
    }
    

    In my case, this solution was right in all possible user-inputs.