VTK: 拾取方式的三種實現

      拾取操作是可視化應用程序中常見的一種功能。拾取主要是用於選擇數據和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);



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章