[英]Python - find closest point to 3D point on 3D spline
我有 2 个 arrays 和 3D 点(名称,X,Y,Z)。 第一个数组包含参考点,我通过这些参考点绘制样条曲线。 第二个数组包含测量点,我需要从中计算样条的法线并获取样条上的法线坐标(我需要计算测量点的 XY 和高度标准偏差)。 这是测试数据(其实我有几千分):
第一个数组 - 参考点/生成样条:
r1,1.5602,6.0310,4.8289
r2,1.6453,5.8504,4.8428
r3,1.7172,5.6732,4.8428
r4,1.8018,5.5296,4.8474
r5,1.8700,5.3597,4.8414
第二个数组 - 测量点:
m1, 1.8592, 5.4707, 4.8212
m2, 1.7642, 5.6362, 4.8441
m3, 1.6842, 5.7920, 4.8424
m4, 1.6048, 5.9707, 4.8465
我编写的代码读取数据,计算样条曲线(使用 scipy)并通过 matplotlib 显示它:
import numpy as np
import matplotlib.pyplot as plt
from scipy import interpolate
# import measured points
filename = "measpts.csv"
meas_pts = np.genfromtxt(filename, delimiter=',')
# import reference points
filename = "refpts.csv"
ref = np.genfromtxt(filename, delimiter=',')
# divide data to X, Y, Z
x = ref[:, 2]
y = ref[:, 1]
z = ref[:, 3]
# spline interpolation
tck, u = interpolate.splprep([x, y, z], s=0)
u_new = np.linspace(u.min(), u.max(), 1000000)
x_new, y_new, z_new = interpolate.splev(u_new, tck, der=0)
xs = tck[1][0]
ys = tck[1][1]
zs = tck[1][2]
# PLOT 3D
fig = plt.figure()
ax3d = fig.add_subplot(111, projection='3d', proj_type='ortho')
ax3d.plot(x, y, z, 'ro') # ref points
ax3d.plot(xs, ys, zs, 'yo') # spline knots
ax3d.plot(x_new, y_new, z_new, 'b--') # spline
ax3d.plot(meas_pts[:, 2], meas_pts[:, 1], meas_pts[:, 3], 'g*') # measured points
# ax3d.view_init(90, -90) # 2D TOP view
# ax3d.view_init(0, -90) # 2D from SOUTH to NORTH view
# ax3d.view_init(0, 0) # 2D from EAST to WEST view
plt.show()
总结一下:我需要数组包含对:[[测量点 X、Y、Z]、[样条曲线 X、Y、Z 上最近的(正常)点]]
给定 3d 空间中的点 P 和线,点 P 和线的点的距离是框的对角线,因此您希望最小化这条对角线,最小距离将垂直于线
您可以使用此属性。 所以,例如
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# generate sample line
x = np.linspace(-2, 2, 100)
y = np.cbrt( np.exp(2*x) -1 )
z = (y + 1) * (y - 2)
# a point
P = (-1, 3, 2)
# 3d plot
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d', proj_type='ortho')
ax.plot(x, y, z)
ax.plot(P[0], P[1], P[2], 'or')
plt.show()
def distance_3d(x, y, z, x0, y0, z0):
"""
3d distance from a point and a line
"""
dx = x - x0
dy = y - y0
dz = z - z0
d = np.sqrt(dx**2 + dy**2 + dz**2)
return d
def min_distance(x, y, z, P, precision=5):
"""
Compute minimum/a distance/s between
a point P[x0,y0,z0] and a curve (x,y,z)
rounded at `precision`.
ARGS:
x, y, z (array)
P (3dtuple)
precision (integer)
Returns min indexes and distances array.
"""
# compute distance
d = distance_3d(x, y, z, P[0], P[1], P[2])
d = np.round(d, precision)
# find the minima
glob_min_idxs = np.argwhere(d==np.min(d)).ravel()
return glob_min_idxs, d
这给了
min_idx, d = min_distance(x, y, z, P)
fig = plt.figure()
ax = fig.add_subplot(111, projection='3d', proj_type='ortho')
ax.plot(x, y, z)
ax.plot(P[0], P[1], P[2], 'or')
ax.plot(x[min_idx], y[min_idx], z[min_idx], 'ok')
for idx in min_idx:
ax.plot(
[P[0], x[idx]],
[P[1], y[idx]],
[P[2], z[idx]],
'k--'
)
plt.show()
print("distance:", d[min_idx])
distance: [2.4721]
您可以根据需要实现类似的 function。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.