PyVista 中的 3D 表面未正确生成。我试图避免关闭中心开口,但不知道该怎么做

3D Surface in PyVista is not generating correctly. I am trying to avoid closing the center opening but can't figure out how to do so

Issue with PyVista filling opening that shouldn't be filled

import math
import numpy as np
import matplotlib as mpl
import pyvista as pv


mpl.use("Qt5Agg")
mpl.rcParams["toolbar"] = "None"  # Get rid of toolbar


def xy_waveguide_contour(throat, x_waveguide, ellipse_x):
    x_initial = (throat + (x_waveguide * (ellipse_x - throat))) / 2

    return x_initial


def xy_waveguide_contour_x2(throat, x_waveguide, ellipse_x):
    x_initial = (throat + (x_waveguide * (ellipse_x - throat)))

    return x_initial


def z_waveguide_contour(x_array, depth_factor, angle_factor, throat):
    angle_factor = angle_factor / 10000

    x_prime = x_array - (throat / 2)

    z = (x_prime / angle_factor) ** (1 / depth_factor)

    return z


def ellipse_contour(a, b):
    a = a / 2
    b = b / 2
    ellipse_steps = np.linspace(0, 0.5 * math.pi, 100)
    x_ellipse_array = np.array([])
    y_ellipse_array = np.array([])
    for h in range(100):
        x_ellipse_array = np.append(x_ellipse_array, a * np.cos(ellipse_steps[h]))
        y_ellipse_array = np.append(y_ellipse_array, b * np.sin(ellipse_steps[h]))
    return x_ellipse_array, y_ellipse_array


def circle_contour(throat):
    throat = (throat / 2)
    circle_steps = np.linspace(0, 0.5 * math.pi, 100)
    x_circle_array = np.array([])
    y_circle_array = np.array([])
    for j in range(100):
        x_circle_array = np.append(x_circle_array, throat * np.cos(circle_steps[j]))
        y_circle_array = np.append(y_circle_array, throat * np.sin(circle_steps[j]))
    return x_circle_array, y_circle_array


waveguide_throat = 30

ellipse_x = 250
ellipse_y = 150
depth_fact = 4
angle_fact = 40

# Total steps = 100
array_length = 100

xy_steps = np.linspace(0, 1, array_length)

# initialize x, y, z, and zero array
x_array = np.array([])
y_array = np.array([])
z_array = np.array([])
xsub_array = np.array([])
ysub_array = np.array([])
zero_array = np.zeros([array_length])

# calculate hor(x), ver(y), and height(z) contour data and add into array
for i in range(array_length):
    x_array = np.append(x_array, xy_waveguide_contour(waveguide_throat, xy_steps[i], ellipse_x))
    y_array = np.append(y_array, xy_waveguide_contour(waveguide_throat, xy_steps[i], ellipse_y))

    z_array = np.append(z_array, z_waveguide_contour(x_array[i], depth_fact, angle_fact, waveguide_throat))

# calculate data for ellipse
x_ellipse_data, y_ellipse_data = ellipse_contour(ellipse_x, ellipse_y)

# grab last point from z_array and make entire array same value to define height of ellipse/waveguide
ellipse_height = z_array[array_length - 1]

ellipse_z = np.full(shape=array_length, fill_value=ellipse_height)

# Calculate data for throat
circle_x, circle_y = circle_contour(waveguide_throat)


for j in range(0, array_length, 20):
    for i in range(array_length):

        xsub_array = np.append(xsub_array, xy_waveguide_contour_x2(circle_x[j], xy_steps[i], x_ellipse_data[j]))
        ysub_array = np.append(ysub_array, xy_waveguide_contour_x2(circle_y[j], xy_steps[i], y_ellipse_data[j]))

# X = np.concatenate((circle_x, x_ellipse_data, x_array, zero_array))
# Y = np.concatenate((circle_y, y_ellipse_data, zero_array, y_array))
# Z = np.concatenate((zero_array, ellipse_z, z_array, z_array))

# Reshape arrays into 1 column, multiple rows
x_array = x_array.reshape(-1, 1)
y_array = y_array.reshape(-1, 1)
z_array = z_array.reshape(-1, 1)
ellipse_z = ellipse_z.reshape(-1, 1)
x_ellipse_data = x_ellipse_data.reshape(-1, 1)
y_ellipse_data = y_ellipse_data.reshape(-1, 1)
circle_x = circle_x.reshape(-1, 1)
circle_y = circle_y.reshape(-1, 1)
zero_array = zero_array.reshape(-1, 1)
xsub_array = xsub_array.reshape(-1, 1)
ysub_array = ysub_array.reshape(-1, 1)

# save arrays to text

X = np.concatenate((circle_x, x_ellipse_data, x_array, zero_array, xsub_array), axis=0)
Y = np.concatenate((circle_y, y_ellipse_data, zero_array, y_array, ysub_array), axis=0)
Z = np.concatenate((zero_array, ellipse_z, z_array, z_array, z_array, z_array, z_array, z_array, z_array), axis=0)


xyz = np.concatenate((X, Y, Z), axis=1)

cloud = pv.PolyData(xyz)
surf = cloud.delaunay_2d()
surf.plot()

我正在尝试使用 pyvista 创建 3D 表面(也尝试过 Mayavi),每当我执行 delaunay_2D 网格来创建表面时,它都会关闭该表面的“嘴”开口,该开口仍然应该开放。我附上了一张显示需要修复的部分的图像,以及生成数据和重现当前问题的代码副本。非常感谢任何人对此问题的帮助。

正如我在您问题的先前版本下的评论中指出的那样,我找不到解决您当前方法的简单方法。

  1. 您可以将 alpha=cloud.length/10 传递给 delaunay_2d(),这已经足够接近了,但这仍然会在波导的边缘留下杂散条纹。
  2. 如果能够使用挤压创建波导会很好,但我看不出这在此处如何适用。

所以我唯一能想到的就是改变你的整个方法:通过参数化你的表面,将你的波导创建为二维结构化网格。这实际上是可能的,而且不太难:

  1. 在 2d 中你有一个圆和一个椭圆,以及两者之间的线性插值。这意味着以 (r*cos(phi), r*sin(phi)) 的形式获取点并插值到 (a*cos(phi), b*sin(phi)) 处的点。这很简单。
  2. z 方向你有一个根函数,它取决于你的二维网格的“径向”坐标。

执行此操作的方法如下:

import numpy as np
import pyvista as pv

# parameters for the waveguide
# diameter of the inner circle
waveguide_throat = 30
# axes of the outer ellipse
ellipse_x = 250
ellipse_y = 150
# shape parameters for the z profile
depth_factor = 4
angle_factor = 40
# number of grid points in radial and angular direction
array_length = 100

# now create the actual structured grid
# 2d circular grid
r, phi = np.mgrid[0:1:array_length*1j, 0:np.pi/2:array_length*1j]

# transform to ellipse on the outside, circle on the inside
x = (ellipse_x/2 * r + waveguide_throat/2 * (1 - r))*np.cos(phi)
y = (ellipse_y/2 * r + waveguide_throat/2 * (1 - r))*np.sin(phi)

# compute z profile
angle_factor = angle_factor / 10000
z = (ellipse_x / 2 * r / angle_factor) ** (1 / depth_factor)

waveguide = pv.StructuredGrid(x, y, z)
waveguide.plot(show_edges=True)

这为您提供了形成波导的密集二维网格。无论你需要用这个表面做什么,你都可以用结构化网格来做。

这是结构化网格,上面覆盖了点云以表明它们是相同的: