diff --git a/Libs/MRML/DisplayableManager/vtkMRMLModelDisplayableManager.cxx b/Libs/MRML/DisplayableManager/vtkMRMLModelDisplayableManager.cxx index f1f41ca49b226b7e90e7f3a2e526b64c13dffa9f..637337e58612ebbfc1220dc15d6748d03af40fc3 100644 --- a/Libs/MRML/DisplayableManager/vtkMRMLModelDisplayableManager.cxx +++ b/Libs/MRML/DisplayableManager/vtkMRMLModelDisplayableManager.cxx @@ -63,6 +63,7 @@ #include #include #include +#include #include #include #include @@ -95,6 +96,12 @@ public: /// Reset all the pick vars void ResetPick(); + /// Find picked node from mesh and set PickedNodeID in Internal + void FindPickedDisplayNodeFromMesh(vtkPointSet* mesh, double pickedPoint[3]); + /// Find picked point index in mesh and picked cell (PickedCellID) and set PickedPointID in Internal + void FindPickedPointOnMeshAndCell(vtkPointSet* mesh, double pickedPoint[3]); + /// Find first picked node from prop3Ds in cell picker and set PickedNodeID in Internal + void FindFirstPickedDisplayNodeFromPickerProp3Ds(); std::map DisplayedActors; std::map DisplayedNodes; @@ -121,8 +128,8 @@ public: int ClippingMethod; bool ClippingOn; - bool ModelHierarchiesPresent; - bool UpdateHierachyRequested; + bool ModelHierarchiesPresent; + bool UpdateHierachyRequested; vtkSmartPointer WorldPointPicker; vtkSmartPointer PropPicker; @@ -137,7 +144,7 @@ public: // Used for caching the node pointer so that we do not have to search in the scene each time. // We do not add an observer therefore we can let the selection node deleted without our knowledge. - vtkWeakPointer SelectionNode; + vtkWeakPointer SelectionNode; }; //--------------------------------------------------------------------------- @@ -200,6 +207,95 @@ void vtkMRMLModelDisplayableManager::vtkInternal::ResetPick() this->PickedPointID = -1; } +//--------------------------------------------------------------------------- +void vtkMRMLModelDisplayableManager::vtkInternal::FindPickedDisplayNodeFromMesh(vtkPointSet* mesh, double pickedPoint[3]) +{ + if (!mesh) + { + return; + } + + std::map::iterator modelIt; + for (modelIt = this->DisplayedNodes.begin(); modelIt != this->DisplayedNodes.end(); modelIt++) + { + if (modelIt->second != 0) + { + if (vtkMRMLModelDisplayNode::SafeDownCast(modelIt->second) && + vtkMRMLModelDisplayNode::SafeDownCast(modelIt->second)->GetOutputMesh() == mesh) + { + this->PickedDisplayNodeID = modelIt->first; + return; // Display node found + } + } + } +} + +//--------------------------------------------------------------------------- +void vtkMRMLModelDisplayableManager::vtkInternal::FindPickedPointOnMeshAndCell(vtkPointSet* mesh, double pickedPoint[3]) +{ + if (!mesh || this->PickedCellID < 0) + { + return; + } + + // Figure out the closest vertex in the picked cell to the picked RAS + // point. Only doing this on model nodes for now. + vtkCell *cell = mesh->GetCell(this->PickedCellID); + if (!cell) + { + return; + } + + int numPoints = cell->GetNumberOfPoints(); + int closestPointId = -1; + double closestDistance = 0.0l; + for (int p = 0; p < numPoints; p++) + { + int pointId = cell->GetPointId(p); + double *pointCoords = mesh->GetPoint(pointId); + if (pointCoords != 0) + { + double distance = sqrt( pow(pointCoords[0]-pickedPoint[0], 2) + + pow(pointCoords[1]-pickedPoint[1], 2) + + pow(pointCoords[2]-pickedPoint[2], 2) ); + if (p == 0 || distance < closestDistance) + { + closestDistance = distance; + closestPointId = pointId; + } + } + } + this->PickedPointID = closestPointId; +} + +//--------------------------------------------------------------------------- +void vtkMRMLModelDisplayableManager::vtkInternal::FindFirstPickedDisplayNodeFromPickerProp3Ds() +{ + if (!this->CellPicker) + { + return; + } + + vtkProp3DCollection* props = this->CellPicker->GetProp3Ds(); + for (int propIndex=0; propIndexGetNumberOfItems(); ++propIndex) + { + vtkProp3D* pickedProp = vtkProp3D::SafeDownCast(props->GetItemAsObject(propIndex)); + if (!pickedProp) + { + continue; + } + std::map::iterator propIt; + for (propIt = this->DisplayedActors.begin(); propIt != this->DisplayedActors.end(); propIt++) + { + if (pickedProp == propIt->second) + { + this->PickedDisplayNodeID = propIt->first; + return; // Display node found + } + } + } +} + //--------------------------------------------------------------------------- // vtkMRMLModelDisplayableManager methods @@ -1854,7 +1950,7 @@ int vtkMRMLModelDisplayableManager::Pick(int x, int y) // get the pointer to the mesh that the cell was in vtkPointSet *mesh = vtkPointSet::SafeDownCast(this->Internal->CellPicker->GetDataSet()); // now find the model this mesh belongs to - this->FindPickedDisplayNodeFromMesh(mesh, pickPoint); + this->Internal->FindPickedDisplayNodeFromMesh(mesh, pickPoint); } else { @@ -1892,75 +1988,29 @@ int vtkMRMLModelDisplayableManager::Pick3D(double ras[3]) if (this->Internal->CellPicker->Pick3DPoint(ras, ren)) { this->SetPickedCellID(this->Internal->CellPicker->GetCellId()); - // Get the pointer to the mesh that the cell was in - vtkPointSet *mesh = vtkPointSet::SafeDownCast(this->Internal->CellPicker->GetDataSet()); - // Find the model this mesh belongs to - this->FindPickedDisplayNodeFromMesh(mesh, ras); + + // Find first picked model from picker + // Note: Getting the mesh using GetDataSet is not a good solution as the dataset is the first + // one that is picked and it may be of different type (volume, segmentation, etc.) + this->Internal->FindFirstPickedDisplayNodeFromPickerProp3Ds(); + // Find picked point in mesh + vtkMRMLModelDisplayNode* displayNode = vtkMRMLModelDisplayNode::SafeDownCast( + this->GetMRMLScene()->GetNodeByID(this->Internal->PickedDisplayNodeID.c_str()) ); + if (displayNode) + { + this->Internal->FindPickedPointOnMeshAndCell(displayNode->GetOutputMesh(), ras); + } + + this->SetPickedRAS(ras); } #else vtkErrorMacro("Pick3D: This function is only accessible in newer VTK version"); + (void)ras; // not used #endif - this->SetPickedRAS(ras); - return 1; } -//--------------------------------------------------------------------------- -void vtkMRMLModelDisplayableManager::FindPickedDisplayNodeFromMesh(vtkPointSet* mesh, double pickedPoint[3]) -{ - if (!mesh) - { - return; - } - - std::map::iterator modelIter; - for ( modelIter = this->Internal->DisplayedNodes.begin(); - modelIter != this->Internal->DisplayedNodes.end(); - modelIter++ ) - { - vtkDebugMacro("FindPickedDisplayNodeFromMesh: Checking model " << modelIter->first.c_str() << "'s mesh"); - if (modelIter->second != 0) - { - if (vtkMRMLModelDisplayNode::SafeDownCast(modelIter->second) && - vtkMRMLModelDisplayNode::SafeDownCast(modelIter->second)->GetOutputMesh() == mesh) - { - vtkDebugMacro("FindPickedDisplayNodeFromMesh: Found matching mesh, pick was on model " << modelIter->first.c_str()); - this->Internal->PickedDisplayNodeID = modelIter->first; - - // Figure out the closest vertex in the picked cell to the picked RAS - // point. Only doing this on model nodes for now. - vtkCell *cell = mesh->GetCell(this->GetPickedCellID()); - if (cell != 0) - { - int numPoints = cell->GetNumberOfPoints(); - int closestPointId = -1; - double closestDistance = 0.0l; - for (int p = 0; p < numPoints; p++) - { - int pointId = cell->GetPointId(p); - double *pointCoords = mesh->GetPoint(pointId); - if (pointCoords != 0) - { - double distance = sqrt( pow(pointCoords[0]-pickedPoint[0], 2) + - pow(pointCoords[1]-pickedPoint[1], 2) + - pow(pointCoords[2]-pickedPoint[2], 2) ); - if (p == 0 || distance < closestDistance) - { - closestDistance = distance; - closestPointId = pointId; - } - } - } - vtkDebugMacro("FindPickedDisplayNodeFromMesh: found closest point id = " << closestPointId << ", distance = " << closestDistance); - this->SetPickedPointID(closestPointId); - } - continue; - } - } - } -} - //--------------------------------------------------------------------------- const char * vtkMRMLModelDisplayableManager::GetPickedNodeID() { diff --git a/Libs/MRML/DisplayableManager/vtkMRMLModelDisplayableManager.h b/Libs/MRML/DisplayableManager/vtkMRMLModelDisplayableManager.h index 5784d7a38671e96167efea87bd23857ab85eeeaa..081f6c7259b90a727ace10f5113adb6df639f17b 100644 --- a/Libs/MRML/DisplayableManager/vtkMRMLModelDisplayableManager.h +++ b/Libs/MRML/DisplayableManager/vtkMRMLModelDisplayableManager.h @@ -149,8 +149,10 @@ public: static vtkLookupTable* CreateLookupTableCopy(vtkLookupTable* source); /// Helper function for determining what type of scalar is active. - static bool IsCellScalarsActive(vtkMRMLDisplayNode* displayNode, - vtkMRMLModelNode* model = 0); + /// \return True if attribute location in display node is vtkAssignAttribute::CELL_DATA + /// or active cell scalar name in the model node is vtkDataSetAttributes::SCALARS. + /// False otherwise. + static bool IsCellScalarsActive(vtkMRMLDisplayNode* displayNode, vtkMRMLModelNode* model = 0); protected: @@ -217,9 +219,6 @@ protected: vtkMRMLSelectionNode* GetSelectionNode(); - /// Find picked node and cell from mesh and set PickedNodeID and PickedPointID in Internal - void FindPickedDisplayNodeFromMesh(vtkPointSet* mesh, double pickedPoint[3]); - private: vtkMRMLModelDisplayableManager(const vtkMRMLModelDisplayableManager&); // Not implemented diff --git a/Modules/Loadable/Segmentations/MRMLDM/vtkMRMLSegmentationsDisplayableManager3D.cxx b/Modules/Loadable/Segmentations/MRMLDM/vtkMRMLSegmentationsDisplayableManager3D.cxx index d25908879e7c40727462fc556ec1040e2739364f..fc3e6921ee6f82c7d5d5b8675877893745092619 100644 --- a/Modules/Loadable/Segmentations/MRMLDM/vtkMRMLSegmentationsDisplayableManager3D.cxx +++ b/Modules/Loadable/Segmentations/MRMLDM/vtkMRMLSegmentationsDisplayableManager3D.cxx @@ -38,6 +38,7 @@ #include #include #include +#include #include #include #include @@ -114,7 +115,10 @@ public: bool UseDisplayableNode(vtkMRMLSegmentationNode* node); void ClearDisplayableNodes(); + /// Find picked node from mesh and set PickedNodeID in Internal void FindPickedDisplayNodeFromMesh(vtkPointSet* mesh); + /// Find first picked node from prop3Ds in cell picker and set PickedNodeID in Internal + void FindFirstPickedDisplayNodeFromPickerProp3Ds(); public: /// Picker of segment prop in renderer @@ -651,11 +655,45 @@ void vtkMRMLSegmentationsDisplayableManager3D::vtkInternal::FindPickedDisplayNod { if (pipelineIt->second->ModelWarper->GetOutput() == mesh) { - vtkDebugWithObjectMacro(currentDisplayNode, "FindPickedDisplayNodeFromMesh: Found matching mesh, pick was on segment " - << pipelineIt->first.c_str() << " of segmentation " - << (currentDisplayNode->GetDisplayableNode() ? currentDisplayNode->GetDisplayableNode()->GetName() : "NULL")); this->PickedDisplayNodeID = currentDisplayNode->GetID(); this->PickedSegmentID = pipelineIt->first; + return; // Display node and segment found + } + } + } +} + +//--------------------------------------------------------------------------- +void vtkMRMLSegmentationsDisplayableManager3D::vtkInternal::FindFirstPickedDisplayNodeFromPickerProp3Ds() +{ + this->PickedDisplayNodeID = ""; + this->PickedSegmentID = ""; + if (!this->CellPicker) + { + return; + } + + vtkProp3DCollection* props = this->CellPicker->GetProp3Ds(); + for (int propIndex=0; propIndexGetNumberOfItems(); ++propIndex) + { + vtkProp3D* pickedProp = vtkProp3D::SafeDownCast(props->GetItemAsObject(propIndex)); + if (!pickedProp) + { + continue; + } + + PipelinesCacheType::iterator pipelinesIt; + for (pipelinesIt = this->DisplayPipelines.begin(); pipelinesIt!=this->DisplayPipelines.end(); ++pipelinesIt) + { + vtkMRMLSegmentationDisplayNode* currentDisplayNode = pipelinesIt->first; + for (PipelineMapType::iterator pipelineIt=pipelinesIt->second.begin(); pipelineIt!=pipelinesIt->second.end(); ++pipelineIt) + { + if (pipelineIt->second->Actor.GetPointer() == pickedProp) + { + this->PickedDisplayNodeID = currentDisplayNode->GetID(); + this->PickedSegmentID = pipelineIt->first; + return; // Display node and segment found + } } } } @@ -854,9 +892,10 @@ int vtkMRMLSegmentationsDisplayableManager3D::Pick3D(double ras[3]) #if VTK_MAJOR_VERSION >= 9 || (VTK_MAJOR_VERSION >= 8 && VTK_MINOR_VERSION >= 2) if (this->Internal->CellPicker->Pick3DPoint(ras, ren)) { - vtkPointSet* mesh = vtkPointSet::SafeDownCast(this->Internal->CellPicker->GetDataSet()); - // Find the segmentation and segment this mesh belongs to - this->Internal->FindPickedDisplayNodeFromMesh(mesh); + // Find first picked segmentation and segment from picker + // Note: Getting the mesh using GetDataSet is not a good solution as the dataset is the first + // one that is picked and it may be of different type (volume, model, etc.) + this->Internal->FindFirstPickedDisplayNodeFromPickerProp3Ds(); } #else vtkErrorMacro("Pick3D: This function is only accessible in newer VTK version");