当前位置: 首页 > news >正文

(23)VTK C++开发示例 --- 读取所有的PolyData类型示例

文章目录

    • 1. 概述
    • 2. CMake链接VTK
    • 3. main.cpp文件
    • 4. 演示效果


更多精彩内容
👉内容导航 👈
👉VTK开发 👈

1. 概述

此示例通过检查文件的扩展名来选择 vtkPolyData 读取器。以网格方式显示多个不同文件。

将多个不同类型的文件放到一个列表中,通过ReadPolyData()函数识别不同的类型,创建对应的读取对象,支持读取显示多个不同类型的PolyData文件。


vtkPolyDatavtkDataSet 的具体实现类,表示由顶点(vertices)、线段(lines)、多边形(polygons)和/或三角形条带(triangle strips)组成的几何结构。同时支持点属性(如标量、向量等)和单元属性。


关键特性

  1. 支持的单元类型
    包括:vtkVertex, vtkPolyVertex, vtkLine, vtkPolyLine, vtkTriangle, vtkQuad, vtkPolygon, vtkTriangleStrip(定义于 vtkCellType.h)。
  2. 高效数据操作
    • 提供专用的遍历和操作方法(如通过 GetPolys() 获取多边形数组,再结合 vtkCellArrayInitTraversal()GetNextCell() 遍历),效率优于通用 vtkDataSet 方法。
  3. 混合单元类型的限制
    • vtkPolyData 使用 4 个独立 vtkCellArray 实例 管理不同维度单元(0D 顶点、1D 线段、2D 多边形、2D 三角形条带)。
    • 插入顺序强制要求:顶点 → 线段 → 多边形 → 三角形条带,以保证单元 ID 一致性和渲染正确性。
    • 过滤器兼容性:部分过滤器(如 vtkDecimatePro 需三角形/三角形条带,vtkTubeFilter 需线段)可能对输入单元类型有特定要求,需仔细查阅文档。

技术要点总结

  1. 设计目的
    vtkPolyData 针对 非结构化表面网格 优化,适用于点云、折线网络、多边形表面等场景。
  2. 性能建议
    • 优先使用 vtkPolyData 专用方法(如 GetVerts(), GetLines(), GetPolys())而非通用 GetCell(),以提高遍历效率。
    • 混合单元时需严格遵循插入顺序,避免数据不一致。
  3. 常见陷阱
    • 未按顺序插入混合单元 → 导致单元 ID 混乱或渲染异常。
    • 未检查过滤器对单元类型的支持 → 引发运行时错误或意外输出。

数据结构组成

vtkPolyData 由三部分数据构成:

  • 几何数据 (Geometry)
    通过 vtkPoints 对象存储所有 点的三维坐标,定义几何形状的空间位置。
  • 拓扑数据 (Topology)
    由多个 vtkCellArray 组织,描述如何将点连接成基本图元,支持四种单元类型:
    • 顶点 (Vertices):单个点构成的单元。
    • 线 (Lines):两点连成的线段。
    • 多边形 (Polygons):闭合的平面多边形(如四边形、五边形)。
    • 三角形条带 (Triangle Strips):连续三角形共享边的高效表示。
  • 属性数据 (Attributes)
    附加到点或单元上的标量、向量等数据(如颜色、温度、法向量),通过 vtkDataArray 存储。

数据存储优势

  • 索引化存储
    单元通过 点的索引(而非直接坐标)引用几何数据中的点,减少冗余存储(如多个单元共享相同点)。
  • 灵活性与效率
    分离几何与拓扑数据,便于局部修改(如仅更新属性)或高效渲染(如复用顶点缓冲区)。

典型应用场景

  • 数据来源
    • 从文件(.vtp, .stl, .obj)导入网格模型。
    • 程序生成(如通过 vtkSphereSource 创建球体)。
  • 用途
    • 3D 模型可视化(表面渲染、线框显示)。
    • 几何处理(如网格简化、平滑)。
    • 科学计算(如流线、等值面提取)。

相关地址

  • vtkPolyData
  • 演示文件下载地址
环境说明
系统ubuntu22.04、windows11
cmake3.22、3.25
Qt5.14.2
编译器g++11.4、msvc2017
VTK9.4.1

