|
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Geometric Relation | Intersection | Algebraic Condition | ||
| All 3 planes are parallel | nj×nk=0 for all j,k=1,3 | |||
| A plane | n1·V1=n1·V2=n1·V3 | |||
| None | n1·V1¹n1·V2¹n1·V3¹n1·V1 | |||
|
|
||||
| Just two planes are parallel, and the 3rd plane cuts each in a line [Note: the 2 parallel planes may coincide] |
2 parallel lines [coincide => 1 line] |
Only one nj×nk=0 for j¹k | ||
|
|
||||
| No two planes are parallel, so pairwise they intersect in 3 lines | nj×nk¹0 for all j¹k | |||
| n1·(n2×n3)=0 | ||||
| 1 line | test a point from one line | |||
| 3 parallel lines | ||||
| A unique point | n1·(n2×n3)¹0 | |||
|
|
||||
As shown in the illustrations:

One should test for the most frequent case of a unique intersect point first, namely that n1·(n2×n3)¹0, since this excludes the other cases. When the intersection is a unique point, it is given by the formula:

which can verified by showing that this P0 satisfies the parametric equations for p1, p2 and p3.
However, there can be a problem with the robustness of this computation when the denominator n1·(n2×n3) is very small. In this case, it would be best to get a robust line of intersection for two of the planes, and then compute the point where this line intersects the third plane.
Here are some sample "C++" implementations of these algorithms.
// Copyright 2001, softSurfer (www.softsurfer.com)
// This code may be freely used and modified for any purpose
// providing that this copyright notice is included with it.
// SoftSurfer makes no warranty for this code, and cannot be held
// liable for any real or imagined damage resulting from its use.
// Users of this code must verify correctness for their application.
// Assume that classes are
already given for the objects:
// Point and Vector with
// coordinates {float x, y, z;}
// operators for:
// == to test
equality
// != to test
inequality
// Point
= Point ± Vector
// Vector =
Point - Point
// Vector =
Scalar * Vector (scalar product)
// Vector =
Vector * Vector (3D cross product)
// Line and Ray and Segment with defining
points {Point P0, P1;}
// (a Line is infinite, Rays and
Segments start at P0)
// (a Ray extends beyond P1, but a
Segment ends at P1)
// Plane with a point and a normal {Point V0; Vector
n;}
//===================================================================
#define SMALL_NUM
0.00000001 // anything that avoids division overflow
// dot product (3D) which allows vector operations in arguments
#define dot(u,v) ((u).x * (v).x + (u).y * (v).y + (u).z * (v).z)
#define perp(u,v) ((u).x * (v).y - (u).y * (v).x) // perp product
(2D)
//
intersect2D_2Segments(): the intersection of 2 finite 2D segments
// Input: two finite segments S1 and S2
// Output: *I0 = intersect point (when it exists)
// *I1 =
endpoint of intersect segment [I0,I1] (when it exists)
// Return: 0=disjoint (no intersect)
// 1=intersect
in unique point I0
// 2=overlap
in segment from I0 to I1
int
intersect2D_Segments( Segment S1, Segment S2, Point* I0, Point* I1 )
{
Vector u = S1.P1 - S1.P0;
Vector v = S2.P1 - S2.P0;
Vector w = S1.P0 - S2.P0;
float D = perp(u,v);
// test if
they are parallel (includes either being a point)
if (fabs(D) < SMALL_NUM) {
// S1 and S2 are parallel
if (perp(u,w) != 0 || perp(v,w) != 0)
{
return 0;
// they are NOT collinear
}
// they are collinear or degenerate
// check if they are degenerate
points
float du = dot(u,u);
float dv = dot(v,v);
if (du==0 && dv==0) {
// both segments are points
if (S1.P0 !=
S2.P0) // they are distinct
points
return 0;
*I0 = S1.P0;
// they are the same point
return 1;
}
if (du==0) {
// S1 is a single point
if
(inSegment(S1.P0, S2) == 0) // but is not in S2
return 0;
*I0 = S1.P0;
return 1;
}
if (dv==0) {
// S2 a single point
if
(inSegment(S2.P0, S1) == 0) // but is not in S1
return 0;
*I0 = S2.P0;
return 1;
}
// they are collinear segments - get
overlap (or not)
float t0, t1;
// endpoints of S1 in eqn for S2
Vector w2 = S1.P1 - S2.P0;
if (v.x != 0) {
t0 = w.x / v.x;
t1 = w2.x / v.x;
}
else {
t0 = w.y / v.y;
t1 = w2.y / v.y;
}
if (t0 > t1) {
// must have t0 smaller than t1
float t=t0; t0=t1; t1=t; // swap if not
}
if (t0 > 1 || t1 < 0) {
return 0;
// NO overlap
}
t0 = t0<0? 0 : t0;
// clip to min 0
t1 = t1>1? 1 : t1;
// clip to max 1
if (t0 == t1) {
// intersect is a point
*I0 = S2.P0 +
t0 * v;
return 1;
}
// they overlap in a valid subsegment
*I0 = S2.P0 + t0 * v;
*I1 = S2.P0 + t1 * v;
return 2;
}
// the segments are skew and may intersect in a point
// get the intersect parameter for S1
float sI = perp(v,w) / D;
if (sI < 0 || sI > 1)
// no intersect with S1
return 0;
// get the intersect parameter for S2
float tI = perp(u,w) / D;
if (tI < 0 || tI > 1)
// no intersect with S2
return 0;
*I0 = S1.P0 + sI * u;
// compute S1 intersect point
return 1;
}
//===================================================================
//
inSegment(): determine if a point is inside a segment
// Input: a point P, and a collinear segment S
// Return: 1 = P is inside S
// 0 = P is
not inside S
int
inSegment( Point P, Segment S)
{
if (S.P0.x != S.P1.x) { // S is not
vertical
if (S.P0.x <= P.x && P.x <= S.P1.x)
return 1;
if (S.P0.x >= P.x && P.x >= S.P1.x)
return 1;
}
else { // S is vertical, so test y
coordinate
if (S.P0.y <= P.y && P.y <= S.P1.y)
return 1;
if (S.P0.y >= P.y && P.y >= S.P1.y)
return 1;
}
return 0;
}
//===================================================================
//
intersect3D_SegmentPlane(): intersect a segment and a plane
// Input: S = a segment, and Pn = a plane = {Point V0;
Vector n;}
// Output: *I0 = the intersect point (when it exists)
// Return: 0 = disjoint (no intersection)
// 1 =
intersection in the unique point *I0
// 2 = the
segment lies in the plane
int
intersect3D_SegmentPlane( Segment S, Plane Pn, Point* I )
{
Vector u = S.P1 - S.P0;
Vector w = S.P0 - Pn.V0;
float D = dot(Pn.n, u);
float N = -dot(Pn.n, w);
if (fabs(D) < SMALL_NUM) {
// segment is parallel to plane
if (N == 0)
// segment lies in plane
return 2;
else
return 0;
// no intersection
}
// they are not parallel
// compute intersect param
float sI = N / D;
if (sI < 0 || sI > 1)
return 0;
// no intersection
*I = S.P0 + sI * u;
// compute segment intersect point
return 1;
}
//===================================================================
//
intersect3D_2Planes(): the 3D intersect of two planes
// Input: two planes Pn1 and Pn2
// Output: *L = the intersection line (when it exists)
// Return: 0 = disjoint (no intersection)
// 1 = the two
planes coincide
// 2 =
intersection in the unique line *L
int
intersect3D_2Planes( Plane Pn1, Plane Pn2, Line* L )
{
Vector u = Pn1.n * Pn2.n;
// cross product
float ax = (u.x >= 0 ? u.x : -u.x);
float ay = (u.y >= 0 ? u.y : -u.y);
float az = (u.z >= 0 ? u.z : -u.z);
// test if the two planes are parallel
if ((ax+ay+az) < SMALL_NUM) {
// Pn1 and Pn2 are near parallel
// test if disjoint or coincide
Vector v = Pn2.V0 -
Pn1.V0;
if (dot(Pn1.n, v) == 0)
// Pn2.V0 lies in Pn1
return 1;
// Pn1 and Pn2 coincide
else
return 0;
// Pn1 and Pn2 are disjoint
}
// Pn1 and Pn2 intersect in a line
// first determine max abs coordinate of cross product
int maxc;
// max coordinate
if (ax > ay) {
if (ax > az)
maxc =
1;
else maxc = 3;
}
else {
if (ay > az)
maxc =
2;
else maxc = 3;
}
// next, to get a point on the intersect line
// zero the max coord, and solve for the other two
Point iP;
// intersect point
float d1, d2;
// the constants in the 2 plane equations
d1 = -dot(Pn1.n, Pn1.V0); // note: could be pre-stored
with plane
d2 = -dot(Pn2.n, Pn2.V0); // ditto
switch (maxc) {
// select max coordinate
case 1:
// intersect with x=0
iP.x = 0;
iP.y = (d2*Pn1.n.z - d1*Pn2.n.z) /
u.x;
iP.z = (d1*Pn2.n.y - d2*Pn1.n.y) /
u.x;
break;
case 2:
// intersect with y=0
iP.x = (d1*Pn2.n.z - d2*Pn1.n.z) /
u.y;
iP.y = 0;
iP.z = (d2*Pn1.n.x - d1*Pn2.n.x) /
u.y;
break;
case 3:
// intersect with z=0
iP.x = (d2*Pn1.n.y - d1*Pn2.n.y) /
u.z;
iP.y = (d1*Pn2.n.x - d2*Pn1.n.x) /
u.z;
iP.z = 0;
}
L->P0 = iP;
L->P1 = iP + u;
return 2;
}
//===================================================================
Foley, van Dam, Feiner & Hughes, Computer Graphics (2nd Edition in C), Section 3.12 "Clipping Lines" (1996)
Francis Hill, "The Pleasures of 'Perp Dot'
Products" in
Graphics Gems IV (1994)
[Note: the first critical definition has a typo, and should be: a^
= (-ay, ax).]
Michael Mortenson, Computer Graphics Handbook : Geometry and Mathematics (1990)
Joseph O'Rourke, Computational Geometry in C (2nd Edition), Chapter 7 "Search and Intersection" (1998)
|
Copyright ©
2001-2006 softSurfer. All rights reserved. |