VTK|结合qt创建通用按钮控制显隐(边框、坐标轴、点线面)

news2025/5/11 15:52:11

文章目录

  • 增加边框BoundingBox
    • 添加addBoundingBox
    • 添加BoundingBox控制按钮
    • 点击按钮之后的槽函数
  • 添加坐标轴
  • 增加点线面显隐控制按钮
    • 添加控制点线面显隐的按钮到三维显示界面
    • 控制面显示槽函数
    • 控制线显示槽函数
    • 控制点显示槽函数

增加边框BoundingBox

增加边框BoundingBox并通过按钮控制显隐
需要的全局变量

    // 显示场景
    QVTKOpenGLWidget *m_pScene;
    vtkSmartPointer<vtkGenericOpenGLRenderWindow> renderWindow_;
    vtkSmartPointer<vtkRenderer> renderer_;
    // 边框显示
    vtkSmartPointer<vtkActor> boundingBoxActor_; // 用于存储BoundingBox的Actor
    bool isBoundingBoxVisible_;                  // 控制BoundingBox的显隐状态
    vtkSmartPointer<vtkTextActor> boundingBoxButtonActor_; 

添加addBoundingBox

void ThreeDimensionalDisplayPage::addBoundingBox(vtkSmartPointer<vtkPolyData> polyData)
{
    if (boundingBoxActor_)
    {
        renderer_->RemoveActor(boundingBoxActor_);
        boundingBoxActor_ = nullptr;
    }

    vtkNew<vtkOutlineFilter> outlineFilter;
    outlineFilter->SetInputData(polyData);
    outlineFilter->Update();

    vtkNew<vtkPolyDataMapper> outlineMapper;
    outlineMapper->SetInputConnection(outlineFilter->GetOutputPort());

    boundingBoxActor_ = vtkSmartPointer<vtkActor>::New();
    boundingBoxActor_->SetMapper(outlineMapper);
    boundingBoxActor_->GetProperty()->SetColor(1.0, 0.0, 0.0);
    boundingBoxActor_->GetProperty()->SetLineWidth(2.0);
    boundingBoxActor_->SetVisibility(isBoundingBoxVisible_); // 根据状态决定是否显示

    renderer_->AddActor(boundingBoxActor_);
}

添加BoundingBox控制按钮

void ThreeDimensionalDisplayPage::addBoundingBoxControlButton()
{
    // 避免重复添加
    if (boundingBoxButtonActor_ && renderer_->HasViewProp(boundingBoxButtonActor_))
        return;

    vtkNew<vtkTextActor> textActor;
    textActor->SetInput("Hide Bounding Box");

    vtkTextProperty *textProp = textActor->GetTextProperty();
    textProp->SetFontSize(24);
    textProp->SetColor(0.0, 0.0, 0.0);           // 黑色文字
    textProp->SetBackgroundColor(0.8, 0.8, 0.8); // 灰色背景
    textProp->SetBackgroundOpacity(1.0);
    textProp->SetFrame(1);
    textProp->SetFrameColor(0.0, 0.0, 0.0);

    textActor->SetDisplayPosition(10, 10);
    renderer_->AddActor2D(textActor);
    boundingBoxButtonActor_ = textActor;

    // 注册鼠标点击事件(只注册一次)
    static bool observerAdded = false;
    if (!observerAdded)
    {
        vtkNew<vtkCallbackCommand> clickCallback;
        clickCallback->SetClientData(this);
        clickCallback->SetCallback([](vtkObject *caller, unsigned long, void *clientData, void *)
                                   {
            auto *self = static_cast<ThreeDimensionalDisplayPage *>(clientData);
            int *clickPos = static_cast<vtkRenderWindowInteractor *>(caller)->GetEventPosition();

            int x = clickPos[0];
            int y = clickPos[1];

            // 判断是否点击在按钮上(近似判断)
            int *pos = self->boundingBoxButtonActor_->GetPositionCoordinate()->GetComputedDisplayValue(self->renderer_);
            int btnX = pos[0];
            int btnY = pos[1];
            int width = 220, height = 40;

            if (x >= btnX && x <= btnX + width &&
                y >= btnY && y <= btnY + height)
            {
                self->OnBoundingBoxButtonClicked();
            } });
        interactor_->AddObserver(vtkCommand::LeftButtonPressEvent, clickCallback);
        observerAdded = true;
    }

    isBoundingBoxVisible_ = true;
}