2. CMake链接VTK

cmake_minimum_required(VERSION 3.20 FATAL_ERROR) # 设置CMake最低版本
project(vtk2) # 设置项目名称
# 查找VTK库
find_package(VTK COMPONENTS 
CommonColor
CommonCore
CommonDataModel
FiltersSources
IOGeometry
IOLegacy
IOPLY
IOXML
InteractionStyle
RenderingContextOpenGL2
RenderingCore
RenderingFreeType
RenderingGL2PSOpenGL2
RenderingOpenGL2
)
if(NOT VTK_FOUND)
message("VTK not found")
return()
endif()add_executable(vtk2 main.cpp) # 添加可执行文件target_link_libraries(vtk2 PRIVATE ${VTK_LIBRARIES}) # 链接VTK库
vtk_module_autoinit(TARGETS vtk2 MODULES ${VTK_LIBRARIES}) # 初始化VTK模块

3. main.cpp文件

/********************************************************************************
* 文件名:   main.cpp
* 创建时间: 2025-03-19 17:18:59
* 开发者:   MHF
* 邮箱:     1603291350@qq.com
* 功能:     读取所有polyData类型的文件,将其转换为vtkPolyData类型的文件
*********************************************************************************/
#include <vtkActor.h>
#include <vtkActor2D.h>
#include <vtkBYUReader.h>
#include <vtkCamera.h>
#include <vtkCellArray.h>
#include <vtkCoordinate.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkOBJReader.h>
#include <vtkPLYReader.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkPolyDataMapper2D.h>
#include <vtkPolyDataReader.h>
#include <vtkPolyLine.h>
#include <vtkProperty.h>
#include <vtkProperty2D.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSTLReader.h>
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkTextMapper.h>
#include <vtkTextProperty.h>
#include <vtkXMLPolyDataReader.h>#include <vtksys/SystemTools.hxx>#include <algorithm>
#include <string>
using namespace std;vtkSmartPointer<vtkPolyData> ReadPolyData(const std::string& fileName)
{vtkSmartPointer<vtkPolyData> polyData; // vtkPolyData类型的智能指针string extension = vtksys::SystemTools::GetFilenameLastExtension(fileName); // 获取文件扩展名transform(extension.begin(), extension.end(), extension.begin(), ::tolower); // 将扩展名转换为小写if(extension == ".ply") {vtkNew<vtkPLYReader> reader; // 创建vtkPLYReader对象reader->SetFileName(fileName.c_str()); // 设置文件名reader->Update(); // 更新数据polyData = reader->GetOutput(); // 获取输出数据}else if(extension == ".vtp"){vtkNew<vtkXMLPolyDataReader> reader; // 创建vtkXMLPolyDataReader对象reader->SetFileName(fileName.c_str()); // 设置文件名reader->Update(); // 更新数据polyData = reader->GetOutput(); // 获取输出数据} else if(extension == ".obj"){vtkNew<vtkOBJReader> reader; // 创建vtkOBJReader对象reader->SetFileName(fileName.c_str()); // 设置文件名reader->Update(); // 更新数据polyData = reader->GetOutput(); // 获取输出数据}else if(extension == ".stl"){vtkNew<vtkSTLReader> reader; // 创建vtkSTLReader对象reader->SetFileName(fileName.c_str()); // 设置文件名reader->Update(); // 更新数据polyData = reader->GetOutput(); // 获取输出数据}else if(extension == ".g"){vtkNew<vtkBYUReader> reader; // 创建vtkBYUReader对象reader->SetGeometryFileName(fileName.c_str()); // 设置文件名reader->Update(); // 更新数据polyData = reader->GetOutput(); // 获取输出数据}else if(extension == ".vtk"){vtkNew<vtkPolyDataReader> reader; // 创建vtkPolyDataReader对象reader->SetFileName(fileName.c_str()); // 设置文件名reader->Update(); // 更新数据polyData = reader->GetOutput(); // 获取输出数据}else{cerr << "未知文件类型: " << extension << endl;vtkNew<vtkSphereSource> sphereSource; // 创建球体数据源sphereSource->Update(); // 更新数据polyData = sphereSource->GetOutput(); // 获取输出数据}return polyData;
}/**
* @brief 设置视口的边框颜色
*
* 为指定的渲染器设置视口的边框颜色。
*
* @param renderer vtkRenderer的智能指针,指向要设置边框的渲染器
* @param color 双精度浮点数数组,包含边框颜色的RGB值(范围在0.0到1.0之间)
* @param last 是否为最后一个渲染器,如果为true,则可能在处理上有所不同
*/
void ViewportBorder(vtkSmartPointer<vtkRenderer>& renderer, double* color, bool last)
{vtkNew<vtkPoints> points; // 点points->SetNumberOfPoints(4); // 设置点的数量points->SetPoint(0, 1, 1, 0); // 设置点的位置points->SetPoint(1, 0, 1, 0);points->SetPoint(2, 0, 0, 0);points->SetPoint(3, 1, 0, 0);vtkNew<vtkCellArray> cells; // 线cells->Initialize(); // 初始化vtkNew<vtkPolyLine> lines; // 多线if(last){lines->GetPointIds()->SetNumberOfIds(5); // 设置点的数量}else{lines->GetPointIds()->SetNumberOfIds(4); // 设置点的数量}for(int i = 0; i < 4; i++){lines->GetPointIds()->SetId(i, i); // 设置点的ID}if(last){lines->GetPointIds()->SetId(4, 0); // 设置点的ID}cells->InsertNextCell(lines); // 插入线vtkNew<vtkPolyData> polyData; // 多边形数据polyData->Initialize(); // 初始化polyData->SetPoints(points); // 设置点polyData->SetLines(cells); // 设置线// 使用标准化视口坐标// 它们与窗口大小无关vtkNew<vtkCoordinate> coordinate; // 坐标coordinate->SetCoordinateSystemToNormalizedViewport(); // 设置坐标系统为标准化视口坐标vtkNew<vtkPolyDataMapper2D> mapper; // 映射器,用于2Dmapper->SetInputData(polyData); // 设置输入数据mapper->SetTransformCoordinate(coordinate); // 设置坐标变换vtkNew<vtkActor2D> actor; // 2D演员actor->SetMapper(mapper); // 设置映射器actor->GetProperty()->SetColor(color); // 设置颜色actor->GetProperty()->SetLineWidth(4); // 设置线宽renderer->AddViewProp(actor); // 添加视图属性
}int main()
{vtkNew<vtkNamedColors> colors;vtkNew<vtkTextProperty> textProperty; // 文本属性textProperty->SetFontSize(16); // 设置字体大小textProperty->SetColor(0.3, 0.3, 0.3); // 设置颜色// 文件列表list<string> fileNames = {"E:/lib/VTK/vtk-data/Data/bunny.ply","E:/lib/VTK/vtk-data/Data/horse.vtp","E:/lib/VTK/vtk-data/Data/dragon.ply","E:/lib/VTK/vtk-data/Data/teapot.g",}; vtkNew<vtkRenderWindow> renderWindow; //渲染窗口vector<vtkSmartPointer<vtkRenderer>> renderers; // 渲染器列表// 读取文件并添加到渲染器中for(auto &fileName : fileNames){cout << "正在读取文件: " << fileName << endl;auto polyData = ReadPolyData(fileName); // 读取文件if(!polyData) // 如果读取失败{cerr << "读取文件失败: " << fileName << endl;return 1;}vtkNew<vtkPolyDataMapper> mapper; // 映射器mapper->SetInputData(polyData); // 设置输入数据vtkNew<vtkActor> actor; // 演员actor->SetMapper(mapper); // 设置映射器actor->GetProperty()->SetDiffuseColor(colors->GetColor3d("Light_salmon").GetData()); // 设置漫反射颜色actor->GetProperty()->SetSpecular(0.6); // 设置镜面反射系数actor->GetProperty()->SetSpecularPower(30); // 设置镜面反射功率vtkNew<vtkTextMapper> textMapper; // 文本映射器textMapper->SetTextProperty(textProperty); // 设置文本属性textMapper->SetInput(vtksys::SystemTools::GetFilenameName(fileName).c_str()); // 设置文本内容vtkNew<vtkActor2D> text; // 2D演员text->SetMapper(textMapper); // 设置映射器text->SetPosition(20, 20); // 设置位置vtkNew<vtkRenderer> renderer; // 渲染器renderer->AddActor(actor); // 添加演员到渲染器renderer->AddActor(text); // 添加文本到渲染器renderer->SetBackground(colors->GetColor3d("mint").GetData()); // 设置背景颜色renderWindow->AddRenderer(renderer); // 添加渲染器到渲染窗口renderers.push_back(renderer); // 添加渲染器到渲染器列表}int rendererSize = 400; // 渲染器大小int xGridDimensions = 2; // 网格的列数// 注意:如果文件数量不是xGridDimensions的倍数,则无法正常显示,因为网格行不完整。int yGridDimensions = fileNames.size() / xGridDimensions; // 网格的行数renderWindow->SetSize(rendererSize * xGridDimensions, rendererSize * yGridDimensions); // 设置渲染窗口大小int blank = fileNames.size() + (fileNames.size() % xGridDimensions); // 添加空白渲染器的数量,确保网格完整for (auto i = fileNames.size() + 1; i < blank; ++i){vtkNew<vtkRenderer> renderer;renderer->SetBackground(colors->GetColor3d("White").GetData());renderers.push_back(renderer);renderWindow->AddRenderer(renderer);}// 设置渲染器视口和边框颜色for(auto row = 0; row < yGridDimensions; row++){for(auto col = 0; col < xGridDimensions; col++){auto index = row * xGridDimensions + col;double viewPort[4] = {double(col) * rendererSize / (xGridDimensions * rendererSize),double(yGridDimensions - (row + 1)) * rendererSize / (yGridDimensions * rendererSize),double(col + 1) * rendererSize / (xGridDimensions * rendererSize),double(yGridDimensions - row) * rendererSize / (yGridDimensions * rendererSize)};renderers[index]->SetViewport(viewPort); // 设置视口ViewportBorder(renderers[index], colors->GetColor3d("SlateGray").GetData(), col == int(xGridDimensions)); // 设置视口边框}}vtkNew<vtkRenderWindowInteractor> renderWindowInteractor; //渲染窗口交互器renderWindowInteractor->SetRenderWindow(renderWindow);renderWindow->Render(); // 渲染窗口renderWindowInteractor->Start(); // 开始渲染窗口交互return 0;
}

