Skip to content

Commit

Permalink
ENH: Translation/rotation of unlocked points in a list
Browse files Browse the repository at this point in the history
This commit adds a new function that allows unlocked markup points to move using the markup interaction handles. Currently, the interaction handles are disabled when any point is locked. This commit also fixes a bug where any points with an undefined position status are reset on using a markup's interaction handles. To support the new functionality, the interaction handle center of rotation is updated to ignore locked and undefined points. This commit is a product of the PW 39 2023 project: https://projectweek.na-mic.org/PW39_2023_Montreal/Projects/TranslationRotationOfSelectPointsInAList/
  • Loading branch information
smrolfe authored and lassoan committed Jul 13, 2023
1 parent 7e320d5 commit 96f85fe
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 48 deletions.
68 changes: 42 additions & 26 deletions Modules/Loadable/Markups/MRML/vtkMRMLMarkupsNode.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -1703,6 +1703,7 @@ void vtkMRMLMarkupsNode::SetNthControlPointLocked(int n, bool flag)
return;
}
controlPoint->Locked = flag;
this->UpdateInteractionHandleToWorldMatrix();
this->InvokeCustomModifiedEvent(vtkMRMLMarkupsNode::PointModifiedEvent, static_cast<void*>(&n));
this->StorableModifiedTime.Modified();
}
Expand Down Expand Up @@ -2230,21 +2231,18 @@ void vtkMRMLMarkupsNode::UnsetNthControlPointPosition(int n)
}
int oldPositionStatus = controlPoint->PositionStatus;
controlPoint->PositionStatus = PositionUndefined;
if (!this->GetDisableModifiedEvent())
{
this->UpdateCurvePolyFromControlPoints();
this->UpdateInteractionHandleToWorldMatrix();
}
this->InvokeCustomModifiedEvent(vtkMRMLMarkupsNode::PointModifiedEvent, static_cast<void*>(&n));
this->InvokeCustomModifiedEvent(vtkMRMLMarkupsNode::PointPositionUndefinedEvent, static_cast<void*>(&n));
if (oldPositionStatus == PositionMissing)
{
this->InvokeCustomModifiedEvent(vtkMRMLMarkupsNode::PointPositionNonMissingEvent, static_cast<void*>(&n));
}

this->StorableModifiedTime.Modified();

if (!this->GetDisableModifiedEvent())
{
this->UpdateCurvePolyFromControlPoints();
this->UpdateInteractionHandleToWorldMatrix();
}

if (!this->GetDisableModifiedEvent())
{
this->UpdateAllMeasurements();
Expand All @@ -2265,15 +2263,14 @@ void vtkMRMLMarkupsNode::SetNthControlPointPositionMissing(int n)
return;
}
controlPoint->PositionStatus = PositionMissing;
this->InvokeCustomModifiedEvent(vtkMRMLMarkupsNode::PointModifiedEvent, static_cast<void*>(&n));
this->InvokeCustomModifiedEvent(vtkMRMLMarkupsNode::PointPositionMissingEvent, static_cast<void*>(&n));
this->StorableModifiedTime.Modified();

if (!this->GetDisableModifiedEvent())
{
this->UpdateCurvePolyFromControlPoints();
this->UpdateInteractionHandleToWorldMatrix();
}
this->InvokeCustomModifiedEvent(vtkMRMLMarkupsNode::PointModifiedEvent, static_cast<void*>(&n));
this->InvokeCustomModifiedEvent(vtkMRMLMarkupsNode::PointPositionMissingEvent, static_cast<void*>(&n));
this->StorableModifiedTime.Modified();

this->UpdateMeasurementsInternal();
}
Expand Down Expand Up @@ -2302,14 +2299,13 @@ void vtkMRMLMarkupsNode::ResetNthControlPointPosition(int n)
}
}
controlPoint->PositionStatus = PositionPreview;
this->InvokeCustomModifiedEvent(vtkMRMLMarkupsNode::PointModifiedEvent, static_cast<void*>(&n));
this->StorableModifiedTime.Modified();

