Skip to content

Commit

Permalink
ENH: Read and use treatment machine state from JSON descriptor file
Browse files Browse the repository at this point in the history
Re #218
  • Loading branch information
cpinter committed Feb 13, 2023
1 parent ab69cf1 commit 5335665
Show file tree
Hide file tree
Showing 2 changed files with 80 additions and 41 deletions.
114 changes: 76 additions & 38 deletions RoomsEyeView/Logic/vtkSlicerRoomsEyeViewModuleLogic.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -252,15 +252,23 @@ vtkMRMLModelNode* vtkSlicerRoomsEyeViewModuleLogic::vtkInternal::EnsureTreatment

std::string partName = this->GetTreatmentMachinePartModelName(parameterNode, partType);
vtkMRMLModelNode* partModelNode = this->GetTreatmentMachinePartModelNode(parameterNode, partType);
if (partModelNode && !partModelNode->GetPolyData())
{
//TODO: Block added for old singleton case, remove if never called
// Remove node if contains empty polydata (e.g. after closing scene), so that it can be loaded again
scene->RemoveNode(partModelNode);
partModelNode = nullptr;
}
if (!partModelNode)
{
// Skip model if state is disabled and part is optional
std::string state = this->External->GetStateForPartType(this->External->GetTreatmentMachinePartTypeAsString(partType));
if (state == "Disabled")
{
if (optional)
{
return nullptr;
}
else
{
vtkWarningWithObjectMacro(this->External, "LoadTreatmentMachine: State for part "
<< partName << " is set to Disabled but the part is mandatory. Loading anyway.");
}
}
// Get model file path
std::string partModelFilePath = this->External->GetFilePathForPartType(
this->External->GetTreatmentMachinePartTypeAsString(partType));
if (partModelFilePath == "")
Expand All @@ -272,6 +280,7 @@ vtkMRMLModelNode* vtkSlicerRoomsEyeViewModuleLogic::vtkInternal::EnsureTreatment
}
return nullptr;
}
// Load model from file
partModelFilePath = this->GetTreatmentMachinePartFullFilePath(parameterNode, partModelFilePath);
if (vtksys::SystemTools::FileExists(partModelFilePath))
{
Expand Down Expand Up @@ -498,7 +507,7 @@ void vtkSlicerRoomsEyeViewModuleLogic::LoadTreatmentMachine(vtkMRMLRoomsEyeViewN
// Table top - mandatory
this->Internal->EnsureTreatmentMachinePartModelNode(parameterNode, TableTop);
// Linac body - optional
this->Internal->EnsureTreatmentMachinePartModelNode(parameterNode, Body);
this->Internal->EnsureTreatmentMachinePartModelNode(parameterNode, Body, true);
// Imaging panel left - optional
this->Internal->EnsureTreatmentMachinePartModelNode(parameterNode, ImagingPanelLeft, true);
// Imaging panel right - optional
Expand Down Expand Up @@ -1389,30 +1398,45 @@ std::string vtkSlicerRoomsEyeViewModuleLogic::CheckForCollisions(vtkMRMLRoomsEye
return statusString;
}

// Get states of the treatment machine parts involved
std::string collimatorState = this->GetStateForPartType(this->GetTreatmentMachinePartTypeAsString(Collimator));
std::string gantryState = this->GetStateForPartType(this->GetTreatmentMachinePartTypeAsString(Gantry));
std::string patientSupportState = this->GetStateForPartType(this->GetTreatmentMachinePartTypeAsString(PatientSupport));
std::string tableTopState = this->GetStateForPartType(this->GetTreatmentMachinePartTypeAsString(TableTop));

// If number of contacts between pieces of treatment room is greater than 0, the collision between which pieces
// will be set to the output string and returned by the function.
this->GantryTableTopCollisionDetection->SetTransform(0, vtkLinearTransform::SafeDownCast(gantryToRasTransform));
this->GantryTableTopCollisionDetection->SetTransform(1, vtkLinearTransform::SafeDownCast(tableTopToRasTransform));
this->GantryTableTopCollisionDetection->Update();
if (this->GantryTableTopCollisionDetection->GetNumberOfContacts() > 0)
if (gantryState == "Active" && tableTopState == "Active")
{
statusString = statusString + "Collision between gantry and table top\n";
this->GantryTableTopCollisionDetection->SetTransform(0, vtkLinearTransform::SafeDownCast(gantryToRasTransform));
this->GantryTableTopCollisionDetection->SetTransform(1, vtkLinearTransform::SafeDownCast(tableTopToRasTransform));
this->GantryTableTopCollisionDetection->Update();
if (this->GantryTableTopCollisionDetection->GetNumberOfContacts() > 0)
{
statusString = statusString + "Collision between gantry and table top\n";
}
}

this->GantryPatientSupportCollisionDetection->SetTransform(0, vtkLinearTransform::SafeDownCast(gantryToRasTransform));
this->GantryPatientSupportCollisionDetection->SetTransform(1, vtkLinearTransform::SafeDownCast(patientSupportToRasTransform));
this->GantryPatientSupportCollisionDetection->Update();
if (this->GantryPatientSupportCollisionDetection->GetNumberOfContacts() > 0)
if (gantryState == "Active" && patientSupportState == "Active")
{
statusString = statusString + "Collision between gantry and patient support\n";
this->GantryPatientSupportCollisionDetection->SetTransform(0, vtkLinearTransform::SafeDownCast(gantryToRasTransform));
this->GantryPatientSupportCollisionDetection->SetTransform(1, vtkLinearTransform::SafeDownCast(patientSupportToRasTransform));
this->GantryPatientSupportCollisionDetection->Update();
if (this->GantryPatientSupportCollisionDetection->GetNumberOfContacts() > 0)
{
statusString = statusString + "Collision between gantry and patient support\n";
}
}

this->CollimatorTableTopCollisionDetection->SetTransform(0, vtkLinearTransform::SafeDownCast(collimatorToRasTransform));
this->CollimatorTableTopCollisionDetection->SetTransform(1, vtkLinearTransform::SafeDownCast(tableTopToRasTransform));
this->CollimatorTableTopCollisionDetection->Update();
if (this->CollimatorTableTopCollisionDetection->GetNumberOfContacts() > 0)
if (collimatorState == "Active" && tableTopState == "Active")
{
statusString = statusString + "Collision between collimator and table top\n";
this->CollimatorTableTopCollisionDetection->SetTransform(0, vtkLinearTransform::SafeDownCast(collimatorToRasTransform));
this->CollimatorTableTopCollisionDetection->SetTransform(1, vtkLinearTransform::SafeDownCast(tableTopToRasTransform));
this->CollimatorTableTopCollisionDetection->Update();
if (this->CollimatorTableTopCollisionDetection->GetNumberOfContacts() > 0)
{
statusString = statusString + "Collision between collimator and table top\n";
}
}

//TODO: Collision detection is disabled for additional devices, see SetupTreatmentMachineModels
Expand All @@ -1432,20 +1456,26 @@ std::string vtkSlicerRoomsEyeViewModuleLogic::CheckForCollisions(vtkMRMLRoomsEye
vtkNew<vtkPolyData> patientBodyPolyData;
if (this->GetPatientBodyPolyData(parameterNode, patientBodyPolyData))
{
this->GantryPatientCollisionDetection->SetInputData(1, patientBodyPolyData);
this->GantryPatientCollisionDetection->SetTransform(0, vtkLinearTransform::SafeDownCast(gantryToRasTransform));
this->GantryPatientCollisionDetection->Update();
if (this->GantryPatientCollisionDetection->GetNumberOfContacts() > 0)
if (gantryState == "Active")
{
statusString = statusString + "Collision between gantry and patient\n";
this->GantryPatientCollisionDetection->SetInputData(1, patientBodyPolyData);
this->GantryPatientCollisionDetection->SetTransform(0, vtkLinearTransform::SafeDownCast(gantryToRasTransform));
this->GantryPatientCollisionDetection->Update();
if (this->GantryPatientCollisionDetection->GetNumberOfContacts() > 0)
{
statusString = statusString + "Collision between gantry and patient\n";
}
}

this->CollimatorPatientCollisionDetection->SetInputData(1, patientBodyPolyData);
this->CollimatorPatientCollisionDetection->SetTransform(0, vtkLinearTransform::SafeDownCast(collimatorToRasTransform));
this->CollimatorPatientCollisionDetection->Update();
if (this->CollimatorPatientCollisionDetection->GetNumberOfContacts() > 0)
if (collimatorState == "Active")
{
statusString = statusString + "Collision between collimator and patient\n";
this->CollimatorPatientCollisionDetection->SetInputData(1, patientBodyPolyData);
this->CollimatorPatientCollisionDetection->SetTransform(0, vtkLinearTransform::SafeDownCast(collimatorToRasTransform));
this->CollimatorPatientCollisionDetection->Update();
if (this->CollimatorPatientCollisionDetection->GetNumberOfContacts() > 0)
{
statusString = statusString + "Collision between collimator and patient\n";
}
}
}

Expand Down Expand Up @@ -1578,7 +1608,7 @@ vtkVector3d vtkSlicerRoomsEyeViewModuleLogic::GetColorForPartType(std::string pa
}

//---------------------------------------------------------------------------
bool vtkSlicerRoomsEyeViewModuleLogic::GetEnabledStateForPartType(std::string partType)
std::string vtkSlicerRoomsEyeViewModuleLogic::GetStateForPartType(std::string partType)
{
rapidjson::Value& partObject = this->Internal->GetTreatmentMachinePart(partType);
if (partObject.IsNull())
Expand All @@ -1587,12 +1617,20 @@ bool vtkSlicerRoomsEyeViewModuleLogic::GetEnabledStateForPartType(std::string pa
return "";
}

rapidjson::Value& enabled = partObject["Enabled"];
if (!enabled.IsBool())
rapidjson::Value& state = partObject["State"];
if (!state.IsString())
{
vtkErrorMacro("GetStateForPartType: Invalid treatment machine state value type for part " << partType);
return "";
}

std::string stateStr(state.GetString());
if (state != "Disabled" && state != "Active" && state != "Passive")
{
vtkErrorMacro("GetEnabledStateForPartType: Invalid treatment machine enabled state for part " << partType);
vtkErrorMacro("GetStateForPartType: Invalid treatment machine state for part " << partType
<< ". Valid states are Disabled, Active, or Passive.");
return "";
}

return enabled.GetBool();
return stateStr;
}
7 changes: 4 additions & 3 deletions RoomsEyeView/Logic/vtkSlicerRoomsEyeViewModuleLogic.h
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,11 @@ class VTK_SLICER_ROOMSEYEVIEW_LOGIC_EXPORT vtkSlicerRoomsEyeViewModuleLogic :
/// \param fileToPartTransformMatrix Output file to RAS
/// \return Success flag
bool GetFileToRASTransformMatrixForPartType(std::string partType, vtkMatrix4x4* fileToPartTransformMatrix);
/// Get part name for part type in the currently loaded treatment machine description
/// Get color for part type in the currently loaded treatment machine description
vtkVector3d GetColorForPartType(std::string partType);
/// Get part name for part type in the currently loaded treatment machine description
bool GetEnabledStateForPartType(std::string partType);
/// Get state for part type in the currently loaded treatment machine description.
/// Valid states are "Disabled" (not loaded), "Active" (loaded and collisions computed), "Passive" (loaded but no collisions).
std::string GetStateForPartType(std::string partType);

// Set/get methods
public:
Expand Down

0 comments on commit 5335665

Please sign in to comment.