您的位置:首页 > 其它

VTK: 拾取方式的三种实现

2017-05-30 16:15 435 查看
      拾取操作是可视化应用程序中常见的一种功能。拾取主要是用于选择数据和Actor或者获取底层的数据值。在显示位置(以像素为坐标值)中拾取时,就会调用vtkAbstractPicker的Pick()方法。依赖于所用的拾取类不同,拾取时返回的信息也不同,最简单的是返回一个x-y-z的全局坐标值,或者是单元(cell)的ID值,点的ID值,单元参数坐标(CellParametric
Coordinates),所拾取的vtkProp实例,以及Assemblypath。与拾取相关的VTK类的 继承图如下:



       本文内容主要介绍一下vtk拾取的实现方式,并不讲解每种拾取器的差别。本文拾取过程以vtkCellPicker为例子讲解。拾取的实现按照vtk交互方式的不同分为两大类:1)重写vtkInteractorStyle完成拾取
 2)重写观察者命令模式完成拾取
      1) 重写vtkInteractorStyle 

class MouseInteractorStyle : public vtkInteractorStyleTrackballCamera
{
public:
static MouseInteractorStyle* New();

MouseInteractorStyle()
{
selectedMapper = vtkSmartPointer<vtkDataSetMapper>::New();
selectedActor = vtkSmartPointer<vtkActor>::New();
}

virtual void OnLeftButtonDown()
{
// Get the location of the click (in window coordinates)
int* pos = this->GetInteractor()->GetEventPosition();

vtkSmartPointer<vtkCellPicker> picker =
vtkSmartPointer<vtkCellPicker>::New();
picker->SetTolerance(0.0005);

// Pick from this location.
picker->Pick(pos[0], pos[1], 0, this->GetDefaultRenderer());

double* worldPosition = picker->GetPickPosition();
std::cout << "Cell id is: " << picker->GetCellId() << std::endl;

if(picker->GetCellId() != -1)
{

std::cout << "Pick position is: " << worldPosition[0] << " " << worldPosition[1]
<< " " << worldPosition[2] << endl;

vtkSmartPointer<vtkIdTypeArray> ids =
vtkSmartPointer<vtkIdTypeArray>::New();
ids->SetNumberOfComponents(1);
ids->InsertNextValue(picker->GetCellId());

vtkSmartPointer<vtkSelectionNode> selectionNode =
vtkSmartPointer<vtkSelectionNode>::New();
selectionNode->SetFieldType(vtkSelectionNode::CELL);
selectionNode->SetContentType(vtkSelectionNode::INDICES);
selectionNode->SetSelectionList(ids);

vtkSmartPointer<vtkSelection> selection =
vtkSmartPointer<vtkSelection>::New();
selection->AddNode(selectionNode);

vtkSmartPointer<vtkExtractSelection> extractSelection =
vtkSmartPointer<vtkExtractSelection>::New();
#if VTK_MAJOR_VERSION <= 5
extractSelection->SetInput(0, this->Data);
extractSelection->SetInput(1, selection);
#else
extractSelection->SetInputData(0, this->Data);
extractSelection->SetInputData(1, selection);
#endif
extractSelection->Update();

// In selection
vtkSmartPointer<vtkUnstructuredGrid> selected =
vtkSmartPointer<vtkUnstructuredGrid>::New();
selected->ShallowCopy(extractSelection->GetOutput());

std::cout << "There are " << selected->GetNumberOfPoints()
<< " points in the selection." << std::endl;
std::cout << "There are " << selected->GetNumberOfCells()
<< " cells in the selection." << std::endl;

#if VTK_MAJOR_VERSION <= 5
selectedMapper->SetInputConnection(
selected->GetProducerPort());
#else
selectedMapper->SetInputData(selected);
#endif

selectedActor->SetMapper(selectedMapper);
selectedActor->GetProperty()->EdgeVisibilityOn();
selectedActor->GetProperty()->SetEdgeColor(1,0,0);
selectedActor->GetProperty()->SetLineWidth(3);

this->Interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer()->AddActor(selectedActor);

}
// Forward events
vtkInteractorStyleTrackballCamera::OnLeftButtonDown();
}

vtkSmartPointer<vtkPolyData> Data;
vtkSmartPointer<vtkDataSetMapper> selectedMapper;
vtkSmartPointer<vtkActor> selectedActor;

};


       2)重写观察者命令模式完成拾取
      根据观察者的不同分为两种实现方法:1)观察者为vtkRenderWindowInteractor
  2)观察者为vtkcellpicker
      1)给vtkRenderWindowInteractor添加回调类,响应的vtk事件是
LeftButtonPressEvent


        拾取方式是鼠标左键点击

     回调类代码如下: 
  

class PickerCallBack : public vtkCommand
{
public:
static PickerCallBack *New()
{
return new PickerCallBack;
}

virtual void Execute(vtkObject *caller, unsigned long eventId, void *callData)
{
//相应拾取结果

if(eventId == vtkCommand::LeftButtonPressEvent){
QVTKInteractor *interactor = QVTKInteractor::SafeDownCast( caller );
vtkRenderer *renderer = interactor->GetRenderWindow()->GetRenderers()->GetFirstRenderer();
int event_pos[3] = {0, 0, 0};
interactor->GetEventPosition(event_pos);
interactor->GetPicker()->Pick(event_pos[0], event_pos[1], 0, renderer);

if(picker->GetCellId() != -1){
double *pos = picker->GetPickPosition();
qDebug() <<"pick coord:" << pos[0] << pos[1] << pos[2];
}
}
}

bool m_enable = false;
};
main函数中 为vtkRenderWindowInteractor添加该回调类:

vtkSmartPointer<PickerCallBack> callBack =
vtkSmartPointer<PickerCallBack>::New();
interactor->AddObserver(vtkCommand::LeftButtonPressEvent,callBack);
 

 
 2)给 vtkCellPicker添加回调类  响应的vtk事件是:

vtkCommand::EndPickEvent
  拾取方式是键盘字母P + 移动鼠标  

 回调类代码如下:

class PickerCallBack : public vtkCommand
{
public:
static PickerCallBack *New()
{
return new PickerCallBack;
}

virtual void Execute(vtkObject *caller, unsigned long eventId, void *callData)
{
if(!m_enable)
return;

if(eventId == vtkCommand::EndPickEvent){
vtkCellPicker *picker = vtkCellPicker::SafeDownCast(caller);
//坐标拾取
if(picker->GetCellId() != -1){
double *pos = picker->GetPickPosition();
qDebug() <<"pick coord:" << pos[0] << pos[1] << pos[2];
}

picker->SetPath(nullptr);
}
}

bool m_enable = false;
};
main函数中 为vtkCellPicker添加该回调类:
vtkSmartPointer<vtkCellPicker> picker =
vtkSmartPointer<vtkCellPicker>::New();
interactor->SetPicker(picker);

vtkSmartPointer<PickerCallBack> callBack =
vtkSmartPointer<PickerCallBack>::New();
interactor->GetPicker->AddObserver(vtkCommand::EndPickEvent,callBack);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  VTK 拾取