原理:
我们用向量sv0点乘法向量N,向量se点乘法向量N,二者相除再乘以向量se,我们就可以得到sv0在法向量上的投影比上se在法向量上的投影,根据相似三角形再乘以向量se即可得到s与线段和平面交点的向量,再加上s坐标即为交点坐标。
#include <iostream>
#include <math.h>
using namespace std;
struct Point
{
double x; // x坐标
double y; // y坐标
double z; // z坐标(默认为0,如果需要三维点则给z赋值)
Point(double a = 0, double b = 0, double c = 0) { x = a; y = b; z = c; } // 构造函数
};
struct Line
{
Point s; // 起点
Point e; // 终点
bool is_seg; // 是否是线段
Line() {}; // 默认构造函数
Line(Point a, Point b, bool _is_seg = true) { s = a; e = b; is_seg = _is_seg; } // 构造函数(默认是线段)
};
struct Triangle//三点确定的平面
{
Point v0;
Point v1;
Point v2;
bool is_plane;
Triangle() {}; // 默认构造函数
Triangle(Point a, Point b, Point c, bool _is_plane = false) { v0 = a; v1 = b; v2 = c; is_plane = _is_plane; }// 构造函数(默认是三角形)
};
Point div(const Point& p, double ratio)//向量除法
{
Point res;
res.x = p.x / ratio;
res.y = p.y / ratio;
res.z = p.z / ratio;
return res;
}
double length(const Point& vec)//向量长度
{
return (sqrt(pow(vec.x, 2) + pow(vec.y, 2) + pow(vec.z, 2)));
}
Point normalize(const Point& vec)//矢量标准化(矢量的长度规约到1)
{
Point res;
res = div(vec, length(vec));//向量除以向量长度
return res;
}
Point sub(const Point& lhs, const Point& rhs)//向量相减
{
Point res;
res.x = lhs.x - rhs.x;
res.y = lhs.y - rhs.y;
res.z = lhs.z - rhs.z;
return res;
}
Point add(const Point& lhs, const Point& rhs)//向量加法
{
Point res;
res.x = lhs.x + rhs.x;
res.y = lhs.y + rhs.y;
res.z = lhs.z + rhs.z;
return res;
}
Point multiply(const Point& vec1, const Point& vec2)//向量叉乘
{
Point result;
result.x = vec1.y * vec2.z - vec2.y * vec1.z;
result.y = vec1.z * vec2.x - vec2.z * vec1.x;
result.z = vec1.x * vec2.y - vec2.x * vec1.y;
return result;
}
double dotMultiply(const Point& vec1, const Point& vec2)//向量点乘
{
return(vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z);
}
Point getUnitNormal(const Triangle& t)//获取平面法向量
{
Point vec1 = sub(t.v1, t.v0);
Point vec2 = sub(t.v2, t.v0);
return normalize(multiply(vec1, vec2));
}
Point mul(const Point& p, double ratio)//向量乘法
{
Point res;
res.x = p.x * ratio;
res.y = p.y * ratio;
res.z = p.z * ratio;
return res;
}
Point ltotInterPoint(const Triangle& t, const Line& l)
{
Point line_vec = sub(l.e, l.s);
Point point_vec = sub(t.v0, l.s);
Point unit_plane_normal = getUnitNormal(t);
double ratio = dotMultiply(point_vec, unit_plane_normal) / dotMultiply(unit_plane_normal, line_vec);
return add(l.s, mul(line_vec, ratio));
}
int main()
{
//测试数据
Point e(0.0,0.0,0.0),s(0.0,0.0,1.0);
Line l(e,s,true);
Point a(1.0,0.0,0.0),b(-1.0,0.0,0.0),c(0.0,1.0,0.0);
Triangle t(a,b,c,true);
cout<<ltotInterPoint(t,l).x<<","<<ltotInterPoint(t,l).y<<","<<ltotInterPoint(t,l).z;
}