Python:距离直线最近的点

Python:距离直线最近的点,python,numpy,scipy,shapely,Python,Numpy,Scipy,Shapely,我有以下问题。我有一个装满坐标和三个点的盒子,它们组成了一条线。现在我想计算所有盒子坐标到那条线的最短距离。我有三种方法可以做到这一点,vtk和numpy版本总是有相同的结果,但不是shapely的距离方法。但是我需要shapely版本,因为我想要测量从一个点到整条直线的最近距离,而不是到单独的线段的最近距离。下面是到目前为止的一个示例代码。因此,问题在于“pdist”: 问题是,使用叉积,您计算的是到由点直线点[m]和直线点[m+1]定义的线段所跨越的直线的正交距离。另一方面,Shapely计

我有以下问题。我有一个装满坐标和三个点的盒子,它们组成了一条线。现在我想计算所有盒子坐标到那条线的最短距离。我有三种方法可以做到这一点,vtk和numpy版本总是有相同的结果,但不是shapely的距离方法。但是我需要shapely版本,因为我想要测量从一个点到整条直线的最近距离,而不是到单独的线段的最近距离。下面是到目前为止的一个示例代码。因此,问题在于“pdist”:


问题是,使用叉积,您计算的是到由点
直线点[m]
直线点[m+1]
定义的线段所跨越的直线的正交距离。另一方面,Shapely计算到线段的距离,即,如果正交投影落在线段的“外部”,则返回到正交投影或其中一个边界点的距离

为了获得一致的结果,您可以自己计算正交投影,然后调用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
但是,请注意,Shapely实际上忽略了z坐标。例如:

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])))
返回距离仅为1

编辑: 根据您的评论,以下版本将计算到管段的距离(任意数量的尺寸):

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)

啊,这是个问题!那么,计算所有三维点到多段线的最近距离的最佳方法是什么?因为在某些情况下,点与线段无限延伸的距离最近,但我需要与线段/直线上的点的距离最近,当然也需要与z方向的距离最近。我想这就是你用正交投影所描述的?@Varlor我已经用我认为通用的方法更新了答案。在
dist
函数中,将参数
t
限制在间隔
[0,1]
内,确保计算到有限段的距离。如果没有这个约束,它将返回到无限直线的距离……啊,很好,它可以工作。你能解释一下这些行中到底是什么形状:n,v=b-a,c-a t=max(0,min(np.dot(v,n)/np.dot(n,n,1))返回np.linalg.norm(c-(a+tn))#或np.linalg.norm(v-tn)@Varlor简言之,我已经包括了额外的注释,
t
定义了连接
a
b
的线段的分数,其中
c
的正交投影位于该线段上。
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)