简体   繁体   English

Python:距离直线最近的点

[英]Python: Closest Point to a line

I have the following question.我有以下问题。 I have a box full of coordinates and three points, which build up a line.我有一个装满坐标和三个点的盒子,它们构成了一条线。 Now i want to calculate the shortest distance of all box coordinates to that line.现在我想计算所有框坐标到那条线的最短距离。 I have three methods to do that and the vtk and numpy version always have the same result but not the distance method of shapely.我有三种方法可以做到这一点,vtk 和 numpy 版本总是有相同的结果,但不是匀称的距离方法。 But i need the shapely version, because i want to measure the closest distance from a point to the whole line and not to the separate line segments.但我需要匀称的版本,因为我想测量从一个点到整条线而不是到单独线段的最近距离。 Here is an example code so far.到目前为止,这是一个示例代码。 So the problem is the "pdist":所以问题是“pdist”:

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)

The problem is that with cross-product you are calculating orthogonal distance to the line spanned by the segment defined by points linepoints[m] and linepoints[m+1] .问题是,使用叉积,您正在计算与由点linepoints[m]linepoints[m+1]定义的线段跨越的直线的正交距离。 On the other hand, Shapely calculates distance to the segment, ie, it returns the distance either to the orthogonal projection or to one of the boundary points should the orthogonal projection fall "outside" of the segment.另一方面,Shapely 计算到线段的距离,即,如果正交投影落在线段的“外部”,它会返回到正交投影或边界点之一的距离。

To get consistent results, you could calculate the orthogonal projection yourself and then invoke the Shapely distance method:为了获得一致的结果,您可以自己计算正交投影,然后调用 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

However, note that Shapely effectively ignores the z-coordinate.但是,请注意 Shapely 有效地忽略了 z 坐标。 Thus for example:因此例如:

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

return as distance merely 1.返回距离仅为 1。

EDIT: based on your comment, here would be a version which calculates the distance (for arbitrary number of dimensions) to the 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)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM