Python 3D线性插值以增加线条分辨率

huangapple go评论75阅读模式
英文:

Python 3d line interpolation to increase the line resolution

问题

我正在构建一个用于建模风力涡轮机叶片的Python模块,这些叶片在X,Y空间沿Z轴被定义为2D剖面,我已经完成了这一部分。我得到了一个具有相同点数的剖面。问题是我想要为该叶片创建一个STL文件,我的想法是使用这些剖面生成一个表面,使用三角剖分(我不知道这是否是最佳解决方案),但是翼型剖面之间的距离太远,所以三角剖分效果不佳,因此我想通过在Z方向添加点来增加叶片的分辨率。

在这张图片中,您可以看到剖面的位置:

Python 3D线性插值以增加线条分辨率

这里我重新格式化数据以在Z方向连接剖面点:

Python 3D线性插值以增加线条分辨率

我认为我可以使用一些3D插值方法在Z方向的每条线上添加n_points。为此,我尝试了splprepsplev,以下是我使用的代码:

import matplotlib.pyplot as plt

edge = np.array(edge)
x = edge[:, 0]
y = edge[:, 1]
z = edge[:, 2]
z_points = np.linspace(z[0], z[-1], n_points)

tck, u = splprep([x, y, z], s=0)
x_knots, y_knots, z_knots = splev(u, tck)
new_points = splev(z_points, tck)

fig2 = plt.figure(2)
ax3d = fig2.add_subplot(111, projection="3d")
ax3d.plot(new_points[0], new_points[1], new_points[2], "g")
ax3d.plot(x, y, z, "bo")
fig2.show()
plt.show()

但是对于每条线,结果看起来像这样,样条远离了边界:

Python 3D线性插值以增加线条分辨率

可以在此链接中找到一个示例数据,可以导入并使用以下代码查看生成的两张图片:

import matplotlib.pyplot as plt

fig = plt.figure()

edges = np.load("edges.npy")
ax = fig.add_subplot(111, projection="3d")
for edge in edges:
    ax.plot(edge[:, 0], edge[:, 1], edge[:, 2], "-.")
ax.set_aspect("equal")
ax.set_axis_off()
plt.show()
英文:

I'm building a Python module to model wind turbine blades, those blades are defined as 2D profiles in X, Y space along a Z axis, I have already done that. I get a profile with the same number of points. The problem is that I want to create an STL file for that blade, and my idea is to generate a surface using the profiles, using triangulation (I don't know if this is the best solution), but the airfoils profiles are too far from each other so triangulation it's not good, so I want to increase the resolution of a blade by adding points along the Z.

in this picture you can see the position of profiles:

Python 3D线性插值以增加线条分辨率

And here I reformat the data to connect profile points in the Z direction:

Python 3D线性插值以增加线条分辨率

I think I can use some 3D interpolation to add n_points to each line in Z direction (above picture). To do this I've tried withsplprep and splev, here is the code that i use

import matplotlib.pyplot as plt

edge = np.array(edge)
x = edge[:, 0]
y = edge[:, 1]
z = edge[:, 2]
z_points = np.linspace(z[0], z[-1], n_points)

tck, u = splprep([x, y, z], s=0)
x_knots, y_knots, z_knots = splev(u, tck)
new_points = splev(z_points, tck)

fig2 = plt.figure(2)
ax3d = fig2.add_subplot(111, projection="3d")
ax3d.plot(new_points[0], new_points[1], new_points[2], "g")
ax3d.plot(x, y, z, "bo")
fig2.show()
plt.show()

but the result is something like this for every line, whete the spline go far fom the limits:

Python 3D线性插值以增加线条分辨率

A sample data can be found here in this link that can be imported and viewed with the following code that produces the 2 picture:

import matplotlib.pyplot as plt

fig = plt.figure()

edges = np.load("edges.npy")
ax = fig.add_subplot(111, projection="3d")
for edge in edges:
    ax.plot(edge[:, 0], edge[:, 1], edge[:, 2], "-.")
