计算机图形学:判断点是否在多边形内部
回转数是指从点P出发,沿着多边形的边界走一圈,回到起点时,点P绕了多少圈。如果回转数为0,则点P在多边形外部;如果回转数不为0,则点P在多边形内部。射线法的基本思想是从待判断的点出发,向任意方向发射一条射线,然后计算这条射线与多边形边界的交点数目。:通过叉乘的符号,我们可以计算出每条边对点P的回转贡献。:遍历多边形的所有边,累加每条边的回转贡献。如果点P在多边形外部,累加的结果将为0。在计算机图形
文章目录
在计算机图形学中,判断点是否在多边形内部是一个常见的问题。这里介绍两种常用的方法—射线法和回转数,并提供相应的理论推导和代码实现。
射线法
理论推导
射线法的基本思想是从待判断的点出发,向任意方向发射一条射线,然后计算这条射线与多边形边界的交点数目。如果交点数为奇数,则该点在多边形内部;如果为偶数,则在外部。
具体步骤如下:
- 选择一个方向,从点P出发画一条射线。
- 遍历多边形的每条边,检查射线是否与该边相交。
- 如果射线与边相交,且交点在射线的延长线上(即交点的x坐标大于点P的x坐标),则交点数加1。
- 遍历完所有边后,如果交点数为奇数,则点P在多边形内部;如果为偶数,则在外部。
C++代码实现
#include <iostream>
#include <vector>
struct Point {
double x, y;
};
// 计算叉积,用于判断点P是否在A和B的连线上
double cross(const Point& A, const Point& B, const Point& C) {
return (B.x - A.x) * (C.y - A.y) - (B.y - A.y) * (C.x - A.x);
}
// 判断点是否在多边形内部
bool isPointInPolygon(const std::vector<Point>& polygon, const Point& P) {
int wn = 0; // 交点数
int n = polygon.size();
for (int i = 0; i < n; i++) {
const Point& A = polygon[i];
const Point& B = polygon[(i + 1) % n];
if (A.y <= P.y && B.y > P.y && cross(B, P, A) > 0) {
wn++;
} else if (A.y > P.y && B.y <= P.y && cross(B, P, A) < 0) {
wn--;
}
}
return wn != 0; // 如果交点数不为0,则点在多边形内部
}
int main() {
// 多边形顶点坐标
std::vector<Point> polygon = {{0, 0}, {2, 0}, {1, 2}};
// 待判断点的坐标
Point P = {1, 1};
// 判断点与多边形的位置关系
if (isPointInPolygon(polygon, P)) {
std::cout << "Point P is inside the polygon." << std::endl;
} else {
std::cout << "Point P is outside the polygon." << std::endl;
}
return 0;
}
Python代码实现
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def cross(A, B, C):
# 计算叉积
return (B.x - A.x) * (C.y - A.y) - (B.y - A.y) * (C.x - A.x)
def is_point_in_polygon(polygon, P):
wn = 0 # 交点数
n = len(polygon)
for i in range(n):
A = polygon[i]
B = polygon[(i + 1) % n]
if A.y <= P.y and B.y > P.y and cross(B, P, A) > 0:
wn += 1
elif A.y > P.y and B.y <= P.y and cross(B, P, A) < 0:
wn -= 1
return wn != 0 # 如果交点数不为0,则点在多边形内部
if __name__ == "__main__":
# 多边形顶点坐标
polygon = [Point(0, 0), Point(2, 0), Point(1, 2)]
# 待判断点的坐标
P = Point(1, 1)
# 判断点与多边形的位置关系
if is_point_in_polygon(polygon, P):
print("Point P is inside the polygon.")
else:
print("Point P is outside the polygon.")
回转数
回转数算法(Winding Number Algorithm)是一种判断点是否在多边形内部的算法。回转数是指从点P出发,沿着多边形的边界走一圈,回到起点时,点P绕了多少圈。如果回转数为0,则点P在多边形外部;如果回转数不为0,则点P在多边形内部。
理论推导
-
向量叉乘:对于多边形的每条边,计算从点P到边的两个端点的向量的叉乘。叉乘的符号可以告诉我们向量的旋转方向。
-
角度计算:通过叉乘的符号,我们可以计算出每条边对点P的回转贡献。如果叉乘为正,表示逆时针旋转,贡献为1;如果叉乘为负,表示顺时针旋转,贡献为-1。
-
回转数累加:遍历多边形的所有边,累加每条边的回转贡献。如果点P在多边形内部,累加的结果将是一个非零整数;如果点P在多边形外部,累加的结果将为0。
C++代码实现
#include <iostream>
#include <vector>
#include <cmath>
struct Point {
double x, y;
};
double cross(const Point& O, const Point& A, const Point& B) {
return (A.x - O.x) * (B.y - O.y) - (A.y - O.y) * (B.x - O.x);
}
int windingNumber(const std::vector<Point>& polygon, const Point& P) {
int wn = 0;
for (size_t i = 0; i < polygon.size(); ++i) {
Point A = polygon[i], B = polygon[(i + 1) % polygon.size()];
if (A.y <= P.y && B.y > P.y) {
if (cross(P, A, B) > 0) {
++wn;
}
} else if (A.y > P.y && B.y <= P.y) {
if (cross(P, A, B) < 0) {
--wn;
}
}
}
return wn;
}
bool isPointInPolygon(const std::vector<Point>& polygon, const Point& P) {
return windingNumber(polygon, P) != 0;
}
int main() {
std::vector<Point> polygon = {{0, 0}, {1, 0}, {1, 1}, {0, 1}};
Point P = {0.5, 0.5};
if (isPointInPolygon(polygon, P)) {
std::cout << "Point is inside the polygon." << std::endl;
} else {
std::cout << "Point is outside the polygon." << std::endl;
}
return 0;
}
Python代码实现
class Point:
def __init__(self, x, y):
self.x = x
self.y = y
def cross(O, A, B):
return (A.x - O.x) * (B.y - O.y) - (A.y - O.y) * (B.x - O.x)
def winding_number(polygon, P):
wn = 0
for i in range(len(polygon)):
A = polygon[i]
B = polygon[(i + 1) % len(polygon)]
if A.y <= P.y and B.y > P.y:
if cross(P, A, B) > 0:
wn += 1
elif A.y > P.y and B.y <= P.y:
if cross(P, A, B) < 0:
wn -= 1
return wn
def is_point_in_polygon(polygon, P):
return winding_number(polygon, P) != 0
# Example usage
polygon = [Point(0, 0), Point(1, 0), Point(1, 1), Point(0, 1)]
P = Point(0.5, 0.5)
if is_point_in_polygon(polygon, P):
print("Point is inside the polygon.")
else:
print("Point is outside the polygon.")
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)