VTK|箱体切割器
文章目录
- 效果
- 实现类头文件
- 实现类源文件
- 如何调用
- 项目git链接
效果
实现类头文件
/*** @file BoxClipperController.h* @brief 该头文件定义了 BoxClipperController 类,用于管理基于盒子的网格数据裁剪操作。* @details 该类提供了使用 vtkBoxWidget 对网格数据进行裁剪的功能,允许用户通过交互方式调整裁剪盒子的位置和大小,* 并实时更新裁剪结果。* @author qtree* @date 2025年5月16日*/
#ifndef BOXCLIPPERCONTROLLER_H
#define BOXCLIPPERCONTROLLER_H#include <vtkSmartPointer.h>
#include <vtkCallbackCommand.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkObjectBase.h>class vtkRenderWindowInteractor;
class vtkBoxWidget;
class vtkPlanes;
class vtkClipPolyData;
class vtkPolyData;
class vtkActor;
class vtkRenderer;/*** @class BoxClipperController* @brief 用于管理基于盒子的网格数据裁剪操作的控制器类。** 该类提供了使用 vtkBoxWidget 对网格数据进行裁剪的功能,允许用户通过交互方式调整裁剪盒子的位置和大小,* 并实时更新裁剪结果。*/
class BoxClipperController
{
public:/*** @brief 构造函数。** 初始化 BoxClipperController 实例,并关联渲染窗口交互器和渲染器。** @param interactor 用于处理用户交互的渲染窗口交互器。* @param renderer 用于渲染裁剪结果的渲染器。*/BoxClipperController(vtkRenderWindowInteractor *interactor, vtkRenderer *renderer);/*** @brief 设置输入数据并替换原始的 Actor。** 该方法设置用于裁剪的输入网格数据,并将原始的 Actor 替换为裁剪后的 Actor。** @param input 用于裁剪的输入网格数据。* @param originalActor 原始的 Actor,将被裁剪后的 Actor 替换。*/void SetInputDataAndReplaceOriginal(vtkSmartPointer<vtkPolyData> input, vtkActor *originalActor);/*** @brief 启用或禁用裁剪功能。** 该方法控制 vtkBoxWidget 的显示和交互状态,从而启用或禁用裁剪功能。** @param enabled 若为 true,则启用裁剪功能;若为 false,则禁用裁剪功能。*/void SetEnabled(bool enabled);/*** @brief 获取裁剪后的 Actor。** 返回经过裁剪操作后生成的 Actor。** @return 裁剪后的 Actor 的智能指针。*/vtkSmartPointer<vtkActor> GetClippedActor();private:vtkSmartPointer<vtkBoxWidget> boxWidget; ///< 用于用户交互的盒子小部件,用于定义裁剪区域vtkSmartPointer<vtkPlanes> clipPlanes; ///< 由盒子小部件定义的裁剪平面vtkSmartPointer<vtkClipPolyData> clipper; ///< 用于执行裁剪操作的 VTK 过滤器vtkSmartPointer<vtkActor> clippedActor; ///< 裁剪后的网格数据对应的 ActorvtkSmartPointer<vtkPolyData> inputData; ///< 用于裁剪的输入网格数据vtkSmartPointer<vtkRenderer> renderer; ///< 用于渲染裁剪结果的渲染器vtkSmartPointer<vtkRenderWindowInteractor> interactor; ///< 用于处理用户交互的渲染窗口交互器vtkActor *originalActor; ///< 原始的 Actor,将被裁剪后的 Actor 替换/*** @brief 更新裁剪结果。** 当盒子小部件的位置或大小发生变化时,该方法会重新执行裁剪操作并更新裁剪后的 Actor。*/void UpdateClipping();
};#endif // BOXCLIPPERCONTROLLER_H
实现类源文件
#include "BoxClipperController.h"#include <vtkBoxWidget.h>
#include <vtkPlanes.h>
#include <vtkPolyData.h>
#include <vtkClipPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkCommand.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>BoxClipperController::BoxClipperController(vtkRenderWindowInteractor *interactor, vtkRenderer *renderer): interactor(interactor), renderer(renderer)
{originalActor = nullptr;// 裁剪用平面集(由 BoxWidget 生成)clipPlanes = vtkSmartPointer<vtkPlanes>::New();// 裁剪器:使用 box widget 的平面集进行裁剪clipper = vtkSmartPointer<vtkClipPolyData>::New();// 映射器连接裁剪器的输出vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();mapper->SetInputConnection(clipper->GetOutputPort());// 显示裁剪后模型的 actorclippedActor = vtkSmartPointer<vtkActor>::New();clippedActor->SetMapper(mapper);// 初始化 box widget 控件boxWidget = vtkSmartPointer<vtkBoxWidget>::New();boxWidget->SetInteractor(interactor); // 控制器绑定boxWidget->SetPlaceFactor(1.0); // 控制缩放比例boxWidget->HandlesOn(); // 显示操作手柄// 添加裁剪更新事件监听器vtkSmartPointer<vtkCallbackCommand> callback = vtkSmartPointer<vtkCallbackCommand>::New();callback->SetClientData(this); // 把当前类传入回调中callback->SetCallback([](vtkObject *caller, unsigned long, void *clientData, void *callData){auto self = static_cast<BoxClipperController *>(clientData);self->UpdateClipping(); // 当 box widget 改变时更新裁剪});boxWidget->AddObserver(vtkCommand::InteractionEvent, callback); // 绑定观察者
}
// 设置原始输入数据与原始 actor(不拥有生命周期)
void BoxClipperController::SetInputDataAndReplaceOriginal(vtkSmartPointer<vtkPolyData> input, vtkActor *original)
{originalActor = original; // 不用智能指针,不控制生命周期inputData = input;clipper->SetInputData(inputData);boxWidget->SetInputData(inputData);boxWidget->PlaceWidget();UpdateClipping(); // 更新 planes 和裁剪结果
}void BoxClipperController::SetEnabled(bool enabled)
{boxWidget->SetEnabled(enabled ? 1 : 0); // 开启或关闭 box 控件if (enabled){if (originalActor && renderer->HasViewProp(originalActor)){renderer->RemoveActor(originalActor); // 移除原始 actor}renderer->AddActor(clippedActor); // 启用裁剪后显示 actor}else{renderer->RemoveActor(clippedActor);if (originalActor){renderer->AddActor(originalActor);}}renderer->GetRenderWindow()->Render();
}void BoxClipperController::UpdateClipping()
{vtkSmartPointer<vtkPlanes> planes = vtkSmartPointer<vtkPlanes>::New();boxWidget->GetPlanes(planes); // 获取当前 box widget 对应的平面clipper->SetClipFunction(planes); // 使用这些平面裁剪clipper->InsideOutOn(); // 保留 box 内部数据clipper->Update(); // 更新裁剪结果
}vtkSmartPointer<vtkActor> BoxClipperController::GetClippedActor()
{return clippedActor;
}
如何调用
头文件声明
// 箱形剪控制器
std::unique_ptr<BoxClipperController> boxClipper_;
bool boxClipper_enabled_;
构造函数里初始化
切割需要把原来的模型隐藏才能看出切割后的,所以把原始数据和原模型都传递到类中控制显隐
boxClipper_ = std::make_unique<BoxClipperController>(interactor_, renderer_);
boxClipper_enabled_ = false;
boxClipper_->SetInputDataAndReplaceOriginal(cylinderSource->GetOutput(), testActor);
控制箱体切割器显隐按钮槽函数
connect(cross_section, &QPushButton::clicked, this, [=](){ boxClipper_enabled_ = !boxClipper_enabled_;boxClipper_->SetEnabled(boxClipper_enabled_); });
更新数据之后调用
boxClipper_->SetInputDataAndReplaceOriginal(vertexGlyphFilter->GetOutput(),ply_point_actor_);
boxClipper_enabled_ = false;
boxClipper_->SetEnabled(boxClipper_enabled_);
项目git链接
gitee:https://gitee.com/strange-tree-qian/vtktest
github:https://github.com/qishuqian666/project-vtk-test