2017-05-23 2 views
0

J'ai la question suivante. J'ai une boîte pleine de coordonnées et trois points, qui forment une ligne. Maintenant, je veux calculer la distance la plus courte de toutes les coordonnées de la boîte à cette ligne. J'ai trois méthodes pour le faire et la version vtk et numpy ont toujours le même résultat mais pas la méthode de la distance de shapely. Mais j'ai besoin de la version galbée, parce que je veux mesurer la distance la plus proche d'un point à la ligne de hwole et pas aux segments séparés de ligne. Voici un exemple de code jusqu'à présent. Le problème est le « pdist »:Python: Point le plus proche d'une ligne

from shapely.geometry import LineString, Point 
import vtk, numpy as np 
import itertools 

import math 

from numpy.linalg import norm 

x1=np.arange(4,21) 
y1=np.arange(4,21) 
z1=np.arange(-7,6) 

linepoints = np.array([[1,10,0],[10,10,0],[15,15,0]]) 


for i in itertools.product(x1,y1,z1): 

    for m in range(len(linepoints)-1): 

     line3 = LineString([linepoints[m],linepoints[m+1]]) 

     p = Point(i) 

     d = norm(np.cross(linepoints[m]-linepoints[m+1], linepoints[m]-i))/norm(linepoints[m+1]-linepoints[m]) 

     dist=math.sqrt(vtk.vtkLine().DistanceToLine(i,linepoints[m],linepoints[m+1])) 

     pdist = p.distance(line3) 

     print(d,dist,pdist) 

Répondre

1

Le problème est que, avec multiproduits vous calculez la distance orthogonale à la ligne enjambé par le segment défini par les points linepoints[m] et linepoints[m+1]. D'un autre côté, Shapely calcule la distance au segment, c'est-à-dire qu'il renvoie la distance soit à la projection orthogonale, soit à l'un des points limites si la projection orthogonale tombe "à l'extérieur" du segment.

Pour obtenir des résultats cohérents, vous pouvez calculer la projection orthogonale vous et ensuite appeler la méthode distance Shapely:

import numpy as np 
from shapely.geometry import Point, LineString 


A = np.array([1,0]) 
B = np.array([3,0]) 
C = np.array([0,1]) 


l = LineString([A, B]) 
p = Point(C) 


d = np.linalg.norm(np.cross(B - A, C - A))/np.linalg.norm(B - A) 

n = B - A 
v = C - A 

z = A + n*(np.dot(v, n)/np.dot(n, n)) 

print(l.distance(p), d, Point(z).distance(p)) 
#1.4142135623730951 1.0 1.0 

Cependant, notez que Shapely ignore effectivement la coordonnée z. Ainsi, par exemple:

import numpy as np 
from shapely.geometry import Point, LineString 

A = np.array([1,0,1]) 
B = np.array([0,0,0]) 

print(Point([1,0,1]).distance(Point([0,0,0]))) 

retour que la distance simplement 1.

EDIT: fonction de vos commentaires, ici serait une version qui calcule la distance (pour un nombre arbitraire de dimensions) au segment:

from shapely.geometry import LineString, Point 
import numpy as np 
import itertools 

import math 

from numpy.linalg import norm 

x1=np.arange(4,21) 
y1=np.arange(4,21) 
z1=np.arange(-7,6) 

linepoints = np.array([[1,10,0],[10,10,0],[15,15,0]]) 

def dist(A, B, C): 
    """Calculate the distance of point C to line segment spanned by points A, B. 

    """ 

    a = np.asarray(A) 
    b = np.asarray(B) 
    c = np.asarray(C) 

    #project c onto line spanned by a,b but consider the end points 
    #should the projection fall "outside" of the segment  
    n, v = b - a, c - a 

    #the projection q of c onto the infinite line defined by points a,b 
    #can be parametrized as q = a + t*(b - a). In terms of dot-products, 
    #the coefficient t is (c - a).(b - a)/((b-a).(b-a)). If we want 
    #to restrict the "projected" point to belong to the finite segment 
    #connecting points a and b, it's sufficient to "clip" it into 
    #interval [0,1] - 0 corresponds to a, 1 corresponds to b. 

    t = max(0, min(np.dot(v, n)/np.dot(n, n), 1)) 
    return np.linalg.norm(c - (a + t*n)) #or np.linalg.norm(v - t*n) 


for coords in itertools.product(x1,y1,z1): 
    for m in range(len(linepoints)-1): 

     line3 = LineString([linepoints[m],linepoints[m+1]]) 
     d = dist(linepoints[m], linepoints[m+1], coords) 
     print(coords, d) 
+0

Ah c'est un problème! Quelle serait alors la meilleure approche pour calculer la distance la plus proche de tous les points 3D à une polyligne? Parce que dans certains cas les points ont la distance la plus proche de l'extension infinie d'un segment de ligne, mais j'ai besoin de la distance la plus proche d'un point sur le segment/ligne et bien sûr dans la direction z aussi. Je pense que c'est ce que vous avez décrit avec cette projection orthogonale? – Varlor

+1

@Vorlor J'ai mis à jour la réponse avec ce que je pense serait une méthode générale. Dans la fonction 'dist', la restriction du paramètre' t' dans l'intervalle '[0,1]' s'assure qu'il calcule la distance jusqu'au segment fini. Sans cette contrainte, il retournerait la distance à la ligne infinie ... – ewcz

+0

Ah sympa, ça marche. Pouvez-vous expliquer ce qui se passe exactement mathématiquement dans les lignes: n, v = b - a, c - a t = max (0, min (np.dot (v, n)/np.dot (n, n) , 1)) renvoie np.linalg.norm (c - (a + t * n)) #ou np.linalg.norm (v - t * n) – Varlor