我有一个凸多边形(通常只是一个旋转的正方形),我知道所有4个点。如何确定给定的点(黄色/绿色)是否在多边形内部?
编辑:对于这个特定的项目,我没有访问JDK的所有库,例如AWT。
这个页面:http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html 显示了如何对任意多边形进行此操作。
我有一个Java实现,但是它太大了,无法完整地在这里发布。不过,您应该能够自己解决:
class Boundary {
private final Point[] points; // Points making up the boundary
...
/**
* Return true if the given point is contained inside the boundary.
* See: http://www.ecse.rpi.edu/Homepages/wrf/Research/Short_Notes/pnpoly.html
* @param test The point to check
* @return true if the point is inside the boundary, false otherwise
*
*/
public boolean contains(Point test) {
int i;
int j;
boolean result = false;
for (i = 0, j = points.length - 1; i < points.length; j = i++) {
if ((points[i].y > test.y) != (points[j].y > test.y) &&
(test.x < (points[j].x - points[i].x) * (test.y - points[i].y) / (points[j].y-points[i].y) + points[i].x)) {
result = !result;
}
}
return result;
}
}
以下是Point类的草图
/**
* Two dimensional cartesian point.
*/
public class Point {
public final double x;
public final double y;
...
}
(points[i].y > test.y) != (points[j].y > test.y)
这部分的含义吗? - SerafFor those who would like to understand how the method written by Dean Povey above works, here is the explanation:
The method looks at a "ray" that starts at the tested spot and extends to infinity to the right side of the X axis. For each polygon segment, it checks if the ray crosses it. If the total number of segment crossing is odd then the tested point is considered inside the polygon, otherwise - it is outside.
To understand the way the crossing is calculated, consider the following figure:
v2
o
/
/ c (intersection)
o--------x----------------------> to infinity
t /
/
/
o
v1
For the intersection to occur, tested.y must be between the y values of the segment's vertices (v1 and v2). This is the first condition of the if statement in the method. If this is what happens, then the horizontal line must intersect the segment. It only remains to establish whether the intersection happens to the right of the tested point or to the left of it. This requires finding the x coordinate of the intersection point, which is:
t.y - v1.y
c.x = v1.x + ----------- * (v2.x - v1.x)
v2.y - v1.y
All that remains to be done is examining the subtleties:
o o
| \ o
| A1 C1 \ /
| \ / C2
o--------x-----------x------------x--------> to infinity
/ / \
A2 / B1 / \ B2
/ / \
o / o
o
Now, to verify if it works, check for yourself what is returned for each of the 4 segments by the if condition in the method body. You should find that the segments above the ray (A1, C1, C2) receive a positive result, while those below it (A2, B1, B2) receive a negative one. This means that the A vertex contributes an odd number (1) to the crossing count, while B and C contribute an even number (0 and 2, respectively), which is exactly what is desired. A is indeed a real crossing of the polygon, while B and C are just two cases of "fly-by".
这里提供一个简单的Java实现,原始代码来自C语言版本的@Dean Povey的建议(我不知道为什么@Dean Povey要引用一个庞大的实现):
static boolean pnpoly(double[] vertx, double[] verty, double testx, double testy)
{
int nvert = vertx.length;
int i, j;
boolean c = false;
for (i = 0, j = nvert-1; i < nvert; j = i++) {
if ( ((verty[i]>testy) != (verty[j]>testy)) &&
(testx < (vertx[j]-vertx[i]) * (testy-verty[i]) / (verty[j]-verty[i]) + vertx[i]) )
c = !c;
}
return c;
}
我没有将大小写更改以符合Java规则,只是为了展示所需的最小更改。我还在简单情况下测试过它,它可以正常工作。
假设x[]是x坐标数组,y[]是y坐标数组。
如果点存在于多边形中,则返回1;如果不存在,则返回2。需要检查的点为(planeX,planeY)。
//check like this
return new Polygon(x,y,x.length).contains(planeX, planeY)?1:2;
多边形的横坐标:x_array: Array[Integer]
多边形的纵坐标:y_array: Array[Integer]
点的坐标:x: Integer, y: Integer
import java.awt.Polygon
import java.awt.Point
...
final boolean isInPolygon =
new Polygon(x_array,y_array,x_array.length).contains(new Point(x, y));
java.awt.Polygon
并使用方法contains来检查您的坐标是否在您设计的形状内。java.awt.Point
来表示坐标以使代码更加优雅,但这是可选的,您也可以直接使用.contains(x, y)
。
java.awt
库中的多边形和点:new Polygon(x_coordinates, y_coordinates, coordinates.length).contains(new Point(x, y))
,其中x_coordinates
和y_coordinates
的类型为Array[Integer]
。 - Seraf