Проблема в том, что с помощью перекрестного произведения вы вычисляете ортогональное расстояние до линии, охватываемой сегментом, определенным точками linepoints[m]
и linepoints[m+1]
. С другой стороны, Shapely вычисляет расстояние до сегмента, то есть возвращает расстояние либо до ортогональной проекции, либо до одной из граничных точек, если ортогональная проекция выпадает «за пределы» сегмента.
Чтобы получить согласованные результаты, вы можете рассчитать ортогональную проекцию самостоятельно, а затем вызвать метод Shapely distance:
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)
person
ewcz
schedule
23.05.2017