if (!this->GetDisableModifiedEvent())
{
this->UpdateCurvePolyFromControlPoints();
this->UpdateInteractionHandleToWorldMatrix();
}
this->InvokeCustomModifiedEvent(vtkMRMLMarkupsNode::PointModifiedEvent, static_cast<void*>(&n));
this->StorableModifiedTime.Modified();

this->UpdateMeasurementsInternal();
}
Expand All @@ -2328,14 +2324,13 @@ void vtkMRMLMarkupsNode::RestoreNthControlPointPosition(int n)
return;
}
controlPoint->PositionStatus = PositionDefined;
this->InvokeCustomModifiedEvent(vtkMRMLMarkupsNode::PointModifiedEvent, static_cast<void*>(&n));
this->StorableModifiedTime.Modified();

if (!this->GetDisableModifiedEvent())
{
this->UpdateCurvePolyFromControlPoints();
this->UpdateInteractionHandleToWorldMatrix();
}
this->InvokeCustomModifiedEvent(vtkMRMLMarkupsNode::PointModifiedEvent, static_cast<void*>(&n));
this->StorableModifiedTime.Modified();

this->UpdateMeasurementsInternal();
}
Expand Down Expand Up @@ -2372,6 +2367,20 @@ bool vtkMRMLMarkupsNode::GetNthControlPointAutoCreated(int n)
}
}

//---------------------------------------------------------------------------
int vtkMRMLMarkupsNode::GetNumberOfMovableControlPoints()
{
int numberOfMovableControlPoints = 0;
for (ControlPointsListType::iterator controlPointIt = this->ControlPoints.begin();
controlPointIt != this->ControlPoints.end(); ++controlPointIt)
{
if ((*controlPointIt)->Locked == false && (*controlPointIt)->PositionStatus == PositionDefined)
{
numberOfMovableControlPoints++;
}
}
return numberOfMovableControlPoints;
}
//---------------------------------------------------------------------------
int vtkMRMLMarkupsNode::GetNumberOfDefinedControlPoints(bool includePreview/*=false*/)
{
Expand Down Expand Up @@ -2470,7 +2479,7 @@ void vtkMRMLMarkupsNode::GetControlPointLabels(vtkStringArray* labels)
}