ax.set_aspect("equal")
ax.set_axis_off()
plt.show()

答案1

得分: 1

看起来你非常接近了。你唯一的错误似乎是创建了一个名为z_points的变量,其范围从z[0]z[1]。在使用splev评估样条结果时,你需要传递一个参数向量,该向量的范围从0到1。

import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import splprep, splev

plt.close("all")

edges = np.load("edges.npy")
x = edges[:, :, 0]
y = edges[:, :, 1]
z = edges[:, :, 2]

# plotting the original edges
fig, ax = plt.subplots(subplot_kw={"projection":"3d"})
for _x, _y, _z in zip(x, y, z):
    ax.plot(_x, _y, _z, "-.")
ax.set_aspect("equal")
ax.set_axis_off()
fig.show()

# generating and plotting new edges with N points
N = 1000
t = np.linspace(0, 1, N)        # t is the parameter, which goes from 0 to 1

x_new = np.empty((x.shape[0], N))
y_new = np.empty((x.shape[0], N))
z_new = np.empty((x.shape[0], N))

fig, ax = plt.subplots(subplot_kw={"projection":"3d"})
for i, xyz in enumerate(zip(x, y, z)):
    tck, _ = splprep([*xyz], s=0)
    xyz_new = splev(t, tck)
    ax.scatter(*xyz_new, s=0.05)
    x_new[i, :], y_new[i, :], z_new[i, :] = xyz_new
ax.set_aspect("equal")
ax.set_axis_off()
fig.show()

# plotting the surface
fig, ax = plt.subplots(subplot_kw={"projection":"3d"})
ax.plot_surface(x_new, y_new, z_new, color="r", lw=0.2, edgecolor="k")
ax.set_aspect("equal")
ax.set_axis_off()
fig.show()
fig.savefig("temp.png", dpi=600, bbox_inches="tight")

Python 3D线性插值以增加线条分辨率

英文:

It looks like you were very close. Your only mistake appears to be creating a variable z_points that varies from z[0] to z[1]. When evaluating the spline result using splev, you need to pass it a parameter vector that goes from 0 to 1.

import numpy as np
import matplotlib.pyplot as plt
from scipy.interpolate import splprep, splev

plt.close("all")

edges = np.load("edges.npy")
x = edges[:, :, 0]
y = edges[:, :, 1]
z = edges[:, :, 2]

# plotting the original edges
fig, ax = plt.subplots(subplot_kw={"projection":"3d"})
for _x, _y, _z in zip(x, y, z):
    ax.plot(_x, _y, _z, "-.")
ax.set_aspect("equal")
ax.set_axis_off()
fig.show()

# generating and plotting new edges with N points
N = 1000
t = np.linspace(0, 1, N)        # t is the parameter, which goes from 0 to 1

x_new = np.empty((x.shape[0], N))
y_new = np.empty((x.shape[0], N))
z_new = np.empty((x.shape[0], N))

fig, ax = plt.subplots(subplot_kw={"projection":"3d"})
for i, xyz in enumerate(zip(x, y, z)):
    tck, _ = splprep([*xyz], s=0)
    xyz_new = splev(t, tck)
    ax.scatter(*xyz_new, s=0.05)
    x_new[i, :], y_new[i, :], z_new[i, :] = xyz_new
ax.set_aspect("equal")
ax.set_axis_off()
fig.show()

# plotting the surface
fig, ax = plt.subplots(subplot_kw={"projection":"3d"})
ax.plot_surface(x_new, y_new, z_new, color="r", lw=0.2, edgecolor="k")
ax.set_aspect("equal")
ax.set_axis_off()
fig.show()
fig.savefig("temp.png", dpi=600, bbox_inches="tight")

Python 3D线性插值以增加线条分辨率

huangapple
  • 本文由 发表于 2023年6月1日 01:59:16
  • 转载请务必保留本文链接:https://go.coder-hub.com/76376183.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定