diff --git a/Beams/MRML/vtkMRMLRTBeamNode.cxx b/Beams/MRML/vtkMRMLRTBeamNode.cxx index 9a086b022..1c02e2ae7 100644 --- a/Beams/MRML/vtkMRMLRTBeamNode.cxx +++ b/Beams/MRML/vtkMRMLRTBeamNode.cxx @@ -47,6 +47,7 @@ #include #include #include +#include //------------------------------------------------------------------------------ const char* vtkMRMLRTBeamNode::NEW_BEAM_NODE_NAME_PREFIX = "NewBeam_"; @@ -515,10 +516,10 @@ void vtkMRMLRTBeamNode::CreateBeamPolyData(vtkPolyData* beamModelPolyData/*=null vtkErrorMacro("CreateBeamPolyData: Invalid beam node"); return; } - + vtkMRMLTableNode* mlcTableNode = nullptr; - vtkIdType nofLeaves = 0; + vtkIdType nofLeafPairs = 0; // MLC boundary data vtkMRMLDoubleArrayNode* arrayNode = this->GetMLCBoundaryDoubleArrayNode(); @@ -526,16 +527,16 @@ void vtkMRMLRTBeamNode::CreateBeamPolyData(vtkPolyData* beamModelPolyData/*=null if (arrayNode) { mlcBoundArray = arrayNode->GetArray(); - nofLeaves = mlcBoundArray ? (mlcBoundArray->GetNumberOfTuples() - 1) : 0; + nofLeafPairs = mlcBoundArray ? (mlcBoundArray->GetNumberOfTuples() - 1) : 0; } // MLC position data - if (nofLeaves) + if (nofLeafPairs) { mlcTableNode = this->GetMLCPositionTableNode(); - if (mlcTableNode && (mlcTableNode->GetNumberOfRows() == nofLeaves)) + if (mlcTableNode && (mlcTableNode->GetNumberOfRows() == nofLeafPairs)) { - vtkDebugMacro("CreateBeamPolyData: Valid MLC nodes, number of leaves: " << nofLeaves); + vtkDebugMacro("CreateBeamPolyData: Valid MLC nodes, number of leaf pairs: " << nofLeafPairs); } else { @@ -558,13 +559,13 @@ void vtkMRMLRTBeamNode::CreateBeamPolyData(vtkPolyData* beamModelPolyData/*=null bool typeMLCY = !strncmp( "MLCY", mlcName, strlen("MLCY")); // copy MLC data for easier processing - for ( vtkIdType leaf = 0; leaf < nofLeaves; leaf++) + for ( vtkIdType leafPair = 0; leafPair < nofLeafPairs; leafPair++) { vtkTable* table = mlcTableNode->GetTable(); - double boundBegin = mlcBoundArray->GetTuple1(leaf); - double boundEnd = mlcBoundArray->GetTuple1(leaf + 1); - double pos1 = table->GetValue( leaf, 0).ToDouble(); - double pos2 = table->GetValue( leaf, 1).ToDouble(); + double boundBegin = mlcBoundArray->GetTuple1(leafPair); + double boundEnd = mlcBoundArray->GetTuple1(leafPair + 1); + double pos1 = table->GetValue( leafPair, 0).ToDouble(); + double pos2 = table->GetValue( leafPair, 1).ToDouble(); mlc.push_back({ boundBegin, boundEnd, pos1, pos2 }); } @@ -737,10 +738,78 @@ void vtkMRMLRTBeamNode::CreateBeamPolyData(vtkPolyData* beamModelPolyData/*=null } //--------------------------------------------------------------------------- -vtkPolyData* vtkMRMLRTBeamNode::CreateMultiLeafCollimatorPolyData() +vtkPolyData* vtkMRMLRTBeamNode::CreateMultiLeafCollimatorModelPolyData() { - //TODO: Create beam limiting device poly data here - return nullptr; + vtkIdType nofLeafPairs = 0; + // MLC boundary data + vtkMRMLDoubleArrayNode* arrayNode = this->GetMLCBoundaryDoubleArrayNode(); + vtkDoubleArray* mlcBoundArray = nullptr; + if (arrayNode) + { + mlcBoundArray = arrayNode->GetArray(); + nofLeafPairs = mlcBoundArray ? (mlcBoundArray->GetNumberOfTuples() - 1) : 0; + } + + // MLC position data + vtkMRMLTableNode* mlcTableNode = nullptr; + if (nofLeafPairs) + { + mlcTableNode = this->GetMLCPositionTableNode(); + if (mlcTableNode && (mlcTableNode->GetNumberOfRows() == nofLeafPairs)) + { + vtkDebugMacro("CreateMultiLeafCollimatorPolyData: Valid MLC nodes, number of leaf pairs: " << nofLeafPairs); + } + else + { + vtkErrorMacro("CreateMultiLeafCollimatorPolyData: Invalid MLC nodes, or " \ + "number of MLC boundaries and positions are different"); + mlcTableNode = nullptr; + } + } + + // Check that we have MLC + // append a leaf pair to form MLC polydata + double isoCenterToMLCDistance = this->SAD - SourceToMultiLeafCollimatorDistance; + auto append = vtkSmartPointer::New(); + if (mlcTableNode) + { + const char* mlcName = mlcTableNode->GetName(); + bool typeMLCX = !strncmp( "MLCX", mlcName, strlen("MLCX")); + bool typeMLCY = !strncmp( "MLCY", mlcName, strlen("MLCY")); + + // create polydata for a leaf pair + for ( vtkIdType leafPair = 0; leafPair < nofLeafPairs; leafPair++) + { + vtkTable* table = mlcTableNode->GetTable(); + double boundBegin = mlcBoundArray->GetTuple1(leafPair); + double boundEnd = mlcBoundArray->GetTuple1(leafPair + 1); + double pos1 = table->GetValue( leafPair, 0).ToDouble(); + double pos2 = table->GetValue( leafPair, 1).ToDouble(); + + auto leaf1 = vtkSmartPointer::New(); + auto leaf2 = vtkSmartPointer::New(); + if (typeMLCX) + { + leaf1->SetBounds( pos1 - 20., pos1, boundBegin, BoundEnd, -isoCenterToMLCDistance, isoCenterToMLCDistance); + leaf2->SetBounds( pos2, pos2 + 20., boundBegin, BoundEnd, -isoCenterToMLCDistance, isoCenterToMLCDistance); + } + else if (typeMLCY) + { + leaf1->SetBounds( boundBegin, BoundEnd, pos1 - 20., pos1, -isoCenterToMLCDistance, isoCenterToMLCDistance); + leaf2->SetBounds( boundBegin, BoundEnd, pos2, pos2 + 20., -isoCenterToMLCDistance, isoCenterToMLCDistance); + } + leaf1->Update(); + leaf2->Update(); + append->AddInputData(leaf1->GetOutput()); + append->AddInputData(leaf2->GetOutput()); + } + } + append->Update(); + + vtkPolyData* mlcModelPolyData = vtkPolyData::New(); + mlcModelPolyData->ShallowCopy(append->GetOutput()); + + return mlcModelPolyData; } //--------------------------------------------------------------------------- diff --git a/Beams/MRML/vtkMRMLRTBeamNode.h b/Beams/MRML/vtkMRMLRTBeamNode.h index edec76d7c..80aca8948 100644 --- a/Beams/MRML/vtkMRMLRTBeamNode.h +++ b/Beams/MRML/vtkMRMLRTBeamNode.h @@ -85,7 +85,7 @@ class VTK_SLICER_BEAMS_MODULE_MRML_EXPORT vtkMRMLRTBeamNode : public vtkMRMLMode virtual void CreateDefaultTransformNode(); /// Create beam limiting device (MLC and jaws) polydata for model node - virtual vtkPolyData* CreateMultiLeafCollimatorPolyData(); + virtual vtkPolyData* CreateMultiLeafCollimatorModelPolyData(); /// Create transform node that places the beam poly data in the right position based on geometry. /// Always creates a new transform node. diff --git a/Beams/MRML/vtkMRMLRTIonBeamNode.cxx b/Beams/MRML/vtkMRMLRTIonBeamNode.cxx index ae919028a..a2edff435 100644 --- a/Beams/MRML/vtkMRMLRTIonBeamNode.cxx +++ b/Beams/MRML/vtkMRMLRTIonBeamNode.cxx @@ -234,7 +234,7 @@ void vtkMRMLRTIonBeamNode::CreateNewBeamTransformNode() } //--------------------------------------------------------------------------- -vtkPolyData* vtkMRMLRTIonBeamNode::CreateMultiLeafCollimatorPolyData() +vtkPolyData* vtkMRMLRTIonBeamNode::CreateMultiLeafCollimatorModelPolyData() { //TODO: Create beam limiting device poly data here return nullptr; diff --git a/Beams/MRML/vtkMRMLRTIonBeamNode.h b/Beams/MRML/vtkMRMLRTIonBeamNode.h index 5589dab11..0fbd5d1e7 100644 --- a/Beams/MRML/vtkMRMLRTIonBeamNode.h +++ b/Beams/MRML/vtkMRMLRTIonBeamNode.h @@ -63,7 +63,7 @@ class VTK_SLICER_BEAMS_MODULE_MRML_EXPORT vtkMRMLRTIonBeamNode : public vtkMRMLR void CreateDefaultTransformNode() override; /// Create beam limiting device (MLC and jaws) polydata for model node - vtkPolyData* CreateMultiLeafCollimatorPolyData() override; + vtkPolyData* CreateMultiLeafCollimatorModelPolyData() override; /// Create transform node that places the beam poly data in the right position based on geometry. /// Always creates a new transform node.