CellsInsideObject 网格面内外与交界的判定

一:主要的知识点

1、说明

本文只是教程内容的一小段,因博客字数限制,故进行拆分。主教程链接:vtk教程------逐行解析官网所有Python示例-CSDN博客

2、知识点纪要

本段代码主要涉及的有①vtkMultiThreshold工作原理,②vtkSelectEnclosedPoints 判断一个数据集 (polyData1) 中的点是否位于另一个封闭曲面 (polyData2) 的内部

二:代码及注释

python 复制代码
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkCommonDataModel import vtkDataObject
from vtkmodules.vtkCommonTransforms import vtkTransform
from vtkmodules.vtkFiltersGeneral import vtkMultiThreshold, vtkTransformPolyDataFilter
from vtkmodules.vtkFiltersModeling import vtkSelectEnclosedPoints
from vtkmodules.vtkIOGeometry import (
    vtkBYUReader,
    vtkOBJReader,
    vtkSTLReader
)
from vtkmodules.vtkIOLegacy import vtkPolyDataReader
from vtkmodules.vtkIOPLY import vtkPLYReader
from vtkmodules.vtkIOXML import vtkXMLPolyDataReader
from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkDataSetMapper,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
    vtkRenderer
)
import os


def ReadPolyData(file_name):
    path, extension = os.path.splitext(file_name)
    extension = extension.lower()
    if extension == '.ply':
        reader = vtkPLYReader()
        reader.SetFileName(file_name)
        reader.Update()
        poly_data = reader.GetOutput()
    elif extension == '.vtp':
        reader = vtkXMLPolyDataReader()
        reader.SetFileName(file_name)
        reader.Update()
        poly_data = reader.GetOutput()
    elif extension == '.obj':
        reader = vtkOBJReader()
        reader.SetFileName(file_name)
        reader.Update()
        poly_data = reader.GetOutput()
    elif extension == '.stl':
        reader = vtkSTLReader()
        reader.SetFileName(file_name)
        reader.Update()
        poly_data = reader.GetOutput()
    elif extension == '.vtk':
        reader = vtkPolyDataReader()
        reader.SetFileName(file_name)
        reader.Update()
        poly_data = reader.GetOutput()
    elif extension == '.g':
        reader = vtkBYUReader()
        reader.SetGeometryFileName(file_name)
        reader.Update()
        poly_data = reader.GetOutput()
    else:
        # Return a None if the extension is unknown.
        poly_data = None
    return poly_data


