Distance between point and segment

1

I want to calculate the distance between a point and a segment, the problem is that I can only calculate the distance between a point and a line (infinite, not bounded by two points).

I used this:

d = norm(np.cross(p2-p1, p1-p3))/norm(p2-p1)

and it works well, but that is the distance between the line joining p1 and p2, with respect to point p3, but I want to measure the distance between p3 and the segment bounded by p1 and p2.

Any ideas?

    
asked by Juanca M 11.04.2017 в 14:12
source

1 answer

3

There are several ways to approach the problem, I will try to explain one of them. In order not to get lost in the meantime, I'm going to change the nomenclature that you use, the points that determine the segment will be called A and B, we will call the segment A̅B̅, the line that passes through A and B will be called AB and the point where we want to calculate the distance we'll call it P. If we break down the problem there are basically four possibilities:

  • The point is one of the points that form the ends of the segment, that is to say that A==P or B==P . The distance is 0.

  • Make it possible to make an orthogonal projection of P on A̅B̅. In this case it is equivalent to calculate the distance from P to line AB.

  • It is not possible to calculate the orthogonal projection of P on A̅B̅, that is, the orthogonal projection of P on AB is outside A̅B̅. In this case there are two possibilities:

    • The orthogonal projection of P on AB is closer to A. The distance will be the distance between A and P.
    • The orthogonal projection of P on AB is closer to B. The distance will be the distance between B and P.

The problem is reduced to know if the point has orthogonal projection on the segment and if it does not have to see which end is closest. We can calculate the result point of the orthogonal projection on the line and see where it is with respect to the segment. Another possibility is to imagine a triangle with vertices A, B and P:

  • If the point has no orthogonal projection on the segment and is closer to A then the angle formed between A̅B̅ and A̅P̅ will be greater than 90 degrees.

  • If the point has no orthogonal projection on the segment and is closer to B then the angle formed between A̅B̅ and B̅P̅ will be greater than 90 degrees.

  • If none of the two angles is greater than 90 degrees it means that there is an orthogonal projection of the point on the segment.

This would be a possible implementation of the previous roll XD:

import numpy as np
from numpy.linalg import norm

def distancia(A, B, P):
    #Comprobamos que el punto no corresponda a los extremos del segmento.
    if all(A==P) or all(B==P):
        return 0

    #Calculamos el angulo entre AB y AP, si es mayor de 90 grados retornamos la distancia enre A y P
    elif np.arccos(np.dot((P-A)/norm(P-A), (B-A)/norm(B-A))) > np.pi/2:
        return norm(P-A)

    #Calculamos el angulo entre AB y BP, si es mayor de 90 grados retornamos la distancia enre B y P.
    elif np.arccos(np.dot((P-B)/norm(P-B), (A-B)/norm(A-B))) > np.pi/2:
        return norm(P-B)

    #Como ambos angulos son menores o iguales a 90º sabemos que podemos hacer una proyección ortogonal del punto.
    return norm(np.cross(B-A, A-P))/norm(B-A)


A = np.array((5,3))
B = np.array((2,1))
P = np.array((1,2))
print(distancia(A, B, P))

Points are passed to the function within an array of NumPy: numpy.array((x, y)) .

    
answered by 11.04.2017 / 18:02
source