2010-06-29 45 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搜索到平面相交算法(或只使用由你的框架提供的一個)...