def main():
    fn1 = "Data/cow.g"
    fn2 = 0
    polyData1 = ReadPolyData(fn1)

    # 根据polyData1进行旋转得到polyData2
    center = polyData1.GetCenter()
    transform = vtkTransform()
    transform.Translate(center[0], center[1], center[2])
    transform.RotateY(90.0)
    transform.Translate(-center[0], -center[1], -center[2])

    transformPD = vtkTransformPolyDataFilter()
    transformPD.SetTransform(transform)
    transformPD.SetInputData(polyData1)
    transformPD.Update()
    polyData2 = transformPD.GetOutput()

    """
    vtkSelectEnclosedPoints 判断一个数据集 (polyData1) 中的点是否位于另一个封闭曲面 (polyData2) 的内部
    """
    select = vtkSelectEnclosedPoints()
    """
    SetInputData  设置输入数据集。这个数据集包含你想要进行判断的点。
    """
    select.SetInputData(polyData1)
    """
    SetSurfaceData 设置参考曲面。这个数据集必须是一个封闭的、流形的多边形网格
    """
    select.SetSurfaceData(polyData2)

    """
    vtkMultiThreshold 是 VTK 里一个 阈值过滤器 (threshold filter)
    它的特点是 可以在一次操作里设置多个阈值条件,并根据这些条件把输入数据分成多个输出结果
    普通的 vtkThreshold 只能设置一个阈值范围,比如提取标量在 [100, 200] 之间的单元格。
    vtkMultiThreshold 则可以定义 多个规则,一次性生成 多个子数据集,省去了重复调用多个 vtkThreshold 的麻烦

    工作原理:
    你给它输入一个 数据集 (vtkDataSet),比如 vtkUnstructuredGrid 或 vtkImageData。
    你定义多个阈值条件,比如:
    规则 1:提取标量 < 50
    规则 2:提取 50 ≤ 标量 < 100
    规则 3:提取 标量 ≥ 100
    它会输出多个数据集,每个对应一个规则。
    """
    threshold = vtkMultiThreshold()
    """
    AddBandpassIntervalSet  作用是定义一个过滤规则,用于从数据中提取出特定范围内的单元(cells)
    这段代码的具体含义是:
    threshold.AddBandpassIntervalSet(): 调用 vtkMultiThreshold 过滤器的这个方法,来创建一个"通带"区间集,即只保留满足特定条件的单元。
    0, 0: 定义了数据值的范围。这里表示数据值必须等于 0。
    vtkDataObject.FIELD_ASSOCIATION_POINTS: 指定要检查的数据是点数据(point data)。
    'SelectedPoints': 指定要检查的数据数组的名称。这是 vtkSelectEnclosedPoints 过滤器在前面步骤中创建的那个数组。
    0, 1: 定义了一个单元中点值满足条件的数量范围。这里表示,要被选中的单元,其所有点(0 到 1)的 'SelectedPoints' 值都必须在前面定义的 [0, 0] 范围内。
    """
    outsideId = threshold.AddBandpassIntervalSet(0, 0,  # 区间范围:下限=0,上限=0
                                                 vtkDataObject.FIELD_ASSOCIATION_POINTS,  # 作用在点数据上
                                                 "SelectedPoints",  # 要筛选的数组名字
                                                 0, 1)  # includeLower=0(不包含下界),includeUpper=1(包含上界)
    """
    具体含义
    0, 0
    → 选取 "SelectedPoints" 数组值在 [0, 0] 之间的点,也就是值恰好等于 0 的点。
    (因为 vtkSelectEnclosedPoints 的 "SelectedPoints" 标量:内部点 = 1 外部点 = 0)

    vtkDataObject.FIELD_ASSOCIATION_POINTS
    → 指定这个筛选条件是作用在 点数据 (point data) 上,而不是单元(cell data)。

    "SelectedPoints"
    → 要筛选的数组名字,就是 vtkSelectEnclosedPoints 生成的标量数组。
    在这段代码里,它之所以是这个名字,是因为 vtkSelectEnclosedPoints 默认就会生成一个标量数组,名字叫 "SelectedPoints"

    如果不知道数组名字,可以先查看数组里有哪些数组
    pointData = polydata.GetPointData()
    for i in range(pointData.GetNumberOfArrays()):
        print(pointData.GetArrayName(i))

    单元数据就是下面这样写
    cellData = polydata.GetCellData()
    for i in range(cellData.GetNumberOfArrays()):
        print(cellData.GetArrayName(i))

    component = 0
    指定数组的第几个分量(例如 0 = x, 1 = y, 2 = z)  如果数组是标量,就写 0
    
    allScalars = 1
    当数组有多个分量时,是否要求所有分量都满足区间条件
    0 → 只检查指定的 component 分量
    1 → 要求数组的所有分量都在 [xmin, xmax] 内
    
    上边界和下边界就是第0和第1个索引所代表的两个数
    所以这里实际上是筛选出 "SelectedPoints" == 0 的点。

    返回值 outsideId 返回的是这个阈值区间的 ID,可以用来后续控制(比如启用/禁用某个条件)
    """

    insideId = threshold.AddBandpassIntervalSet(1, 1, vtkDataObject.FIELD_ASSOCIATION_POINTS, "SelectedPoints", 0, 1)
    """
    AddIntervalSet  寻找那些至少有一个点在内部(值1),同时至少有一个点在外部(值0)的单元。这些单元恰好就是位于边界上的单元
    0, 1: 定义了数据值范围。这个区间是 [0, 1],表示所有值为 0 或 1 的点都符合条件
    OPEN参数:定义了区间的开闭类型,所以 [0, 1] 在这里实际上指的是所有大于 0 且小于 1 的值。但是,由于我们前面 vtkSelectEnclosedPoints 过滤器生成的 'SelectedPoints' 数组值只有 0 和 1,所以这里的 OPEN 会使我们定义的规则变得特殊
    0, 0:当与 vtkMultiThreshold.OPEN, vtkMultiThreshold.OPEN 结合使用时,它会检查一个单元中既有值在 0-1 范围内的点(即 0 或 1),又有值不在 0-1 范围内的点。在这里,它用来捕捉那些**既有值为 0 的点(外部),又有值为 1 的点(内部)**的单元
    """
    borderId = threshold.AddIntervalSet(0, 1, vtkMultiThreshold.OPEN, vtkMultiThreshold.OPEN,
                                        vtkDataObject.FIELD_ASSOCIATION_POINTS, 'SelectedPoints', 0, 0)
    threshold.SetInputConnection(select.GetOutputPort())
    """
    OutputSet  设置最终要输出的数据集
    """
    threshold.OutputSet(outsideId)
    threshold.OutputSet(insideId)
    threshold.OutputSet(borderId)
    threshold.Update()

    colors = vtkNamedColors()
    outsideColor = colors.GetColor3d('Crimson')
    insideColor = colors.GetColor3d('Banana')
    borderColor = colors.GetColor3d('Mint')
    surfaceColor = colors.GetColor3d('Peacock')
    backgroundColor = colors.GetColor3d('Silver')

    outsideMapper = vtkDataSetMapper()
    outsideMapper.SetInputData(threshold.GetOutput().GetBlock(outsideId).GetBlock(0))
    outsideMapper.ScalarVisibilityOff()

    outsideActor = vtkActor()
    outsideActor.SetMapper(outsideMapper)
    outsideActor.GetProperty().SetDiffuseColor(outsideColor)
    outsideActor.GetProperty().SetSpecular(.6)
    outsideActor.GetProperty().SetSpecularPower(30)

    insideMapper = vtkDataSetMapper()
    insideMapper.SetInputData(threshold.GetOutput().GetBlock(insideId).GetBlock(0))
    insideMapper.ScalarVisibilityOff()

    insideActor = vtkActor()
    insideActor.SetMapper(insideMapper)
    insideActor.GetProperty().SetDiffuseColor(insideColor)
    insideActor.GetProperty().SetSpecular(.6)
    insideActor.GetProperty().SetSpecularPower(30)
    insideActor.GetProperty().EdgeVisibilityOn()

    borderMapper = vtkDataSetMapper()
    borderMapper.SetInputData(threshold.GetOutput().GetBlock(borderId).GetBlock(0))
    borderMapper.ScalarVisibilityOff()

    borderActor = vtkActor()
    borderActor.SetMapper(borderMapper)
    borderActor.GetProperty().SetDiffuseColor(borderColor)
    borderActor.GetProperty().SetSpecular(.6)
    borderActor.GetProperty().SetSpecularPower(30)
    borderActor.GetProperty().EdgeVisibilityOn()

    surfaceMapper = vtkDataSetMapper()
    surfaceMapper.SetInputData(polyData2)
    surfaceMapper.ScalarVisibilityOff()

    surfaceActor = vtkActor()
    surfaceActor.SetMapper(surfaceMapper)
    surfaceActor.GetProperty().SetDiffuseColor(surfaceColor)
    surfaceActor.GetProperty().SetOpacity(.1)

    renderer = vtkRenderer()
    renderWindow = vtkRenderWindow()
    renderWindow.AddRenderer(renderer)
    renderWindow.SetSize(640, 480)

    renderWindowInteractor = vtkRenderWindowInteractor()
    renderWindowInteractor.SetRenderWindow(renderWindow)

    renderer.SetBackground(backgroundColor)
    renderer.UseHiddenLineRemovalOn()

    renderer.AddActor(surfaceActor)
    renderer.AddActor(outsideActor)
    renderer.AddActor(insideActor)
    renderer.AddActor(borderActor)

    renderWindow.SetWindowName('CellsInsideObject')
    renderWindow.Render()
    renderer.GetActiveCamera().Azimuth(30)
    renderer.GetActiveCamera().Elevation(30)
    renderer.GetActiveCamera().Dolly(1.25)
    renderWindow.Render()

    renderWindowInteractor.Start()


