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

QT6 QML vtk学习之(1)点云在QML窗口中显示

QT6 QML vtk学习之(1)点云在QML窗口中显示

系统环境是ubantu22.04 QT6.6.3 opengl(这个使用apt安装dev版本就行)
需要编译一个VTK9.4(最新的就行)

QTcreator构建工程,新建一个QML工程
然后对cmakelists.txt做如下修改

cmake_minimum_required(VERSION 3.16)

project(vtk_qml_test VERSION 0.1 LANGUAGES CXX)

set(CMAKE_CXX_STANDARD_REQUIRED ON)

find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core Quick)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Quick)
find_package(Qt6 REQUIRED COMPONENTS LinguistTools)

find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core)
find_package(Qt6 6.2 COMPONENTS Core Quick QuickControls2 Gui
    Widgets Charts Concurrent Sql SerialBus Network
    Core5Compat
    REQUIRED
)
find_package(VTK
  COMPONENTS
    CommonCore
    FiltersSources
    GUISupportQtQuick)
qt_standard_project_setup(REQUIRES 6.5)

qt_add_executable(appvtk_qml_test
    main.cpp
)

qt_add_qml_module(appvtk_qml_test
    URI vtk_qml_test
    VERSION 1.0
    QML_FILES
        Main.qml
        SOURCES PFG3DVTKItem.h PFG3DVTKItem.cpp
)

# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
# If you are developing for iOS or macOS you should consider setting an
# explicit, fixed bundle identifier manually though.
set_target_properties(appvtk_qml_test PROPERTIES
#    MACOSX_BUNDLE_GUI_IDENTIFIER com.example.appvtk_qml_test
    MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
    MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
    MACOSX_BUNDLE TRUE
    WIN32_EXECUTABLE TRUE
)

target_link_libraries(appvtk_qml_test
    PUBLIC
        Qt${QT_VERSION_MAJOR}::Core
        Qt${QT_VERSION_MAJOR}::Quick
        Qt6::QuickControls2
        Qt6::Quick
        Qt6::Gui
        Qt6::Widgets
        Qt6::Charts
        Qt6::Concurrent
        Qt6::Core5Compat
        ${VTK_LIBRARIES}
)

vtk_module_autoinit(
    TARGETS ${PROJECT_NAME}
    MODULES ${VTK_LIBRARIES}
)

include(GNUInstallDirs)
install(TARGETS appvtk_qml_test
    BUNDLE DESTINATION .
    LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
    RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
)

然后是新建一个VTKItem类
需要注意的是,新建的类文件头字母必须为大写,不然会报错,然而QT新建文件默认是全小写

代码如下

#ifndef VTKITEM_H
#define VTKITEM_H

#include <QMetaObject>
#include <QOpenGLContext>
#include <QOpenGLFunctions>
#include <QQuickVTKItem.h>
#include <QRandomGenerator>
#include <QVTKRenderWindowAdapter.h>
#include <vtkRenderWindow.h>
#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkOpenGLRenderWindow.h>
#include <vtkOpenGLState.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSmartPointer.h>
#include <vtkVertexGlyphFilter.h>
#include <vtkPointData.h>
#include <QVTKInteractor.h>


class VTKItem : public QQuickVTKItem
{
    Q_OBJECT
public:
    VTKItem(QQuickItem* parent = nullptr);

    ~VTKItem();

    vtkUserData initializeVTK(vtkRenderWindow* renderWindow) override;
    void destroyingVTK(vtkRenderWindow *renderWindow, vtkUserData userData) override;
    // Q_INVOKABLE void close(){
    //     m_cylinder->close();
    //     m_cylinder=nullptr;
    // }
    // Q_INVOKABLE void start(){
    //     if (m_renderWin && !m_cylinder) {
    //         m_cylinder = new RandomCylinderGenerator(m_renderWin);
    //         m_cylinder->generateRandomCylinderPoints();
    //     }
    // }
    // vtkRenderWindow* render(){
    //     return m_renderWin;
    // }

    void updatePoints(vtkSmartPointer<vtkPoints> points,
                      vtkSmartPointer<vtkUnsignedCharArray> colors);
    void clearPointCloud();

    Q_INVOKABLE void resetCamera(int view);

    void SetView(vtkSmartPointer<vtkRenderer> renderer, const int& view);

    // 缩放操作
    Q_INVOKABLE void zoom(qreal scaleFactor) {
        auto camera = m_renderer->GetActiveCamera();
        camera->Zoom(scaleFactor);  // 调整摄像机缩放
        m_renderWin->Render();     // 刷新渲染窗口
    }

    // 新增的缩放方法
    Q_INVOKABLE void zoom_in() {
        zoom(1.1);  // 放大
    }

    Q_INVOKABLE void zoom_out() {
        zoom(0.9);  // 缩小
    }
private:
    void Init();

public slots:

private:
    vtkRenderWindow* m_renderWin;