点击按钮之后的槽函数


void ThreeDimensionalDisplayPage::OnBoundingBoxButtonClicked()
{
    if (!boundingBoxActor_)
        return;

    isBoundingBoxVisible_ = !isBoundingBoxVisible_;
    boundingBoxActor_->SetVisibility(isBoundingBoxVisible_);

    if (boundingBoxButtonActor_)
    {
        boundingBoxButtonActor_->SetInput(isBoundingBoxVisible_ ? "Hide Bounding Box" : "Show Bounding Box");
    }

    renderWindow_->Render();
}

添加坐标轴

需要的全局变量,防止重复创建

    // 坐标轴显示
    vtkSmartPointer<vtkAxesActor> axes_;
    vtkSmartPointer<vtkOrientationMarkerWidget> marker_;

创建坐标轴

void ThreeDimensionalDisplayPage::addCoordinateAxes()
{
    if (!axes_)
        axes_ = vtkSmartPointer<vtkAxesActor>::New();
    axes_->SetTotalLength(10.0, 10.0, 10.0);

    if (!marker_)
        marker_ = vtkSmartPointer<vtkOrientationMarkerWidget>::New();

    marker_->SetOrientationMarker(axes_);
    marker_->SetOutlineColor(0.9300, 0.5700, 0.1300);
    marker_->SetInteractor(m_pScene->GetInteractor());
    marker_->SetDefaultRenderer(renderer_);
    marker_->SetViewport(0.8, 0.0, 1.0, 0.2);
    marker_->SetEnabled(1);
    marker_->InteractiveOn();
}

增加点线面显隐控制按钮

需要的全局变量,防止重复创建

    // 添加控制点线面显隐的按钮到三维显示界面
    void addObjVisibilityControlButtons();
    // 控制面显示槽函数
    void toggleSurfaceVisibility();
    // 控制线显示槽函数
    void toggleWireframeVisibility();
    // 控制点显示槽函数
    void togglePointsVisibility();
    // 控制obj点线面的显隐
    vtkSmartPointer<vtkActor> surfaceActor_;
    vtkSmartPointer<vtkActor> wireframeActor_;
    vtkSmartPointer<vtkActor> pointsActor_;
    // 控制obj点线面显隐的按钮
    vtkSmartPointer<vtkTextActor> surfaceToggleButton_;
    vtkSmartPointer<vtkTextActor> wireframeToggleButton_;
    vtkSmartPointer<vtkTextActor> pointsToggleButton_;

添加控制点线面显隐的按钮到三维显示界面

