24 #include <vtkAppendPolyData.h> 25 #include <vtkCellArray.h> 26 #include <vtkCharArray.h> 27 #include <vtkConeSource.h> 28 #include <vtkCylinderSource.h> 30 #include <vtkPointData.h> 31 #include <vtkPoints.h> 32 #include <vtkPolyDataNormals.h> 33 #include <vtkRenderWindow.h> 34 #include <vtkSphereSource.h> 35 #include <vtkTransformPolyDataFilter.h> 36 #include <vtkTubeFilter.h> 39 #include <itkCommand.h> 46 const char *PROPERTY_KEY_ORIGINAL_OBJECT_OPACITY =
"gizmo.originalObjectOpacity";
55 GizmoRemover() : m_Storage(nullptr), m_GizmoNode(nullptr), m_ManipulatedNode(nullptr), m_StorageObserverTag(0) {}
66 if (m_Storage !=
nullptr)
68 m_Storage->RemoveNodeEvent.RemoveListener(
70 m_Storage->RemoveObserver(m_StorageObserverTag);
74 m_GizmoNode = gizmo_node;
75 m_ManipulatedNode = manipulated_node;
77 if (m_Storage !=
nullptr)
79 m_Storage->RemoveNodeEvent.AddListener(
82 itk::SimpleMemberCommand<GizmoRemover>::Pointer command = itk::SimpleMemberCommand<GizmoRemover>::New();
83 command->SetCallbackFunction(
this, &mitk::GizmoRemover::OnDataStorageDeleted);
84 m_StorageObserverTag = m_Storage->AddObserver(itk::ModifiedEvent(), command);
89 void OnDataStorageDeleted() { m_Storage =
nullptr; }
93 if (node == m_ManipulatedNode)
96 if (m_Storage->Exists(m_GizmoNode))
98 m_Storage->Remove(m_GizmoNode);
110 m_Storage->RemoveNodeEvent.RemoveListener(
112 m_Storage->RemoveObserver(m_StorageObserverTag);
120 unsigned long m_StorageObserverTag;
128 auto gizmoChildren = storage->
GetDerivations(node, typeCondition);
129 return !gizmoChildren->empty();
134 if (node ==
nullptr || storage ==
nullptr)
140 auto gizmoChildren = storage->
GetDerivations(node, typeCondition);
142 for (
auto &gizmoChild : *gizmoChildren)
144 auto *gizmo =
dynamic_cast<Gizmo *
>(gizmoChild->GetData());
147 storage->
Remove(gizmoChild);
148 gizmo->m_GizmoRemover->UpdateStorageObservation(
nullptr,
nullptr,
nullptr);
155 float originalOpacity = 1.0;
156 if (node->
GetFloatProperty(PROPERTY_KEY_ORIGINAL_OBJECT_OPACITY, originalOpacity))
162 return !gizmoChildren->empty();
178 gizmoNode->SetName(
"Gizmo");
179 gizmoNode->SetData(gizmo);
190 interactor->SetGizmoNode(gizmoNode);
191 interactor->SetManipulatedObjectNode(node);
197 float currentNodeOpacity = 1.0;
198 if (node->
GetOpacity(currentNodeOpacity,
nullptr))
200 if (currentNodeOpacity > 0.5f)
202 node->
SetFloatProperty(PROPERTY_KEY_ORIGINAL_OBJECT_OPACITY, currentNodeOpacity);
209 storage->
Add(gizmoNode, node);
210 gizmo->m_GizmoRemover->UpdateStorageObservation(storage, gizmoNode, node);
217 :
Surface(), m_AllowTranslation(true), m_AllowRotation(true), m_AllowScaling(true), m_GizmoRemover(new GizmoRemover())
235 if (m_FollowedGeometry.IsNotNull())
237 m_FollowedGeometry->RemoveObserver(m_FollowerTag);
258 void AssignScalarValueTo(vtkPolyData *polydata,
char value)
260 vtkSmartPointer<vtkCharArray> pointData = vtkSmartPointer<vtkCharArray>::New();
262 int numberOfPoints = polydata->GetNumberOfPoints();
263 pointData->SetNumberOfComponents(1);
264 pointData->SetNumberOfTuples(numberOfPoints);
265 pointData->FillComponent(0, value);
266 polydata->GetPointData()->SetScalars(pointData);
269 vtkSmartPointer<vtkPolyData> BuildAxis(
const mitk::Point3D ¢er,
273 char vertexValueAxis,
274 char vertexValueRing,
275 char vertexValueScale)
282 const double shaftRadius = halflength * 0.02;
283 const double arrowHeight = shaftRadius * 6;
284 const int tubeSides = 15;
287 vtkSmartPointer<vtkAppendPolyData> axisSource = vtkSmartPointer<vtkAppendPolyData>::New();
290 for (
double sign = -1.0; sign < 3.0; sign += 2)
292 vtkSmartPointer<vtkConeSource> cone = vtkConeSource::New();
294 cone->SetCenter(center[0] + sign * axis[0] * (halflength * 1.1 + arrowHeight * 0.5),
295 center[1] + sign * axis[1] * (halflength * 1.1 + arrowHeight * 0.5),
296 center[2] + sign * axis[2] * (halflength * 1.1 + arrowHeight * 0.5));
297 cone->SetDirection(sign * axis[0], sign * axis[1], sign * axis[2]);
298 cone->SetRadius(shaftRadius * 3);
299 cone->SetHeight(arrowHeight);
300 cone->SetResolution(tubeSides);
303 AssignScalarValueTo(cone->GetOutput(), vertexValueScale);
304 axisSource->AddInputData(cone->GetOutput());
308 vtkSmartPointer<vtkPolyData> shaftSkeleton = vtkSmartPointer<vtkPolyData>::New();
309 vtkSmartPointer<vtkPoints> shaftPoints = vtkSmartPointer<vtkPoints>::New();
310 shaftPoints->InsertPoint(0, (center - axis * halflength * 1.1).GetDataPointer());
311 shaftPoints->InsertPoint(1, (center + axis * halflength * 1.1).GetDataPointer());
312 shaftSkeleton->SetPoints(shaftPoints);
314 vtkSmartPointer<vtkCellArray> shaftLines = vtkSmartPointer<vtkCellArray>::New();
315 vtkIdType shaftLinePoints[] = {0, 1};
316 shaftLines->InsertNextCell(2, shaftLinePoints);
317 shaftSkeleton->SetLines(shaftLines);
319 vtkSmartPointer<vtkTubeFilter> shaftSource = vtkSmartPointer<vtkTubeFilter>::New();
320 shaftSource->SetInputData(shaftSkeleton);
321 shaftSource->SetNumberOfSides(tubeSides);
322 shaftSource->SetVaryRadiusToVaryRadiusOff();
323 shaftSource->SetRadius(shaftRadius);
324 shaftSource->Update();
325 AssignScalarValueTo(shaftSource->GetOutput(), vertexValueAxis);
327 axisSource->AddInputData(shaftSource->GetOutput());
328 axisSource->Update();
330 vtkSmartPointer<vtkTubeFilter> ringSource;
334 vtkSmartPointer<vtkPolyData> ringSkeleton = vtkSmartPointer<vtkPolyData>::New();
335 vtkSmartPointer<vtkPoints> ringPoints = vtkSmartPointer<vtkPoints>::New();
336 ringPoints->SetDataTypeToDouble();
337 unsigned int numberOfRingPoints = 100;
338 vtkSmartPointer<vtkCellArray> ringLines = vtkSmartPointer<vtkCellArray>::New();
339 ringLines->InsertNextCell(numberOfRingPoints + 1);
341 for (
unsigned int segment = 0; segment < numberOfRingPoints; ++segment)
344 ringPointer[1] = std::cos((
double)(segment) / (
double)numberOfRingPoints * 2.0 * vtkMath::Pi());
345 ringPointer[2] = std::sin((
double)(segment) / (
double)numberOfRingPoints * 2.0 * vtkMath::Pi());
347 ringPoints->InsertPoint(segment, (ringPointer * halflength).GetDataPointer());
349 ringLines->InsertCellPoint(segment);
351 ringLines->InsertCellPoint(0);
354 vtkSmartPointer<vtkTransform> t = vtkSmartPointer<vtkTransform>::New();
355 t->Translate(center.GetDataPointer());
356 double vMag = vtkMath::Norm(axis.GetDataPointer());
360 t->RotateWXYZ(180.0, (axis[0] - vMag) / 2.0, axis[1] / 2.0, axis[2] / 2.0);
361 t->RotateWXYZ(180.0, 0, 1, 0);
365 t->RotateWXYZ(180.0, (axis[0] + vMag) / 2.0, axis[1] / 2.0, axis[2] / 2.0);
369 for (
unsigned int i = 0; i < numberOfRingPoints; ++i)
371 ringPoints->GetPoint(i, thisPoint);
372 t->TransformPoint(thisPoint, thisPoint);
373 ringPoints->SetPoint(i, thisPoint);
376 ringSkeleton->SetPoints(ringPoints);
377 ringSkeleton->SetLines(ringLines);
379 ringSource = vtkSmartPointer<vtkTubeFilter>::New();
380 ringSource->SetInputData(ringSkeleton);
381 ringSource->SetNumberOfSides(tubeSides);
382 ringSource->SetVaryRadiusToVaryRadiusOff();
383 ringSource->SetRadius(shaftRadius);
384 ringSource->Update();
385 AssignScalarValueTo(ringSource->GetOutput(), vertexValueRing);
389 vtkSmartPointer<vtkAppendPolyData> appenderGlobal = vtkSmartPointer<vtkAppendPolyData>::New();
390 appenderGlobal->AddInputData(axisSource->GetOutput());
393 appenderGlobal->AddInputData(ringSource->GetOutput());
395 appenderGlobal->Update();
398 vtkSmartPointer<vtkPolyDataNormals> normalsSource = vtkSmartPointer<vtkPolyDataNormals>::New();
399 normalsSource->SetInputConnection(appenderGlobal->GetOutputPort());
400 normalsSource->ComputePointNormalsOn();
401 normalsSource->ComputeCellNormalsOff();
402 normalsSource->SplittingOn();
403 normalsSource->Update();
405 vtkSmartPointer<vtkPolyData> result = normalsSource->GetOutput();
413 double longestAxis =
std::max(m_Radius[0], m_Radius[1]);
414 longestAxis =
std::max(longestAxis, m_Radius[2]);
422 vtkSmartPointer<vtkAppendPolyData> appender = vtkSmartPointer<vtkAppendPolyData>::New();
423 appender->AddInputData(BuildAxis(m_Center,
429 m_AllowScaling ?
ScaleX : NoHandle));
430 appender->AddInputData(BuildAxis(m_Center,
436 m_AllowScaling ?
ScaleY : NoHandle));
437 appender->AddInputData(BuildAxis(m_Center,
443 m_AllowScaling ?
ScaleZ : NoHandle));
445 auto sphereSource = vtkSmartPointer<vtkSphereSource>::New();
446 sphereSource->SetCenter(m_Center[0], m_Center[1], m_Center[2]);
447 sphereSource->SetRadius(longestAxis * 0.06);
448 sphereSource->Update();
449 AssignScalarValueTo(sphereSource->GetOutput(),
MoveFreely);
451 appender->AddInputData(sphereSource->GetOutput());
454 return appender->GetOutput();
459 auto observer = itk::SimpleMemberCommand<Gizmo>::New();
462 if (m_FollowedGeometry.IsNotNull())
464 m_FollowedGeometry->RemoveObserver(m_FollowerTag);
467 m_FollowedGeometry = geom;
468 m_FollowerTag = m_FollowedGeometry->AddObserver(itk::ModifiedEvent(), observer);
476 m_Center = m_FollowedGeometry->GetCenter();
478 m_AxisX = m_FollowedGeometry->GetAxisVector(0);
479 m_AxisY = m_FollowedGeometry->GetAxisVector(1);
480 m_AxisZ = m_FollowedGeometry->GetAxisVector(2);
486 for (
int dim = 0; dim < 3; ++dim)
488 m_Radius[dim] = 0.5 * m_FollowedGeometry->GetExtentInMM(dim);
496 #define CheckHandleType(type) \ 497 if (static_cast<int>(value) == static_cast<int>(type)) \ 511 #undef CheckHandleType 519 double dataValue =
GetVtkPolyData()->GetPointData()->GetScalars()->GetTuple1(
id);
525 #define CheckHandleType(candidateType) \ 526 if (type == candidateType) \ 527 return std::string(#candidateType); 540 return "InvalidHandleType";
541 #undef CheckHandleType
Class for storing surfaces (vtkPolyData).
Data management class that handles 'was created by' relations.
virtual vtkPolyData * GetVtkPolyData(unsigned int t=0) const
virtual SetOfObjects::ConstPointer GetDerivations(const DataNode *node, const NodePredicateBase *condition=nullptr, bool onlyDirectDerivations=true) const =0
returns a set of derived objects for a given node.
HandleType GetHandleFromPointID(vtkIdType id)
bool GetFloatProperty(const char *propertyKey, float &floatValue, const mitk::BaseRenderer *renderer=nullptr) const
Convenience access method for float properties (instances of FloatProperty)
static DataNode::Pointer AddGizmoToNode(DataNode *node, DataStorage *storage)
static Module * GetModule(long id)
DataCollection - Class to facilitate loading/accessing structured data.
virtual void Add(DataNode *node, const DataStorage::SetOfObjects *parents=nullptr)=0
Adds a DataNode containing a data object to its internal storage.
bool GetOpacity(float &opacity, const mitk::BaseRenderer *renderer, const char *propertyKey="opacity") const
Convenience access method for opacity properties (instances of FloatProperty)
#define CheckHandleType(type)
static bool HasGizmoAttached(mitk::DataNode *node, DataStorage *storage)
bool DeleteProperty(const std::string &propertyKey)
Remove a property from the list/map.
void FollowGeometry(BaseGeometry *geom)
HandleType
Names for the different parts of the gizmo.
const mitk::TimeGeometry * GetTimeGeometry() const
Return the TimeGeometry of the data as const pointer.
void SetFloatProperty(const char *propertyKey, float floatValue, const mitk::BaseRenderer *renderer=nullptr)
Convenience method for setting float properties (instances of FloatProperty)
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
void SetOpacity(float opacity, const mitk::BaseRenderer *renderer=nullptr, const char *propertyKey="opacity")
Convenience method for setting opacity properties (instances of FloatProperty)
virtual void SetVtkPolyData(vtkPolyData *polydata, unsigned int t=0)
virtual void Remove(const DataNode *node)=0
Removes node from the DataStorage.
mitk::PropertyList * GetPropertyList(const mitk::BaseRenderer *renderer=nullptr) const
Get the PropertyList of the renderer. If renderer is nullptr, the BaseRenderer-independent PropertyLi...
void UpdateRepresentation()
Updates the representing surface object after changes to center, axes, or radius. ...
double GetLongestRadius() const
Return the longest of the three axes.
void SetBounds(const BoundsArrayType &bounds)
Set the bounding box (in index/unit coordinates)
mitk::Gizmo::HandleType GetHandleFromPointDataValue(double value)
vtkSmartPointer< vtkPolyData > BuildGizmo()
Creates a vtkPolyData representing the parameters defining the gizmo.
void Update()
Updates the geometry.
mitk::BaseGeometry * GetGeometry(int t=0) const
Return the geometry, which is a TimeGeometry, of the data as non-const pointer.
static ModuleContext * GetModuleContext()
Returns the module context of the calling module.
void OnFollowedGeometryModified()
The ITK callback to receive modified events of the followed geometry.
static std::string HandleTypeToString(HandleType type)
Conversion for any kind of logging/debug/... purposes.
BaseGeometry Describes the geometry of a data object.
Class for nodes of the DataTree.
static bool RemoveGizmoFromNode(DataNode *node, DataStorage *storage)