19

How can I find the line of intersection between two planes?

I know the mathematics idea, and I did the cross product between the the planes normal vectors

but how to get the line from the resulted vector programmatically

ideasman42
  • 42,413
  • 44
  • 197
  • 320
AMH
  • 6,363
  • 27
  • 84
  • 135

7 Answers7

19

The equation of the plane is ax + by + cz + d = 0, where (a,b,c) is the plane's normal, and d is the distance to the origin. This means that every point (x,y,z) that satisfies that equation is a member of the plane.

Given two planes:

P1: a1x + b1y + c1z + d1 = 0
P2: a2x + b2y + c2z + d2 = 0

The intersection between the two is the set of points that verifies both equations. To find points along this line, you can simply pick a value for x, any value, and then solve the equations for y and z.

y = (-c1z -a1x -d1) / b1
z = ((b2/b1)*(a1x+d1) -a2x -d2)/(c2 - c1*b2/b1)

If you make x=0, this gets simpler:

y = (-c1z -d1) / b1
z = ((b2/b1)*d1 -d2)/(c2 - c1*b2/b1)
Julien-L
  • 5,267
  • 3
  • 34
  • 51
R. Martinho Fernandes
  • 228,013
  • 71
  • 433
  • 510
  • 1
    how to get the start and the end of line , and the second point – AMH Jun 22 '11 at 08:52
  • 4
    x=0 may not always work. E.g. if the resulting line is parallel to the y-z plane. – Onur Apr 09 '14 at 09:02
  • what do the values b1, b2, c1, c2 represent? – ideasman42 Sep 05 '15 at 06:09
  • 1
    This approach will need a bit more work to be made robust. But not much! Simply repeat the above, starting from `y`, and then from `z`. Then choose the solution with the lowest norm. (Guard for the case where `b1` is zero, etc.) This makes it robust, because any line (intersection of our planes) has to intersect at least one of x=0, y=0 or the z=0 planes at a point that's not halfway to infinity — which it could be in poorly conditioned cases (which are not rare, but happen all the time, with axis-aligned planes and round-off errors). – Evgeni Sergeev Dec 01 '15 at 05:04
16

Finding the line between two planes can be calculated using a simplified version of the 3-plane intersection algorithm.

The 2'nd, "more robust method" from bobobobo's answer references the 3-plane intersection.

