Numpy код, который работает как для 2D, так и для 3D (на основе 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