//---------------------------------------------------------------------------
void vtkMRMLMarkupsNode::SetControlPointPositionsWorld(vtkPoints* points)
void vtkMRMLMarkupsNode::SetControlPointPositionsWorld(vtkPoints* points, bool setUndefinedPoints/*=true*/)
{
if (!points)
{
Expand All @@ -2488,7 +2497,10 @@ void vtkMRMLMarkupsNode::SetControlPointPositionsWorld(vtkPoints* points)
if (pointIndex < this->GetNumberOfControlPoints())
{
// point already exists, just update it
this->SetNthControlPointPositionWorld(pointIndex, posWorld);
if (setUndefinedPoints || this->GetNthControlPointPositionStatus(pointIndex) == PositionDefined)
{
this->SetNthControlPointPositionWorld(pointIndex, posWorld);
}
}
else
{
Expand Down Expand Up @@ -2849,25 +2861,29 @@ void vtkMRMLMarkupsNode::UpdateInteractionHandleToWorldMatrix()
// The origin of the coordinate system is at the center of mass of the control points
double origin_World[3] = { 0 };
int numberOfControlPoints = this->GetNumberOfControlPoints();
int numberOfMovableControlPoints = this->GetNumberOfMovableControlPoints();
vtkNew<vtkPoints> controlPoints_World;
for (int i = 0; i < numberOfControlPoints; ++i)
{
double controlPointPosition_World[3] = { 0.0, 0.0, 0.0 };
this->GetNthControlPointPositionWorld(i, controlPointPosition_World);
if (!this->GetNthControlPointLocked(i) && this->GetNthControlPointPositionStatus(i) == PositionDefined)
{
this->GetNthControlPointPositionWorld(i, controlPointPosition_World);

origin_World[0] += controlPointPosition_World[0] / numberOfControlPoints;
origin_World[1] += controlPointPosition_World[1] / numberOfControlPoints;
origin_World[2] += controlPointPosition_World[2] / numberOfControlPoints;
origin_World[0] += controlPointPosition_World[0] / numberOfMovableControlPoints;
origin_World[1] += controlPointPosition_World[1] / numberOfMovableControlPoints;
origin_World[2] += controlPointPosition_World[2] / numberOfMovableControlPoints;

controlPoints_World->InsertNextPoint(controlPointPosition_World);
controlPoints_World->InsertNextPoint(controlPointPosition_World);
}
}

for (int i = 0; i < 3; ++i)
{
this->InteractionHandleToWorldMatrix->SetElement(i, 3, origin_World[i]);
}

if (this->GetNumberOfControlPoints() < 3)
if (numberOfMovableControlPoints < 3)
{
return;
}
Expand Down
4 changes: 3 additions & 1 deletion Modules/Loadable/Markups/MRML/vtkMRMLMarkupsNode.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,8 @@ class VTK_SLICER_MARKUPS_MODULE_MRML_EXPORT vtkMRMLMarkupsNode : public vtkMRML

/// Return the number of control points that are stored in this node
int GetNumberOfControlPoints();
/// Return the number of unlocked control points with defined position in this node
int GetNumberOfMovableControlPoints();
/// Return the number of control points that are already placed (not being previewed or undefined).
int GetNumberOfDefinedControlPoints(bool includePreview=false);
/// Return the number of control points that have not been placed (not being previewed or skipped).
Expand All @@ -312,7 +314,7 @@ class VTK_SLICER_MARKUPS_MODULE_MRML_EXPORT vtkMRMLMarkupsNode : public vtkMRML
/// New control points are added if needed.
/// Existing control points are updated with the new positions.
/// Any extra existing control points are removed.
void SetControlPointPositionsWorld(vtkPoints* points);
void SetControlPointPositionsWorld(vtkPoints* points, bool setUndefinedPoints=true);

/// Get a copy of all control point positions in world coordinate system
void GetControlPointPositionsWorld(vtkPoints* points);
Expand Down
61 changes: 40 additions & 21 deletions Modules/Loadable/Markups/VTKWidgets/vtkSlicerMarkupsWidget.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -157,8 +157,7 @@ bool vtkSlicerMarkupsWidget::ProcessControlPointInsert(vtkMRMLInteractionEventDa
//----------------------------------------------------------------------
bool vtkSlicerMarkupsWidget::ProcessWidgetRotateStart(vtkMRMLInteractionEventData* eventData)
{
if ((this->WidgetState != vtkSlicerMarkupsWidget::WidgetStateOnWidget && this->WidgetState != vtkSlicerMarkupsWidget::WidgetStateOnRotationHandle)
|| this->IsAnyControlPointLocked())
if ((this->WidgetState != vtkSlicerMarkupsWidget::WidgetStateOnWidget && this->WidgetState != vtkSlicerMarkupsWidget::WidgetStateOnRotationHandle))
{
return false;
}
Expand All @@ -171,8 +170,7 @@ bool vtkSlicerMarkupsWidget::ProcessWidgetRotateStart(vtkMRMLInteractionEventDat
//-------------------------------------------------------------------------
bool vtkSlicerMarkupsWidget::ProcessWidgetScaleStart(vtkMRMLInteractionEventData* eventData)
{
if ((this->WidgetState != vtkSlicerMarkupsWidget::WidgetStateOnWidget && this->WidgetState != vtkSlicerMarkupsWidget::WidgetStateOnScaleHandle)
|| this->IsAnyControlPointLocked())
if ((this->WidgetState != vtkSlicerMarkupsWidget::WidgetStateOnWidget && this->WidgetState != vtkSlicerMarkupsWidget::WidgetStateOnScaleHandle))
{
return false;
}
Expand All @@ -185,8 +183,7 @@ bool vtkSlicerMarkupsWidget::ProcessWidgetScaleStart(vtkMRMLInteractionEventData
//-------------------------------------------------------------------------
bool vtkSlicerMarkupsWidget::ProcessWidgetTranslateStart(vtkMRMLInteractionEventData* eventData)
{
if ((this->WidgetState != vtkSlicerMarkupsWidget::WidgetStateOnWidget && this->WidgetState != vtkSlicerMarkupsWidget::WidgetStateOnTranslationHandle)
|| this->IsAnyControlPointLocked())
if ((this->WidgetState != vtkSlicerMarkupsWidget::WidgetStateOnWidget && this->WidgetState != vtkSlicerMarkupsWidget::WidgetStateOnTranslationHandle))
{
return false;
}
Expand Down Expand Up @@ -1179,12 +1176,19 @@ void vtkSlicerMarkupsWidget::TranslateWidget(double eventPos[2])
{
double currentControlPointPosition_World[3] = { 0.0 };
markupsNode->GetNthControlPointPositionWorld(i, currentControlPointPosition_World);

double newControlPointPosition_World[3] = { 0.0 };
translationTransform->TransformPoint(currentControlPointPosition_World, newControlPointPosition_World);
transformedPoints_World->SetPoint(i, newControlPointPosition_World);
if (markupsNode->GetNthControlPointLocked(i))
{
transformedPoints_World->SetPoint(i, currentControlPointPosition_World);
}
else
{
double newControlPointPosition_World[3] = { 0.0 };
translationTransform->TransformPoint(currentControlPointPosition_World, newControlPointPosition_World);
transformedPoints_World->SetPoint(i, newControlPointPosition_World);
}
}
markupsNode->SetControlPointPositionsWorld(transformedPoints_World);
bool setUndefinedPoints = false;
markupsNode->SetControlPointPositionsWorld(transformedPoints_World, setUndefinedPoints);

if (transformedPoints_World->GetNumberOfPoints() == 0)
{
Expand Down Expand Up @@ -1266,13 +1270,21 @@ void vtkSlicerMarkupsWidget::ScaleWidget(double eventPos[2])
for (int i = 0; i < markupsNode->GetNumberOfControlPoints(); i++)
{
markupsNode->GetNthControlPointPositionWorld(i, ref);
for (int j = 0; j < 3; j++)
if (markupsNode->GetNthControlPointLocked(i))
{
worldPos[j] = center[j] + ratio * (ref[j] - center[j]);
transformedPoints_World->SetPoint(i, ref);
}
else
{
for (int j = 0; j < 3; j++)
{
worldPos[j] = center[j] + ratio * (ref[j] - center[j]);
}
transformedPoints_World->SetPoint(i, worldPos);
}
transformedPoints_World->SetPoint(i, worldPos);
}
markupsNode->SetControlPointPositionsWorld(transformedPoints_World);
bool setUndefinedPoints = false;
markupsNode->SetControlPointPositionsWorld(transformedPoints_World, setUndefinedPoints);
}

//----------------------------------------------------------------------
Expand Down Expand Up @@ -1417,12 +1429,19 @@ void vtkSlicerMarkupsWidget::RotateWidget(double eventPos[2])
{
double currentControlPointPosition_World[3] = { 0.0 };
markupsNode->GetNthControlPointPositionWorld(i, currentControlPointPosition_World);

double newControlPointPosition_World[3] = { 0.0 };
rotateTransform->TransformPoint(currentControlPointPosition_World, newControlPointPosition_World);
transformedPoints_World->SetPoint(i, newControlPointPosition_World);
if (markupsNode->GetNthControlPointLocked(i))
{
transformedPoints_World->SetPoint(i, currentControlPointPosition_World);
}
else
{
double newControlPointPosition_World[3] = { 0.0 };
rotateTransform->TransformPoint(currentControlPointPosition_World, newControlPointPosition_World);
transformedPoints_World->SetPoint(i, newControlPointPosition_World);
}
}
markupsNode->SetControlPointPositionsWorld(transformedPoints_World);
bool setUndefinedPoints = false;
markupsNode->SetControlPointPositionsWorld(transformedPoints_World, setUndefinedPoints);
}

//----------------------------------------------------------------------
Expand Down Expand Up @@ -1862,4 +1881,4 @@ vtkMRMLSelectionNode* vtkSlicerMarkupsWidget::selectionNode()
return vtkMRMLSelectionNode::SafeDownCast(
this->GetMarkupsNode()->GetScene()->GetNodeByID("vtkMRMLSelectionNodeSingleton"));

}
}

0 comments on commit 96f85fe

Please sign in to comment.