(23)VTK C++开发示例 --- 读取所有的PolyData类型示例
文章目录
- 1. 概述
- 2. CMake链接VTK
- 3. main.cpp文件
- 4. 演示效果
更多精彩内容 |
---|
👉内容导航 👈 |
👉VTK开发 👈 |
1. 概述
此示例通过检查文件的扩展名来选择 vtkPolyData 读取器。以网格方式显示多个不同文件。
将多个不同类型的文件放到一个列表中,通过
ReadPolyData()
函数识别不同的类型,创建对应的读取对象,支持读取显示多个不同类型的PolyData文件。
vtkPolyData
是vtkDataSet
的具体实现类,表示由顶点(vertices)、线段(lines)、多边形(polygons)和/或三角形条带(triangle strips)组成的几何结构。同时支持点属性(如标量、向量等)和单元属性。
关键特性
- 支持的单元类型
包括:vtkVertex
,vtkPolyVertex
,vtkLine
,vtkPolyLine
,vtkTriangle
,vtkQuad
,vtkPolygon
,vtkTriangleStrip
(定义于vtkCellType.h
)。- 高效数据操作
- 提供专用的遍历和操作方法(如通过
GetPolys()
获取多边形数组,再结合vtkCellArray
的InitTraversal()
和GetNextCell()
遍历),效率优于通用vtkDataSet
方法。- 混合单元类型的限制
vtkPolyData
使用 4 个独立vtkCellArray
实例 管理不同维度单元(0D 顶点、1D 线段、2D 多边形、2D 三角形条带)。- 插入顺序强制要求:顶点 → 线段 → 多边形 → 三角形条带,以保证单元 ID 一致性和渲染正确性。
- 过滤器兼容性:部分过滤器(如
vtkDecimatePro
需三角形/三角形条带,vtkTubeFilter
需线段)可能对输入单元类型有特定要求,需仔细查阅文档。
技术要点总结
- 设计目的
vtkPolyData
针对 非结构化表面网格 优化,适用于点云、折线网络、多边形表面等场景。- 性能建议
- 优先使用
vtkPolyData
专用方法(如GetVerts()
,GetLines()
,GetPolys()
)而非通用GetCell()
,以提高遍历效率。- 混合单元时需严格遵循插入顺序,避免数据不一致。
- 常见陷阱
- 未按顺序插入混合单元 → 导致单元 ID 混乱或渲染异常。
- 未检查过滤器对单元类型的支持 → 引发运行时错误或意外输出。
数据结构组成
vtkPolyData
由三部分数据构成:
- 几何数据 (Geometry)
通过vtkPoints
对象存储所有 点的三维坐标,定义几何形状的空间位置。- 拓扑数据 (Topology)
由多个vtkCellArray
组织,描述如何将点连接成基本图元,支持四种单元类型:
- 顶点 (Vertices):单个点构成的单元。
- 线 (Lines):两点连成的线段。
- 多边形 (Polygons):闭合的平面多边形(如四边形、五边形)。
- 三角形条带 (Triangle Strips):连续三角形共享边的高效表示。
- 属性数据 (Attributes)
附加到点或单元上的标量、向量等数据(如颜色、温度、法向量),通过vtkDataArray
存储。
数据存储优势
- 索引化存储
单元通过 点的索引(而非直接坐标)引用几何数据中的点,减少冗余存储(如多个单元共享相同点)。- 灵活性与效率
分离几何与拓扑数据,便于局部修改(如仅更新属性)或高效渲染(如复用顶点缓冲区)。
典型应用场景
- 数据来源
- 从文件(
.vtp
,.stl
,.obj
)导入网格模型。- 程序生成(如通过
vtkSphereSource
创建球体)。- 用途
- 3D 模型可视化(表面渲染、线框显示)。
- 几何处理(如网格简化、平滑)。
- 科学计算(如流线、等值面提取)。
相关地址
- vtkPolyData
- 演示文件下载地址
环境 | 说明 |
---|---|
系统 | ubuntu22.04、windows11 |
cmake | 3.22、3.25 |
Qt | 5.14.2 |
编译器 | g++11.4、msvc2017 |
VTK | 9.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;
}