【VTK+有限元后处理】节点属性值查询

15 篇文章 18 订阅
8 篇文章 5 订阅

功能

有限元在后处理过程中,我们如果想获取某一个节点的属性数据值,最直接的方法就是点击这个节点,然后显示其属性数据。

代码实现

首先我们需要使用到VTK的点拾取类vtkPointPicker类。

从需求可知,我们需要与窗口进行交互,所以先自定义一个继承自vtkInteractorStyleTrackballCamera的类(在类中定义了点拾取的交互类型)。我最开始参考了这篇文章VTK:交互与拾取——点拾取的代码,虽然运行成功了,但有些地方似乎不符合预期。第一,其中点拾取代码中有一行为actor->SetScale(0.05);,即把选中点的圆点标记大小设为常值。带来的结果是,当在一个模型整体尺寸小于这一设定常值(0.05)的时候,标记点会变得特别大(甚至直接覆盖原模型),相反,当模型尺寸远大于这一常值,标记点会变得特别小(很难发现那种)。第二,对于一些不在模型上的点也会被选中并标记,在后处理中,我们希望选中的都是有限元模型节点。对于上述两个问题,我进行了一些优化。优化后的代码如下:

class PointPickerInteractorStyle(vtk.vtkInteractorStyleTrackballCamera):

    def __init__(self, parent = None, dataset = None):
        self.AddObserver("LeftButtonPressEvent", self.leftButtonPressEvent)
        self.dataset = dataset
        self.points = dataset.GetPoints()
        # 对拾取点进行标记
        sphereSource = vtk.vtkSphereSource()
        sphereSource.Update()
        self.mapper = vtk.vtkPolyDataMapper()
        self.mapper.SetInputConnection(sphereSource.GetOutputPort())
        self.marker_actor = vtk.vtkActor()
        self.marker_actor.SetMapper(self.mapper)
        # Setup the text and add it to the renderer
        self.textActor = vtk.vtkTextActor()
        self.textActor.SetPosition(10, 10)
        self.textActor.GetTextProperty().SetFontSize(24)
        self.textActor.GetTextProperty().SetColor(241 / 255, 135 / 255, 184 / 255)
        # kd-tree
        self.tree = vtk.vtkKdTree()
        self.tree.BuildLocatorFromPoints(self.points)

    def leftButtonPressEvent(self, obj, event):
        clickPos = self.GetInteractor().GetEventPosition()
        # 打印鼠标左键像素位置
        # print(f"Picking pixel: {clickPos[0]} {clickPos[1]}")
        # 注册拾取点函数
        pointPicker = self.GetInteractor().GetPicker()
        pointPicker.Pick(clickPos[0], clickPos[1], 0, self.GetDefaultRenderer())
        # 打印拾取点空间位置
        pickId = pointPicker.GetPointId()  # 获取拾取点的ID,无ID返回-1
        if pickId != -1:
            # 显示模型上被拾取的点
            pickPos = pointPicker.GetPickPosition()
            # print(f"Picked value: {pickPos[0]} {pickPos[1]} {pickPos[2]}")
            self.marker_actor.SetPosition(pickPos)
            # Find the 2 closest points to pickPos
            ClosestIdList = vtk.vtkIdList()
            self.tree.FindClosestNPoints(2, pickPos, ClosestIdList)
            pt1 = self.points.GetPoint(ClosestIdList.GetId(0))
            pt2 = self.points.GetPoint(ClosestIdList.GetId(1))
            distance = np.sqrt(vtk.vtkMath.Distance2BetweenPoints(pt1, pt2))
            self.marker_actor.SetScale(distance / 5)
            self.marker_actor.GetProperty().SetColor(0.0, 1.0, 0.0)
            self.GetDefaultRenderer().AddActor(self.marker_actor)
            # 打印节点信息
            if self.dataset.GetPointData().GetScalars():
                scalars = self.dataset.GetPointData().GetScalars()
                self.textActor.SetInput("Picked Point: %.2f %.2f %.2f\nAttribute Value: %.2f" % (
                    pickPos[0], pickPos[1], pickPos[2], scalars.GetValue(pickId)))
            else:
                self.textActor.SetInput("Picked Point: %.2f %.2f %.2f\n" % (pickPos[0], pickPos[1], pickPos[2]))
            self.GetDefaultRenderer().AddActor2D(self.textActor)
        self.OnLeftButtonDown()

为了能根据模型尺寸改变标记点的大小,我目前的思路是:寻找到距离被拾取点最近的一个点(不包括拾取点本身),计算与其之间的距离distance,然后设置标记对象的尺寸为distance / 5,即设置标签点的直径为与其最近点的五分之一(反正比distance小就行),这样就实现了动态的尺寸调整。当然这种方法也不是唯一解,只要是能动态合理调节标记对象尺寸的方法都可。因为只有节点才具有ID,所以我们对其ID进行判断,实现只标记节点。

pickId = pointPicker.GetPointId()  # 获取拾取点的ID,无ID返回-1
        if pickId != -1:
        	# 标记代码

主干代码如下:

def piontPick(self):
    dataset = self.main_actor.GetMapper().GetInput()

    pointPicker = vtk.vtkPointPicker()
    self.interactor.SetPicker(pointPicker)  # 设置pointPicker
    style = PointPickerInteractorStyle(dataset = dataset)  # 设置自定义的点拾取交互类型
    style.SetDefaultRenderer(self.renderer)
    self.interactor.SetInteractorStyle(style)

这里传入数据对象dataset的原因是实现对不同的模型尺寸动态调节标记尺寸。

结果

下面测试结果演示了标记点随模型整体尺寸动态变化。
在这里插入图片描述
下面测试结果演示了对有限元节点的属性值查询。
在这里插入图片描述

参考

[1] VTK:交互与拾取——点拾取
[2] VTK: vtkKdTree Class Reference
[3] VTK: vtkMath Class Reference
[4] VTK: vtkPointPicker Class Reference

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值