射线法
1.从点P发射一条射线,射线的方向可以是任意的,但是要避免平行多面体任何一个面的法向量,避免射线落在多面体的边界上。
2.检测射线与多面体的交点,判断射线是否与每个多面体的面相交。
3.计算交点数量,若为奇数则点在多面体内,若为偶数,则线在多面体外。
//以空间中任意凸六面体为例
//定义点(向量)
class Point {
double x, y, z;
Point(double x = 0, double y = 0, double z = 0) : x(x), y(y), z(z) {}
Point operator-(const Point& v) const {
return Point(x - v.x, y - v.y, z - v.z);
}
//向量点乘
double dotProduct(const Point& v) const{
return x * v.x + y * v.y + z * v.z;
}
//向量叉乘
Point crossProduct(const Point& v) const{
return Point(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x)
}
};
// 六面体结构体
struct Hexahedron {
std::array<Point, 8> vertices;
std::array<std::array<int, 4>, 6> faces;
Hexahedron(const std::array<Point, 8>& verts) : vertices(verts) {
faces = {{
{0, 1, 5, 4}, {7, 6, 2, 3}, // 前后面
{3, 0, 4, 7}, {1, 2, 6, 5}, // 左右面
{4, 5, 6, 7}, {3, 2, 1, 0} // 上下面
}};
}
};
//检测一条射线是否与三角形相交
bool intersectTriangle(const Point& rayOrigin, const Point& rayDirection, const Point& v0, const Point& v1, const Point& v2) {
const double EPSILON = 1e-6;
Point edge1 = v1 - v0;
Point edge2 = v2 - v0;
Point h = rayDirection.crossProduct(edge2);
double a = edge1.dotProduct(h);
if (a > -EPSILON && a < EPSILON) return false;
double f = 1.0 / a;
Point s = rayOrigin - v0;
double u = f * s.dotProduct(h);
if (u < 0.0 || u > 1.0) return false;
Point q = s.crossProduct(edge1);
double v = f * rayDirection.dotProduct(q);
if (v < 0.0 || u + v > 1.0) return false;
double t = f * edge2.dotProduct(q);
return t > EPSILON;
}
//判断点是否在六面体中
bool pointInHexahedron(const Point& point, const Hexahedron& hexahedron) {
Point rayDirection(1, 0, 0); // 沿x轴正方向的射线
int intersectionCount = 0;
for (const auto& face : hexahedron.faces) {
if (intersectTriangle(point, rayDirection,
hexahedron.vertices[face[0]],
hexahedron.vertices[face[1]],
hexahedron.vertices[face[2]]))
++intersectionCount;
if (intersectTriangle(point, rayDirection,
hexahedron.vertices[face[0]],
hexahedron.vertices[face[2]],
hexahedron.vertices[face[3]]))
++intersectionCount;
}
return intersectionCount % 2 == 1;
}
点到面的有向距离
点到平面的有向距离是指从空间中的一个点到一个给定平面的垂直距离,并且这个距离是有方向性的。这意味着它不仅可以告诉我们点离平面有多远,还可以告诉我们点是在平面的哪一侧。计算点到所有面的有向距离,若符号都一致,则该点在多面体内。
//判断点在平面的哪一侧
bool isPointOnSameSide(const Point& p, const Point& p0, const Point& p1, const Point& p2)
{
//计算平面法向量
Point v1=p1-p0;
Point v2=p2-p0;
Point h=v1.crossProduct(v2);
return normal.dotProduct(p - h) <= 0;
}
//判断点是否在六面体内部
bool isPointInHex(const Point& p, const Hexahedron& hexahedron)
{
for (const auto& face : hexahedron.faces)
{
//检查点是否在平面的同一侧
if (!isPointOnSameSide(p, hexahedron.vertices[face[0]], hexahedron.vertices[face[1]], hexahedron.vertices[face[2]]))
{
return false;
}
}
return true;
}