How to project a point onto a plane in 3D?

C++C

C++ Problem Overview


I have a 3D point (point_x,point_y,point_z) and I want to project it onto a 2D plane in 3D space which (the plane) is defined by a point coordinates (orig_x,orig_y,orig_z) and a unary perpendicular vector (normal_dx,normal_dy,normal_dz).

How should I handle this?enter image description here

C++ Solutions


Solution 1 - C++

  1. Make a vector from your orig point to the point of interest:

v = point-orig (in each dimension);

  1. Take the dot product of that vector with the unit normal vector n:

dist = vx*nx + vy*ny + vz*nz; dist = scalar distance from point to plane along the normal

  1. Multiply the unit normal vector by the distance, and subtract that vector from your point.

projected_point = point - dist*normal;

Edit with picture: I've modified your picture a bit. Red is v; v dot normal = length of blue and green (dist above). Blue is normal*dist. Green = blue * -1 : to find planar_xyz, start from point and add the green vector.

![enter image description here][1] [1]: http://i.stack.imgur.com/f5a1I.png

Solution 2 - C++

This is really easy, all you have to do is find the perpendicular (abbr here |_) distance from the point P to the plane, then translate P back by the perpendicular distance in the direction of the plane normal. The result is the translated P sits in the plane.

Taking an easy example (that we can verify by inspection) :

Set n=(0,1,0), and P=(10,20,-5).

enter image description here

The projected point should be (10,10,-5). You can see by inspection that Pproj is 10 units perpendicular from the plane, and if it were in the plane, it would have y=10.

So how do we find this analytically?

The plane equation is Ax+By+Cz+d=0. What this equation means is "in order for a point (x,y,z) to be in the plane, it must satisfy Ax+By+Cz+d=0".

What is the Ax+By+Cz+d=0 equation for the plane drawn above?

The plane has normal n=(0,1,0). The d is found simply by using a test point already in the plane:

(0)x + (1)y + (0)z + d = 0

The point (0,10,0) is in the plane. Plugging in above, we find, d=-10. The plane equation is then 0x + 1y + 0z - 10 = 0 (if you simplify, you get y=10).

A nice interpretation of d is it speaks of the perpendicular distance you would need to translate the plane along its normal to have the plane pass through the origin.

Anyway, once we have d, we can find the |_ distance of any point to the plane by the following equation:

enter image description here

There are 3 possible classes of results for |_ distance to plane:

  • 0: ON PLANE EXACTLY (almost never happens with floating point inaccuracy issues)
  • +1: >0: IN FRONT of plane (on normal side)
  • -1: <0: BEHIND plane (ON OPPOSITE SIDE OF NORMAL)

Anyway,

enter image description here

Which you can verify as correct by inspection in the diagram above

Solution 3 - C++

This answer is an addition to two existing answers. I aim to show how the explanations by @tmpearce and @bobobobo boil down to the same thing, while at the same time providing quick answers to those who are merely interested in copying the equation best suited for their situation.

Method for planes defined by normal n and point o

This method was explained in the answer by @tmpearce.

Given a point-normal definition of a plane with normal n and point o on the plane, a point p', being the point on the plane closest to the given point p, can be found by:

  1. p' = p - (n ⋅ (p - o)) * n

Method for planes defined by normal n and scalar d

This method was explained in the answer by @bobobobo.

Given a plane defined by normal n and scalar d, a point p', being the point on the plane closest to the given point p, can be found by:

  1. p' = p - (np + d) * n

If instead you've got a point-normal definition of a plane (the plane is defined by normal n and point o on the plane) @bobobobo suggests to find d:

  1. d = -no

and insert this into equation 2. This yields:

  1. p' = p - (np - no) * n

A note about the difference

Take a closer look at equations 1 and 4. By comparing them you'll see that equation 1 uses n ⋅ (p - o) where equation 2 uses np - no. That's actually two ways of writing down the same thing:

  1. n ⋅ (p - o) = np - no = np + d

