繁体   English   中英

Python - 在 3D 样条曲线上找到最接近 3D 点的点

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM