QT中使用VTK

VTK (Visualization Toolkit) 是一个强大的开源三维可视化库,而QT是一个流行的跨平台GUI框架。将两者结合可以创建功能丰富的科学可视化应用程序。

一、环境准备

首先确保已安装:

  • QT (5.9或更高版本)

  • VTK (9.0或更高版本)

  • CMake (构建工具)

二、基本集成方法

1. 使用QVTKOpenGLNativeWidget(推荐方式)

#include <QApplication>
#include <QSurfaceFormat>

#include <vtkActor.h>
#include <vtkConeSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <QVTKOpenGLNativeWidget.h>

int main(int argc, char** argv)
{
    // 设置QT应用
    QApplication app(argc, argv);
    
    // 设置OpenGL版本和格式
    QSurfaceFormat::setDefaultFormat(QVTKOpenGLNativeWidget::defaultFormat());
    
    // 创建QT窗口和VTK部件
    QMainWindow mainWindow;
    QVTKOpenGLNativeWidget* vtkWidget = new QVTKOpenGLNativeWidget(&mainWindow);
    
    // 创建VTK管线
    vtkNew<vtkConeSource> cone;
    vtkNew<vtkPolyDataMapper> mapper;
    mapper->SetInputConnection(cone->GetOutputPort());
    
    vtkNew<vtkActor> actor;
    actor->SetMapper(mapper);
    
    vtkNew<vtkRenderer> renderer;
    renderer->AddActor(actor);
    
    vtkWidget->renderWindow()->AddRenderer(renderer);
    
    // 设置窗口并显示
    mainWindow.setCentralWidget(vtkWidget);
    mainWindow.resize(800, 600);
    mainWindow.show();
    
    return app.exec();
}

2. 使用QVTKOpenGLWidget (旧版方式)

#include <QVTKOpenGLWidget.h>
// 其他包含与上面类似

// 使用方式与QVTKOpenGLNativeWidget类似

三、Make配置 

CMake配置示例

cmake_minimum_required(VERSION 3.12)
project(VTK_QT_Example)

find_package(Qt5 REQUIRED COMPONENTS Widgets)
find_package(VTK REQUIRED)

add_executable(vtk_qt_example main.cpp)

target_link_libraries(vtk_qt_example
    PRIVATE
    Qt5::Widgets
    ${VTK_LIBRARIES}
)

或者 QMake配置示例(.pro文件)

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mainwindow.cpp

HEADERS += \
    mainwindow.h

FORMS += \
    mainwindow.ui


# Unix/Linux 配置
unix {
    # 假设 VTK 安装在 /usr 目录下
    VTK_DIR = /usr/lib/cmake/vtk-9.2
    INCLUDEPATH += $$system(/usr/lib/vtk-9.2/include/vtk-9.2)
    LIBS += -L$$system(/usr/lib/vtk-9.2/lib)
    LIBS += -lGL
}

# Windows 配置
win32 {
    INCLUDEPATH += $$PWD/'../../../../Program Files/VTK/include/vtk-9.2'
    DEPENDPATH += $$PWD/'../../../../Program Files/VTK/include/vtk-9.2'
    LIBS += -lopengl32
}

win32:CONFIG(release, debug|release):{
LIBS += -L$$PWD/'../../../../Program Files/VTK/lib/'
}
else:win32:CONFIG(debug, debug|release): {
LIBS += -L$$PWD/'../../../../Program Files/VTK/lib/'
}
else:unix:{
LIBS += -L$$PWD/'../../../../Program Files/VTK/lib/'
LIBS += -lGL
}

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target


# 必需的核心 VTK 库
LIBS += -lvtksys-9.2
LIBS += -lvtkCommonColor-9.2
LIBS += -lvtkCommonCore-9.2
LIBS += -lvtkCommonDataModel-9.2
LIBS += -lvtkFiltersCore-9.2
LIBS += -lvtkInteractionStyle-9.2
LIBS += -lvtkRenderingCore-9.2
LIBS += -lvtkRenderingOpenGL2-9.2
LIBS += -lvtkViewsQt-9.2
LIBS += -lvtkGUISupportQt-9.2
LIBS += -lvtkRenderingAnnotation-9.2

# 可选: 用于数据处理和可视化的附加库
LIBS += -lvtkFiltersSources-9.2
LIBS += -lvtkFiltersGeneral-9.2
LIBS += -lvtkIOCore-9.2
LIBS += -lvtkIOXML-9.2

四、创建基本QT-VTK应用

1 创建QT项目

创建一个基本的QT Widgets Application项目。

2 修改main.cpp和mainwindow.h/mainwindow.cpp文件

 mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>

// VTK 头文件
#include <vtkActor.h>
#include <vtkDataSetMapper.h>
#include <vtkDoubleArray.h>
#include <vtkGenericOpenGLRenderWindow.h>
#include <vtkNamedColors.h>
#include <vtkNew.h>
#include <vtkPointData.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <vtkScalarBarActor.h>
#include <vtkTriangle.h>
#include <vtkUnstructuredGrid.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkRendererCollection.h>
#include <vtkCamera.h>
// Qt VTK 集成组件
#include <QVTKOpenGLNativeWidget.h>  // 或 QVTKOpenGLWidget

QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

public slots:
    void setupColorMap(int scheme = 0);

private:
    void setupVTK();
    void createSampleData();
    void createToolBar();

    QVTKOpenGLNativeWidget *vtkWidget;
    vtkRenderWindow *renderWindow;
    vtkRenderer *renderer;
    vtkUnstructuredGrid *unstructuredGrid;
    vtkActor *actor;
    vtkDataSetMapper *mapper;
    vtkScalarBarActor *scalarBar;

private:
    Ui::MainWindow *ui;
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QVBoxLayout>
#include <QToolBar>
#include <vtkLookupTable.h>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    setWindowTitle("VTK Stress Cloud");
    resize(800, 600);

    createToolBar();

    // 创建中央部件和布局
    QWidget *centralWidget = new QWidget(this);
    QVBoxLayout *layout = new QVBoxLayout(centralWidget);

    // 创建 VTK 部件
    vtkWidget = new QVTKOpenGLNativeWidget(centralWidget);
    layout->addWidget(vtkWidget);

    setCentralWidget(centralWidget);

    // 初始化 VTK
    setupVTK();
}

MainWindow::~MainWindow()
{
    // 清理 VTK 对象
    if (renderWindow) renderWindow->Delete();
    if (renderer) renderer->Delete();
    if (unstructuredGrid) unstructuredGrid->Delete();
    if (actor) actor->Delete();
    if (mapper) mapper->Delete();
    if (scalarBar) scalarBar->Delete();

    delete ui;
}

void MainWindow::setupVTK()
{
    // 创建渲染窗口和渲染器
    renderWindow = vtkGenericOpenGLRenderWindow::New();
    vtkWidget->setRenderWindow(renderWindow);

    renderer = vtkRenderer::New();
    renderWindow->AddRenderer(renderer);

    //添加交互功能
    vtkNew<vtkInteractorStyleTrackballCamera> style;
    renderWindow->GetInteractor()->SetInteractorStyle(style);

    // 创建示例数据
    createSampleData();

    // 设置背景色
    vtkNew<vtkNamedColors> colors;
    renderer->SetBackground(colors->GetColor3d("SlateGray").GetData());

    // 重置相机并渲染
    renderer->ResetCamera();
    renderWindow->Render();
}

void MainWindow::createSampleData()
{
    // 1. 创建点数据 (节点坐标)
    vtkNew<vtkPoints> points;
    points->InsertNextPoint(0.0, 0.0, 0.0);
    points->InsertNextPoint(1.0, 0.0, 0.0);
    points->InsertNextPoint(0.0, 1.0, 0.0);
    points->InsertNextPoint(1.0, 1.0, 0.0);
    points->InsertNextPoint(0.5, 0.5, 0.0); // 中心点

    // 2. 创建非结构化网格
    unstructuredGrid = vtkUnstructuredGrid::New();
    unstructuredGrid->SetPoints(points);

    // 创建三角形单元
    vtkNew<vtkTriangle> triangle1;
    triangle1->GetPointIds()->SetId(0, 0);
    triangle1->GetPointIds()->SetId(1, 1);
    triangle1->GetPointIds()->SetId(2, 4);

    vtkNew<vtkTriangle> triangle2;
    triangle2->GetPointIds()->SetId(0, 1);
    triangle2->GetPointIds()->SetId(1, 3);
    triangle2->GetPointIds()->SetId(2, 4);

    vtkNew<vtkTriangle> triangle3;
    triangle3->GetPointIds()->SetId(0, 3);
    triangle3->GetPointIds()->SetId(1, 2);
    triangle3->GetPointIds()->SetId(2, 4);

    vtkNew<vtkTriangle> triangle4;
    triangle4->GetPointIds()->SetId(0, 2);
    triangle4->GetPointIds()->SetId(1, 0);
    triangle4->GetPointIds()->SetId(2, 4);

    unstructuredGrid->InsertNextCell(triangle1->GetCellType(), triangle1->GetPointIds());
    unstructuredGrid->InsertNextCell(triangle2->GetCellType(), triangle2->GetPointIds());
    unstructuredGrid->InsertNextCell(triangle3->GetCellType(), triangle3->GetPointIds());
    unstructuredGrid->InsertNextCell(triangle4->GetCellType(), triangle4->GetPointIds());

    // 3. 创建应力数据 (节点标量数据)
    vtkNew<vtkDoubleArray> stressData;
    stressData->SetNumberOfComponents(1);
    stressData->SetName("Stress");

    // 为每个节点添加应力值
    stressData->InsertNextValue(10.0); // 节点0
    stressData->InsertNextValue(20.0); // 节点1
    stressData->InsertNextValue(15.0); // 节点2
    stressData->InsertNextValue(25.0); // 节点3
    stressData->InsertNextValue(50.0); // 中心节点4 (高应力区域)

    unstructuredGrid->GetPointData()->SetScalars(stressData);

    // 4. 创建映射器
    mapper = vtkDataSetMapper::New();
    mapper->SetInputData(unstructuredGrid);

    // 设置颜色映射范围
    double range[2];
    stressData->GetRange(range);
    mapper->SetScalarRange(range);

    // 5. 创建演员
    actor = vtkActor::New();
    actor->SetMapper(mapper);

    // 6. 创建标量条
    scalarBar = vtkScalarBarActor::New();
    scalarBar->SetLookupTable(mapper->GetLookupTable());
    scalarBar->SetTitle("Stress (MPa)\n");
    scalarBar->SetNumberOfLabels(5);
    scalarBar->SetMaximumWidthInPixels(80);
    scalarBar->SetMaximumHeightInPixels(200);

    // 7. 添加到渲染器
    renderer->AddActor(actor);
    renderer->AddActor2D(scalarBar);
}

// 在主窗口类中添加:
void MainWindow::createToolBar()
{
    QToolBar* toolBar = addToolBar("Controls");

    QAction* zoomInAction = new QAction("Zoom In", this);
    QAction* zoomOutAction = new QAction("Zoom Out", this);
    //QAction* colorMapAction = new QAction("Color Map", this);

    toolBar->addAction(zoomInAction);
    toolBar->addAction(zoomOutAction);
    //toolBar->addAction(colorMapAction);

    connect(zoomInAction, &QAction::triggered, [this]() {
        vtkCamera* camera = vtkWidget->renderWindow()->GetRenderers()->GetFirstRenderer()->GetActiveCamera();
        camera->Zoom(1.2);
        vtkWidget->renderWindow()->Render();
    });

    connect(zoomOutAction, &QAction::triggered, [this]() {
        vtkCamera* camera = vtkWidget->renderWindow()->GetRenderers()->GetFirstRenderer()->GetActiveCamera();
        camera->Zoom(0.8);
        vtkWidget->renderWindow()->Render();
    });

    /*
    connect(colorMapAction, &QAction::triggered, [this]() {
        setupColorMap(2);
        vtkWidget->renderWindow()->Render();
    });
    */
}

void MainWindow::setupColorMap(int scheme)
{
    if (!mapper) return;

    vtkNew<vtkLookupTable> lut;

    switch (scheme) {
    case 0: // 蓝到红
        lut->SetHueRange(0.667, 0.0);
        break;
    case 1: // 彩虹色
        lut->SetHueRange(0.0, 0.667);
        break;
    case 2: // 灰度
        lut->SetHueRange(0.0, 0.0);
        lut->SetSaturationRange(0.0, 0.0);
        lut->SetValueRange(0.2, 1.0);
        break;
    case 3: // 热力图
        lut->SetHueRange(0.0, 0.2);
        break;
    }

    lut->SetSaturationRange(1.0, 1.0);
    lut->SetValueRange(1.0, 1.0);
    lut->Build();

    mapper->SetLookupTable(lut);
    scalarBar->SetLookupTable(lut);
    renderWindow->Render();
}

main.cpp

#include "mainwindow.h"

#include <QApplication>
#include <QSurfaceFormat>

int main(int argc, char *argv[])
{
    // 设置 OpenGL 表面格式
    QSurfaceFormat::setDefaultFormat(QVTKOpenGLNativeWidget::defaultFormat());

    QApplication a(argc, argv);
    MainWindow w;
    w.show();
    return a.exec();
}

.pro

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
    main.cpp \
    mainwindow.cpp

HEADERS += \
    mainwindow.h

FORMS += \
    mainwindow.ui


# Unix/Linux 配置
unix {
    # 假设 VTK 安装在 /usr 目录下
    VTK_DIR = /usr/lib/cmake/vtk-9.2
    INCLUDEPATH += $$system(/usr/lib/vtk-9.2/include/vtk-9.2)
    LIBS += -L$$system(/usr/lib/vtk-9.2/lib)
    LIBS += -lGL
}

