Pyvista读取VTK文件渲染三维云图并切片裁剪(1)

1 篇文章 0 订阅
1 篇文章 0 订阅

Pyvista官方文档:https://qtdocs.pyvista.org/index.html
下面的代码是本人查看官方文档API之后编写的,里面含有对官方API的翻译。注释写的很详细,作者就不多赘述了。
三维云图绘制效果:
表面:
表面
表面+网格:
表面+网格:
网格线:
网格线
表面点+右键选中显示数据:
表面点+右键选中显示数据
高斯点+右键选中显示数据:
鼠标右键单击选中点,进行其数据值的显示
在这里插入图片描述
切片和裁剪
盒子裁剪:
盒子所在的六面体,可以对每个面进行法向拖动,也可以旋转、移动盒子
在这里插入图片描述
在这里插入图片描述
平面裁剪:
箭头为法线所在的平面对模型进行裁剪,既可以拖动箭头和箭尾对平面的角度进行改变,也可以法向拖动平面
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
平面切片:
箭头为法线所在的平面对模型进行切片,既可以拖动箭头和箭尾对平面的角度进行改变,也可以法向拖动平面
在这里插入图片描述
三平面切片:
三个互相垂直的平面,均可在其法向拖动,进行切片
在这里插入图片描述
在这里插入图片描述
曲面切片:
小球组成的线所在的曲面进行切片,小球可以随意拖动
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
数据阈值裁剪:
拖动滑块改变阈值,默认滑块右侧(>=滑块值)的数据部分显示出来,可以反向
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

import numpy as np
import pyvista as pv
from pyvista.plotting.opts import PickerType

vtu_filename = "../Data/cylinderdemo4_out.vtu"
# 读取 VTK 文件
mesh = pv.read(vtu_filename)
# 读取节点数据
node_data_name = "Temperature"  # 替换为您的节点数据名称
node_data = mesh.point_data[node_data_name]



plotter = pv.Plotter(shape="1|1")  # TODO   shape="3|1", 分隔绘图窗口,左边3个,右边一个
print(plotter)
plotter.subplot(0, 0)   # TODO 第1个框里绘制
cylinder = plotter.add_mesh(mesh, scalars=node_data, cmap="coolwarm",
                 # show_scalar_bar=False,
                 scalar_bar_args={'title': 'Temperature',
                                  "vertical":"False",
                                  "height":0.65,
                                  "position_x":0.85,
                                  "position_y":0.1},
                 # show_vertices=True,  # TODO   显示点
                 point_size=3, # TODO   点的大小
                 # style='points_gaussian',
                 # show_edges=True,     # TODO   显示网格
                 style='surface', # TODO  显示样式默认:'surface'表面,'wireframe'线条,'points'表面的点配合point_size设置大小,
                 )   # TODO   圆柱

_ = plotter.add_axes(   # TODO 左下角坐标轴
    line_width=5,
    cone_radius=0.6,
    shaft_length=0.7,
    tip_length=0.3,
    ambient=0.5,
    label_size=(0.4, 0.16),
)
plotter.subplot(1, 0)
# TODO 添加切片盒子裁剪网格  剪裁的网格保存到plotter.box_clipped_meshes的属性
# plotter.add_mesh_clip_box(mesh,
#                           interaction_event='end',  # TODO 什么时候触发改变,'start'刚开始拖动, 'end'拖动松开, 'always'一直变
#                           show_scalar_bar=False,
#                           cmap="coolwarm",
#                           )  # TODO 切片
actor =plotter.add_mesh_clip_box(mesh,
                          invert=False, # TODO 是否翻转/反转剪辑的标志
                          rotation_enabled=True,    # TODO 如果False,框小部件不能旋转,并且严格正交于笛卡尔轴
                          widget_color=None,    # TODO 小工具的颜色。字符串、RGB序列或十六进制颜色字符串,as color='white'
                          outline_translation=True,    # TODO 如果False,平面小部件不能被转换,并且被严格地放置在给定的边界内
                          merge_points=True,    # TODO 如果True(默认),独立定义的网格元素的重合点将被合并
                          crinkle=False,    # TODO 通过沿剪辑提取整个单元格来使剪辑起皱
                          interaction_event='end',  # TODO 什么时候触发改变,'start'刚开始拖动, 'end'拖动松开, 'always'一直变
                          # **kwargs    # TODO 所有add_mesh()的参数都可以用
                          cmap="coolwarm",
                          )
# print(type(actor))
# print(actor)
# clip = plotter.box_clipped_meshes
# print(type(clip))

