从Python中计算点到直线的距离

3

我有三个要点

p1 = 48.36736702002282, 11.112351406920268
p2 = 48.36728222003929, 11.112716801718284
p3 = 48.36720362305641,11.112587917596102

我想要找到从 p3p1p2 所构成的直线的垂直距离。

为此,我的计划是,使用 p1p2 创建一条线,然后尝试找到点 p3 到此直线的垂直距离。
我正在遵循来自这里的指导。
geeksforgeeks 上的代码如下:
# Python program to find the distance between 
# a given point and a given line in 2 D. 

import math 

# Function to find distance 
def shortest_distance(x1, y1, a, b, c): 
    
    d = abs((a * x1 + b * y1 + c)) / (math.sqrt(a * a + b * b)) 
    print("Perpendicular distance is"),d 
    

# Driver Code 
x1 = 5
y1 = 6
a = -2
b = 3
c = 4
shortest_distance(x1, y1, a, b, c) 

我不太理解如何使用 p1p2 创建线段,以及上面代码中 x1、y1、a、b、c 应该是什么值。


有经纬度坐标吗?那会使事情变得复杂。 - Willem Hendriks
@user3184950 是的 - L Lawliet
cross-track distance here 横跨轨道的距离 - MBo
这是以公里、米、英里为单位吗? - There
5个回答

1

使用wikipedia上的公式(在我看来是一个不错的来源,但这是有争议的):

import math
def find_distance(p1,p2,p3):
    nom = abs((p2[0]-p1[0])*(p1[1]-p3[1])-(p1[0]-p3[0])*(p2[1]-p1[1]))
    denom = math.sqrt((p2[0]-p1[0])**2+(p2[1]-p1[1])**2)
    return nom/denom

print(find_distance(p1,p2,p3))

输出:

0.0001056989661888993

距离是以 cm 还是 m 为单位? - L Lawliet
@L Lawliet 距离以点为单位,您需要使用 np.radiant(p1) 将您的坐标转换为弧度值,并在最后乘以地球半径(6371000米)以获得米。 - QuagTeX

1
这是使用Haversine公式在Python中计算距离的答案,使用从纬度/经度点到小弧段的距离
import numpy as np
from sklearn.neighbors import DistanceMetric

dist = DistanceMetric.get_metric('haversine')

def bear( latA,lonA,latB,lonB ):
    b= np.arctan2( np.sin(lonB-lonA)*np.cos(latB) , np.cos(latA)*np.sin(latB) - np.sin(latA)*np.cos(latB)*np.cos(lonB-lonA) )
    
    return b

def crossarc( p1, p2, p3 ):
    """
     CROSSARC Calculates the shortest distance 

     between an arc (defined by p1 and p2) and a third point, p3.

     Input lat1,lon1,lat2,lon2,lat3,lon3 in degrees.
    """
    lat1,lon1 = p1
    lat2,lon2 = p2
    lat3,lon3 = p3
    
    lat1= np.radians(lat1);
    lat2= np.radians(lat2);
    lat3= np.radians(lat3);
    lon1= np.radians(lon1);
    lon2= np.radians(lon2);
    lon3= np.radians(lon3);

    bear12 = bear(lat1,lon1,lat2,lon2);
    bear13 = bear(lat1,lon1,lat3,lon3);
    
    dis13 = dist.pairwise(np.array([[lat1, lon1]]), np.array([[lat3, lon3]]))[0][0]

    diff = np.abs(bear13-bear12);
    
    if diff > np.pi:
        diff = 2 * np.pi - diff;

    if diff > (np.pi/2):
        dxa = dis13
        
    else:
        dxt = np.arcsin( np.sin(dis13)* np.sin(bear13 - bear12) );

        dis12 = dist.pairwise(np.array([[lat1, lon1]]), np.array([[lat2, lon2]]))[0][0]
        dis14 = np.arccos( np.cos(dis13) / np.cos(dxt) );
        
        if dis14 > dis12:
            dxa = dist.pairwise(np.array([[lat2, lon2]]), np.array([[lat3, lon3]]))[0][0]
        else:
            dxa = np.abs(dxt);
            
    return dxa

并且我们有

p1 = 48.36736702002282, 11.112351406920268
p2 = 48.36728222003929, 11.112716801718284
p3 = 48.36720362305641, 11.112587917596102

然后,crossarc(p1,p2,p3)将返回距离(haversine),例如要转换为米,请使用地球半径。

print("Distance in meters: {}".format( 6371000 * crossarc(p1,p2,p3) ))

输出结果为

Distance in meters: 11.390566923942787


1

使用例如scikit-spatial库很容易实现:

from skspatial.objects import Point, Line

# Define points
p1 = Point([48.36736702002282, 11.112351406920268])
p2 = Point([48.36728222003929, 11.112716801718284])
p3 = Point([48.36720362305641,11.112587917596102])

# Define line passing through p1 and p2
line_p12 = Line.from_points(p1, p2)

# Compute p3-line_p12 distance
distance = line_p12.distance_point(p3)

这个答案并没有给出“真实”的距离。你的代码输出将是0.00010569896,单位为点。你需要使用np.radians()将点转换为弧度。然后,你需要将距离乘以6371公里(地球半径)以获得公里数,或者乘以6371000以获得米数。在这些调整之后,新的结果是11.75318...m - QuagTeX
我不知道为什么这个结果和其他答案的结果有所不同。 - QuagTeX

0
如果你在谈论地球表面上的点,给定纬度和经度坐标,其中地球被建模为半径为R = 6371000米的完美球体,那么很多这些公式都可以从简单的三维向量几何中轻松推导出来。
import numpy as np
import math

R = 6371000

def cos_sin(angle):
    return math.cos(math.pi*angle/180), math.sin(math.pi*angle/180)

def S(point):
    cos_phi, sin_phi = cos_sin(point[0])
    cos_lambda, sin_lambda = cos_sin(point[1])
    return np.array([cos_phi*cos_lambda,
                      cos_phi*sin_lambda,
                      sin_phi])

def height(P1, P2, P3):
    N = np.cross(S(P1), S(P2))
    N = N / np.linalg.norm(N)
    return R*(math.pi/2 - math.acos( abs( S(P3).dot(N)) ))




p1 = 48.36736702002282, 11.112351406920268
p2 = 48.36728222003929, 11.112716801718284
p3 = 48.36720362305641, 11.112587917596102   

print(height(p1, p2, p3))

输出为:11.390566074500175 - There

0
我不明白的是如何使用p1和p2创建一条线,并且在以上代码中x1,y1,a,b,c应该是什么值。
这里,(x1,y1)是需要找到距离的点的坐标。 a,b,c是直线方程ax + by + c = 0的系数。
要从p1,p2创建形式为ax + by + c = 0的线, 您可以使用斜率截距公式(y = mx + c)
斜率= m = (y2-y1) / (x2-x1) 截距= i = y1 - m * x1
现在方程可以写成格式mx -y + i = 0 因此a = m,b = -1,c = i

另外,如果你有一条线的两个点,你不需要找到方程来解决它。你可以使用以下公式

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接