简体   繁体   中英

How to define java.awt.Rectangle using 4 points?

I want to draw a rectangle with the four 4 corners at A(16,14) B(12,18) C(8,14) D(12,10) . I then want to check if the point P(12,11) is inside the rectangle or not.

Is it possible to achieve this using java.awt.Rectangle ?

I tried the code below and not working as desired (reports that 1, 1 is inside the rectangle, when it is clearly not):

Rectangle bounds = new Rectangle(16, 14);
bounds.add(12, 18);
bounds.add(8, 14);
bounds.add(12, 10);

System.out.println(bounds.contains(1,1)); // printing true which is not right

Creating a rectangle with 4 points is quite easy.

First, you need to select an arbitrary point and assign the point's x and y to x and y respectively. Then, create a rectangle with the arguments (x, y, 0, 0) . After that, call add three times to add the other points.

In your case, this would work:

Rectangle rect = new Rectangle(8, 14, 0, 0); // 8 and 14 are the smallerst x and y
rect.add(16, 14);
rect.add(12, 18);
rect.add(12, 10);
System.out.println(rect.contains(1,1)); // false

I have written a method for you:

public static Rectangle createRectangeWithPoints(Point p1, Point p2, Point p3, Point p4) {
    int x = p1.getX();
    int y = p1.getY();
    Rectangle rect = new Rectangle(x, y, 0, 0);
    rect.add(p2);
    rect.add(p3);
    rect.add(p4);
    return rect;
}

java.awt.Rectangle is not the right tool for the job you have in mind. Rectangles are used to represent screen drawing areas with sides that are always parallel to the axes of the xy coordinate system. There is no provision for angle of rotation. The quadrilateral you are specifying is rotated, so checking the bounds on a Rectangle will include a point like (8, 13) , which you don't want. See the diagram below:

在此处输入图片说明

A better choice would be java.awt.Polygon . You could construct it via

Polygon p = new Polygon(new int[] {16, 12, 8, 12}, new int[] {14, 18, 14, 10}, 4);

or alternatively

Polygon p = new Polygon();
p.add(16, 14);
p.add(12, 18);
p.add(8, 14);
p.add(12, 10);

The main issue with using Polygon is that it is really intended for manipulating graphical elements and is not really designed to handle non-integer math very well. If you read the docs for Polygon.contains(double, double) and follow the link that explains the definition of insideness, you will see that Polygon has the same issue as Regtangle on its lower-left boundary. A way to work around that is to use Polygon.contains(x, y, 1, 1) , but that seems like overkill.

A better option may be to use the classes in java.awt.geom . My personal recommendation would be to use Path2D.Double . Path2D.Float and GeneralPath are also options, but they have limited precision. If that is OK with you, use Path2D.Float for a preference.

You would construct the path using the default constructor :

Path2D.Double p = new Path2D.Double();

You can ignore the capacity and winding since you have a tiny and convex shape. Now fill in the path using moveTo to start the path, lineTo to add points, and then closePath to complete the rectangle and make containment work:

p.moveTo(16, 14);
p.lineTo(12, 18);
p.lineTo(8, 14);
p.lineTo(12, 10);
p.closePath();

Now you should see that the point (8, 13) is indeed outside your shape:

System.out.println(p.contains(8, 13));

Same goes for (1, 1) :

System.out.println(p.contains(1, 1));

Your approach is clever, but you are using the wrong constructor for Rectangle . The two-int constructor is Rectangle(int width, int height) , and it implicitly sets the upper-left corner to (0, 0) , which is why your code prints true .

You need to specify your first point as the upper-left corner to a zero-width rectangle before adding the remaining point. Use the four-int constructor for this: Rectangle(int x, int y, int width, int height) .

Rectangle bounds = new Rectangle(16, 14, 0, 0);
bounds.add(12, 18);
bounds.add(8, 14);
bounds.add(12, 10);

System.out.println(bounds.contains(1,1));

Now keep in mind the following quote from the docs for Rectangle.add(Point) :

After adding a point, a call to contains with the added point as an argument does not necessarily return true. The contains method does not return true for points on the right or bottom edges of a Rectangle. Therefore, if the added point falls on the right or bottom edge of the enlarged Rectangle, contains returns false for that point. If the specified point must be contained within the new Rectangle, a 1x1 rectangle should be added instead:

 r.add(newx, newy, 1, 1); 

As OP pointed out in his comment, this is technically incorrect, since there is no corresponding four-int add method. However, the add(Rectangle) method can be used if your rectangle is a mathematical construct rather than a drawn object:

Rectangle bounds = new Rectangle(16, 14, 1, 1);
bounds.add(new Rectangle(12, 18, 1, 1));
bounds.add(new Rectangle(8, 14, 1, 1));
bounds.add(new Rectangle(12, 10, 1, 1));

System.out.println(bounds.contains(1,1));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM