700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > 【VTK】VTK框选表面拾取面片——仅选中前表面

【VTK】VTK框选表面拾取面片——仅选中前表面

时间:2022-12-08 11:58:31

相关推荐

【VTK】VTK框选表面拾取面片——仅选中前表面

VTK框选表面拾取面片——仅选中前表面

接上一篇 VTK框选表面拾取三角面片——通过观察者命令模式

上一篇最后遗留一个问题,框选表面后,会把模型背面的面片也一起选中。所以这篇内容是解决该问题的。

效果预览

功能说明

通过鼠标框选模型表面的面片,然后利用红色边框显示被框选的三角面片,实现仅选中前表面部分的面片,不会把背面的面片也选中

方法介绍

利用vtkInteractorStyleRubberBandPick交互方式实现框选。(通过R键切换交互模式和框选模式)

利用vtkAreaPicker收集框选的信息。VTK还提供了vtkCellPicker,但是CellPicker只能选中某个对象,不能框选一个集合。

使用vtkCellLocator中的IntersectWithLine函数,用光线投射法寻找靠近摄像头一侧的面片cell,然后利用vtkPolyDataConnectivityFilter找出与最近面片cell相连的表面,该表面即要显示的前表面。

源代码中已经写好详细注释。

源代码

完整代码可以直接编译运行

