Oto kilka sugerowanych pseudo kodu. Najpierw prosta wersja, bardziej rozbudowana wersja później (aby pomóc oddzielić zasadę od niuansów). Prosta wersja:
// 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);
}
Teraz dodając trochę solidności:
[Edycja: Dodano wyraźne uwzględnienie w przypadku jednego wierzchołka na płaszczyźnie]
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
}
miejmy nadzieję, że daje wyobrażenie, ale nie wciąż jest kilka potencjalnych optymalizacji. Jeśli, na przykład, obliczasz te przecięcia dla każdego trójkąta w dużej siatce, możesz obliczyć i buforować DistanceFromPlane raz na jeden wierzchołek, i po prostu pobrać go dla każdej krawędzi, w której uczestniczy dany wierzchołek. Może być też bardziej zaawansowane buforowanie, w zależności od scenariusza i reprezentacji danych.
Dziękuję bardzo, to wyjaśnia to cudownie – Martin
Myślę, że powinno to być p1 + t * (p2 - p1); zamiast tego, co masz? – Martin
dzięki! Naprawiono też inną literówkę. –