Skip to content

Commit

Permalink
ENH: Add finer control of 2D interaction handle axis display
Browse files Browse the repository at this point in the history
The visibility of individual interaction axes can now be controlled separately for transform nodes.

Default 3D visibility:
- Translation: X, Y, Z, View
- Rotation: X, Y, Z
- Scaling: None

Default 2D visibility:
- Translation: View
- Rotation: View
- Scaling: None

vtkMRMLTransformDisplayNode:
- EditorVisibility3D and EditorSliceIntersectionVisibility control the visibility in their respective views, while EditorVisibility controls visibility in both.
- Editor{XYZ}Enabled now only works for 3D while Editor{XYZ}SliceEnabled has been added to control 2D view visibility.
- {XYZ}HandleComponentVisibility3D allows individual axes to be enabled disabled in 3D, while {XYZ}HandleComponentVisibilitySlice does the same in 2D.

qSlicerSubjectHierarchyTransformsPlugin:
- "Interaction in 3D view" is now "Interaction", and controls visibility in both views.

Re #7570
  • Loading branch information
Sunderlandkyl authored and lassoan committed Feb 15, 2024
1 parent 1b247c2 commit b2be7c3
Show file tree
Hide file tree
Showing 9 changed files with 1,164 additions and 615 deletions.
61 changes: 43 additions & 18 deletions Libs/MRML/Core/vtkMRMLTransformDisplayNode.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -91,18 +91,28 @@ vtkMRMLTransformDisplayNode::vtkMRMLTransformDisplayNode()
}

this->EditorVisibility = false;
this->EditorSliceIntersectionVisibility = false;
this->EditorVisibility3D = true;
this->EditorSliceIntersectionVisibility = true;
this->EditorTranslationEnabled = true;
this->EditorTranslationSliceEnabled = true;
this->EditorRotationEnabled = true;
this->EditorRotationSliceEnabled = true;
this->EditorScalingEnabled = false;
this->EditorScalingSliceEnabled = false;

for (int i = 0; i < 4; ++i)
{
this->RotationHandleComponentVisibility[i] = true;
this->ScaleHandleComponentVisibility[i] = true;
this->TranslationHandleComponentVisibility[i] = true;
this->RotationHandleComponentVisibility3D[i] = true;
this->ScaleHandleComponentVisibility3D[i] = true;
this->TranslationHandleComponentVisibility3D[i] = true;

this->RotationHandleComponentVisibilitySlice[i] = false;
this->ScaleHandleComponentVisibilitySlice[i] = true;
this->TranslationHandleComponentVisibilitySlice[i] = false;
}
this->RotationHandleComponentVisibility[3] = false;
this->RotationHandleComponentVisibility3D[3] = false;
this->RotationHandleComponentVisibilitySlice[3] = true;
this->TranslationHandleComponentVisibilitySlice[3] = true;

vtkNew<vtkIntArray> regionModifiedEvents;
regionModifiedEvents->InsertNextValue(vtkCommand::ModifiedEvent);
Expand Down Expand Up @@ -152,17 +162,20 @@ void vtkMRMLTransformDisplayNode::WriteXML(ostream& of, int nIndent)
of << " EditorRotationEnabled=\"" << this->EditorRotationEnabled << "\"";
of << " EditorScalingEnabled=\""<< this->EditorScalingEnabled << "\"";

vtkMRMLWriteXMLBooleanMacro(EditorVisibility3D, EditorVisibility3D);
vtkMRMLWriteXMLFloatMacro(InteractionSizeAbsolute, InteractionSizeAbsolute);
vtkMRMLWriteXMLFloatMacro(InteractionSizeMm, InteractionSizeMm);
vtkMRMLWriteXMLFloatMacro(InteractionScalePercent, InteractionScalePercent);
vtkMRMLWriteXMLVectorMacro(TranslationHandleComponentVisibility, TranslationHandleComponentVisibility, bool, 4);
vtkMRMLWriteXMLVectorMacro(RotationHandleComponentVisibility, RotationHandleComponentVisibility, bool, 4)
vtkMRMLWriteXMLVectorMacro(ScaleHandleComponentVisibility, ScaleHandleComponentVisibility, bool, 4);
vtkMRMLWriteXMLVectorMacro(TranslationHandleComponentVisibility3D, TranslationHandleComponentVisibility3D, bool, 4);
vtkMRMLWriteXMLVectorMacro(RotationHandleComponentVisibility3D, RotationHandleComponentVisibility3D, bool, 4)
vtkMRMLWriteXMLVectorMacro(ScaleHandleComponentVisibility3D, ScaleHandleComponentVisibility3D, bool, 4);
vtkMRMLWriteXMLVectorMacro(TranslationHandleComponentVisibilitySlice, TranslationHandleComponentVisibilitySlice, bool, 4);
vtkMRMLWriteXMLVectorMacro(RotationHandleComponentVisibilitySlice, RotationHandleComponentVisibilitySlice, bool, 4)
vtkMRMLWriteXMLVectorMacro(ScaleHandleComponentVisibilitySlice, ScaleHandleComponentVisibilitySlice, bool, 4);

