2017-05-23 5 views
0

Ich habe die folgende Frage. Ich habe eine Kiste voller Koordinaten und drei Punkte, die eine Linie bilden. Jetzt möchte ich die kürzeste Entfernung aller Boxkoordinaten zu dieser Linie berechnen. Ich habe drei Methoden, das zu tun und die vtk und numpy Version haben immer das gleiche Ergebnis, aber nicht die Distanzmethode von shapely. Aber ich brauche die formschöne Version, weil ich die kürzeste Entfernung von einem Punkt zu der hwole Linie und nicht zu den einzelnen Liniensegmenten messen möchte. Hier ist ein Beispielcode soweit. Das Problem ist also der „pdist“:Python: Der nächste Punkt zu einer Linie

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) 

Antwort

1

Das Problem ist, dass mit Kreuzprodukt Sie orthogonalen Abstandes zu der durch die Punkte durch das Segment überspannte Linie Berechnung linepoints[m] und linepoints[m+1]. Andererseits berechnet Shapely den Abstand zu dem Segment, d. H. Er gibt den Abstand entweder zu der orthogonalen Projektion oder zu einem der Grenzpunkte zurück, sollte die orthogonale Projektion "außerhalb" des Segments fallen.

Um konsistente Ergebnisse, können Sie die orthogonale Projektion selbst berechnen kann und dann die Shapely Entfernung Methode aufrufen:

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 

Beachten Sie jedoch, dass Shapely die z-Koordinate effektiv ignoriert. So zum Beispiel:

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]))) 

Rückkehr als Abstand lediglich 1.

EDIT: basierend auf Ihrem Kommentar, hier würde eine Version sein, die den Abstand (für beliebige Anzahl von Dimensionen) auf das Segment berechnet:

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 das ist ein Problem! Was wäre dann der beste Ansatz, um den kürzesten Abstand aller 3D-Punkte zu einer Polylinie zu berechnen? Denn in einigen Fällen haben die Punkte den geringsten Abstand zur unendlichen Ausdehnung eines Liniensegments, aber ich benötige den kürzesten Abstand zu einem Punkt auf dem Segment/Linie und natürlich auch in z-Richtung. Ich denke, das haben Sie mit dieser orthogonalen Projektion beschrieben? – Varlor

+1

@Varlor Ich habe update die Antwort mit, was ich denke, wäre eine allgemeine Methode. In der 'dist'-Funktion sorgt die Beschränkung des Parameters' t' in das Intervall '[0,1]' dafür, dass der Abstand zum endlichen Segment berechnet wird. Ohne diese Einschränkung würde die Entfernung zur unendlichen Linie zurückkehren ... – ewcz

+0

Ah schön, es funktioniert. Können Sie erklären, was genau in den Zeilen mathematisch geschieht: n, v = b - a, c - a t = max (0, min (np.dot (v, n)/np.dot (n, n) , 1)) Rückkehr np.linalg.norm (c - (a + t * n)) # oder np.linalg.norm (v - t * n) – Varlor

Verwandte Themen