    vtkSmartPointer<vtkRenderer> m_renderer;
    vtkSmartPointer<vtkPolyData> polyData;
    // vtkSmartPointer<vtkUnsignedCharArray> colors;

    bool m_flag=false;

    // QQuickVTKItem interface

};
#endif

#include "VTKItem.h"

VTKItem::VTKItem(QQuickItem *parent)
    : QQuickVTKItem(parent)
// , m_cylinder(nullptr)
{}

VTKItem::~VTKItem()
{
    // if (m_cylinder) {
    //     delete m_cylinder;
    //     m_cylinder = nullptr;
    // }
}

QQuickVTKItem::vtkUserData VTKItem::initializeVTK(vtkRenderWindow *renderWindow)
{
    // qDebug()<<"initialize VTK";
    m_renderWin = renderWindow;
    Init();
    return nullptr;
}

void VTKItem::destroyingVTK(vtkRenderWindow *renderWindow, vtkUserData userData) {}

// void PFG3DVTKItem::Update()
// {
//     if (m_cylinder!=nullptr)
//     {
//         // qDebug()<<"toUpdate";
//         m_cylinder->generatePoints();
//     }
// }

void VTKItem::SetView(vtkSmartPointer<vtkRenderer> renderer, const int& view) {
    vtkSmartPointer<vtkCamera> camera = renderer->GetActiveCamera();

    if (view == 0) {
        camera->SetPosition(0, 0, 1); // 从前面查看
        camera->SetFocalPoint(0, 0, 0);
    } else if (view == 1) {
        camera->SetPosition(0, 0, -1); // 从后面查看
        camera->SetFocalPoint(0, 0, 0);
    } else if (view == 2) {
        camera->SetPosition(-1, 0, 0); // 从左边查看
        camera->SetFocalPoint(0, 0, 0);
    } else if (view == 3) {
        camera->SetPosition(1, 0, 0); // 从右边查看
        camera->SetFocalPoint(0, 0, 0);
    } else if (view == 4) {
        camera->SetPosition(0, -1, 0); // 从上面查看
        camera->SetFocalPoint(0, 0, 0);
    } else if (view == 5) {
        camera->SetPosition(0, 1, 0); // 从下面查看
        camera->SetFocalPoint(0, 0, 0);
    } else {
        std::cerr << "Unknown view: " << view << std::endl;
        return;
    }

    camera->SetViewUp(0, 1, 0); // 设置视图的上方向,视角的上下方向
    renderer->ResetCamera(); // 重新设置相机
}
void VTKItem::resetCamera(int view)
{
    SetView(m_renderer, view);
}
void VTKItem::updatePoints(vtkSmartPointer<vtkPoints> points,
                                vtkSmartPointer<vtkUnsignedCharArray> colors)
{
    if(polyData==nullptr||m_renderWin==nullptr)
        return;

    polyData->SetPoints(points);
    polyData->GetPointData()->SetScalars(colors);
    polyData->Modified();

    //TODO  need reset button
    if (!m_flag) {
        // Reset the camera to view the entire point cloud
        m_renderer->ResetCamera();
        m_flag = true;
    }


    // Ensure the render window updates the renderer before resetting the camera
    // m_renderer->GetRenderWindow()->Render();
    m_renderWin->Render();
}

void VTKItem::clearPointCloud() {
    if (!polyData) {
        return;
    }
    auto points=vtkSmartPointer<vtkPoints>::New();
    auto colors=vtkSmartPointer<vtkUnsignedCharArray>::New();
    colors->SetNumberOfComponents(3);
    colors->SetName("Colors");
    colors->Reset();
    points->Reset();

    points->InsertNextPoint(0,0,0);
    colors->InsertNextTuple3(255,255,255);

    // Clear the points and reset the polyData
    polyData->SetPoints(points);
    polyData->GetPointData()->SetScalars(colors);
    polyData->Modified();  // Mark the polyData as modified

    // Clear the renderer
    m_renderWin->Render();  // Request a render update
}

