views:

195

answers:

4

I have a single triangle and a plane (in 3 dimensional space), How would I calculate the line segment where the two cross, if there is no crossing then I need to detect this case.

The end result I'm looking for is two 3 dimensional vectors, which define the start and end points of the line segment.

To help you out a little, I have already calculated the intersection ray between the plane of the face, and the plane, I simply need to find the endpoints to clip that ray into a line segment.

For those who like reading things in code:

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
+1  A: 

It depends a bit on what libraries you have. I have created my own geometry library which can calculate the intersection of a line with a plane. In this case calculate the three points of intersection of the three edges of the triangle and then calculate which of them lie between vertices. This could be 0 (no intersection), or 2 which is the case you want. (There are special cases where the two points are coincident - a point of the triangle).

peter.murray.rust
+2  A: 

Plug the 3 points into the plane equation (defined by the 4 parameters you listed a,b,c,d) and determine which pairs are on opposite sides of the plane.

Given the plane equation:

Ax + By + Cz + D = 0

where A,B,C is the normal (unit length) and D is the distance to origin IIRC, you plug in points (x,y,z) and see if this result is positive or negative. It will be zero for points on the plane, and the sign will tell you which side a point is on when the result is not 0. So pick pairs of points on opposite sides (there will be at most 2) and compute the intersection of those 2 segments with the plane using a standard ray/plane intersection formula which escapes me right now. Those will be the 2 points that form the segment you seek.

EDIT Come to think of it, the values you get from plugging the points into the plane equation should be useful for interpolating between pairs of points to get the intersection of segments with the plane.

Len Fn = A*xn + B*yn + C*zn + D be the result of plugging in point n. Then suppose F1 = -4 and F2 = 8. So points P1 and P2 are on opposite sides of the plane. We will also have P = P1*2/3 + P2*1/3 is the point of intersection of the segment from P1 to P2 with the plane. Generalizing this into a proper formula is left as an exorcise.

phkahler
Normal doesn't have to be unit length (although if it isn't unit length, D won't represent distance). The rest is correct. Also you forgot to mention situation when all points lie on one side of the plane and there is no intersection.
SigTerm
Yes, I was a bit sloppy - what you said about normal and the equation are correct. Also 1/3 and 2/3 were reversed (edited) the smaller value is the one closer to the plane and gets weight closer to 1. When all points are on one side all the Fn will have the same sign and there is no intersection.
phkahler
+1  A: 

Find the intersection of each line segment bounding the triangle with the plane. Merge identical points, then

  • if 0 intersections exist, there is no intersection
  • if 1 intersection exists (i.e. you found two but they were identical to within tolerance) you have a point of the triangle just touching the plane
  • if 2 points then the line segment between them is the intersection

next step, search SO for line-segment to plane intersection algorithms (or just use the one provided by your framework)...

dmckee
+3  A: 

Here's some suggested pseudo code. Simple version first, more robust version later (just to help separate the principle from the neuances). Simple version:

// 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);
}

Now adding some robustness:
[Edit: Added explicit consideration for the case of a single vertex on the plane]

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( triA, triB, outSegTips));
   GetSegmentPlaneIntersection( triA, triB, outSegTips));

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

Hopefully that gives an idea, but there are still quite a few potential optimizations. If, for example, you're calculating these intersections for every triangle in a large mesh, you might calculate and cache the DistanceFromPlane once per vertex, and just retrieve it for every edge the vertex participates in. There can be more advanced caching too, depending on your scenario and data representation.

Ofek Shilon
thankyou very much, this explains it wonderfully
Martin
I think that should be p1 + t * (p2 - p1); rather than what you have?
Martin
thanks! another typo fixed too.
Ofek Shilon