if __name__ == '__main__':
    main()
相关推荐
@小码农6 小时前
2025年厦门市小学生信息学竞赛C++(初赛)真题-附答案
开发语言·c++·python·算法·蓝桥杯
星川皆无恙6 小时前
基于ARIMA 算法模型和NLP:社交媒体舆情分析在涉众型经济犯罪情报挖掘中的应用研究
人工智能·爬虫·python·算法·机器学习·自然语言处理·数据分析
SCBAiotAigc6 小时前
一个github的proxy url
人工智能·python
Chen--Xing6 小时前
LeetCode 11.盛最多水的容器
c++·python·算法·leetcode·rust·双指针
free-elcmacom6 小时前
机器学习高阶教程<1>优化理论:破解优化器的底层密码
人工智能·python·机器学习·优化理论
DeltaTime6 小时前
二 线性变换, 齐次坐标, 变换组合, 变换分解, 3D变换
c++·3d·图形渲染
瀚岳-诸葛弩6 小时前
对比tensorflow,从0开始学pytorch(五)--CBAM
人工智能·pytorch·python
runepic6 小时前
Python 批量合并多个 Excel 数据(自动补 0 + 生成明细)
java·python·excel
ULTRA??6 小时前
排序算法之快排与TIMSORT的比较测试,python
c++·python·算法·golang