# Windows 配置
win32 {
    INCLUDEPATH += $$PWD/'../../../../Program Files/VTK/include/vtk-9.2'
    DEPENDPATH += $$PWD/'../../../../Program Files/VTK/include/vtk-9.2'
    LIBS += -lopengl32
}

win32:CONFIG(release, debug|release):{
LIBS += -L$$PWD/'../../../../Program Files/VTK/lib/'
}
else:win32:CONFIG(debug, debug|release): {
LIBS += -L$$PWD/'../../../../Program Files/VTK/lib/'
}
else:unix:{
LIBS += -L$$PWD/'../../../../Program Files/VTK/lib/'
LIBS += -lGL
}

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target


# 必需的核心 VTK 库
LIBS += -lvtksys-9.2
LIBS += -lvtkCommonColor-9.2
LIBS += -lvtkCommonCore-9.2
LIBS += -lvtkCommonDataModel-9.2
LIBS += -lvtkFiltersCore-9.2
LIBS += -lvtkInteractionStyle-9.2
LIBS += -lvtkRenderingCore-9.2
LIBS += -lvtkRenderingOpenGL2-9.2
LIBS += -lvtkViewsQt-9.2
LIBS += -lvtkGUISupportQt-9.2
LIBS += -lvtkRenderingAnnotation-9.2

# 可选: 用于数据处理和可视化的附加库
LIBS += -lvtkFiltersSources-9.2
LIBS += -lvtkFiltersGeneral-9.2
LIBS += -lvtkIOCore-9.2
LIBS += -lvtkIOXML-9.2

运行结果:

五、常见问题解决

1. OpenGL上下文问题

如果遇到OpenGL相关错误,确保正确设置了OpenGL格式:

QSurfaceFormat::setDefaultFormat(QVTKOpenGLNativeWidget::defaultFormat());

2. 窗口大小变化问题

当QT窗口大小变化时,可能需要手动更新VTK渲染窗口:

void resizeEvent(QResizeEvent* event) override {
    QVTKOpenGLNativeWidget::resizeEvent(event);
    vtkWidget->renderWindow()->Render();
}

3. 交互问题

确保启用了交互器:

vtkNew<vtkRenderWindowInteractor> interactor;
interactor->SetRenderWindow(vtkWidget->renderWindow());

4. 内存泄漏

  • VTK使用引用计数,通常不需要手动删除对象

  • 对于VTK与QT混合的对象,确保正确管理所有权

5. 渲染问题 

  • 如果出现黑屏,检查渲染器是否添加到渲染窗口

  • 确保调用了ResetCamera()或设置了合适的相机位置

6.高DPI显示支持

启用QT的高DPI缩放

QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

六、高级用法

1. 多视图布局

// 创建多个QVTKOpenGLNativeWidget
QVTKOpenGLNativeWidget* vtkWidget1 = new QVTKOpenGLNativeWidget;
QVTKOpenGLNativeWidget* vtkWidget2 = new QVTKOpenGLNativeWidget;

// 创建不同的渲染器和场景
// ...

// 添加到布局
QHBoxLayout* layout = new QHBoxLayout;
layout->addWidget(vtkWidget1);
layout->addWidget(vtkWidget2);

QWidget* centralWidget = new QWidget;
centralWidget->setLayout(layout);
mainWindow.setCentralWidget(centralWidget);

2. 信号与槽连接

// 连接VTK事件到QT槽
QObject::connect(vtkWidget, &QVTKOpenGLNativeWidget::mouseEvent, 
    [](QMouseEvent* event) {
        // 处理鼠标事件
    });
// 连接VTK交互事件到QT槽
class MyInteractorStyle : public vtkInteractorStyleTrackballCamera {
public:
    static MyInteractorStyle* New();
    vtkTypeMacro(MyInteractorStyle, vtkInteractorStyleTrackballCamera);
    
    void OnLeftButtonDown() override {
        // VTK交互代码
        emit clicked();
    }
    
Q_SIGNALS:
    void clicked();
};

// 在QT中连接
MyInteractorStyle* style = MyInteractorStyle::New();
widget->interactor()->SetInteractorStyle(style);
QObject::connect(style, &MyInteractorStyle::clicked, [](){
    qDebug() << "VTK view clicked";
});

 

七、注意事项

  1. 确保VTK和QT版本兼容

  2. 在Windows上可能需要设置平台插件路径

  3. 对于复杂场景,考虑使用vtkGenericOpenGLRenderWindow

  4. 调试时注意OpenGL版本和显卡驱动兼容性


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

byxdaz

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值