vtkMRMLWriteXMLEndMacro();
}


#define READ_FROM_ATT(varName) \
if (!strcmp(xmlReadAttName,#varName)) \
{ \
Expand Down Expand Up @@ -217,13 +230,17 @@ void vtkMRMLTransformDisplayNode::ReadXMLAttributes(const char** atts)
READ_FROM_ATT(EditorRotationEnabled);
READ_FROM_ATT(EditorScalingEnabled);

vtkMRMLReadXMLBooleanMacro(EditorVisibility3D, EditorVisibility3D);
vtkMRMLReadXMLFloatMacro(InteractionSizeAbsolute, InteractionSizeAbsolute);
vtkMRMLReadXMLFloatMacro(InteractionSizeMm, InteractionSizeMm);
vtkMRMLReadXMLFloatMacro(InteractionScalePercent, InteractionScalePercent);

vtkMRMLReadXMLVectorMacro(RotationHandleComponentVisibility, RotationHandleComponentVisibility, bool, 4);
vtkMRMLReadXMLVectorMacro(ScaleHandleComponentVisibility, ScaleHandleComponentVisibility, bool, 4);
vtkMRMLReadXMLVectorMacro(TranslationHandleComponentVisibility, TranslationHandleComponentVisibility, bool, 4);
vtkMRMLReadXMLVectorMacro(RotationHandleComponentVisibility3D, RotationHandleComponentVisibility3D, bool, 4);
vtkMRMLReadXMLVectorMacro(ScaleHandleComponentVisibility3D, ScaleHandleComponentVisibility3D, bool, 4);
vtkMRMLReadXMLVectorMacro(TranslationHandleComponentVisibility3D, TranslationHandleComponentVisibility3D, bool, 4);
vtkMRMLReadXMLVectorMacro(RotationHandleComponentVisibilitySlice, RotationHandleComponentVisibilitySlice, bool, 4);
vtkMRMLReadXMLVectorMacro(ScaleHandleComponentVisibilitySlice, ScaleHandleComponentVisibilitySlice, bool, 4);
vtkMRMLReadXMLVectorMacro(TranslationHandleComponentVisibilitySlice, TranslationHandleComponentVisibilitySlice, bool, 4);

vtkMRMLReadXMLEndMacro();
}
Expand Down Expand Up @@ -270,9 +287,13 @@ void vtkMRMLTransformDisplayNode::CopyContent(vtkMRMLNode* anode, bool deepCopy/
this->EditorRotationEnabled = node->EditorRotationEnabled;
this->EditorScalingEnabled = node->EditorScalingEnabled;

vtkMRMLCopyVectorMacro(RotationHandleComponentVisibility, bool, 4);
vtkMRMLCopyVectorMacro(ScaleHandleComponentVisibility, bool, 4);
vtkMRMLCopyVectorMacro(TranslationHandleComponentVisibility, bool, 4);
vtkMRMLCopyBooleanMacro(EditorVisibility3D);
vtkMRMLCopyVectorMacro(RotationHandleComponentVisibility3D, bool, 4);
vtkMRMLCopyVectorMacro(ScaleHandleComponentVisibility3D, bool, 4);
vtkMRMLCopyVectorMacro(TranslationHandleComponentVisibility3D, bool, 4);
vtkMRMLCopyVectorMacro(RotationHandleComponentVisibilitySlice, bool, 4);
vtkMRMLCopyVectorMacro(ScaleHandleComponentVisibilitySlice, bool, 4);
vtkMRMLCopyVectorMacro(TranslationHandleComponentVisibilitySlice, bool, 4);

vtkMRMLCopyEndMacro();
}
Expand Down Expand Up @@ -310,9 +331,13 @@ void vtkMRMLTransformDisplayNode::PrintSelf(ostream& os, vtkIndent indent)
os << indent << " EditorRotationEnabled=\"" << this->EditorRotationEnabled << "\n";
os << indent << " EditorScalingEnabled=\""<< this->EditorScalingEnabled << "\n";

vtkMRMLPrintVectorMacro(RotationHandleComponentVisibility, bool, 4);
vtkMRMLPrintVectorMacro(ScaleHandleComponentVisibility, bool, 4);
vtkMRMLPrintVectorMacro(TranslationHandleComponentVisibility, bool, 4);
vtkMRMLPrintBooleanMacro(EditorVisibility3D);
vtkMRMLPrintVectorMacro(RotationHandleComponentVisibility3D, bool, 4);
vtkMRMLPrintVectorMacro(ScaleHandleComponentVisibility3D, bool, 4);
vtkMRMLPrintVectorMacro(TranslationHandleComponentVisibility3D, bool, 4);
vtkMRMLPrintVectorMacro(RotationHandleComponentVisibilitySlice, bool, 4);
vtkMRMLPrintVectorMacro(ScaleHandleComponentVisibilitySlice, bool, 4);
vtkMRMLPrintVectorMacro(TranslationHandleComponentVisibilitySlice, bool, 4);

vtkMRMLPrintEndMacro();
}
Expand Down
44 changes: 35 additions & 9 deletions Libs/MRML/Core/vtkMRMLTransformDisplayNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,18 +170,30 @@ class VTK_MRML_EXPORT vtkMRMLTransformDisplayNode : public vtkMRMLDisplayNode
vtkGetMacro(EditorVisibility, bool);
vtkSetMacro(EditorVisibility, bool);
vtkBooleanMacro(EditorVisibility, bool);
vtkGetMacro(EditorVisibility3D, bool);
vtkSetMacro(EditorVisibility3D, bool);
vtkBooleanMacro(EditorVisibility3D, bool);
vtkGetMacro(EditorSliceIntersectionVisibility, bool);
vtkSetMacro(EditorSliceIntersectionVisibility, bool);
vtkBooleanMacro(EditorSliceIntersectionVisibility, bool);
vtkGetMacro(EditorTranslationEnabled, bool);
vtkSetMacro(EditorTranslationEnabled, bool);
vtkBooleanMacro(EditorTranslationEnabled, bool);
vtkGetMacro(EditorTranslationSliceEnabled, bool);
vtkSetMacro(EditorTranslationSliceEnabled, bool);
vtkBooleanMacro(EditorTranslationSliceEnabled, bool);
vtkGetMacro(EditorRotationEnabled, bool);
vtkSetMacro(EditorRotationEnabled, bool);
vtkBooleanMacro(EditorRotationEnabled, bool);
vtkGetMacro(EditorRotationSliceEnabled, bool);
vtkSetMacro(EditorRotationSliceEnabled, bool);
vtkBooleanMacro(EditorRotationSliceEnabled, bool);
vtkGetMacro(EditorScalingEnabled, bool);
vtkSetMacro(EditorScalingEnabled, bool);
vtkBooleanMacro(EditorScalingEnabled, bool);
vtkGetMacro(EditorScalingSliceEnabled, bool);
vtkSetMacro(EditorScalingSliceEnabled, bool);
vtkBooleanMacro(EditorScalingSliceEnabled, bool);

/// Ask the editor to recompute its bounds by invoking the
/// TransformUpdateEditorBoundsEvent event.
Expand Down Expand Up @@ -224,12 +236,18 @@ class VTK_MRML_EXPORT vtkMRMLTransformDisplayNode : public vtkMRMLDisplayNode
/// The order of the vector is: [X, Y, Z, ViewPlane]
/// "ViewPlane" scale/translation allows transformations to take place along the active view plane.
/// (ex. center translation point and ROI corner scale handles.
vtkSetVector4Macro(RotationHandleComponentVisibility, bool);
vtkGetVector4Macro(RotationHandleComponentVisibility, bool);
vtkSetVector4Macro(ScaleHandleComponentVisibility, bool);
vtkGetVector4Macro(ScaleHandleComponentVisibility, bool);
vtkSetVector4Macro(TranslationHandleComponentVisibility, bool);
vtkGetVector4Macro(TranslationHandleComponentVisibility, bool);
vtkSetVector4Macro(RotationHandleComponentVisibility3D, bool);
vtkGetVector4Macro(RotationHandleComponentVisibility3D, bool);
vtkSetVector4Macro(ScaleHandleComponentVisibility3D, bool);
vtkGetVector4Macro(ScaleHandleComponentVisibility3D, bool);
vtkSetVector4Macro(TranslationHandleComponentVisibility3D, bool);
vtkGetVector4Macro(TranslationHandleComponentVisibility3D, bool);
vtkSetVector4Macro(RotationHandleComponentVisibilitySlice, bool);
vtkGetVector4Macro(RotationHandleComponentVisibilitySlice, bool);
vtkSetVector4Macro(ScaleHandleComponentVisibilitySlice, bool);
vtkGetVector4Macro(ScaleHandleComponentVisibilitySlice, bool);
vtkSetVector4Macro(TranslationHandleComponentVisibilitySlice, bool);
vtkGetVector4Macro(TranslationHandleComponentVisibilitySlice, bool);
//@}

protected:
Expand Down Expand Up @@ -270,20 +288,28 @@ class VTK_MRML_EXPORT vtkMRMLTransformDisplayNode : public vtkMRMLDisplayNode

// Interaction Parameters
bool EditorVisibility;
bool EditorVisibility3D;
bool EditorSliceIntersectionVisibility;
bool EditorTranslationEnabled;
bool EditorTranslationSliceEnabled;
bool EditorRotationEnabled;
bool EditorRotationSliceEnabled;
bool EditorScalingEnabled;
bool EditorScalingSliceEnabled;

int ActiveInteractionType{-1};
int ActiveInteractionIndex{-1};
bool InteractionSizeAbsolute{false};
double InteractionSizeMm{5.0};
double InteractionScalePercent{15.0};

bool RotationHandleComponentVisibility[4];
bool ScaleHandleComponentVisibility[4];
bool TranslationHandleComponentVisibility[4];
bool RotationHandleComponentVisibility3D[4];
bool ScaleHandleComponentVisibility3D[4];
bool TranslationHandleComponentVisibility3D[4];

bool RotationHandleComponentVisibilitySlice[4];
bool ScaleHandleComponentVisibilitySlice[4];
bool TranslationHandleComponentVisibilitySlice[4];

protected:
vtkMRMLTransformDisplayNode ( );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ void vtkMRMLLinearTransformsDisplayableManager2D::vtkInternal::RemoveDisplayNode
//---------------------------------------------------------------------------
void vtkMRMLLinearTransformsDisplayableManager2D::vtkInternal::AddDisplayNode(vtkMRMLTransformNode* mNode, vtkMRMLTransformDisplayNode* displayNode)
{
if (!mNode || !displayNode)
if (!mNode || !displayNode || !mNode->IsLinear())
{
return;
}
Expand Down Expand Up @@ -281,6 +281,12 @@ void vtkMRMLLinearTransformsDisplayableManager2D::vtkInternal::UpdateDisplayNode
return;
}

vtkMRMLTransformNode* transformNode = vtkMRMLTransformNode::SafeDownCast(displayNode->GetDisplayableNode());
if (!transformNode || !transformNode->IsLinear())
{
return;
}

vtkSmartPointer<vtkMRMLTransformHandleWidget> widget;
InteractionWidgetsCacheType::iterator pipelineIt;
pipelineIt = this->InteractionWidgets.find(displayNode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -339,15 +339,15 @@ void vtkMRMLLinearTransformsDisplayableManager3D::vtkInternal::UpdateInteraction
void vtkMRMLLinearTransformsDisplayableManager3D::vtkInternal::UpdateInteractionPipeline(
vtkMRMLTransformNode* displayableNode, unsigned long event, vtkMRMLTransformDisplayNode* displayNode)
{
if (!displayableNode || !displayNode)
if (!displayableNode || !displayNode || !displayableNode->IsLinear())
{
return;
}

vtkSmartPointer<vtkMRMLTransformHandleWidget> widget;
InteractionPipelinesCacheType::iterator pipelineIt = this->InteractionPipelines.find(displayNode);

bool visible = displayNode->GetEditorVisibility();
bool visible = displayNode->GetEditorVisibility() && displayNode->GetEditorVisibility3D();
if (visible && pipelineIt == this->InteractionPipelines.end())
{
// No pipeline, yet interaction visibility is on, create a new one
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ bool vtkMRMLTransformHandleWidgetRepresentation::IsDisplayable()
return this->GetDisplayNode()->GetEditorSliceIntersectionVisibility();
}

return true;
return this->GetDisplayNode()->GetEditorVisibility3D();
}

//----------------------------------------------------------------------
Expand Down Expand Up @@ -205,32 +205,40 @@ bool vtkMRMLTransformHandleWidgetRepresentation::GetHandleVisibility(int type, i
return false;
}

vtkMRMLSliceNode* sliceNode = this->GetSliceNode();

bool visible = Superclass::GetHandleVisibility(type, index);
if (type == InteractionRotationHandle)
{
visible &= displayNode->GetEditorRotationEnabled();
visible &= sliceNode ? displayNode->GetEditorRotationSliceEnabled() : displayNode->GetEditorRotationEnabled();
}
else if (type == InteractionTranslationHandle)
{
visible &= displayNode->GetEditorTranslationEnabled();
visible &= sliceNode ? displayNode->GetEditorTranslationSliceEnabled() : displayNode->GetEditorTranslationEnabled();
}
else if (type == InteractionScaleHandle)
{
visible &= displayNode->GetEditorScalingEnabled();
visible &= sliceNode ? displayNode->GetEditorScalingSliceEnabled() : displayNode->GetEditorScalingEnabled();
}

bool handleVisibility[4] = { false, false, false, false };
if (type == InteractionRotationHandle)
{
this->GetDisplayNode()->GetRotationHandleComponentVisibility(handleVisibility);
sliceNode
? this->GetDisplayNode()->GetRotationHandleComponentVisibilitySlice(handleVisibility)
: this->GetDisplayNode()->GetRotationHandleComponentVisibility3D(handleVisibility);
}
else if (type == InteractionScaleHandle)
{
this->GetDisplayNode()->GetScaleHandleComponentVisibility(handleVisibility);
sliceNode
? this->GetDisplayNode()->GetScaleHandleComponentVisibilitySlice(handleVisibility)
: this->GetDisplayNode()->GetScaleHandleComponentVisibility3D(handleVisibility);
}
else if (type == InteractionTranslationHandle)
{
this->GetDisplayNode()->GetTranslationHandleComponentVisibility(handleVisibility);
sliceNode
? this->GetDisplayNode()->GetTranslationHandleComponentVisibilitySlice(handleVisibility)
: this->GetDisplayNode()->GetTranslationHandleComponentVisibility3D(handleVisibility);
}

if (index >= 0 && index <= 3)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,12 +121,12 @@ void qSlicerSubjectHierarchyTransformsPluginPrivate::init()
this->ResetCenterOfTransformCurrentItemAction = new QAction(qSlicerSubjectHierarchyTransformsPlugin::tr("Reset center of transformation"), q);
QObject::connect(this->ResetCenterOfTransformCurrentItemAction, SIGNAL(triggered()), q, SLOT(resetCenterOfTransformationCurrentItem()));

this->ToggleInteractionAction = new QAction(qSlicerSubjectHierarchyTransformsPlugin::tr("Interaction in 3D view"), q);
this->ToggleInteractionAction = new QAction(qSlicerSubjectHierarchyTransformsPlugin::tr("Interaction"), q);
QObject::connect(this->ToggleInteractionAction, SIGNAL(toggled(bool)), q, SLOT(toggleInteractionBox(bool)));
this->ToggleInteractionAction->setCheckable(true);
this->ToggleInteractionAction->setChecked(false);

this->ToggleInteractionItemAction = new QAction(qSlicerSubjectHierarchyTransformsPlugin::tr("Interaction in 3D view"), q);
this->ToggleInteractionItemAction = new QAction(qSlicerSubjectHierarchyTransformsPlugin::tr("Interaction"), q);
QObject::connect(this->ToggleInteractionItemAction, SIGNAL(toggled(bool)), q, SLOT(toggleInteractionBox(bool)));
this->ToggleInteractionItemAction->setCheckable(true);
this->ToggleInteractionItemAction->setChecked(false);
Expand Down Expand Up @@ -440,15 +440,11 @@ void qSlicerSubjectHierarchyTransformsPlugin::showVisibilityContextMenuActionsFo
}

vtkMRMLTransformNode* transformNode = vtkMRMLTransformNode::SafeDownCast(shNode->GetItemDataNode(itemID));
if (transformNode)
if (!transformNode)
{
// We only display this option for transformable nodes, not transform nodes where
// the option is controlled by regular visibility options.
return;
transformNode = transformableNode->GetParentTransformNode();
}

transformNode = transformableNode->GetParentTransformNode();

vtkMRMLTransformDisplayNode* displayNode = transformNode ? vtkMRMLTransformDisplayNode::SafeDownCast(transformNode->GetDisplayNode()) : nullptr;

d->ToggleInteractionItemAction->setVisible(true);
Expand Down Expand Up @@ -661,6 +657,8 @@ void qSlicerSubjectHierarchyTransformsPlugin::toggleInteractionBox(bool visible)
qCritical() << Q_FUNC_INFO << ": Failed to get or create transform node";
return;
}
transformNode->CreateDefaultDisplayNodes();

vtkMRMLTransformDisplayNode* displayNode = vtkMRMLTransformDisplayNode::SafeDownCast(
transformNode->GetDisplayNode() );
if (!displayNode)
Expand Down

0 comments on commit b2be7c3

Please sign in to comment.