# TODO 使用平面裁剪网格 保留剩下的三维网格  剪裁的网格保存到plotter.plane_clipped_meshes的属性
# plotter.add_mesh_clip_plane(mesh,
#                             normal='x', # TODO 平面的起始法向量
#                             invert=False,   # TODO 是否翻转/反转剪辑的标志
#                             widget_color=None,  # TODO 组件的颜色 字符串、RGB列表或十六进制颜色字符串
#                             value=0.0,  # TODO 沿法线方向设置剪裁值。默认值为0.0
#                             assign_to_axis=None,    # TODO 指定平面的法线与给定的轴平行。选项有(0, 'x'), (1, 'y'),或者(2, 'z')
#                             tubing=False,   # TODO 当使用隐式平面wiget时,这将控制是否在平面边界周围显示管状体
#                             origin_translation=True,    # TODO 如果False,平面小部件不能通过其原点平移,而是严格放置在给定的原点。仅在使用隐式平面时有效
#                             outline_translation=False,  # TODO 如果False时,box小部件不能被翻译,并且被严格地放置在给定的边界内。
#                             implicit=True,  # TODO  当为True时,使用vtkImplicitPlaneWidget,当为False时,使用vtkPlaneWidget。
#                             normal_rotation=True,   # TODO 设置法向量箭头的不透明度为0,这样它就被有效地禁用了。这可以防止用户旋转法线。当设置assign_to_axis时,该值强制为False。
#                             crinkle=False,  # TODO 通过沿剪辑提取整个单元格来使剪辑起皱
#                             interaction_event='end',    # TODO 什么时候触发改变,'start'刚开始拖动, 'end'拖动松开, 'always'一直变
#                             origin=None,    # TODO 平面中心的起始坐标
#                             # **kwargs    # TODO 所有add_mesh()的参数都可以用
#                             cmap="coolwarm",
#                             )


# TODO 使用平面裁剪网格  保留平面所在的二维网格  切片网格被保存到plotter.plane_sliced_meshes的属性
# plotter.add_mesh_slice(mesh,
#                        normal='x',  # TODO 平面的起始法向量
#                        generate_triangles=False,    # TODO 如果这被启用(False默认情况下),输出将是三角形,否则,输出将是相交多边形
#                        widget_color=None,   # TODO 平面组件的颜色 字符串、RGB序列或十六进制颜色字符串。默认为'white'
#                        assign_to_axis=None, # TODO 指定平面的法线与给定的轴平行:选项有(0,' x ')、(1,' y ')或(2,' z ')
#                        tubing=False,    # TODO 当使用隐式平面wiget时,这将控制是否在平面边界周围显示管状体
#                        origin_translation=True, # TODO 如果False,平面小部件不能通过其原点平移,而是严格放置在给定的原点。仅在使用隐式平面时有效
#                        outline_translation=False,   # TODO 如果为False,则无法翻译框小部件,并严格放置在给定的边界上。
#                        implicit=True,   # TODO  当为True时,使用vtkImplicitPlanewidget,当为False时,使用vtkPlaneWidget。
#                        normal_rotation=True,    # TODO 设置法向量箭头的不透明度为0,这样它就被有效地禁用了。这可以防止用户旋转法线。当设置assign_to_axis时,该值强制为False。
#                        interaction_event="end",    # TODO 什么时候触发(事件id)45:结束交互 44:拖动时
#                        origin=None, # TODO  平面中心的起始坐标。
#                        # **kwargs   # TODO 所有add_mesh()的参数都可以用
#                        cmap="coolwarm",
#                        )


# TODO 用三个相互垂直的平面切割网格  保留三个平面所在的二维网格
# plotter.add_mesh_slice_orthogonal(mesh,
#                                   generate_triangles=False, # TODO 如果这被启用(False默认情况下),输出将是三角形,否则,输出将是相交多边形
#                                   widget_color=None,    # TODO 小工具的颜色。字符串、RGB序列或十六进制颜色字符串,as color='white'
#                                   tubing=False,     # TODO 当使用隐式平面wiget时,这将控制是否在平面边界周围显示管状体
#                                   interaction_event='end',     # TODO 什么时候触发改变,'start'刚开始拖动, 'end'拖动松开, 'always'一直变
#                                   # **kwargs    # TODO 所有add_mesh()的参数都可以用
#                                   cmap="coolwarm",
#                                   )