void ThreeDimensionalDisplayPage::addObjVisibilityControlButtons()
{
    // 如果已经创建过按钮,则直接重新添加到 renderer_
    if (surfaceToggleButton_)
    {
        surfaceToggleButton_->SetInput("Hide Surface");
        wireframeToggleButton_->SetInput("Hide Wireframe");
        pointsToggleButton_->SetInput("Hide Points");
        renderer_->AddActor2D(surfaceToggleButton_);
        renderer_->AddActor2D(wireframeToggleButton_);
        renderer_->AddActor2D(pointsToggleButton_);
        return;
    }

    // 按钮文字及初始状态
    std::vector<std::pair<std::string, vtkSmartPointer<vtkTextActor> *>> buttons = {
        {"Hide Surface", &surfaceToggleButton_},
        {"Hide Wireframe", &wireframeToggleButton_},
        {"Hide Points", &pointsToggleButton_}};

    int startY = 60; // 初始 Y 位置
    for (auto &[text, actorPtr] : buttons)
    {
        auto textActor = vtkSmartPointer<vtkTextActor>::New();
        textActor->SetInput(text.c_str());
        auto *textProp = textActor->GetTextProperty();
        textProp->SetFontSize(20);
        textProp->SetColor(0.0, 0.0, 0.0);
        textProp->SetBackgroundColor(0.9, 0.9, 0.9);
        textProp->SetBackgroundOpacity(1.0);
        textProp->SetFrame(1);
        textProp->SetFrameColor(0.0, 0.0, 0.0);
        textActor->SetDisplayPosition(10, startY);
        renderer_->AddActor2D(textActor);
        *actorPtr = textActor;
        startY += 50; // 下一个按钮向下偏移
    }

    // 注册鼠标事件(只注册一次)
    static bool observerAdded = false;
    if (!observerAdded)
    {
        vtkNew<vtkCallbackCommand> clickCallback;
        clickCallback->SetClientData(this);
        clickCallback->SetCallback([](vtkObject *caller, unsigned long, void *clientData, void *)
                                   {
            auto* self = static_cast<ThreeDimensionalDisplayPage*>(clientData);
            int* clickPos = static_cast<vtkRenderWindowInteractor*>(caller)->GetEventPosition();
            int x = clickPos[0];
            int y = clickPos[1];

            std::vector<std::pair<vtkSmartPointer<vtkTextActor>, std::function<void()>>> buttons = {
                {self->surfaceToggleButton_, [&]() { self->toggleSurfaceVisibility(); }},
                {self->wireframeToggleButton_, [&]() { self->toggleWireframeVisibility(); }},
                {self->pointsToggleButton_, [&]() { self->togglePointsVisibility(); }}
            };

            for (auto& [actor, func] : buttons)
            {
                int* pos = actor->GetPositionCoordinate()->GetComputedDisplayValue(self->renderer_);
                int bx = pos[0];
                int by = pos[1];
                int width = 200, height = 40;

                if (x >= bx && x <= bx + width &&
                    y >= by && y <= by + height)
                {
                    func();
                    break;
                }
            } });

        interactor_->AddObserver(vtkCommand::LeftButtonPressEvent, clickCallback);
        observerAdded = true;
    }
}

控制面显示槽函数


void ThreeDimensionalDisplayPage::toggleSurfaceVisibility()
{
    if (surfaceActor_)
    {
        bool visible = surfaceActor_->GetVisibility();
        surfaceActor_->SetVisibility(!visible);
        if (surfaceToggleButton_)
            surfaceToggleButton_->SetInput(visible ? "Show Surface" : "Hide Surface");
        renderWindow_->Render();
    }
}

控制线显示槽函数

void ThreeDimensionalDisplayPage::toggleWireframeVisibility()
{
    if (wireframeActor_)
    {
        bool visible = wireframeActor_->GetVisibility();
        wireframeActor_->SetVisibility(!visible);
        if (wireframeToggleButton_)
            wireframeToggleButton_->SetInput(visible ? "Show Wireframe" : "Hide Wireframe");
        renderWindow_->Render();
    }
}

控制点显示槽函数


void ThreeDimensionalDisplayPage::togglePointsVisibility()
{
    if (pointsActor_)
    {
        bool visible = pointsActor_->GetVisibility();
        pointsActor_->SetVisibility(!visible);
        if (pointsToggleButton_)
            pointsToggleButton_->SetInput(visible ? "Show Points" : "Hide Points");
        renderWindow_->Render();
    }
}

也可以使用qpushbutton进行控制,逻辑更加简单,不需要场景里添加按钮了,创建按钮后直接连接toggleSurfaceVisibility即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2373236.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

CentOS 7.9 安装详解:手动分区完全指南

