Skip to content

Commit

Permalink
ENH: Use FixedReferenceToRAS to keep table top under patient in Rooms…
Browse files Browse the repository at this point in the history
…EyeView

Re #218
  • Loading branch information
cpinter committed May 17, 2023
1 parent 291c36e commit 23d1f55
Show file tree
Hide file tree
Showing 3 changed files with 58 additions and 41 deletions.
92 changes: 51 additions & 41 deletions RoomsEyeView/Logic/vtkSlicerRoomsEyeViewModuleLogic.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -955,20 +955,27 @@ bool vtkSlicerRoomsEyeViewModuleLogic::GetPatientBodyPolyData(vtkMRMLRoomsEyeVie
}

//----------------------------------------------------------------------------
void vtkSlicerRoomsEyeViewModuleLogic::UpdateCollimatorToGantryTransform(vtkMRMLRoomsEyeViewNode* parameterNode)
void vtkSlicerRoomsEyeViewModuleLogic::UpdateFixedReferenceToRASTransform(vtkMRMLRoomsEyeViewNode* parameterNode)
{
if (!parameterNode)
{
vtkErrorMacro("UpdateFixedReferenceIsocenterToCollimatorRotatedTransform: Invalid parameter set node");
vtkErrorMacro("UpdateFixedReferenceToRASTransform: Invalid parameter set node");
return;
}

vtkMRMLLinearTransformNode* collimatorToGantryTransformNode =
this->IECLogic->GetTransformNodeBetween(vtkSlicerIECTransformLogic::Collimator, vtkSlicerIECTransformLogic::Gantry);
vtkMRMLLinearTransformNode* fixedReferenceToRasTransformNode =
this->IECLogic->GetTransformNodeBetween(vtkSlicerIECTransformLogic::FixedReference, vtkSlicerIECTransformLogic::RAS);

vtkNew<vtkTransform> collimatorToGantryTransform;
collimatorToGantryTransform->RotateZ(parameterNode->GetCollimatorRotationAngle());
collimatorToGantryTransformNode->SetAndObserveTransformToParent(collimatorToGantryTransform);
vtkMRMLLinearTransformNode* patientSupportRotationToFixedReferenceTransformNode =
this->IECLogic->GetTransformNodeBetween(vtkSlicerIECTransformLogic::PatientSupportRotation, vtkSlicerIECTransformLogic::FixedReference);
vtkMRMLLinearTransformNode* tableTopToTableTopEccentricRotationTransformNode =
this->IECLogic->GetTransformNodeBetween(vtkSlicerIECTransformLogic::TableTop, vtkSlicerIECTransformLogic::TableTopEccentricRotation);

vtkNew<vtkTransform> fixedReferenceToRASTransform;
fixedReferenceToRASTransform->Concatenate(vtkTransform::SafeDownCast(tableTopToTableTopEccentricRotationTransformNode->GetTransformFromParent()));
fixedReferenceToRASTransform->Concatenate(vtkTransform::SafeDownCast(patientSupportRotationToFixedReferenceTransformNode->GetTransformFromParent()));

fixedReferenceToRasTransformNode->SetAndObserveTransformToParent(fixedReferenceToRASTransform);
}

//----------------------------------------------------------------------------
Expand All @@ -988,6 +995,23 @@ void vtkSlicerRoomsEyeViewModuleLogic::UpdateGantryToFixedReferenceTransform(vtk
gantryToFixedReferenceTransformNode->SetAndObserveTransformToParent(gantryToFixedReferenceTransform);
}

//----------------------------------------------------------------------------
void vtkSlicerRoomsEyeViewModuleLogic::UpdateCollimatorToGantryTransform(vtkMRMLRoomsEyeViewNode* parameterNode)
{
if (!parameterNode)
{
vtkErrorMacro("UpdateFixedReferenceIsocenterToCollimatorRotatedTransform: Invalid parameter set node");
return;
}

vtkMRMLLinearTransformNode* collimatorToGantryTransformNode =
this->IECLogic->GetTransformNodeBetween(vtkSlicerIECTransformLogic::Collimator, vtkSlicerIECTransformLogic::Gantry);

vtkNew<vtkTransform> collimatorToGantryTransform;
collimatorToGantryTransform->RotateZ(parameterNode->GetCollimatorRotationAngle());
collimatorToGantryTransformNode->SetAndObserveTransformToParent(collimatorToGantryTransform);
}

