【问题标题】:Calculate Projected Point location (x,y) on given line start(x,y) end(x,y)计算给定线 start(x,y) end(x,y) 上的投影点位置 (x,y)
【发布时间】:2020-04-21 10:48:02
【问题描述】:

如果我有三个点 P1、P2、P3 及其坐标(x,y)

P1(x,y)和P3(x,y)是直线(start, end)的坐标,P3是需要投影的点。

如何找到点 r(x,y) 的坐标,它是 P3 在 P1 和 P2 上的投影

【问题讨论】:

  • 这能回答你的问题吗? Projection of a point on line defined by 2 points
  • 不一样,它使用 Microsoft.Maps.Location API,我希望用 Python 和 Numpy 解决它
  • 将它移植到 python 是微不足道的 - 使用你的点表示
  • 我在这里检查是因为我需要对其进行矢量化。我有数千个点需要预测。为了简单起见,我没有提到我的观点是 3d (x,y,z)
  • 在你的问题中你说 P1(x,y) 和 P3(x,y) ,它清楚地定义了@D 点,而不是你说你需要 3D 解决方案。下定决心:)

标签: python numpy


【解决方案1】:

此解决方案扩展到具有任何几何尺寸(2D、3D、4D,...)的点。它假设所有点都是一维 numpy 数组(或一维形状为 1 的二维)。我不确定您是否需要投影落在线段或线段的延伸上,所以我将两者都包括在内。您可以选择最适合您的问题的选项:

#distance between p1 and p2
l2 = np.sum((p1-p2)**2)
if l2 == 0:
  print('p1 and p2 are the same points')

#The line extending the segment is parameterized as p1 + t (p2 - p1).
#The projection falls where t = [(p3-p1) . (p2-p1)] / |p2-p1|^2

#if you need the point to project on line extention connecting p1 and p2
t = np.sum((p3 - p1) * (p2 - p1)) / l2

#if you need to ignore if p3 does not project onto line segment
if t > 1 or t < 0:
  print('p3 does not project onto p1-p2 line segment')

#if you need the point to project on line segment between p1 and p2 or closest point of the line segment
t = max(0, min(1, np.sum((p3 - p1) * (p2 - p1)) / l2))

projection = p1 + t * (p2 - p1)

【讨论】:

  • 是的,这就是我要找的,非常感谢
  • @MSallal 欢迎您。如果它解决了您的问题,请接受答案以帮助其他人发现它有用。谢谢。
  • 我不确定我是否理解这个问题。在我的帖子中使用 t 的第一个方程会导致投影在基本上垂直于它的延伸线/线段线上。
【解决方案2】:

适用于 2D 和 3D 的 Numpy 代码(基于 https://gamedev.stackexchange.com/questions/72528/how-can-i-project-a-3d-point-onto-a-3d-line):

import numpy as np

def point_on_line(a, b, p):
    ap = p - a
    ab = b - a
    result = a + np.dot(ap, ab) / np.dot(ab, ab) * ab
    return result

A = np.array([2, 0])
B = np.array([4, 4])
P = np.array([1, 3])
projected = point_on_line(A, B, P)
print(projected)

更新

剧情:

A = np.array([ 10.5, 15.6 ])
B = np.array([ 2, 6 ])
P = np.array([ 18.561, -19.451])

projected = point_on_line(A, B, P) 
print(projected)
# [-3.35411076 -0.04699568]

plt.xlim(-20, 20)
plt.ylim(-20, 20)
plt.axis('equal')

x_values = [A[0], B[0]]
y_values = [A[1], B[1]]

plt.plot(B[0], B[1], 'ro')
plt.plot(A[0], A[1], 'ro')
plt.plot(P[0], P[1], 'ro')
plt.plot(x_values, y_values, 'b-')
plt.plot(projected[0], projected[1], 'rx')

更新 2

如果你需要点属于段,你需要做一个小修改

def point_on_line(a, b, p):
    ap = p - a
    ab = b - a
    t = np.dot(ap, ab) / np.dot(ab, ab)
    # if you need the the closest point belonging to the segment
    t = max(0, min(1, t))
    result = a + t * ab
    return result

【讨论】:

  • 我之前试过这个,它没有显示投影点检查这个笔记本projected-msallal.notebooks.azure.com/j/notebooks/…
  • 我看了你的笔记本,你有两个错误: 1:你调用了projected = ClosestPointOnLine(A, P, B) 而它需要被projected = ClosestPointOnLine(A, B, P) . 2>你的情节不正确
  • 怎样才能让它垂直在线
  • 查看更新如何让它属于就行了。请注意,接受的答案基本上是使用更多基本函数的相同算法:np.sum((p1-p2)**2) 等于 np.dot(ab, ab) 等。
  • 哈哈。这是完全相同的答案:D。最好检查ab != 0 以避免引发除以零错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多