CentOS 7.9 安装详解&#xff1a;手动分区完全指南 为什么需要手动分区&#xff1f;CentOS 7.9 基本分区说明1. /boot/efi 分区2. /boot 分区3. swap 交换分区4. / (根) 分区 可选分区&#xff08;进阶设置&#xff09;5. /home 分区6. /var 分区7. /tmp 分区 分区方案建议标准…

如何使用测试软件 Jmeter

第一步&#xff0c;点击 编辑 添加线程组 第二步&#xff0c;右键单击线程组&#xff0c;添加取样器 HTTP 请求 第三步&#xff0c;设置请求路径 第四步&#xff0c;添加 查看结果树 用于查看请求响应 最后点击绿色小三角启动即可

2025盘古石初赛WP

来不及做&#xff0c;还有n道题待填坑 文章目录 手机取证 Mobile Forensics分析安卓手机检材&#xff0c;手机的IMSI是&#xff1f; [答案格式&#xff1a;660336842291717]养鱼诈骗投资1000&#xff0c;五天后收益是&#xff1f; [答案格式&#xff1a;123]分析苹果手机检材&a…

系统分析与设计期末复习

第一章 系统的五个特性 整体性、目的性、相关性、环境适应性、层次性 软件系统的四个特性 复杂性、一致性、可变性、不可见性 第二章 系统规划 系统开发生命周期 系统规划->系统分析->系统设计->系统实施->系统运行维护->系统规划 诺兰阶段模型 阶段&a…

IBM BAW(原BPM升级版)使用教程第八讲

续前篇&#xff01; 一、流程开发功能模块使用逻辑和顺序 前面我们已经对 流程、用户界面、公开的自动化服务、服务、事件、团队、数据、性能、文件各个模块进行了详细讲解&#xff0c;现在统一进行全面统一讲解。 在 IBM Business Automation Workflow (BAW) 中&#xff0c;…

从电动化到智能化,法雷奥“猛攻”中国汽车市场

当前&#xff0c;全球汽车产业正在经历前所未有的变革&#xff0c;外资Tier1巨头开始向中国智能电动汽车市场发起新一轮“猛攻”。 在4月23日-5月2日上海国际车展期间&#xff0c;博世、采埃孚、大陆集团、法雷奥等全球百强零部件厂商纷纷发布战略新品与转型计划。在这其中&am…

鸿蒙开发——3.ArkTS声明式开发:构建第一个ArkTS应用

鸿蒙开发——3.ArkTS声明式开发:构建第一个ArkTS应用 一、创建ArkTS工程二、ArkTS工程目录结构&#xff08;Stage模型&#xff09;三、构建第一个页面四、构建第二个页面五、实现页面之间的跳转六、模拟器运行 一、创建ArkTS工程 1、若首次打开DevEco Studio&#xff0c;请点击…

word换行符和段落标记

换行符&#xff1a;只换行不分段 作用&#xff1a;我们需要对它进行分段&#xff0c;但它是一个信息群组&#xff0c;我希望它们有同样的段落格式&#xff01; 快捷键&#xff1a;shiftenter 段落标记&#xff1a;分段 快捷键&#xff1a;enter 修改字体格式或段落格式 …

AI时代的数据可视化:未来已来

你有没有想过&#xff0c;数据可视化在未来会变成什么样&#xff1f;随着人工智能&#xff08;AI&#xff09;的飞速发展&#xff0c;数据可视化已经不再是简单的图表和图形&#xff0c;而是一个充满无限可能的智能领域。AI时代的可视化不仅能自动解读数据&#xff0c;还能预测…

深入理解 TCP:重传机制、滑动窗口、流量控制与拥塞控制

TCP&#xff08;Transmission Control Protocol&#xff09;是一个面向连接、可靠传输的协议&#xff0c;支撑着绝大多数互联网通信。在实现可靠性的背后&#xff0c;TCP 引入了多个关键机制&#xff1a;重传机制、滑动窗口、流量控制 和 拥塞控制。这些机制共同协作&#xff0…

