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>
class vtkPickerCallback : public vtkCommand
{
public:
static vtkPickerCallback* New() {return new vtkPickerCallback;}
virtual void Execute(vtkObject* caller, unsigned long, void*);
void SetPolyData(vtkPolyData* input);
void SetRenderer(vtkRenderer* input);
private:
vtkPolyData* polyData;
vtkRenderer* renderer;
vtkDataSetMapper* mapper;
vtkActor* actor;
};
int main()
{
vtkSphereSource* sphere = vtkSphereSource::New();
sphere->SetThetaResolution(18);
sphere->SetPhiResolution(18);
sphere->SetRadius(10);
sphere->SetCenter(0, 0, 0);
sphere->Update();
vtkPolyDataMapper* mapper = vtkPolyDataMapper::New();
mapper->SetInputConnection(sphere->GetOutputPort());
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();
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;
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();
mapper->SetInputConnection(connectivity->GetOutputPort());
mapper->ScalarVisibilityOff();
actor->GetProperty()->SetColor(1, 0, 0);
actor->GetProperty()->SetPointSize(5);
actor->GetProperty()->SetRepresentationToWireframe();
renderer->AddActor(actor);
}
void vtkPickerCallback::SetPolyData(vtkPolyData* input)
{
polyData = input;
}
void vtkPickerCallback::SetRenderer(vtkRenderer* input)
{
renderer = input;
mapper = vtkDataSetMapper::New();
actor = vtkActor::New();
actor->SetMapper(mapper);
}
存在问题
源代码为了说明算法,所以算法的是实现以精简为目标,因此没有去释放内存。
而且算法会存在小Bug(框选无面片的时候和边缘的时候可能会报警告),通过调整rayStart和rayDirection两个向量来改善。
需要用到该算法的话,别忘了自行Debug完善代码。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)