While this works well for 2 planes (where the 3rd plane can be calculated using the cross product of the first two), the problem can be further reduced for the 2-plane version.

  • No need to use a 3x3 matrix determinant,
    instead we can use the squared length of the cross product between the first and second plane (which is the direction of the 3'rd plane).
  • No need to include the 3rd planes distance,
    (calculating the final location).
  • No need to negate the distances.
    Save some cpu-cycles by swapping the cross product order instead.

Including this code-example, since it may not be immediately obvious.

// Intersection of 2-planes: a variation based on the 3-plane version.
// see: Graphics Gems 1 pg 305
//
// Note that the 'normal' components of the planes need not be unit length
bool isect_plane_plane_to_normal_ray(
        const Plane& p1, const Plane& p2,
        // output args
        Vector3f& r_point, Vector3f& r_normal)
{
    // logically the 3rd plane, but we only use the normal component.
    const Vector3f p3_normal = p1.normal.cross(p2.normal);
    const float det = p3_normal.length_squared();
    
    // If the determinant is 0, that means parallel planes, no intersection.
    // note: you may want to check against an epsilon value here.
    if (det != 0.0) {
        // calculate the final (point, normal)
        r_point = ((p3_normal.cross(p2.normal) * p1.d) +
                   (p1.normal.cross(p3_normal) * p2.d)) / det;
        r_normal = p3_normal;
        return true;
    }
    else {
        return false;
    }
}

Adding this answer for completeness, since at time of writing, none of the answers here contain a working code-example which directly addresses the question.

Though other answers here already covered the principles.

ideasman42
  • 42,413
  • 44
  • 197
  • 320
  • 1
    Of course! The third vector in a matrix formed this way is orthogonal to the other two, so the determinant is the area of the prism, whose base is the parallelogram formed by the normals of the two planes. The area of that parallelogram is the size of the cross product, and the height of that prism is also the size of the cross product. Hence, the volume is the cross product squared. However, the `if (det != 0)` is not the way to check for parallel planes, as it's very likely to be something like 1.1212e-12 due to round-off errors. – Evgeni Sergeev Dec 01 '15 at 01:05
  • @EvgeniSergeev, right - with these kinds of calculations in practice you'll need to compare with an epsilon, noted in the answer. – ideasman42 Dec 01 '15 at 01:38
  • Why are you doing cross products to calculate r_point ? Since we define 3rd plane perpendicular to plane 1 and 2 isn't ```p3.normal.cross(p2.normal) = p1.normal``` and ```p1.normal.cross(p3_normal) = p2.normal``` ? – Ghetolay Jan 08 '16 at 14:45
  • Also from [bobobobo's answer](http://stackoverflow.com/a/18092154/873229) the formula to get the intersection point negate d like this : ```plane2.normal.cross( plane3.normal )* - plane1.d``` Second question, maybe related, how could you remove ```plane1.normal.cross( plane2.normal )*-plane3.d``` from the formula ? I know we don't have ```p3.d``` so this would be impossible to compute but removing it should invalidate the formula. – Ghetolay Jan 08 '16 at 14:54
  • re: `p3.normal.cross(p2.normal) = p1.normal` and `p1.normal.cross(p3_normal) = p2.normal`, The directions will match, but not the vector lengths. re: `plane2.normal.cross( plane3.normal )* - plane1.d`, This is the same as what I have, just with the cross product swapped and an added negation. (but the same outcome). Not sure what your asking in your last point. - But this is easy enough to check - feel free to link to some snippet. – ideasman42 Jan 08 '16 at 15:29
  • Thks for clarification about 2 first question. My last interrogation was how could you pass from a double addition to only 1 on the formula of ```r_point```. I think I know why now, since there is an infinite number of intersecting points, you just assume ```p3.d = 0``` to find this particular point. – Ghetolay Jan 11 '16 at 14:49
  • This doesn't seem to work as there's a sign issue somewhere. If using two planes: `{n: [0, 1, 0], d: 0}` and `{n: [1, 0, 0], d: 1}` then this algorithm leads to `p3_normal: [0, 0, -1]` and `p1 x p3 = [-1, 0, 0]` (the other term cancels out), which is unfortunately not a point on the line. – Luxalpa Jun 15 '23 at 08:37
  • @luxalpa with two hessian normal form planes, the answer is correct. The `d` value of the second plane must be negated for the result your after. – ideasman42 Jun 16 '23 at 01:15
  • @ideasman42 I'm sorry I don't follow. From my research the HNF has nothing to do with this, as both given planes are in general form (which I assumed was what your algorithm are using). Negating `d` on the second plane will lead to an incorrect input plane as far as I can see (it would be shifted by -2 on the X axis). I don't understand what needs to be done to make this algorithm work for arbitrary planes? – Luxalpa Jun 16 '23 at 17:40
  • @Luxalpa this works in arbitrary planes in my tests, it's used as the basis of this API https://docs.blender.org/api/current/mathutils.geometry.html#mathutils.geometry.intersect_plane_plane - which is open-source, check https://projects.blender.org/blender/blender/src/commit/a53eb4a5608cd0fdb7b26022ac2b5583c3392c63/source/blender/python/mathutils/mathutils_geometry.c#L555 ... in short though, it works well in my tests. I think your 4th (dot) value is flipped from what is typically used but it depends on how your defining planes. – ideasman42 Jun 17 '23 at 07:44
  • @ideasman42 thanks a lot, that was it! needed to negate the dot product for when calculating the plane from Point + Normal. I wonder if I need to do something similar for calculating the plane from 3 Points. – Luxalpa Jun 17 '23 at 09:19
15

Finding a point on the line

To get the intersection of 2 planes, you need a point on the line and the direction of that line.

Finding the direction of that line is really easy, just cross the 2 normals of the 2 planes that are intersecting.

lineDir = n1 × n2

But that line passes through the origin, and the line that runs along your plane intersections might not. So, Martinho's answer provides a great start to finding a point on the line of intersection (basically any point that is on both planes).

In case you wanted to see the derivation for how to solve this, here's the math behind it:

First let x=0. Now we have 2 unknowns in 2 equations instead of 3 unknowns in 2 equations (we arbitrarily chose one of the unknowns).

Then the plane equations are (A terms were eliminated since we chose x=0):

B1y + C1z + D1 = 0

B2y + C2z + D2 = 0

We want y and z such that those equations are both solved correctly (=0) for the B1, C1 given.

So, just multiply the top eq by (-B2/B1) to get

-B2y + (-B2/B1)*C1z + (-B2/B1)*D1 = 0

B2y + C2z + D2 = 0

Add the eqs to get

z = ( (-B2/B1)*D1 - D2 ) / (C2 * B2/B1)*C1)

Throw the z you find into the 1st equation now to find y as

y = (-D1 - C1z) / B1

Note the best variable to make 0 is the one with the lowest coefficients, because it carries no information anyway. So if C1 and C2 were both 0, choosing z=0 (instead of x=0) would be a better choice.

The above solution can still screw up if B1=0 (which isn't that unlikely). You could add in some if statements that check if B1=0, and if it is, be sure to solve for one of the other variables instead.

Solution using intersection of 3 planes

From user's answer, a closed form solution for the intersection of 3 planes was actually in Graphics Gems 1. The formula is:

P_intersection = (( point_on1 • n1 )( n2 × n3 ) + ( point_on2 • n2 )( n3 × n1 ) + ( point_on3 • n3 )( n1 × n2 )) / det(n1,n2,n3)

Actually point_on1 • n1 = -d1 (assuming you write your planes Ax + By + Cz + D=0, and not =-D). So, you could rewrite it as:

P_intersection = (( -d1 )( n2 × n3 ) + ( -d2 )( n3 × n1 ) + ( -d3 )( n1 × n2 )) / det(n1,n2,n3)

A function that intersects 3 planes:

// Intersection of 3 planes, Graphics Gems 1 pg 305
static Vector3f getIntersection( const Plane& plane1, const Plane& plane2, const Plane& plane3 )
{
  float det = Matrix3f::det( plane1.normal, plane2.normal, plane3.normal ) ;
    
  // If the determinant is 0, that means parallel planes, no intn.
  if( det == 0.f ) return 0 ; //could return inf or whatever
  
  return ( plane2.normal.cross( plane3.normal )*-plane1.d +
           plane3.normal.cross( plane1.normal )*-plane2.d + 
           plane1.normal.cross( plane2.normal )*-plane3.d ) / det ;            
}

Proof it works (yellow dot is intersection of rgb planes here)

enter image description here

Getting the line

Once you have a point of intersection common to the 2 planes, the line just goes

P + t*d

Where P is the point of intersection, t can go from (-inf, inf), and d is the direction vector that is the cross product of the normals of the two original planes.

The line of intersection between the red and blue planes looks like this

enter image description here

Efficiency and stability

The "robust" (2nd way) takes 48 elementary ops by my count, vs the 36 elementary ops that the 1st way (isolation of x,y) uses. There is a trade off between stability and # computations between these 2 ways.

It'd be pretty catastrophic to get (0,inf,inf) back from a call to the 1st way in the case that B1 was 0 and you didn't check. So adding in if statements and making sure not to divide by 0 to the 1st way may give you the stability at the cost of code bloat, and the added branching (which might be quite expensive). The 3 plane intersection method is almost branchless and won't give you infinities.

Community
  • 1
  • 1
bobobobo
  • 64,917
  • 62
  • 258
  • 363
  • Note: the equation `z = ( (-B2/B1)*D1 - D2 ) / (C2 * B2/B1)*C1)` is incorrect - it should read `z = ((B2/B1)*D1 - D2)/(C2 - B2/B1*C1)` – chopper Jan 18 '16 at 21:06
9

This method avoids division by zero as long as the two planes are not parallel.

If these are the planes:

A1*x + B1*y + C1*z + D1 = 0
A2*x + B2*y + C2*z + D2 = 0

1) Find a vector parallel to the line of intersection. This is also the normal of a 3rd plane which is perpendicular to the other two planes:

(A3,B3,C3) = (A1,B1,C1) cross (A2,B2,C2)

2) Form a system of 3 equations. These describe 3 planes which intersect at a point:

A1*x1 + B1*y1 + C1*z1 + D1 = 0
A2*x1 + B2*y1 + C2*z1 + D2 = 0
A3*x1 + B3*y1 + C3*z1 = 0

3) Solve them to find x1,y1,z1. This is a point on the line of intersection.

4) The parametric equations of the line of intersection are:

x = x1 + A3 * t
y = y1 + B3 * t
z = z1 + C3 * t
user1318499
  • 1,327
  • 11
  • 33
  • Good answer. A closed form solution for the intersection of 3 planes is actually in Graphics Gems 1, pg 305. – bobobobo Aug 06 '13 at 23:18
  • Where does the "t" (from step 4) come from and what does it stand for? – Petru Lutenco Jan 06 '23 at 10:54
  • t is a free parameter that you replace with all possible values to obtain all points on the line. Same equations as on the first page of this https://www.math.usm.edu/lambers/mat169/fall09/lecture25.pdf – user1318499 Jan 07 '23 at 00:21
2

The determinant-based approach is neat, but it's hard to follow why it works.

Here's another way that's more intuitive.

The idea is to first go from the origin to the closest point on the first plane (p1), and then from there go to the closest point on the line of intersection of the two planes. (Along a vector that I'm calling v below.)

Given
=====
 First plane: n1 • r = k1
Second plane: n2 • r = k2

Working
=======
dir = n1 × n2
p1 = (k1 / (n1 • n1)) * n1
v = n1 × dir
pt = LineIntersectPlane(line = (p1, v), plane = (n2, k2))

LineIntersectPlane
==================
#We have n2 • (p1 + lambda * v) = k2
lambda = (k2 - n2 • p1) / (n2 • v)
Return p1 + lambda * v

Output
======
Line where two planes intersect: (pt, dir)

This should give the same point as the determinant-based approach. There's almost certainly a link between the two. At least the denominator, n2 • v, is the same, if we apply the "scalar triple product" rule. So these methods are probably similar as far as condition numbers go.

Don't forget to check for (almost) parallel planes. For example: if (dir • dir < 1e-8) should work well if unit normals are used.

Evgeni Sergeev
  • 22,495
  • 17
  • 107
  • 124
0

You can find the formula for the intersection line of two planes in this link.

P1: a1x + b1y + c1z  = d1
P2: a2x + b2y + c2z  = d2
n1=(a1,b1,c1); n2=(a2,b2,c2); n12=Norm[Cross[n1,n2]]^2
If n12 != 0
 a1 = (d1*Norm[n2]^2 - d2*n1.n2)/n12;  
 a2 = (d2*Norm[n1]^2 - d1*n1.n2)/n12;
 P = a1 n1 + a2 n2;
 (*formula for the intersection line*)
 Li[t_] := P + t*Cross[n1, n2]; 
wmora2
  • 119
  • 3
-2

The cross product of the line is the direction of the intersection line. Now you need a point in the intersection.

You can do this by taking a point on the cross product, then subtracting Normal of plane A * distance to plane A and Normal of plane B * distance to plane b. Cleaner:

p = Point on cross product

intersection point = ([p] - ([Normal of plane A] * [distance from p to plane A]) - ([Normal of plane B] * [distance from p to plane B]))

Edit:

You have two planes with two normals:

N1 and N2

The cross product is the direction of the Intersection Line:

C = N1 x N2

The class above has a function to calculate the distance between a point and a plane. Use it to get the distance of some point p on C to both planes:

p = C //p = 1 times C to get a point on C
d1 = plane1.getDistance(p)
d2 = plane2.getDistance(p)

Intersection line:

resultPoint1 = (p - (d1 * N1) - (d2 * N2))
resultPoint2 = resultPoint1 + C
hcb
  • 8,147
  • 1
  • 18
  • 17
  • I will tell u what I understand 1. get the cross product 2. get point in this cross product , then get the intersection point [p] mean the magnitude is this true , I have a question I need two points to draw the line , how to get the second point – AMH Jun 20 '11 at 10:11
  • the intersectionpoint is one point. The cross product is the direction of the line, so the second point will be intersectionpoint + x * cross product, for example intersectionpoint + 1 * cross product – hcb Jun 20 '11 at 12:55
  • Excuse me what p = C //p = 1 times C to get a point on C mean , Ok I get the C using the cross product of n1 and n2 , why I use p = c – AMH Jun 21 '11 at 09:01
  • I create a structure of plane that define the plane by normal and distance from point , and a vector3 structure that define the points, the cross product is vector x,y,z . So c will be avector of x,y and z , how to continue – AMH Jun 21 '11 at 09:28
  • I tried your algorithm, it work very well, but the x value are not correct – AMH Aug 07 '11 at 07:46
  • The formula suggested for the intersection point is wrong. Just try visualising it for two planes at a sharp angle. The first correction gets us onto the first plane, but then the second correction only keeps us within the first plane as long as the planes' normals are orthogonal. – Evgeni Sergeev Dec 01 '15 at 01:00