uniapp-商城-51-后台 商家信息(logo处理)

前面对页面基本进行了梳理和说明&#xff0c;特别是对验证规则进行了阐述&#xff0c;并对自定义规则的兼容性进行了特别补充&#xff0c;应该说是干货满满。不知道有没有小伙伴已经消化了。 下面我们继续前进&#xff0c;说说页面上的logo上传组件&#xff0c;主要就是uni-fil…

springboot 加载 tomcat 源码追踪

加载 TomcatServletWebServerFactory 从 SpringApplication.run(&#xff09;方法进入 进入到 refresh () 方法 选择实现类 ServletWebServerApplicationContext 进入到 AbstractApplicationContext onRefresh() 方法创建容器 找到加载bean 得到 webServer 实例 点击 get…

使用countDownLatch导致的线程安全问题,线程不安全的List-ArrayList,线程安全的List-CopyOnWriteArrayList

示例代码 package com.example.demo.service;import java.util.ArrayList; import java.util.List; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors;public class UnSafeCDTest {Executor…

C++ - 仿 RabbitMQ 实现消息队列(1)(环境搭建)

C - 仿 RabbitMQ 实现消息队列&#xff08;1&#xff09;&#xff08;环境搭建&#xff09; 什么是消息队列核心特点核心组件工作原理常见消息队列实现应用场景优缺点 项目配置开发环境技术选型 更换软件源安装一些工具安装epel 软件源安装 lrzsz 传输工具安装git安装 cmake安装…

RK3568-OpenHarmony(1) : OpenHarmony 5.1的编译

概述: 本文主要描述了&#xff0c;如何在ubuntu-20.04操作系统上&#xff0c;编译RK3568平台的OpenHarmony 5.1版本。 搭建编译环境 a. 安装软件包 sudo apt-get install git-lfs ruby genext2fs build-essential git curl libncurses5-dev libncursesw5-dev openjdk-11-jd…

eFish-SBC-RK3576工控板外部RTC测试操作指南

备注&#xff1a; 1&#xff09;测试时一定要接电池&#xff0c;否则外部RTC断电后无法工作导致测试失败&#xff1b; 2&#xff09;如果连接了网络&#xff0c;系统会自动同步NTP时钟&#xff0c;所以需要关闭自动同步时钟。 关闭自动同步NTP时钟方法&#xff1a; 先查看是…

vue3的深入组件-组件 v-model

组件 v-model 基本用法​ v-model 可以在组件上使用以实现双向绑定。 从 Vue 3.4 开始&#xff0c;推荐的实现方式是使用 defineModel() 宏&#xff1a; <script setup> const model defineModel()function update() {model.value } </script><template>…

【MySQL】数据库、数据表的基本操作

个人主页&#xff1a;Guiat 归属专栏&#xff1a;MySQL 文章目录 1. MySQL基础命令1.1 连接MySQL1.2 基本命令概览 2. 数据库操作2.1 创建数据库2.2 查看数据库2.3 选择数据库2.4 修改数据库2.5 删除数据库2.6 数据库备份与恢复 3. 表操作基础3.1 创建表3.2 查看表信息3.3 创建…

TCP的连接管理

三次握手 什么是三次握手&#xff1f; 1. 第一次握手&#xff08;客户端 → 服务器&#xff09; 客户端发送一个 SYN 报文&#xff0c;请求建立连接。 报文中包含一个初始序列号 SEQ x。 表示&#xff1a;我想和你建立连接&#xff0c;我的序列号是 x。 2. 第二次握手&a…

初识Linux · 传输层协议TCP · 下

目录 前言&#xff1a; 滑动窗口和流量控制机制 流量控制 滑动窗口 1.滑动窗口如何移动 2.滑动窗口的大小如何变化的 3.如果发生了丢包如何解决&#xff08;快重传&#xff09; 拥塞控制 延迟应答 面向字节流 RST PSH URG 什么是 PSH&#xff1f; 什么是 URG&…