直线与平面的交点有两种情况,交点在平面内或平面外,计算出交点后需确定此交点是否在已知平面内。
代码如下:
/// <summary>
/// 计算直线与平面的交点
/// </summary>
/// <param name="point">直线上某一点</param>
/// <param name="direct">直线的方向</param>
/// <param name="planePoints">平面的顶点(最少需传入平面内三个点)</param>
/// <returns></returns>
private XYZ GetIntersectWithLineAndPlane(XYZ point, XYZ direct, List<XYZ> planePoints)
{
//根据3点求平面法向量
XYZ p1 = planePoints[0]; XYZ p2 = planePoints[1]; XYZ p3 = planePoints[2];
///v1(n1,n2,n3); 平面方程: na * (x – n1) + nb * (y – n2) + nc * (z – n3) = 0 ;
double na = (p2.Y - p1.Y) * (p3.Z - p1.Z) - (p2.Z - p1.Z) * (p3.Y - p1.Y);
double nb = (p2.Z - p1.Z) * (p3.X - p1.X) - (p2.X - p1.X) * (p3.Z - p1.Z);
double nc = (p2.X - p1.X) * (p3.Y - p1.Y) - (p2.Y - p1.Y) * (p3.X - p1.X);
XYZ planeNormal = new XYZ(na, nb, nc);
//平面上任意一点
XYZ planePoint = planePoints.Last();
//使用点积计算交点距直线上点point的距离
double d = (planePoint - point).DotProduct(planeNormal) / direct.Normalize().DotProduct(planeNormal);
XYZ pointResult = d * direct.Normalize() + point;
return pointResult;
}
/// <summary>
/// 确定坐标是否在平面内
/// </summary>
/// <param name="points">平面顶点坐标</param>
/// <param name="pos">已知坐标(传入上述方法计算得来的交点)</param>
/// <returns></returns>
private bool IsPosPlane(List<XYZ> points, XYZ pos)
{
double RadianValue = 0;
XYZ potOld = XYZ.Zero;
XYZ potNew = XYZ.Zero;
for (int i = 0; i < points.Count; i++)
{
if (i == 0)
{
potOld = points[i] - pos;
}
if (i == points.Count - 1)
{
potNew = points[0] - pos;
}
else
{
potNew = points[i + 1] - pos;
}
//夹角和
RadianValue += Math.Acos(potOld.Normalize().DotProduct(potNew.Normalize())) * (180 / Math.PI);
potOld = potNew;
}
//夹角的和等于360度表示在平面内
if (Math.Abs(RadianValue - 360) < 0.1f)
{
return true;
}
else
{
return false;
}
}
方法解析
代数方式
我们假设它们的交点为P,既然我们有一个平面,那么平面上面的一个点P0和平面的normal(垂直于平面的向量)我们是肯定知道的。
根据3D数学知识,(P-P₀) · normal = 0(公式一);(既然垂直,那么它们点乘肯定为0)。
对于这条直线,我们肯定知道直线上面的某一点L0和直线的方向L,那么 P = L₀ + dL(公式二),d是距离。
把公式二代入公式一,我们可以得到如下:
(L₀ + dL - P₀)· normal = 0;—> dL · normal + (L₀ - P₀) · normal = 0;
这样我们可以求出d值,然后我们就可以通过公式二求出P!
//point 是直线上面某一点,direct是直线的方向,planeNormal是垂直于平面的向量,planePoint是平面上的任意一点
public XYZ GetIntersectWithLineAndPlane(XYZ point,XYZ direct,XYZ planeNormal,XYZ planePoint)
{
float d = (planePoint - point).DotProduct(planeNormal)/direct.DotProduct(planeNormal);
return d * direct.Normalize() + point;
}