5

I am looking for Python function that would compute distance from a point in 3D (x_0,y_0,z_0) to a line segment defined by its endpoints (x_1,y_1,z_1) and (x_2,y_2,z_2).

I have only found solution for 2D for this problem.

There are solutions to finding a distance from a point to a line in 3d, but not to a line segment, like here: dist to segment

(picture taken from Calculate distance point to line segment with special cases)

Sanya Pushkar
  • 180
  • 1
  • 16
  • @meowgoesthedog the question you referred to is about a line, not a line segment. – Sanya Pushkar Jun 05 '19 at 15:33
  • Possible duplicate of [Shortest distance between a point and a line in 3 d space](https://stackoverflow.com/questions/50727961/shortest-distance-between-a-point-and-a-line-in-3-d-space) – jose_bacoy Jun 05 '19 at 15:43
  • @meowgoesthedog this is in 2D, I need 3D – Sanya Pushkar Jun 05 '19 at 15:56
  • @âńōŋŷXmoůŜ that question addresses the question for a line, not for a segment. – Sanya Pushkar Jun 05 '19 at 15:57
  • The [answer here](https://stackoverflow.com/questions/54442057/calculate-the-euclidian-distance-between-an-array-of-points-to-a-line-segment-in/54442561#54442561) also works for 3D; the only change required is to take the **magnitude** of the cross-product (because it is a vector in 3D instead of a scalar). – meowgoesthedog Jun 05 '19 at 16:16
  • @meowgoesthedog thank you. How would I change np.maximum.reduce to fit 3D solution? It returns an error now. – Sanya Pushkar Jun 05 '19 at 16:25
  • 1
    For future reference always be more specific about problems than "it returns an error" or "it doesn't work". In this instance I believe changing `np.zeros(...)` to `0` would do the trick (the solution in that answer deals with an arbitrary number of tests in parallel, so `s` and `t` are **arrays** of scalars instead of single scalars). – meowgoesthedog Jun 05 '19 at 16:28
  • @meowgoesthedog thank you! so is it true that I also need to substitute c for np.linalg.norm(c) in return? Otherwise the return is a 3d vector. – Sanya Pushkar Jun 05 '19 at 20:15
  • @meowgoesthedog also, as far as I understand, the np.all loop isn't needed for this question. – Sanya Pushkar Jun 05 '19 at 20:31

1 Answers1

5

This answer is adapted from here: Calculate the euclidian distance between an array of points to a line segment in Python without for loop.

Function lineseg_dist returns the distance the distance from point p to line segment [a,b]. p, a and b are np.arrays.

import numpy as np

def lineseg_dist(p, a, b):

    # normalized tangent vector
    d = np.divide(b - a, np.linalg.norm(b - a))

    # signed parallel distance components
    s = np.dot(a - p, d)
    t = np.dot(p - b, d)

    # clamped parallel distance
    h = np.maximum.reduce([s, t, 0])

    # perpendicular distance component
    c = np.cross(p - a, d)

    return np.hypot(h, np.linalg.norm(c))
Sanya Pushkar
  • 180
  • 1
  • 16
  • 2
    Beware that `p, a, b` are *arrays of arrays* (i.e. arrays of points). For your problem you probably want to work with a single set of points, in which case `s` and `t` will be scalars - thus `np.zeros(len(p))` will need to be placed with `0`. And yes if you can guarantee that `a` is never equal to `b` then the "`np.all`" check is unnecessary – meowgoesthedog Jun 05 '19 at 20:56
  • 1
    @meowgoesthedog yeah, forgot to make that edit about s and t. also, np.all as far as I understood checks if a and b are along the same axis, I am not sure if you need to substitute for np.array_equal – Sanya Pushkar Jun 05 '19 at 21:01