【回锅肉的修炼】C++下使用射线法判断点与多边形的位置关系
判断点与多边形的位置关系的方法——射线法
射线法的思想是:以目标点为端点引一条射线,计算这条射线和多边形所有边的交点数目。如果交点个数为奇数,则点在多边形部,反之则在多边形外部。
以图为例说明原理
O点在多边形内部,P点在多边形外部,内部点O无论向左或向右,始终与多边形的交点数目为奇数个,外部点P无论向左或向右,始终与多边形的交点数目为偶数个,这里切记射线法,关键在于单向发射
给一段C++代码
下面展示一些 内联代码片
。
#include <iostream>
#include <vector>
using namespace std;
struct Point {
double x, y;
};
// 计算叉积
double cross(Point A, Point B, Point C) {
double BAx = A.x - B.x;
double BAy = A.y - B.y;
double BCx = C.x - B.x;
double BCy = C.y - B.y;
return BAx * BCy - BAy * BCx;
}
// 判断点是否在多边形内部
int isPointInPolygon(vector<Point> polygon, Point P) {
int wn = 0;
int n = polygon.size();
for (int i = 0; i < n; i++) {
Point A = polygon[i];
Point B = polygon[(i + 1) % n];
if (A.y <= P.y) {
if (B.y > P.y && cross(B, P, A) > 0) wn++; // 从下往上穿过线段
}
else {
if (B.y <= P.y && cross(B, P, A) < 0) wn--; // 从上往下穿过线段
}
}
return wn == 0 ? 2 : 0;
}
int main() {
// 多边形顶点坐标
vector<Point> polygon = {{0, 0}, {2, 0}, {1, 2}};
// 待判断点的坐标
Point P = {1, 1};
// 判断点与多边形的位置关系
int res = isPointInPolygon(polygon, P);
if (res == 0) {
cout << "Point P is inside the polygon." << endl;
} else if (res == 1) {
cout << "Point P is on the edge of the polygon." << endl;
} else {
cout << "Point P is outside the polygon." << endl;
}
return 0;
}
代码解释
当点P沿着水平方向向右移动时,通过该点的射线会与多边形相交,交点的个数即为点P是否在多边形内部的判断条件。此算法的基本思想是通过射线法遍历多边形的每条边,统计与射线相交的边的个数,最后根据交点的个数判断点是否在多边形内部。
具体实现过程如下:
1.确定一个从点P向右射出的射线,计算该射线与多边形的每条边的交点,并统计交点的个数。
2. 如果交点的个数是奇数,则点P在多边形内部;如果交点的个数是偶数,则点P在多边形外部。
3.在计算交点时,只有当射线与边有交点时才需要进行计算,此时需要判断交点是否在点P的左侧
cross()函数解释:
这段代码实现了计算三个点 A、B 和 C 所形成的两条线段 AB 和 BC 的叉积。
在二维空间中,叉积可以用来计算向量的大小、方向和垂直性。对于向量 a = (a1, a2) 和向量 b = (b1, b2),它们的叉积为 a × b = a1 * b2 - a2 * b1。其中,向量 a 和向量 b 所张成的平行四边形的面积等于向量 a × b 的大小。
在计算几何中,利用向量的叉积可以方便地计算两条线段的位置关系,具体方法是计算它们所张成的平行四边形的面积是否为零,若为零则两条线段共线。
具体来说,假设有三个点 A(x1, y1), B(x2, y2) 和 C(x3, y3),则 BA 向量为 (x1-x2, y1-y2),BC 向量为 (x3-x2, y3-y2),因此它们的叉积可以用上面提到的公式计算得到。
在这个代码中,函数 cross() 接受三个参数 A、B 和 C,其中 B 是三角形的一个顶点,A 和 C 是三角形的另外两个顶点。函数中先计算出向量 BA 和向量 BC,然后使用上面的公式计算出它们的叉积。如果叉积大于 0,则说明 AB 和 BC 所张成的角度是小于 180 度的,也就是 AB 和 BC 处于 B 顶点的同侧,可以认为点 C 在直线 AB 的逆时针方向;如果叉积小于 0,则说明 AB 和 BC 所张成的角度是大于 180 度的,也就是 AB 和 BC 处于 B 顶点的异侧,可以认为点 C 在直线 AB 的顺时针方向;如果叉积等于 0,则说明 AB 和 BC 共线,可以通过其他方法来判断它们的位置关系。
关于叉积的解释
叉积