#include <vtkPolyData.h>#include <vtkPolyDataMapper.h>#include <vtkActor.h>#include <vtkRenderer.h>#include <vtkRenderWindow.h>#include <vtkRenderWindowInteractor.h>#include <vtkInteractorStyleRubberBandPick.h>#include <vtkAreaPicker.h>#include <vtkCommand.h>#include <vtkCallbackCommand.h>#include <vtkIdFilter.h>#include <vtkExtractPolyDataGeometry.h>#include <vtkSphereSource.h>#include <vtkPlanes.h>#include <vtkDataSetMapper.h>#include <vtkProperty.h>#include <vtkCellLocator.h>#include <vtkCamera.h>#include <vtkPolyDataConnectivityFilter.h>/** 定义命令:* 使用vtkInteractorStyleRubberBandPick交互方式时,会自动触发vtkAreaPicker* 交互时框选的信息会存储在vtkAreaPicker中* 将vtkAreaPicker的结束拾取事件绑定vtkPickerCallback* 类似QT中信号与槽的机制* vtkAreaPicker触发结束拾取信号,然后执行vtkPickerCallback中的Execute函数*/class vtkPickerCallback : public vtkCommand{public://@brief 定义New函数(固定格式)static vtkPickerCallback* New() {return new vtkPickerCallback;}//@brief 定义Execute函数(vtkCommand中的Execute为纯虚函数,必须要实现)virtual void Execute(vtkObject* caller, unsigned long, void*);void SetPolyData(vtkPolyData* input);void SetRenderer(vtkRenderer* input);private:vtkPolyData* polyData;//需要处理的几何数据vtkRenderer* renderer;//需要调用的渲染器vtkDataSetMapper* mapper;//用于显示框选面片的mappervtkActor* actor;//用于显示框选面片的actor};int main(){//****************创建球体*****************vtkSphereSource* sphere = vtkSphereSource::New();sphere->SetThetaResolution(18);sphere->SetPhiResolution(18);sphere->SetRadius(10);sphere->SetCenter(0, 0, 0);sphere->Update();//****************创建Mapper***************vtkPolyDataMapper* mapper = vtkPolyDataMapper::New();mapper->SetInputConnection(sphere->GetOutputPort());//换成此语句效果一致:mapper->SetInputData(sphere->GetOutput());//****************创建Actor****************vtkActor* actor = vtkActor::New();actor->SetMapper(mapper);//****************创建渲染器***************vtkRenderer* renderer = vtkRenderer::New();renderer->AddActor(actor);//****************创建渲染窗口*************vtkRenderWindow* renderWindow = vtkRenderWindow::New();renderWindow->AddRenderer(renderer);//****************创建交互器***************vtkRenderWindowInteractor* renderWindowInteractor = vtkRenderWindowInteractor::New();//****************创建交互方式*************vtkInteractorStyleRubberBandPick* interactorStyle = vtkInteractorStyleRubberBandPick::New();//****************创建拾取回调函数*********vtkPickerCallback* callback = vtkPickerCallback::New();callback->SetPolyData(sphere->GetOutput());callback->SetRenderer(renderer);//****************创建区域拾取器***********vtkAreaPicker* areaPicker = vtkAreaPicker::New();areaPicker->AddObserver(vtkCommand::EndPickEvent, callback);//为“结束拾取”事件绑定“拾取回调函数”renderWindowInteractor->SetRenderWindow(renderWindow);//为交互器设置渲染窗口renderWindowInteractor->SetInteractorStyle(interactorStyle);//为交互器设置交互方式renderWindowInteractor->SetPicker(areaPicker);//为交互器设置拾取器renderWindowInteractor->Start();return 0;}void vtkPickerCallback::Execute(vtkObject* caller, unsigned long, void*){//通过反射获取调用者vtkAreaPicker* areaPicker = static_cast<vtkAreaPicker*>(caller);//获取框选的视锥体(由六个面组成)vtkPlanes* frustum = areaPicker->GetFrustum();//提前标记几何数据的CellId(目前没有,用于后面实现删除面片的)vtkIdFilter* idFilter = vtkIdFilter::New();idFilter->SetInputData(polyData);idFilter->SetCellIdsArrayName("OriginalCellId");idFilter->Update();//提取视锥体内的模型vtkExtractPolyDataGeometry* extract = vtkExtractPolyDataGeometry::New();extract->SetInputConnection(idFilter->GetOutputPort());extract->SetImplicitFunction(frustum);extract->Update();if (!extract->GetOutput()->GetPolys()){return;}//创建面片定位器vtkCellLocator* locator = vtkCellLocator::New();locator->SetDataSet(extract->GetOutput());locator->BuildLocator();//----------利用光线投射的方法寻找更靠近摄像机的面片------------double rayStart[3];//光线起点坐标:设置为摄像机位置double rayDirection[3];//光线方向向量:设置为框选数据包围盒的中心renderer->GetActiveCamera()->GetPosition(rayStart);extract->GetOutput()->GetCenter(rayDirection);double xyz[3];double t;double pcoords[3];int subId;vtkIdType cellId = -1;//记录光线击中的面片Id号locator->IntersectWithLine(rayStart, rayDirection, 0.0001, t, xyz, pcoords, subId, cellId);//-----------利用找到的面片获取相连的面vtkPolyDataConnectivityFilter* connectivity = vtkPolyDataConnectivityFilter::New();connectivity->SetInputConnection(extract->GetOutputPort());connectivity->SetExtractionModeToCellSeededRegions();connectivity->InitializeSeedList();connectivity->AddSeed(cellId);connectivity->Update();//设置actormapper->SetInputConnection(connectivity->GetOutputPort());mapper->ScalarVisibilityOff();actor->GetProperty()->SetColor(1, 0, 0);actor->GetProperty()->SetPointSize(5);actor->GetProperty()->SetRepresentationToWireframe();//渲染器加入显示框选的actorrenderer->AddActor(actor);}void vtkPickerCallback::SetPolyData(vtkPolyData* input){polyData = input;}void vtkPickerCallback::SetRenderer(vtkRenderer* input){renderer = input;//初始化用于显示框选面片的mapper和actormapper = vtkDataSetMapper::New();actor = vtkActor::New();actor->SetMapper(mapper);}

存在问题

源代码为了说明算法,所以算法的是实现以精简为目标,因此没有去释放内存。

而且算法会存在小Bug(框选无面片的时候和边缘的时候可能会报警告),通过调整rayStart和rayDirection两个向量来改善。

需要用到该算法的话,别忘了自行Debug完善代码

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。