//-----------------------------------------------------------------------------
void vtkSlicerRoomsEyeViewModuleLogic::UpdateLeftImagingPanelToGantryTransform(vtkMRMLRoomsEyeViewNode* parameterNode)
{
Expand Down Expand Up @@ -1192,52 +1216,38 @@ void vtkSlicerRoomsEyeViewModuleLogic::UpdatePatientSupportToPatientSupportRotat
std::string machineType = this->Internal->GetTreatmentMachineFileNameWithoutExtension(parameterNode);

vtkMRMLModelNode* patientSupportModel = this->Internal->GetTreatmentMachinePartModelNode(parameterNode, PatientSupport);
if (!patientSupportModel)
vtkMRMLModelNode* tableTopModel = this->Internal->GetTreatmentMachinePartModelNode(parameterNode, TableTop);
if (!patientSupportModel || !patientSupportModel->GetPolyData() || !tableTopModel || !tableTopModel->GetPolyData())
{
vtkErrorMacro("UpdatePatientSupportToPatientSupportRotationTransform: Invalid MRML model node");
vtkErrorMacro("UpdatePatientSupportToPatientSupportRotationTransform: Failed to access treatment machine part models");
return;
}
vtkPolyData* patientSupportModelPolyData = patientSupportModel->GetPolyData();

// Get bounds of parts involved in computation
double patientSupportModelBounds[6] = { 0, 0, 0, 0, 0, 0 };
patientSupportModelPolyData->GetBounds(patientSupportModelBounds);
patientSupportModel->GetPolyData()->GetBounds(patientSupportModelBounds);
double tableTopModelBounds[6] = { 0, 0, 0, 0, 0, 0 };
tableTopModel->GetPolyData()->GetBounds(tableTopModelBounds);

// Translation to origin for in-place vertical scaling
vtkNew<vtkTransform> patientSupportRotationToRasTransform;
double patientSupportTranslationToOrigin[3] = { 0, 0, (-1.0) * patientSupportModelBounds[4]}; //TODO: Subtract [1]?
patientSupportRotationToRasTransform->Translate(patientSupportTranslationToOrigin);
vtkNew<vtkTransform> patientSupportScalingTransform;
patientSupportScalingTransform->PostMultiply();
double patientSupportTranslationToOrigin[3] = { 0, 0, (-1.0) * patientSupportModelBounds[4]};
patientSupportScalingTransform->Translate(patientSupportTranslationToOrigin);

// Vertical scaling
// Apply patient support vertical scale
double tableTopDisplacement = parameterNode->GetVerticalTableTopDisplacement();
double tableTopDisplacementScaling = 1.0;
//TODO: Support this from the descriptor JSON file
//char* treatmentMachineType = parameterNode->GetTreatmentMachineType();
//if (treatmentMachineType && !strcmp(treatmentMachineType, "VarianTrueBeamSTx"))
//{
tableTopDisplacementScaling = 0.525;
//}
//else if (treatmentMachineType && !strcmp(treatmentMachineType, "SiemensArtiste"))
//{
// tableTopDisplacementScaling = 0.095;
//}
vtkNew<vtkTransform> rasToScaledRasTransform;
rasToScaledRasTransform->Scale(1, 1,
( ( fabs(patientSupportModelBounds[5]) + tableTopDisplacement*tableTopDisplacementScaling)
/ fabs(patientSupportModelBounds[5]) ) ); //TODO: Subtract [2]?
double newPatientSupportHeight = /*tableTopModelBounds[4] + */patientSupportModelBounds[5] + tableTopDisplacement - patientSupportModelBounds[4];
double originalPatientSupportHeight = patientSupportModelBounds[5] - patientSupportModelBounds[4];
patientSupportScalingTransform->Scale(1.0, 1.0, newPatientSupportHeight / originalPatientSupportHeight);

// Translation back from origin after in-place scaling
vtkNew<vtkTransform> scaledRasToFixedReferenceTransform;
double patientSupportTranslationFromOrigin[3] = { 0, 0, patientSupportModelBounds[4] }; //TODO: Subtract [1]?
scaledRasToFixedReferenceTransform->Translate(patientSupportTranslationFromOrigin);
// Translate back so that the patient support base is at the same height
double patientSupportTranslationFromOrigin[3] = { 0, 0, patientSupportModelBounds[4]};
patientSupportScalingTransform->Translate(patientSupportTranslationFromOrigin);

// Assemble transform and update node
vtkMRMLLinearTransformNode* patientSupportToPatientSupportRotationTransformNode =
this->IECLogic->GetTransformNodeBetween(vtkSlicerIECTransformLogic::PatientSupport, vtkSlicerIECTransformLogic::PatientSupportRotation);
vtkNew<vtkTransform> patientSupportToFixedReferenceTransform;
patientSupportToFixedReferenceTransform->PostMultiply();
patientSupportToFixedReferenceTransform->Concatenate(patientSupportRotationToRasTransform);
patientSupportToFixedReferenceTransform->Concatenate(rasToScaledRasTransform);
patientSupportToFixedReferenceTransform->Concatenate(scaledRasToFixedReferenceTransform);
patientSupportToPatientSupportRotationTransformNode->SetAndObserveTransformToParent(patientSupportToFixedReferenceTransform);
patientSupportToPatientSupportRotationTransformNode->SetAndObserveTransformToParent(patientSupportScalingTransform);
}

