24
\$\begingroup\$

Let's say I have a line defined by two points, A and B, both in the form (x, y, z). These points represent a line in 3D space.

I also have a point P, defined in the same format, that isn't on the line.

How would I calculate the projection of that point on to the line? I'm aware of how to do this in 2D but 3D seems to have bugger all resources on it.

\$\endgroup\$
0
35
\$\begingroup\$

You simply need to project vector AP onto vector AB, then add the resulting vector to point A.

Here is one way to compute it:

A + dot(AP,AB) / dot(AB,AB) * AB

This formula will work in 2D and in 3D. In fact it works in all dimensions.

\$\endgroup\$
5
  • \$\begingroup\$ thank you mr Sam - how did you derive the above formula? \$\endgroup\$
    – BenKoshy
    May 4 '17 at 5:31
  • 2
    \$\begingroup\$ I did not derive it, it is a well known formula you can find in many handbooks. \$\endgroup\$ May 4 '17 at 12:13
  • \$\begingroup\$ Is there a sample on how to write that in a programming language like C++? \$\endgroup\$ Jul 5 '19 at 14:47
  • 1
    \$\begingroup\$ @ViniciusdeMeloRocha dot would be a.x*b.x+a.y*b.y+a.z*b.z ... everything else is as straightforward as per-coordinate operation between vectors. \$\endgroup\$
    – Ocelot
    Aug 12 '19 at 1:26
  • 2
    \$\begingroup\$ Sort of obvious, but maybe worth mentioning that the scalar dot(AP,AB) / dot(AB,AB) represents a parameterization along the AB vector. So if the points actually define a line segment, you can quickly determine if the projection lies within the segment (or maybe you need to clamp the projection to one of the endpoints) by comparing the scalar to range [0,1]. \$\endgroup\$
    – mcmcc
    Jun 10 at 15:41
6
\$\begingroup\$

Here's a fast and easy way to do it in python:

from numpy import *
def ClosestPointOnLine(a, b, p):
    ap = p-a
    ab = b-a
    result = a + dot(ap,ab)/dot(ab,ab) * ab
    return result

Use floats; If your vectors contain integers the division will be an integer division, and the results will be incorrect.

\$\endgroup\$
2
  • 1
    \$\begingroup\$ /dot(ab,ab) is redundant \$\endgroup\$ Jul 4 '17 at 23:20
  • 3
    \$\begingroup\$ Answering to Waldo, /dot(ab,ab) is ONLY redundant if ab has norm 1, so that dot(ab,ab) = 1. So unless you are 100% sure that is the case and you are looking for super hyper performance (assuming this function would have to be run 1M times / second), don't remove it... \$\endgroup\$ Mar 27 '20 at 15:56
1
\$\begingroup\$

Just for an explanation about the formula from Sam Hocevar:

  1. If A,B are on the line, then the vector

$$\vec{u} = \vec{AB} / \left\|\vec{AB}\right\| $$

is the unit vector for this line (don't forget that \$\left\|\vec{AB}\right\| = \sqrt {\vec{AB} \cdot \vec{AB}} \$ or respectively \$\vec{AB} \cdot \vec{AB} = \left\|\vec{AB}\right\|^2\$).

The line equation follows:

$$k \cdot{\vec{u}} + A $$ for any \$k\$ scalar.

Then when projecting P on this line, the projected point \$I\$ is defined as perpendicular to the line's unit vector, that is:

$$ \vec{IP} \cdot \vec{u} = 0 $$ and $$ I = \vec{u} \cdot \left\|\vec{AI}\right\| + A $$

Since projecting P on the line is the dot product of \$\vec{AP}\$ and \$\vec{AB}\$, we can compute:

$$ \left\|\vec{AI}\right\| = \vec{AP} \cdot \vec{AB} / \left\|\vec{AB}\right\| $$

since \$\vec{AP} = \vec{AI} + \vec{IP}\$ and \$\vec{IP} \cdot \vec{u} = \vec{IP} \cdot \vec{AB} = 0\$, then:

$$ \vec{AP} \cdot \vec{AB} = \vec{AI} \cdot \vec{AB}=\vec{AI}\cdot\vec{u} *\left\|\vec{AB}\right\| = \left\|\vec{AI}\right\| * \left\|\vec{AB}\right\|$$

That means that only the colinear component of \$\vec{AP}\$ to \$\vec{AB}\$ is participating to the scalar result

Which finally gives:

$$ \begin{matrix} I_{x} \\ I_{y} \\ I_{z} \end{matrix} = \begin{matrix} A_{x} \\ A_{y} \\ A_{z} \end{matrix} + \begin{pmatrix} P_{x} - A_{x} \\ P_{y} - A_{y} \\ P_{z} - A_{z} \end{pmatrix} \cdot \begin{pmatrix} B_{x} - A_{x} \\ B_{y} - A_{y} \\ B_{z} - A_{z} \end{pmatrix} \cdot \begin{pmatrix} u_{x} \\ u_{y} \\ u_{z} \end{pmatrix} / \left\|\vec{AB}\right\|$$

This is the formula from Sam above.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.