4. 演示效果

在这里插入图片描述



相关文章:

  • Apache NetBeans 25 发布
  • dl学习笔记(13):从强化学习到PPO
  • MySQL之视图
  • 基于Docker、Kubernetes和Jenkins的百节点部署架构图及信息流描述
  • 大数据模型现状分析
  • 小程序Npm package entry file not found?
  • 定制一款国密浏览器(12):分析SM2签名算法的实现
  • HTTP 协议深度解析:从基础到实战的完整指南
  • Qt动态库信号崩溃问题解决方案
  • 【实战】基于 Hugging Face 的 LLM 高效微调全解析
  • ASAM MDF 文件格式简介:测量数据的标准化存储
  • Goland终端PowerShell命令失效
  • 量子计算与GPU的异构加速:基于CUDA Quantum的混合编程实践
  • Android7 Input(五)InputDispatcher
  • Missashe考研日记-day27
  • 碰一碰发视频源码搭建全解析,支持OEM
  • 分类数据处理全解析:从独热编码到高维特征优化
  • 如何解决docker运行Java程序导出Excel中文报错的问题?
  • [官方IP] Shift RAM
  • 五年经验Java开发如何破局创业
  • 哈马斯官员:只要以军持续占领,哈马斯就不会放下武器
  • 政治局会议深度|提出“设立新型政策性金融工具”有何深意?
  • 农贸美学、业态再构、智能管理,今天的菜市场不止有菜
  • 马上评|起名“朱雀玄武敕令”?姓名权别滥用
  • 84%白化!全球珊瑚正经历最严重最大范围白化现象
  • 百位名人写“茶”字,莫言王蒙贾平凹都写了