# TODO 使用样条线小部件(多点可拖动线)切割网格  保留线所组成的平面、曲面的网格 切片网格被保存到plotter.spline_sliced_meshes的属性
# plotter.add_mesh_slice_spline(mesh,
#                               generate_triangles=False, # TODO  如果这被启用(False默认情况下),输出将是三角形,否则,输出将是相交多边形
#                               n_handles=5,  # TODO  控制样条曲线参数函数的交互球体的数量
#                               resolution=25,    # TODO  要在样条上生成的点数
#                               widget_color=None,    # TODO  小工具的颜色。字符串、RGB序列或十六进制颜色字符串,as color='white'
#                               show_ribbon=True,    # TODO  如果True,也将显示用于切片的多边形平面
#                               ribbon_color='pink',  # TODO  丝带的颜色。字符串、RGB序列或十六进制颜色字符串
#                               ribbon_opacity=0.5,   # TODO  色带的不透明度。默认值为1.0,必须介于[0, 1]
#                               initial_points=None,  # TODO  初始化小部件位置的点。必须具有与相同数量的元素n_handles。如果第一个点和最后一个点相同,这将是一个封闭环样条
#                               closed=False, # TODO  使样条曲线成为闭合环
#                               interaction_event=44, # TODO 什么时候触发(事件id)45:结束交互 44:拖动时
#                               # **kwargs    # TODO 所有add_mesh()的参数都可以用
#                               cmap="coolwarm",
#                               )

# TODO 使用滑块在网格上应用阈值
# plotter.add_mesh_threshold(mesh,
#                           show_scalar_bar=False,
#                           cmap="coolwarm",
#                           )  # TODO
# plotter.add_mesh_threshold(mesh,
#                            scalars=None,    # TODO 要设定阈值和显示的网格上标量的字符串名称
#                            invert=False,    # TODO 反转阈值结果。也就是说,此选项关闭时输出中的像元将被排除,而输出中的像元将被包括
#                            widget_color=None,   # TODO 小工具的颜色。字符串、RGB序列或十六进制颜色字符串。as color='white'
#                            preference='cell',   # TODO 该参数设置标量如何映射到网格。默认'cell',导致标量与网格单元相关联。可以是'point'或者'cell'
#                            title=None,  # TODO 滑块小工具的字符串标签
#                            pointa=(0.4, 0.9),   # TODO 显示端口上滑块左侧点的相对坐标
#                            pointb=(0.9, 0.9),# TODO 显示端口上滑块右点的相对坐标
#                            continuous=False,    # TODO 如果启用了此选项(默认为False),使用连续音程[minimum cell scalar, maximum cell scalar]与阈值边界相交,而不是与顶点的离散标量值集合相交
#                            all_scalars=False,   # TODO 如果使用点数据的标量,当该值为True时,单元中的所有点必须满足阈值。当False的时候,具有满足阈值标准的标量值的像元的任何点将提取像元。使用单元格数据时无效
#                            method='upper',  # TODO 为单值设置阈值方法,定义要使用的阈值界限。如果value是一个范围,此参数将被忽略,提取两个值之间的数据。对于单个值,'lower'将提取低于value. 'upper'将提取大于value.
#                            # **kwargs    # TODO 所有add_mesh()的参数都可以用
#                            cmap="coolwarm",
#                            )



# TODO   对指定点   添加  label标签   后期可以尝试鼠标点击某个点 为其添加 值的标签
# point_A = pv.pyvista_ndarray([mesh.points[0]])
# label_A = pv.pyvista_ndarray([node_data[0]])
# print(point_A)
# print(type(point_A))
# plotter.add_point_labels(points=point_A, labels=label_A)

# TODO 将轮廓添加到场景中  可以在切割的时候使用,方便观察
# plotter.add_silhouette(mesh,
#                        color=None,  # TODO 轮廓线条的颜色
#                        line_width=None, # TODO  轮廓线条宽度
#                        opacity=None,    # TODO  之间的线条透明度0和1
#                        feature_angle=None,  # TODO  如果设置,显示超过该角度的锐边
#                        decimate=None,   # TODO  之间的抽取级别0和1。抽取将提高渲染性能。一个好的经验法则是尝试0.9直到达到所需的渲染性能
#                        )









# plotter.subplot(1, 0)   # TODO 第2个框里绘制
# plotter.add_mesh(mesh, scalars=node_data, cmap="coolwarm",
#                  show_scalar_bar=False,
#                  # scalar_bar_args={
#                  #                  'title': '',
#                  #                  "vertical":"False",
#                  #                  "height":0.65,
#                  #                  "position_x":0.85,
#                  #                  "position_y":0.1},
#                  # show_vertices=True,  # TODO   显示点
#                  # point_size=5, # TODO   点的大小
#                  # style='points_gaussian',
#                  show_edges=True,     # TODO   显示网格
#
#                  )   # TODO   圆柱
#
# _ = plotter.add_axes(   # TODO 左下角坐标轴
#     line_width=5,
#     cone_radius=0.6,
#     shaft_length=0.7,
#     tip_length=0.3,
#     ambient=0.5,
#     label_size=(0.4, 0.16),
# )

