英文:
How to check if a 2d point is inside a 2D polygon in Java?
问题
在我的Java应用程序中,我使用顶点数组创建2D多边形。例如,我想使用以下4个顶点创建一个简单的正方形:
[-130, -74], [-125, -74], [-125, -70], [-130, -70]
然后,我想要检查一个点是否在生成的多边形内。但是,如果我检查例如这个点:
[-125, -73]
使用 polygon.contains(x, z)
,它会判断该点不在多边形内。即使我检查一个角落,比如 [-125, -74]
,它也返回false。我感到困惑的是,如果我检查这个点 [-126, -74]
,它却返回true。所以有些点实际上被视为在多边形内,而另一些点则不是,我无法理解其中的原因。这是我设置的一个用于测试的示例代码,其中没有特殊之处:
public static void main(String[] args) {
Polygon polygon = new Polygon(new int[]{-130, -125, -125, -130}, new int[]{-74, -74, -70, -70}, 4);
System.out.println("" + polygon.contains(-125, -73));
System.out.println("" + polygon.contains(-125, -74));
System.out.println("" + polygon.contains(-126, -74));
}
输出也是这样的:
false
false
true
我还要指出这只是一个简单的示例,但多边形可能是一个非常复杂的形状,例如像这样的疯狂形状:
英文:
In my Java application I'm creating 2D polygons using an array of vertices. For example, I want to create a simple square using these 4 vertices
[-130, -74], [-125, -74], [-125, -70], [-130, -70]
Then I want to check if a point is inside the generated Polygon. But if I check, for example, this point
[-125, -73]
using polygon.contains(x, z)
it says is not inside the Polygon. Even if I check a corner, like [-125, -74]
is returns false. The strange part for me is that is I check this point [-126, -74]
is returns true, so some points are actually seen as inside the polygon, while others are not, and I can't understand why is it. This is a sample code I set up to test this, nothing special about it
public static void main(String[] args) {
Polygon polygon = new Polygon(new int[]{-130, -125, -125, -130}, new int[]{-74, -74, -70, -70}, 4);
System.out.println("" + polygon.contains(-125, -73));
System.out.println("" + polygon.contains(-125, -74));
System.out.println("" + polygon.contains(-126, -74));
}
And the output as well
false
false
true
I would also point out the fact that this is just a simple example, but the Polygon could be a really complex shape, for example something crazy like this
答案1
得分: 2
这份文档中提到:
> 这个多边形使用奇偶绕组规则进行定义。参见WIND_EVEN_ODD以获取奇偶绕组规则的定义。
> WIND_EVEN_ODD<br>
> 用于指定用奇偶规则来确定路径内部的绕组规则常数。奇偶规则指出,如果从一个点引出的射线在任意方向上延伸至无穷远,与路径线段相交的次数为奇数,则该点位于路径内部。
你可以像这样进行操作。
static Polygon mirror(Polygon p) {
int npoints = p.npoints;
int[] xpoints = new int[npoints];
int[] ypoints = new int[npoints];
for (int i = 0; i < npoints; ++i) {
xpoints[i] = -p.xpoints[i];
ypoints[i] = -p.ypoints[i];
}
return new Polygon(xpoints, ypoints, npoints);
}
static boolean onVertex(Polygon p, int x, int y) {
int npoints = p.npoints;
for (int i = 0; i < npoints; ++i)
if (p.xpoints[i] == x && p.ypoints[i] == y)
return true;
return false;
}
static boolean contains(Polygon p, int x, int y) {
return p.contains(x, y)
|| onVertex(p, x, y)
|| mirror(p).contains(-x, -y);
}
以及
Polygon polygon = new Polygon(new int[]{-130, -125, -125, -130}, new int[]{-74, -74, -70, -70}, 4);
System.out.println("" + contains(polygon, -125, -73));
System.out.println("" + contains(polygon, -125, -74));
System.out.println("" + contains(polygon, -126, -74));
输出:
true
true
true
一个带洞的多边形测试。
int width = 100, height = 100;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
int[] xs = {20, 80, 80, 20, 20, 40, 60, 60, 40, 40};
int[] ys = {20, 20, 80, 80, 20, 40, 40, 60, 60, 40};
Polygon p = new Polygon(xs, ys, xs.length);
Graphics2D g = image.createGraphics();
try (Closeable c = () -> g.dispose()) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
g.setColor(Color.BLACK);
g.drawPolygon(p);
g.setColor(Color.RED);
for (int x = 0; x < width; ++x)
for (int y = 0; y < height; ++y)
if (contains(p, x, y))
g.fillRect(x, y, 1, 1);
}
ImageIO.write(image, "png", new File("data/testPolygon.png"));
输出为图像文件 "testPolygon.png"。
如果 contains(p, x, y)
-> p.contains(x, y)
,则:
英文:
The document Polygon says
> This Polygon is defined with an even-odd winding rule. See WIND_EVEN_ODD for a definition of the even-odd winding rule.
> WIND_EVEN_ODD<br>
> The winding rule constant for specifying an even-odd rule for determining the interior of a path. The even-odd rule specifies that a point lies inside the path if a ray drawn in any direction from that point to infinity is crossed by path segments an odd number of times.
So you can do like this.
static Polygon mirror(Polygon p) {
int npoints = p.npoints;
int[] xpoints = new int[npoints];
int[] ypoints = new int[npoints];
for (int i = 0; i < npoints; ++i) {
xpoints[i] = -p.xpoints[i];
ypoints[i] = -p.ypoints[i];
}
return new Polygon(xpoints, ypoints, npoints);
}
static boolean onVertex(Polygon p, int x, int y) {
int npoints = p.npoints;
for (int i = 0; i < npoints; ++i)
if (p.xpoints[i] == x && p.ypoints[i] == y)
return true;
return false;
}
static boolean contains(Polygon p, int x, int y) {
return p.contains(x, y)
|| onVertex(p, x, y)
|| mirror(p).contains(-x, -y);
}
And
Polygon polygon = new Polygon(new int[]{-130, -125, -125, -130}, new int[]{-74, -74, -70, -70}, 4);
System.out.println("" + contains(polygon, -125, -73));
System.out.println("" + contains(polygon, -125, -74));
System.out.println("" + contains(polygon, -126, -74));
output:
true
true
true
A test for a polygon with a hole.
int width = 100, height = 100;
BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
int[] xs = {20, 80, 80, 20, 20, 40, 60, 60, 40, 40};
int[] ys = {20, 20, 80, 80, 20, 40, 40, 60, 60, 40};
Polygon p = new Polygon(xs, ys, xs.length);
Graphics2D g = image.createGraphics();
try (Closeable c = () -> g.dispose()) {
g.setColor(Color.WHITE);
g.fillRect(0, 0, width, height);
g.setColor(Color.BLACK);
g.drawPolygon(p);
g.setColor(Color.RED);
for (int x = 0; x < width; ++x)
for (int y = 0; y < height; ++y)
if (contains(p, x, y))
g.fillRect(x, y, 1, 1);
}
ImageIO.write(image, "png", new File("data/testPolygon.png"));
output
If contains(p, x, y)
-> p.contains(x, y)
then
答案2
得分: 1
从点P(x, y)发射一条射线,并计算与边界的相交情况,如果相交计数为奇数,则P在多边形内。
然而,如果射线与其中一个顶点相交,由于舍入问题可能难以确定相交点。因此,您可以按照以下步骤操作:
- 以任意方向发射射线,使射线不直接命中任何顶点。
- 对多边形中的每条边确定射线是否与边相交,如果是-增加计数器。
- 在检查完所有边之后,如果交点计数为奇数,则P在内部。
https://en.wikipedia.org/wiki/Point_in_polygon
英文:
Shoot a ray from point P(x, y) and count for intersection with the edges, if intersection count is odd, then P is inside polygon.
However if ray intersects with one of the vertices it might be difficult to determine intersection point due to rounding problem. Therefore you may follow these steps:
- Shoot a ray in any direction, such that the ray does not directly hit any vertices.
- For each edge in polygon determine whether the ray intersects the edge, if yes - increase counter
- After all edges have been checked, P inside if intersection counter is odd.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论