如何用4个点来定义java.awt.Rectangle?

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

我想用 A(16,14) B(12,18) C(8,14) D(12,10) 处的四个角绘制一个矩形。然后我想检查点 P(12,11) 是否在矩形内。

是否可以使用 java.awt.Rectangle 实现此目的?

我尝试了下面的代码,但没有按预期工作(报告说 1, 1 在矩形内,但显然不在矩形内):

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

创建一个有 4 个点的矩形非常容易。

首先,您需要select任意一个点,并将该点的x和y分别赋值给xy。然后,使用参数 (x, y, 0, 0) 创建一个矩形。之后,调用add 三次以添加其他点。

在你的情况下,这会起作用:

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

我给你写了一个方法:

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;
}

您的方法很聪明,但是您为 Rectangle 使用了错误的构造函数。 two-int 构造函数是 Rectangle(int width, int height),它隐式地将左上角设置为 (0, 0),这就是您的代码打印 true.

的原因

在添加剩余点之前,您需要将第一个点指定为零宽度矩形的左上角。为此使用四整数构造函数: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));

现在请记住 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);

正如 OP 在他的评论中指出的那样,这在技术上是不正确的,因为没有相应的四整数 add 方法。但是,如果您的矩形是数学构造而不是绘制对象,则可以使用 add(Rectangle) 方法:

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));

java.awt.Rectangle 不是您想要的工作的正确工具。 Rectangles用于表示边始终平行于x-y坐标轴的屏幕绘图区域。没有规定旋转角度。您指定的四边形已旋转,因此检查 Rectangle 上的边界将包含您不想要的点,例如 (8, 13)。见下图:

更好的选择是 java.awt.Polygon。你可以通过

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

或者

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

使用 Polygon 的主要问题是它旨在处理图形元素,并不是真正设计用于很好地处理非整数数学。如果您阅读 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) 的文档,但这似乎有些过分了。

更好的选择可能是使用 java.awt.geom. My personal recommendation would be to use Path2D.Double. Path2D.Float and GeneralPath 中的 类 也是选项,但它们的精度有限。如果您愿意,请使用 Path2D.Float 作为首选项。

您将使用 default constructor:

构建路径
Path2D.Double p = new Path2D.Double();

你可以忽略容量和绕组,因为你有一个小而凸起的形状。现在使用 moveTo to start the path, lineTo to add points, and then closePath 填写路径以完成矩形并使包含工作:

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

现在你应该看到点 (8, 13) 确实在你的形状之外:

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

(1, 1)也是如此:

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