//-----------------------------------------------------------------------------
Expand Down
3 changes: 3 additions & 0 deletions RoomsEyeView/Logic/vtkSlicerRoomsEyeViewModuleLogic.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ class VTK_SLICER_ROOMSEYEVIEW_LOGIC_EXPORT vtkSlicerRoomsEyeViewModuleLogic :
/// Create or get transforms taking part in the IEC logic and additional devices, and build the transform hierarchy
void BuildRoomsEyeViewTransformHierarchy();

/// Update FixedReferenceToRAS transform, making sure the patient stays fixed on the table top
void UpdateFixedReferenceToRASTransform(vtkMRMLRoomsEyeViewNode* parameterNode);

/// Update GantryToFixedReference transform based on gantry angle from UI slider
void UpdateGantryToFixedReferenceTransform(vtkMRMLRoomsEyeViewNode* parameterNode);

Expand Down
4 changes: 4 additions & 0 deletions RoomsEyeView/qSlicerRoomsEyeViewModuleWidget.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -589,6 +589,7 @@ void qSlicerRoomsEyeViewModuleWidget::onPatientSupportRotationSliderValueChanged

// Update IEC transform
d->logic()->UpdatePatientSupportRotationToFixedReferenceTransform(paramNode);
d->logic()->UpdateFixedReferenceToRASTransform(paramNode);

// Update beam parameter
vtkMRMLRTBeamNode* beamNode = vtkMRMLRTBeamNode::SafeDownCast(paramNode->GetBeamNode());
Expand Down Expand Up @@ -618,6 +619,7 @@ void qSlicerRoomsEyeViewModuleWidget::onVerticalTableTopDisplacementSliderValueC

d->logic()->UpdatePatientSupportToPatientSupportRotationTransform(paramNode);
d->logic()->UpdateTableTopToTableTopEccentricRotationTransform(paramNode);
d->logic()->UpdateFixedReferenceToRASTransform(paramNode);

this->checkForCollisions();
this->updateTreatmentOrientationMarker();
Expand All @@ -639,6 +641,7 @@ void qSlicerRoomsEyeViewModuleWidget::onLongitudinalTableTopDisplacementSliderVa
paramNode->DisableModifiedEventOff();

d->logic()->UpdateTableTopToTableTopEccentricRotationTransform(paramNode);
d->logic()->UpdateFixedReferenceToRASTransform(paramNode);

this->checkForCollisions();
this->updateTreatmentOrientationMarker();
Expand All @@ -662,6 +665,7 @@ void qSlicerRoomsEyeViewModuleWidget::onLateralTableTopDisplacementSliderValueCh
paramNode->DisableModifiedEventOff();

d->logic()->UpdateTableTopToTableTopEccentricRotationTransform(paramNode);
d->logic()->UpdateFixedReferenceToRASTransform(paramNode);

this->checkForCollisions();
this->updateTreatmentOrientationMarker();
Expand Down

0 comments on commit 23d1f55

Please sign in to comment.