Skip to content

Commit

Permalink
ENH: Disable collision detection for too many triangles and warn user
Browse files Browse the repository at this point in the history
Re #218
  • Loading branch information
cpinter committed Oct 17, 2023
1 parent 0bd7dda commit 47d8eb3
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 6 deletions.
44 changes: 38 additions & 6 deletions RoomsEyeView/Logic/vtkSlicerRoomsEyeViewModuleLogic.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
#include "vtkSlicerIECTransformLogic.h"

// SlicerRT includes
#include "vtkCollisionDetectionFilter.h"
#include "vtkMRMLRTBeamNode.h"

// MRML includes
Expand All @@ -49,6 +48,7 @@

// VTK includes
#include <vtkAppendPolyData.h>
#include "vtkCollisionDetectionFilter.h"
#include <vtkGeneralTransform.h>
#include <vtkMatrix4x4.h>
#include <vtkObjectFactory.h>
Expand All @@ -66,10 +66,10 @@
#include "rapidjson/document.h" // rapidjson's DOM-style API
#include "rapidjson/filereadstream.h"


// Constants
const char* vtkSlicerRoomsEyeViewModuleLogic::ORIENTATION_MARKER_MODEL_NODE_NAME = "RoomsEyeViewOrientationMarker";
const char* vtkSlicerRoomsEyeViewModuleLogic::TREATMENT_MACHINE_DESCRIPTOR_FILE_PATH_ATTRIBUTE_NAME = "TreatmentMachineDescriptorFilePath";
unsigned int vtkSlicerRoomsEyeViewModuleLogic::MAX_TRIANGLE_NUMBER_PRODUCT_FOR_COLLISIONS = 1e10;
//TODO: Add this dynamically to the IEC transform map
static const char* ADDITIONALCOLLIMATORMOUNTEDDEVICES_TO_COLLIMATOR_TRANSFORM_NODE_NAME = "AdditionalCollimatorDevicesToCollimatorTransform";
static rapidjson::Value JSON_EMPTY_VALUE;
Expand Down Expand Up @@ -324,12 +324,19 @@ vtkSlicerRoomsEyeViewModuleLogic::vtkSlicerRoomsEyeViewModuleLogic()
this->IECLogic = vtkSlicerIECTransformLogic::New();

this->GantryPatientCollisionDetection = vtkCollisionDetectionFilter::New();
this->GantryPatientCollisionDetection->SetCollisionModeToFirstContact();
this->GantryTableTopCollisionDetection = vtkCollisionDetectionFilter::New();
this->GantryTableTopCollisionDetection->SetCollisionModeToFirstContact();
this->GantryPatientSupportCollisionDetection = vtkCollisionDetectionFilter::New();
this->GantryPatientSupportCollisionDetection->SetCollisionModeToFirstContact();
this->CollimatorPatientCollisionDetection = vtkCollisionDetectionFilter::New();
this->CollimatorPatientCollisionDetection->SetCollisionModeToFirstContact();
this->CollimatorTableTopCollisionDetection = vtkCollisionDetectionFilter::New();
this->CollimatorTableTopCollisionDetection->SetCollisionModeToFirstContact();
this->AdditionalModelsTableTopCollisionDetection = vtkCollisionDetectionFilter::New();
this->AdditionalModelsTableTopCollisionDetection->SetCollisionModeToFirstContact();
this->AdditionalModelsPatientSupportCollisionDetection = vtkCollisionDetectionFilter::New();
this->AdditionalModelsPatientSupportCollisionDetection->SetCollisionModeToFirstContact();
}

//----------------------------------------------------------------------------
Expand Down Expand Up @@ -537,11 +544,12 @@ vtkSlicerRoomsEyeViewModuleLogic::SetupTreatmentMachineModels(vtkMRMLRoomsEyeVie
}