void VTKItem::Init()
{
    // // 保存相机状态
    // vtkSmartPointer<vtkCamera> camera = this->renderer->GetActiveCamera();
    // double position[3];
    // double focalPoint[3];
    // double viewUp[3];
    // camera->GetPosition(position);
    // camera->GetFocalPoint(focalPoint);
    // camera->GetViewUp(viewUp);

    // this->renderer->RemoveAllViewProps();
    // this->renderWindow->RemoveRenderer(this->renderer);
    // this->renderer=nullptr;

    auto renderer = vtkSmartPointer<vtkRenderer>::New();
    renderer->SetBackground(0, 0, 0);
    m_renderer = renderer;
    // 清除以前的演员
    // this->renderer->RemoveAllViewProps();

    // Create initial point cloud
    auto pointCloud = vtkSmartPointer<vtkPoints>::New();

    double diameter = 100;
    int height = 200;

    diameter = diameter + (QRandomGenerator64::global()->bounded(11) - 5); // Radius of the cylinder

    const int numCircles = 100;         // Number of circles along the height
    const int numPointsPerCircle = 100; // Number of points per circle
    const double radius = diameter / 2.0;
    const double angleStep = 2.0 * vtkMath::Pi() / numPointsPerCircle;
    const double heightStep = height / numCircles;

    auto colors = vtkSmartPointer<vtkUnsignedCharArray>::New();
    colors->SetNumberOfComponents(3);
    colors->SetName("Colors");

    for (int i = 0; i < numCircles; ++i) {
        double z = i * heightStep;
        for (int j = 0; j < numPointsPerCircle; ++j) {
            double angle = j * angleStep;
            double x = radius * cos(angle);
            double y = radius * sin(angle);
            pointCloud->InsertNextPoint(x, y, z);
            colors->InsertNextTuple3(192, 192, 192);
        }
    }

    // 创建PolyData对象
    polyData = vtkSmartPointer<vtkPolyData>::New();
    polyData->SetPoints(pointCloud);
    polyData->GetPointData()->SetScalars(colors);

    // 创建顶点过滤器
    vtkSmartPointer<vtkVertexGlyphFilter> glyphFilter = vtkSmartPointer<vtkVertexGlyphFilter>::New();
    glyphFilter->SetInputData(polyData);
    glyphFilter->Update();

    // 创建映射器
    vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
    mapper->SetColorModeToDefault();
    mapper->SetScalarVisibility(1);
    mapper->SetInputConnection(glyphFilter->GetOutputPort());

    // 创建演员
    auto actor = vtkSmartPointer<vtkActor>::New();
    actor->SetMapper(mapper);
    actor->GetProperty()->SetPointSize(3); // 设置点的大小

    // 随机设置演员位置
    // actor->SetPosition(static_cast<double>(rand()) / RAND_MAX * 20.0 - 10.0,
    //                    static_cast<double>(rand()) / RAND_MAX * 20.0 - 10.0,
    //                    static_cast<double>(rand()) / RAND_MAX * 20.0 - 10.0);
    actor->SetPosition(0, 100, 0);

    // 将演员添加到渲染器
    renderer->AddActor(actor);

    m_renderWin->AddRenderer(renderer);
    m_renderWin->Render();

    // qDebug()<<"Init 3DItem";
}

然后是main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "VTKItem.h"
int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);


    qmlRegisterType<VTKItem>("TESTQml", 1, 0, "VTKItem");

    QQmlApplicationEngine engine;
    QObject::connect(
        &engine,
        &QQmlApplicationEngine::objectCreationFailed,
        &app,
        []() { QCoreApplication::exit(-1); },
        Qt::QueuedConnection);
    engine.loadFromModule("vtk_qml_test", "Main");

    return app.exec();
}

然后是Main.qml

import QtQuick
import TESTQml
Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("Hello World")

    VTKItem {
        id: testVTKItem
        anchors.fill: parent
        opacity: 0.7

    }
}

代码里包含了一些缩放和角度设置,界面代码暂时没用到,后面代码会更新
运行结果
在这里插入图片描述

VTK编译可以参考

https://blog.csdn.net/caz28/article/details/131466946

opengl安装可以参考

sudo apt-get install build-essential libxmu-dev libxi-dev libgl-dev

http://www.kler.cn/a/396012.html

相关文章:

  • LeetCode Hot 100 题解[java版本,冲大厂]
  • python程序对服务器cpu和内存资源占用的管理。
  • uniapp ios app以framwork形式接入sentry
  • QT_CONFIG宏使用
  • 项目技术栈-解决方案-web3去中心化
  • git入门环境搭建
  • 深入理解UML用例图:概念、构成与应用实例
  • java瑞吉外卖
  • AI入驻电商江湖:智能算法如何打响“带货”大战?
  • 微信小程序02-页面制作
  • 【freertos】FreeRTOS中如何保护共享资源
  • Qt文件目录操作
  • 告别Print,使用IceCream进行高效的Python调试
  • 利用栈实现中缀表达式的简单计算
  • pytorch中的transform用法
  • 21.<基于Spring图书管理系统②(图书列表+删除图书+更改图书)(非强制登录版本完结)>
  • Kafka入门:Java客户端库的使用
  • C语言.冒泡排序的练习
  • 在word文档中,内容是一段英文,一段英文的显示,且段落的前后都有空行,我如何只去掉英文段落后面的空行。
  • 25浙江省考-28天学行测-Day5 Day6-判断推理(中)
  • reduce-scatter:适合分布式计算;Reduce、LayerNorm和Broadcast算子的执行顺序对计算结果的影响,以及它们对资源消耗的影响
  • R门 - rust第一课陈天 -内存知识学习笔记
  • Apache Doris:监控与运维及系统调优
  • 【RabbitMQ】07-业务幂等处理
  • Tomcat NIO 配置实操指南
  • JVM——类加载器、类加载器的分类