# plotter.subplot(2, 0)   # TODO 第3个框里绘制
# plotter.add_mesh(mesh, scalars=node_data, cmap="coolwarm",
#                  show_scalar_bar=False,
#                  # scalar_bar_args={
#                  #     'title': 't',
#                  #                  "vertical":"False",
#                  #                  "height":0.65,
#                  #                  "position_x":0.85,
#                  #                  "position_y":0.1},
#                  show_vertices=True,  # TODO   显示点
#                  # point_size=5, # TODO   点的大小
#                  # style='points_gaussian',
#                  # show_edges=True,     # TODO   显示网格
#
#                  )   # TODO   圆柱
#
# _ = plotter.add_axes(   # TODO 左下角坐标轴
#     line_width=5,
#     cone_radius=0.6,
#     shaft_length=0.7,
#     tip_length=0.3,
#     ambient=0.5,
#     label_size=(0.4, 0.16),
# )

# plotter.subplot(3, 0)   # TODO 第4个框里绘制
# # TODO 绘制高斯点
# plotter.add_mesh(pv.PolyData(mesh.points),scalars=node_data, cmap='coolwarm',
#                  scalar_bar_args={
#                      'title': 'Temperature',
#                                   "vertical": "False",
#                                   "height": 0.65,
#                                   "position_x": 0.85,
#                                   "position_y": 0.1},
#                  show_edges=False)


def fun_pick(point):
    points = mesh.points
    # 计算点与数组中每个点的距离
    distances = np.linalg.norm(points - point, axis=1)
    # 找到距离最接近的点的索引
    index = np.argmin(distances)
    plotter.add_point_labels(np.array([points[index]]), np.array([node_data[index]]),
                             point_color='black',
                             point_size=10,
                             font_size=20,
                             name='point_1' # TODO 添加的参与者的名称,以便于更新。如果此名称的参与者已经存在于呈现窗口中,它将被新参与者替换。
                             )

# TODO 拾取点
plotter.enable_point_picking(callback=fun_pick,   # TODO 回调函数,第一个参数是被点击的点坐标 [-33.262 -27.3781 -22.936]
        tolerance=0.025,    # TODO 拾取的误差,按照屏幕百分比
        left_clicking=False,     # TODO 默认鼠标右键选取,True则鼠标左键
        picker=PickerType.POINT,     # TODO 选取的类型 hardware、cell、point、volume
        show_message=True,       # TODO 显示关于如何使用点拾取工具的消息。如果这是一个字符串,那将是显示的消息。
        font_size=18,    # TODO 设置消息的大小。
        color='black',    # TODO 显示被选中后的颜色。
        point_size=10,   # TODO 如果' show_point ' '为' True',则所选点的大小。
        show_point=True,    # TODO  点击后显示选中点。
        use_picker=False,   # TODO  当' ' True ' '时,回调函数也将被传递给选择器。
        pickable_window=False,   # TODO 当“True”并且所选拾取器支持它时,3D窗口中的点是可拾取的。
        clear_on_no_selection=True,  # TODO 当没有选择任何点时清除所选内容。
        # **kwargs,  # TODO
        )






cent = np.random.random((1, 3))
direction = np.random.random((1, 3))
print(cent)
print(direction)
# _ = plotter.add_arrows(cent, direction, mag=1)  # TODO 箭头

_ = plotter.add_axes(   # TODO 左下角坐标轴
    line_width=5,
    cone_radius=0.6,
    shaft_length=0.7,
    tip_length=0.3,
    ambient=0.5,
    label_size=(0.4, 0.16),
)
# _ = plotter.add_axes_at_origin()    # TODO 中心位置添加坐标轴

_ = plotter.add_camera_orientation_widget() # TODO 右上角坐标轴带负轴

chart = pv.Chart2D()   # TODO 图表
_ = chart.plot(range(10), range(10))
# plotter.add_chart(chart)

# mesh = pyvista.Sphere()
# actor = plotter.add_mesh(mesh)
# def toggle_vis(flag):
#     actor.SetVisibility(flag)
# _ = plotter.add_checkbox_button_widget(toggle_vis, value=True) # TODO 左下角添加一个复选框CheckBox


# _ = plotter.add_cursor()    # TODO 添加光标  框起来  不是鼠标

# _ = plotter.add_legend(bcolor='w', face=None)

plotter.show()
  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值