std::vector<TreatmentMachinePartType> loadedParts;
std::map<TreatmentMachinePartType, unsigned int> loadedPartsNumTriangles;
for (int partIdx=0; partIdx<LastPartType; ++partIdx)
{
std::string partType = this->GetTreatmentMachinePartTypeAsString((TreatmentMachinePartType)partIdx);
vtkMRMLModelNode* partModel = this->Internal->GetTreatmentMachinePartModelNode(parameterNode, (TreatmentMachinePartType)partIdx);
if (!partModel)
if (!partModel || !partModel->GetPolyData())
{
switch (partIdx)
{
Expand All @@ -552,6 +560,7 @@ vtkSlicerRoomsEyeViewModuleLogic::SetupTreatmentMachineModels(vtkMRMLRoomsEyeVie
}

loadedParts.push_back((TreatmentMachinePartType)partIdx);
loadedPartsNumTriangles[(TreatmentMachinePartType)partIdx] = partModel->GetPolyData()->GetNumberOfCells();

// Set color
vtkVector3d partColor(this->GetColorForPartType(partType));
Expand Down Expand Up @@ -639,6 +648,29 @@ vtkSlicerRoomsEyeViewModuleLogic::SetupTreatmentMachineModels(vtkMRMLRoomsEyeVie
//TODO: ApplicatorHolder, ElectronApplicator?
}

// Disable collision detection if product of number of triangles of the two models is above threshold
if (loadedPartsNumTriangles[Gantry] * loadedPartsNumTriangles[TableTop] > MAX_TRIANGLE_NUMBER_PRODUCT_FOR_COLLISIONS)
{
vtkWarningMacro("Collision detection between gantry and table top is disabled due to too many combined triangles (product = "
<< loadedPartsNumTriangles[Gantry] * loadedPartsNumTriangles[TableTop] << ")");
this->GantryTableTopCollisionDetection->SetInputData(0, nullptr);
this->GantryTableTopCollisionDetection->SetInputData(1, nullptr);
}
if (loadedPartsNumTriangles[Gantry] * loadedPartsNumTriangles[PatientSupport] > MAX_TRIANGLE_NUMBER_PRODUCT_FOR_COLLISIONS)
{
vtkWarningMacro("Collision detection between gantry and patient support is disabled due to too many combined triangles (product = "
<< loadedPartsNumTriangles[Gantry] * loadedPartsNumTriangles[PatientSupport] << ")");
this->GantryPatientSupportCollisionDetection->SetInputData(0, nullptr);
this->GantryPatientSupportCollisionDetection->SetInputData(1, nullptr);
}
if (loadedPartsNumTriangles[Collimator] * loadedPartsNumTriangles[TableTop] > MAX_TRIANGLE_NUMBER_PRODUCT_FOR_COLLISIONS)
{
vtkWarningMacro("Collision detection between collimator and table top is disabled due to too many combined triangles (product = "
<< loadedPartsNumTriangles[Collimator] * loadedPartsNumTriangles[TableTop] << ")");
this->CollimatorTableTopCollisionDetection->SetInputData(0, nullptr);
this->CollimatorTableTopCollisionDetection->SetInputData(1, nullptr);
}

// Set identity transform for patient (parent transform is taken into account when getting poly data from segmentation)
vtkNew<vtkTransform> identityTransform;
identityTransform->Identity();
Expand Down Expand Up @@ -1382,7 +1414,7 @@ std::string vtkSlicerRoomsEyeViewModuleLogic::CheckForCollisions(vtkMRMLRoomsEye

// 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.
if (gantryState == "Active" && tableTopState == "Active")
if (gantryState == "Active" && tableTopState == "Active" && this->GantryTableTopCollisionDetection->GetInputData(0))
{
this->GantryTableTopCollisionDetection->SetTransform(0, vtkLinearTransform::SafeDownCast(gantryToRasTransform));
this->GantryTableTopCollisionDetection->SetTransform(1, vtkLinearTransform::SafeDownCast(tableTopToRasTransform));
Expand All @@ -1393,7 +1425,7 @@ std::string vtkSlicerRoomsEyeViewModuleLogic::CheckForCollisions(vtkMRMLRoomsEye
}
}

if (gantryState == "Active" && patientSupportState == "Active")
if (gantryState == "Active" && patientSupportState == "Active" && this->GantryTableTopCollisionDetection->GetInputData(0))
{
this->GantryPatientSupportCollisionDetection->SetTransform(0, vtkLinearTransform::SafeDownCast(gantryToRasTransform));
this->GantryPatientSupportCollisionDetection->SetTransform(1, vtkLinearTransform::SafeDownCast(patientSupportToRasTransform));
Expand All @@ -1404,7 +1436,7 @@ std::string vtkSlicerRoomsEyeViewModuleLogic::CheckForCollisions(vtkMRMLRoomsEye
}
}

if (collimatorState == "Active" && tableTopState == "Active")
if (collimatorState == "Active" && tableTopState == "Active" && this->CollimatorTableTopCollisionDetection->GetInputData(0))
{
this->CollimatorTableTopCollisionDetection->SetTransform(0, vtkLinearTransform::SafeDownCast(collimatorToRasTransform));
this->CollimatorTableTopCollisionDetection->SetTransform(1, vtkLinearTransform::SafeDownCast(tableTopToRasTransform));
Expand Down
1 change: 1 addition & 0 deletions RoomsEyeView/Logic/vtkSlicerRoomsEyeViewModuleLogic.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ class VTK_SLICER_ROOMSEYEVIEW_LOGIC_EXPORT vtkSlicerRoomsEyeViewModuleLogic :

static const char* ORIENTATION_MARKER_MODEL_NODE_NAME;
static const char* TREATMENT_MACHINE_DESCRIPTOR_FILE_PATH_ATTRIBUTE_NAME;
static unsigned int MAX_TRIANGLE_NUMBER_PRODUCT_FOR_COLLISIONS;

public:
static vtkSlicerRoomsEyeViewModuleLogic *New();
Expand Down
25 changes: 25 additions & 0 deletions RoomsEyeView/qSlicerRoomsEyeViewModuleWidget.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@

// VTK includes
#include <vtkCamera.h>
#include "vtkCollisionDetectionFilter.h"
#include <vtkPolyData.h>
#include <vtkMatrix4x4.h>
#include <vtkTransform.h>
Expand Down Expand Up @@ -589,6 +590,30 @@ void qSlicerRoomsEyeViewModuleWidget::onLoadTreatmentMachineButtonClicked()
std::vector<vtkSlicerRoomsEyeViewModuleLogic::TreatmentMachinePartType> loadedParts =
d->logic()->LoadTreatmentMachine(paramNode);

// Warn the user if collision detection is disabled for certain part pairs
QString disabledCollisionDetectionMessage(
"Collision detection has been disabled for the following part pairs due to high triangle numbers:\n\n");
bool collisionDetectionDisabled = false;
if (d->logic()->GetGantryTableTopCollisionDetection()->GetInputData(0) == nullptr)
{
disabledCollisionDetectionMessage.append("Gantry-TableTop\n");
collisionDetectionDisabled = true;
}
if (d->logic()->GetGantryPatientSupportCollisionDetection()->GetInputData(0) == nullptr)
{
disabledCollisionDetectionMessage.append("Gantry-PatientSupport\n");
collisionDetectionDisabled = true;
}
if (d->logic()->GetCollimatorTableTopCollisionDetection()->GetInputData(0) == nullptr)
{
disabledCollisionDetectionMessage.append("Collimator-TableTop\n");
collisionDetectionDisabled = true;
}
if (collisionDetectionDisabled)
{
QMessageBox::warning(this, tr("Collision detection disabled"), disabledCollisionDetectionMessage);
}

// Set treatment machine dependent properties //TODO: Use degrees of freedom from JSON
if (!treatmentMachineType.compare("VarianTrueBeamSTx"))
{
Expand Down

0 comments on commit 47d8eb3

Please sign in to comment.