28 #include <vtkAppendPolyData.h>
29 #include <vtkCellArray.h>
30 #include <vtkCharArray.h>
31 #include <vtkConeSource.h>
32 #include <vtkCylinderSource.h>
34 #include <vtkPointData.h>
35 #include <vtkPoints.h>
36 #include <vtkPolyDataNormals.h>
37 #include <vtkRenderWindow.h>
38 #include <vtkSphereSource.h>
39 #include <vtkTransformPolyDataFilter.h>
40 #include <vtkTubeFilter.h>
43 #include <itkCommand.h>
50 const char *PROPERTY_KEY_ORIGINAL_OBJECT_OPACITY =
"gizmo.originalObjectOpacity";
59 GizmoRemover() : m_Storage(nullptr), m_GizmoNode(nullptr), m_ManipulatedNode(nullptr), m_StorageObserverTag(0) {}
70 if (m_Storage !=
nullptr)
72 m_Storage->RemoveNodeEvent.RemoveListener(
74 m_Storage->RemoveObserver(m_StorageObserverTag);
78 m_GizmoNode = gizmo_node;
79 m_ManipulatedNode = manipulated_node;
81 if (m_Storage !=
nullptr)
83 m_Storage->RemoveNodeEvent.AddListener(
87 command->SetCallbackFunction(
this, &mitk::GizmoRemover::OnDataStorageDeleted);
88 m_StorageObserverTag = m_Storage->AddObserver(itk::ModifiedEvent(), command);
93 void OnDataStorageDeleted() { m_Storage =
nullptr; }
97 if (node == m_ManipulatedNode)
100 if (m_Storage->Exists(m_GizmoNode))
102 m_Storage->Remove(m_GizmoNode);
114 m_Storage->RemoveNodeEvent.RemoveListener(
116 m_Storage->RemoveObserver(m_StorageObserverTag);
124 unsigned long m_StorageObserverTag;
132 auto gizmoChildren = storage->
GetDerivations(node, typeCondition);
133 return !gizmoChildren->empty();
138 if (node ==
nullptr || storage ==
nullptr)
144 auto gizmoChildren = storage->
GetDerivations(node, typeCondition);
146 for (
auto &gizmoChild : *gizmoChildren)
148 Gizmo *gizmo =
dynamic_cast<Gizmo *
>(gizmoChild->GetData());
151 storage->
Remove(gizmoChild);
152 gizmo->m_GizmoRemover->UpdateStorageObservation(
nullptr,
nullptr,
nullptr);
159 float originalOpacity = 1.0;
160 if (node->
GetFloatProperty(PROPERTY_KEY_ORIGINAL_OBJECT_OPACITY, originalOpacity))
166 return !gizmoChildren->empty();
182 gizmoNode->SetName(
"Gizmo");
183 gizmoNode->SetData(gizmo);
194 interactor->SetGizmoNode(gizmoNode);
195 interactor->SetManipulatedObjectNode(node);
201 float currentNodeOpacity = 1.0;
202 if (node->
GetOpacity(currentNodeOpacity,
nullptr))
204 if (currentNodeOpacity > 0.5f)
206 node->
SetFloatProperty(PROPERTY_KEY_ORIGINAL_OBJECT_OPACITY, currentNodeOpacity);
213 storage->
Add(gizmoNode, node);
214 gizmo->m_GizmoRemover->UpdateStorageObservation(storage, gizmoNode, node);
221 :
Surface(), m_AllowTranslation(true), m_AllowRotation(true), m_AllowScaling(true), m_GizmoRemover(new GizmoRemover())
239 if (m_FollowedGeometry.IsNotNull())
241 m_FollowedGeometry->RemoveObserver(m_FollowerTag);
254 GetGeometry()->SetBounds(bounds);
255 GetTimeGeometry()->Update();
257 SetVtkPolyData(BuildGizmo());
262 void AssignScalarValueTo(vtkPolyData *polydata,
char value)
266 int numberOfPoints = polydata->GetNumberOfPoints();
267 pointData->SetNumberOfComponents(1);
268 pointData->SetNumberOfTuples(numberOfPoints);
269 pointData->FillComponent(0, value);
270 polydata->GetPointData()->SetScalars(pointData);
273 vtkSmartPointer<vtkPolyData> BuildAxis(
const mitk::Point3D ¢er,
277 char vertexValueAxis,
278 char vertexValueRing,
279 char vertexValueScale)
286 const double shaftRadius = halflength * 0.02;
287 const double arrowHeight = shaftRadius * 6;
288 const int tubeSides = 15;
294 for (
double sign = -1.0; sign < 3.0; sign += 2)
298 cone->SetCenter(center[0] + sign * axis[0] * (halflength * 1.1 + arrowHeight * 0.5),
299 center[1] + sign * axis[1] * (halflength * 1.1 + arrowHeight * 0.5),
300 center[2] + sign * axis[2] * (halflength * 1.1 + arrowHeight * 0.5));
301 cone->SetDirection(sign * axis[0], sign * axis[1], sign * axis[2]);
302 cone->SetRadius(shaftRadius * 3);
303 cone->SetHeight(arrowHeight);
304 cone->SetResolution(tubeSides);
307 AssignScalarValueTo(cone->GetOutput(), vertexValueScale);
308 axisSource->AddInputData(cone->GetOutput());
314 shaftPoints->InsertPoint(0, (center - axis * halflength * 1.1).GetDataPointer());
315 shaftPoints->InsertPoint(1, (center + axis * halflength * 1.1).GetDataPointer());
316 shaftSkeleton->SetPoints(shaftPoints);
319 vtkIdType shaftLinePoints[] = {0, 1};
320 shaftLines->InsertNextCell(2, shaftLinePoints);
321 shaftSkeleton->SetLines(shaftLines);
324 shaftSource->SetInputData(shaftSkeleton);
325 shaftSource->SetNumberOfSides(tubeSides);
326 shaftSource->SetVaryRadiusToVaryRadiusOff();
327 shaftSource->SetRadius(shaftRadius);
328 shaftSource->Update();
329 AssignScalarValueTo(shaftSource->GetOutput(), vertexValueAxis);
331 axisSource->AddInputData(shaftSource->GetOutput());
332 axisSource->Update();
334 vtkSmartPointer<vtkTubeFilter> ringSource;
340 ringPoints->SetDataTypeToDouble();
341 unsigned int numberOfRingPoints = 100;
343 ringLines->InsertNextCell(numberOfRingPoints + 1);
345 for (
unsigned int segment = 0; segment < numberOfRingPoints; ++segment)
348 ringPointer[1] = std::cos((
double)(segment) / (
double)numberOfRingPoints * 2.0 * vtkMath::Pi());
349 ringPointer[2] = std::sin((
double)(segment) / (
double)numberOfRingPoints * 2.0 * vtkMath::Pi());
351 ringPoints->InsertPoint(segment, (ringPointer * halflength).GetDataPointer());
353 ringLines->InsertCellPoint(segment);
355 ringLines->InsertCellPoint(0);
359 t->Translate(center.GetDataPointer());
360 double vMag = vtkMath::Norm(axis.GetDataPointer());
364 t->RotateWXYZ(180.0, (axis[0] - vMag) / 2.0, axis[1] / 2.0, axis[2] / 2.0);
365 t->RotateWXYZ(180.0, 0, 1, 0);
369 t->RotateWXYZ(180.0, (axis[0] + vMag) / 2.0, axis[1] / 2.0, axis[2] / 2.0);
373 for (
unsigned int i = 0; i < numberOfRingPoints; ++i)
375 ringPoints->GetPoint(i, thisPoint);
376 t->TransformPoint(thisPoint, thisPoint);
377 ringPoints->SetPoint(i, thisPoint);
380 ringSkeleton->SetPoints(ringPoints);
381 ringSkeleton->SetLines(ringLines);
384 ringSource->SetInputData(ringSkeleton);
385 ringSource->SetNumberOfSides(tubeSides);
386 ringSource->SetVaryRadiusToVaryRadiusOff();
387 ringSource->SetRadius(shaftRadius);
388 ringSource->Update();
389 AssignScalarValueTo(ringSource->GetOutput(), vertexValueRing);
394 appenderGlobal->AddInputData(axisSource->GetOutput());
397 appenderGlobal->AddInputData(ringSource->GetOutput());
399 appenderGlobal->Update();
403 normalsSource->SetInputConnection(appenderGlobal->GetOutputPort());
404 normalsSource->ComputePointNormalsOn();
405 normalsSource->ComputeCellNormalsOff();
406 normalsSource->SplittingOn();
407 normalsSource->Update();
409 vtkSmartPointer<vtkPolyData> result = normalsSource->GetOutput();
417 double longestAxis =
std::max(m_Radius[0], m_Radius[1]);
418 longestAxis =
std::max(longestAxis, m_Radius[2]);
424 double longestAxis = GetLongestRadius();
427 appender->AddInputData(BuildAxis(m_Center,
431 m_AllowTranslation ? MoveAlongAxisX : NoHandle,
432 m_AllowRotation ? RotateAroundAxisX : NoHandle,
433 m_AllowScaling ? ScaleX : NoHandle));
434 appender->AddInputData(BuildAxis(m_Center,
438 m_AllowTranslation ? MoveAlongAxisY : NoHandle,
439 m_AllowRotation ? RotateAroundAxisY : NoHandle,
440 m_AllowScaling ? ScaleY : NoHandle));
441 appender->AddInputData(BuildAxis(m_Center,
445 m_AllowTranslation ? MoveAlongAxisZ : NoHandle,
446 m_AllowRotation ? RotateAroundAxisZ : NoHandle,
447 m_AllowScaling ? ScaleZ : NoHandle));
450 sphereSource->SetCenter(m_Center[0], m_Center[1], m_Center[2]);
451 sphereSource->SetRadius(longestAxis * 0.06);
452 sphereSource->Update();
453 AssignScalarValueTo(sphereSource->GetOutput(), MoveFreely);
455 appender->AddInputData(sphereSource->GetOutput());
458 return appender->GetOutput();
466 if (m_FollowedGeometry.IsNotNull())
468 m_FollowedGeometry->RemoveObserver(m_FollowerTag);
471 m_FollowedGeometry = geom;
472 m_FollowerTag = m_FollowedGeometry->AddObserver(itk::ModifiedEvent(), observer);
475 OnFollowedGeometryModified();
480 m_Center = m_FollowedGeometry->GetCenter();
482 m_AxisX = m_FollowedGeometry->GetAxisVector(0);
483 m_AxisY = m_FollowedGeometry->GetAxisVector(1);
484 m_AxisZ = m_FollowedGeometry->GetAxisVector(2);
490 for (
int dim = 0; dim < 3; ++dim)
492 m_Radius[dim] = 0.5 * m_FollowedGeometry->GetExtentInMM(dim);
495 UpdateRepresentation();
500 #define CheckHandleType(type) \
501 if (static_cast<int>(value) == static_cast<int>(type)) \
515 #undef CheckHandleType
520 assert(GetVtkPolyData());
521 assert(GetVtkPolyData()->GetPointData());
522 assert(GetVtkPolyData()->GetPointData()->GetScalars());
523 double dataValue = GetVtkPolyData()->GetPointData()->GetScalars()->GetTuple1(
id);
524 return GetHandleFromPointDataValue(dataValue);
529 #define CheckHandleType(candidateType) \
530 if (type == candidateType) \
531 return std::string(#candidateType);
544 return "InvalidHandleType";
545 #undef CheckHandleType
virtual void Add(mitk::DataNode *node, const mitk::DataStorage::SetOfObjects *parents=nullptr)=0
Adds a DataNode containing a data object to its internal storage.
Class for storing surfaces (vtkPolyData).
mitk::PropertyList * GetPropertyList(const mitk::BaseRenderer *renderer=nullptr) const
Get the PropertyList of the renderer. If renderer is NULL, the BaseRenderer-independent PropertyList ...
Data management class that handles 'was created by' relations.
itk::SmartPointer< Self > Pointer
HandleType GetHandleFromPointID(vtkIdType id)
virtual SetOfObjects::ConstPointer GetDerivations(const mitk::DataNode *node, const NodePredicateBase *condition=nullptr, bool onlyDirectDerivations=true) const =0
returns a set of derived objects for a given node.
static DataNode::Pointer AddGizmoToNode(DataNode *node, DataStorage *storage)
static Module * GetModule(long id)
DataCollection - Class to facilitate loading/accessing structured data.
BaseData * GetData() const
Get the data object (instance of BaseData, e.g., an Image) managed by this DataNode.
#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.
void SetFloatProperty(const char *propertyKey, float floatValue, const mitk::BaseRenderer *renderer=nullptr)
Convenience method for setting float properties (instances of FloatProperty)
bool GetOpacity(float &opacity, const mitk::BaseRenderer *renderer, const char *propertyKey="opacity") const
Convenience access method for opacity properties (instances of FloatProperty)
void SetOpacity(float opacity, const mitk::BaseRenderer *renderer=nullptr, const char *propertyKey="opacity")
Convenience method for setting opacity properties (instances of FloatProperty)
bool GetFloatProperty(const char *propertyKey, float &floatValue, const mitk::BaseRenderer *renderer=nullptr) const
Convenience access method for float properties (instances of FloatProperty)
double GetLongestRadius() const
Return the longest of the three axes.
void UpdateRepresentation()
Updates the representing surface object after changes to center, axes, or radius. ...
mitk::Gizmo::HandleType GetHandleFromPointDataValue(double value)
virtual void Remove(const mitk::DataNode *node)=0
Removes node from the DataStorage.
mitk::BaseGeometry * GetGeometry(int t=0) const
Return the geometry, which is a TimeGeometry, of the data as non-const pointer.
vtkSmartPointer< vtkPolyData > BuildGizmo()
Creates a vtkPolyData representing the parameters defining the gizmo.
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)
static itkEventMacro(BoundingShapeInteractionEvent, itk::AnyEvent) class MITKBOUNDINGSHAPE_EXPORT BoundingShapeInteractor Pointer New()
Basic interaction methods for mitk::GeometryData.