One may thus choose to interpret the scalar d as if it were a 'pre-calculation'. I'll explain: if a plane's n and o are known, but o is only used to calculate n ⋅ (p - o), we may as well define the plane by n and d and calculate np + d instead, because we've just seen that that's the same thing.

Additionally for programming using d has two advantages:

  1. Finding p' now is a simpler calculation, especially for computers. Compare:
  • using n and o: 3 subtractions + 3 multiplications + 2 additions
  • using n and d: 0 subtractions + 3 multiplications + 3 additions.
  1. Using d limits the definition of a plane to only 4 real numbers (3 for n + 1 for d), instead of 6 (3 for n + 3 for o). This saves ⅓ memory.

Solution 4 - C++

It's not sufficient to provide only the plane origin and the normal vector. This does define the 3d plane, however this does not define the coordinate system on the plane.

Think that you may rotate your plane around the normal vector with regard to its origin (i.e. put the normal vector at the origin and "rotate").

You may however find the distance of the projected point to the origin (which is obviously invariant to rotation).

Subtract the origin from the 3d point. Then do a cross product with the normal direction. If your normal vector is normalized - the resulting vector's length equals to the needed value.

EDIT

A complete answer would need an extra parameter. Say, you supply also the vector that denotes the x-axis on your plane. So we have vectors n and x. Assume they're normalized.

The origin is denoted by O, your 3D point is p.

Then your point is projected by the following:

x = (p - O) dot x

y = (p - O) dot (n cross x)

Solution 5 - C++

Let V = (orig_x,orig_y,orig_z) - (point_x,point_y,point_z)

N = (normal_dx,normal_dy,normal_dz)

Let d = V.dotproduct(N);

Projected point P = V + d.N

Solution 6 - C++

I think you should slightly change the way you describe the plane. Indeed, the best way to describe the plane is via a vector n and a scalar c

(x, n) = c

The (absolute value of the) constant c is the distance of the plane from the origin, and is equal to (P, n), where P is any point on the plane.

So, let P be your orig point and A' be the projection of a new point A onto the plane. What you need to do is find a such that A' = A - a*n satisfies the equation of the plane, that is

(A - a*n, n) = (P, n)

Solving for a, you find that

a = (A, n) - (P, n) = (A, n) - c

which gives

A' = A - [(A, n) - c]n

Using your names, this reads

c = orig_x*normal_dx + orig_y*normal_dy+orig_z*normal_dz;
a = point_x*normal_dx + point_y*normal_dy + point_z*normal_dz - c;
planar_x = point_x - a*normal_dx;
planar_y = point_y - a*normal_dy;
planar_z = point_z - a*normal_dz;

Note: your code would save one scalar product if instead of the orig point P you store c=(P, n), which means basically 25% less flops for each projection (in case this routine is used many times in your code).

Solution 7 - C++

Let r be the point to project and p be the result of the projection. Let c be any point on the plane and let n be a normal to the plane (not necessarily normalised). Write p = r + m d for some scalar m which will be seen to be indeterminate if their is no solution. Since (p - c).n = 0 because all points on the plane satisfy this restriction one has (r - c).n + m(d . n) = 0 and so m = [(c - r).n]/[d.n] where the dot product (.) is used. But if d.n = 0 there is no solution. For example if d and n are perpendicular to one another no solution is available.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionGeorgeView Question on Stackoverflow
Solution 1 - C++tmpearceView Answer on Stackoverflow
Solution 2 - C++boboboboView Answer on Stackoverflow
Solution 3 - C++Mr.HView Answer on Stackoverflow
Solution 4 - C++valdoView Answer on Stackoverflow
Solution 5 - C++PermanentGuestView Answer on Stackoverflow
Solution 6 - C++bartgolView Answer on Stackoverflow
Solution 7 - C++PeterView Answer on Stackoverflow