2010-06-29 117 views
17

我有一个三角形和一个平面(在三维空间中),如何计算两个交叉点的线段,如果没有交叉点,那么我需要检测此案件。确定三角形和平面的交点

我正在寻找的最终结果是两个三维向量,它定义了线段的起点和终点。

为了帮助你一点,我已经计算了面和飞机之间的相交线,我只需要找到端点将该线夹到线段中。

对于那些谁在代码中喜欢阅读的东西:

Face face;  //a face, defined by 3 points 
Plane plane;  //a plane, defined by a normal vector and a distance 
Ray intersection; //a ray, defined by a point and a direction, initialised to the intersection of the face plane and the face 

Segment s = CalculateSegment(face, plane, intersection); //this method needs defining 

回答

16

这里有一些建议的伪代码。首先是简单的版本,后来更强大的版本(只是为了帮助将原理与细微差别分开)。 简单的版本:

// Assume the plane is given as the equation dot(N,X) + d = 0, where N is a (not 
// neccessarily normalized) plane normal, and d is a scalar. Any way the plane is given - 
// DistFromPlane should just let the input vector into the plane equation. 

vector3d planeN; 
float planeD; 

float DistFromPlane(vector3d P) 
{ 
// if N is not normalized this is *not* really the distance, 
// but the computations work just the same. 
    return dot(planeN,P) + planeD; 
} 

bool GetSegmentPlaneIntersection(vector3d P1, vector3d P2, vector3d& outP) 
{ 
    float d1 = DistFromPlane(P1), 
     d2 = DistFromPlane(P2); 

    if (d1*d2 > 0) // points on the same side of plane 
    return false; 

    float t = d1/(d1 - d2); // 'time' of intersection point on the segment 
    outP = P1 + t * (P2 - P1); 

    return true; 
} 

void TrianglePlaneIntersection(vector3d triA, vector3d triB, vector3d triC, 
           vector3dArray& outSegTips) 
{ 
    vector3d IntersectionPoint; 
    if(GetSegmentPlaneIntersection(triA, triB, IntersectionPoint)) 
    outSegTips.Add(IntersectionPoint); 

    if(GetSegmentPlaneIntersection(triB, triC, IntersectionPoint)) 
    outSegTips.Add(IntersectionPoint); 

    if(GetSegmentPlaneIntersection(triC, triA, IntersectionPoint)) 
    outSegTips.Add(IntersectionPoint); 
} 

现在增加了一些稳健性:
[编辑:增加了明确的考虑单个顶点上飞机的情况下],让一个想法

vector3d planeN; 
float planeD; 

float DistFromPlane(vector3d P) 
{ 
    return dot(planeN,P) + planeD; 
} 

void GetSegmentPlaneIntersection(vector3d P1, vector3d P2, vector3dArray& outSegTips) 
{ 
    float d1 = DistFromPlane(P1), 
     d2 = DistFromPlane(P2); 

    bool bP1OnPlane = (abs(d1) < eps), 
     bP2OnPlane = (abs(d2) < eps); 

    if (bP1OnPlane) 
    outSegTips.Add(P1); 

    if (bP2OnPlane) 
    outSegTips.Add(P2); 

    if (bP1OnPlane && bP2OnPlane) 
    return; 

    if (d1*d2 > eps) // points on the same side of plane 
    return; 

    float t = d1/(d1 - d2); // 'time' of intersection point on the segment 
    outSegTips.Add(P1 + t * (P2 - P1)); 
} 

void TrianglePlaneIntersection(vector3d triA, vector3d triB, vector3d triC, 
           vector3dArray& outSegTips) 
{ 
    GetSegmentPlaneIntersection(triA, triB, outSegTips)); 
    GetSegmentPlaneIntersection(triB, triC, outSegTips)); 
    GetSegmentPlaneIntersection(triC, triA, outSegTips)); 

    RemoveDuplicates(outSegTips); // not listed here - obvious functionality 
} 

希望,但有仍然有很多潜在的优化。例如,如果您计算大网格中每个三角形的这些交点,则可以计算并缓存每个顶点的DistanceFromPlane,并只为顶点参与的每条边检索它。还可以有更高级的缓存,取决于您的场景和数据表示。

+0

非常感谢,这解释了奇妙 – Martin 2010-06-29 20:06:25

+0

我认为应该是p1 + t *(p2 - p1);而不是你有什么? – Martin 2010-06-29 20:35:01

+0

谢谢!另一个错字也是固定的。 – 2010-06-30 05:19:09

1

这取决于什么库,你有几分。我创建了自己的几何库,可以计算一条线与一个平面的交点。在这种情况下,计算三角形的三条边的三个交点,然后计算它们中哪些位于顶点之间。这可能是0(不相交),或者2这是你想要的情况。 (有两个点重合的特殊情况 - 三角形的一个点)。

2

将3个点插入平面方程(由列出的4个参数a,b,c,d定义),并确定哪些对在平面的相对两侧。

鉴于平面方程:

 
Ax + By + Cz + D = 0 

其中A,B,C是正常的(单位长度)和d是指起源IIRC的距离,则在点(X,Y,Z)插头和看看这个结果是正面的还是负面的。对于飞机上的点,它将为零,并且当结果不为0时,该符号会告诉您哪一侧是点。因此,选择相反两侧的点对(最多只有2个)并计算交点这两个部分的飞机使用了一个标准的射线/平面相交公式,这个公式现在就逃脱了我。这些将成为您寻求的细分市场的两个点。

编辑 试想想起来了,你从堵塞点到平面方程得到的值应该是对点之间进行插值得到与平面段的交集是有用的。

Len Fn = A xn + B yn + C * zn + D是插入点n的结果。 然后假设F1 = -4和F2 = 8。因此,点P1和P2位于平面的相对两侧。我们还将有P = P1 * 2/3 + P2 * 1/3是从P1到P2的线段与平面的交点。把它归结为一个适当的公式就是一种驱除。

+0

正常不一定是单位长度(但如果它不是单位长度,D不会代表距离)。其余是正确的。此外,当所有点位于飞机的一侧并且没有交叉点时,您也忘记提及情况。 – SigTerm 2010-06-29 19:04:44

+0

是的,我有点sl - - 你说的正常和方程是正确的。另外1/3和2/3被逆转(编辑),越小的值越接近平面并且重量接近1.当所有点位于一侧时,所有的Fn将具有相同的符号并且没有相交。 – phkahler 2010-06-30 12:35:00

1

找出三角形与平面相交的每条线段的交点。合并相同的点,然后

  • 如果0交叉点存在的,没有交集
  • 如果1个交点存在(即你发现了两个,但他们是相同的内容差)你有三角形的点刚好接触平面
  • 如果2点然后将它们之间的线段是交点

下一步骤中,对线段SO搜索到平面相交算法(或只使用由你的框架提供的一个)...