Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ENH: Initial RTIonPlan and multiple control points support #124

Merged
merged 6 commits into from
Jan 15, 2020

Conversation

MichaelColonel
Copy link
Collaborator

Greetings,

vtkSlicerDicomRtReader class - RTIonPlan support and control points support, some C-like arrays replaced with std::array for easier copy and assign operations. Scan spot position map inital support for modulated scan type of rt ion beam. Fraction module from DICOM is used to check if beams are available.

vtkSlicerDicomRtImportExportModuleLogic class - each control point is represented as a separate beam. Table nodes are set a children of a corresponding beam nodes.

vtkMRMLRTIonBeamNode class is added for ion beam parameters and visualization.

vtkMRMLRTBeamNode multiple visible sections of MLC opening have been added (corvus-6.2.2-phantom example data control point 10 & 11)

I can split this pull request on several parts if its very big.

Copy link
Member

@cpinter cpinter left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Happy new year :) Thanks again for the great work! I left a few comments.

Please also

  • Squash these 47 commits into a single one (or 2-3 commits if they can be cleanly separated) and add descriptive comments in it, explaining in detail what changed and why (for example a line about each original commit, since you made them separately on purpose)
  • Run the automated tests and make sure no new failures happen

Thank you!

namespace
{

typedef std::vector< std::pair< double, double > > PointVector;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please rename variable to something more meaningful (points of what?)

{

typedef std::vector< std::pair< double, double > > PointVector;
typedef std::vector< std::array< double, 4 > > LeafDataVector;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, please don't use the word data, but call it something more informative.

{

typedef std::vector< std::pair< double, double > > PointVector;
typedef std::vector< std::array< double, 4 > > LeafDataVector;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, please don't use the word data, but call it something more informative.

@@ -57,6 +58,155 @@ static const char* MLCPOSITION_REFERENCE_ROLE = "MLCPositionRef";
static const char* DRR_REFERENCE_ROLE = "DRRRef";
static const char* CONTOUR_BEV_REFERENCE_ROLE = "contourBEVRef";

//------------------------------------------------------------------------------
namespace
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do you use a namespace here? It would be much better making this part of the class

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By means of vtkInternal, or just private?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there is no internal class yet, then no need to bother, just private. Otherwise internal please.

}

//----------------------------------------------------------------------------
void vtkMRMLRTIonBeamNode::WriteXML(ostream& of, int nIndent)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I fixed that, not so sure about Copy method though.

this->VSADx = xComponent;
this->VSADy = yComponent;
this->Modified();
this->InvokeCustomModifiedEvent(vtkMRMLRTBeamNode::BeamGeometryModified);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In some places you use Superclass, in others the class name itself. Please make it consistent.

Copy link
Collaborator Author

@MichaelColonel MichaelColonel Jan 6, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be Superclass only for overridden methods and inherited constructor.

Distance(-1.),
NumberOfLeafJawPairs(0)
SourceIsoDistance(400.),
NumberOfPairs(0)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why did you rename this variable to have a less informative name? I'm actually curious, so if it's justifiable then no need to change, but in general we prefer longer but unambiguoug names. Not every reader of the code is an expert in every aspect of RT.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will return previous names.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! You also changed some names to be more informative, so those should be kept (like the SourceIsoDistance)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

SourceIsoDistance parameter has different physical meaning for RTPlan and RTIonPlan but the same DICOM tag (300A,00BA)

  1. For RTPlan its "Source to Beam Limiting Device Distance";
  2. For RTIonPlan its "Isocenter to Beam Limiting Device Distance".

In any case the name of the parameters isn't obvious, but i will keep it.

};

/// Structure storing a treatment compensator parameters associated with beam
class CompensatorEntry
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this class and BlockEntry future work? Since they don't contain anything... In that case please add "//TODO: ..." comments

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will do this.

@@ -103,7 +138,7 @@ class vtkSlicerDicomRtReader::vtkInternal
unsigned int Number;
std::string Name;
std::string Description;
double DisplayColor[3];
std::array< double, 3 > DisplayColor;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe we used a static array because of VTK set/get macros. Is there a good reason to change this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is only one method which use DisplayColor
double* vtkSlicerDicomRtReader::GetRoiDisplayColor(unsigned int internalIndex).
The return value is a pointer, so no difference. Everything else is a DCMTK specific.

No setters to change a display color, within internal elements of the reader.

I that case i had thought it's better to use std::array, rather C array (no copy, assign problems).

I can roll it back, if its required to use C array.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If it's only internal then it's fine like this, thanks!

@@ -182,7 +322,7 @@ class vtkSlicerDicomRtReader::vtkInternal
public:
ChannelEntry()
{
Number = -1;
Number = 0;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please explain why you changed this. -1 is an obvious "uninitialized" state, while 0 is valid, so this changes the way a newly instantiated object can be handled.

@MichaelColonel MichaelColonel force-pushed the ion-plan-support branch 2 times, most recently from bb48371 to 67465ed Compare January 7, 2020 10:09
MichaelColonel pushed a commit to MichaelColonel/SlicerRT that referenced this pull request Jan 7, 2020
@MichaelColonel
Copy link
Collaborator Author

Squashed to 6 commits.

@cpinter
Copy link
Member

cpinter commented Jan 7, 2020

Thank you very much! I'll take a look shortly and integrate.
Please let me know about the automated tests.

MichaelColonel pushed a commit to MichaelColonel/SlicerRT that referenced this pull request Jan 7, 2020
@MichaelColonel
Copy link
Collaborator Author

23 failed out of 70

 12 - py_DicomRtImportTest (Failed)
 18 - vtkSlicerDoseVolumeHistogramModuleLogicTest_EclipseProstate_Base (Failed)
 19 - vtkSlicerDoseVolumeHistogramModuleLogicTest_EclipseProstate_CERR (Failed)
 20 - vtkSlicerDoseVolumeHistogramModuleLogicTest_EclipseEnt_CERR (Failed)
 21 - vtkSlicerDoseVolumeHistogramModuleLogicTest_EclipseProstate_Eclipse (Failed)
 22 - vtkSlicerDoseVolumeHistogramModuleLogicTest_EclipseEnt_Eclipse (Failed)
 23 - vtkSlicerDoseVolumeHistogramModuleLogicTest_EclipseProstate_CERR_AutomaticOversampling (Failed)
 24 - vtkSlicerDoseVolumeHistogramModuleLogicTest_EclipseEnt_CERR_AutomaticOversampling (Failed)
 25 - vtkSlicerDoseVolumeHistogramModuleLogicTest_EclipseProstate_Eclipse_AutomaticOversampling (Failed)
 26 - vtkSlicerDoseVolumeHistogramModuleLogicTest_EclipseEnt_Eclipse_AutomaticOversampling (Failed)
 27 - vtkSlicerDoseVolumeHistogramModuleLogicTest_DoseSurfaceHistogram_EclipseEnt_Base_Inside (Failed)
 28 - vtkSlicerDoseVolumeHistogramModuleLogicTest_DoseSurfaceHistogram_EclipseEnt_Base_Outside (Failed)
 29 - vtkSlicerDoseVolumeHistogramModuleLogicTest_DoseSurfaceHistogram_EclipseProstate_Base_Inside (Failed)
 30 - vtkSlicerDoseVolumeHistogramModuleLogicTest_DoseSurfaceHistogram_EclipseProstate_Base_Outside (Failed)
 37 - vtkSlicerSegmentMorphologyModuleLogicTest_EclipseProstate_Expand (Failed)
 38 - vtkSlicerSegmentMorphologyModuleLogicTest_EclipseProstate_Shrink (Failed)
 39 - vtkSlicerSegmentMorphologyModuleLogicTest_EclipseProstate_Union (Failed)
 40 - vtkSlicerSegmentMorphologyModuleLogicTest_EclipseProstate_Intersect (Failed)
 41 - vtkSlicerSegmentMorphologyModuleLogicTest_EclipseProstate_Subtract (Failed)
 42 - vtkSlicerSegmentMorphologyModuleLogicTest_EclipseProstate_Intersect_ApplyTransform (Failed)
 45 - vtkSlicerSegmentComparisonModuleLogicTest_EclipseProstate_Base (Failed)
 46 - vtkSlicerSegmentComparisonModuleLogicTest_EclipseProstate_SameInput (Failed)
 47 - vtkSlicerSegmentComparisonModuleLogicTest_EclipseProstate_Transformed (Failed)

@MichaelColonel
Copy link
Collaborator Author

MichaelColonel commented Jan 8, 2020

Offtopic question. If i have been needed a MLC visualization like in XiO, should i create a custom node for MLC model, or i could use a beam node?

From this post

@cpinter
Copy link
Member

cpinter commented Jan 9, 2020

23 failed out of 70

Well, those will need to be fixed. I see that these failures are the same as what SlicerRT has had since the end of October. It would be great if the tests could be fixed by the developer team so that you can (after a rebase) see if your changes have broken anything or not.
I added a ticket for this (#125) and contacted the team about it. Please stand by for a bit until we see if you can rebase and try it again soon.

@cpinter
Copy link
Member

cpinter commented Jan 9, 2020

About the XiO question: Is this visualization in the 3D view? If so, then special overlay would be needed to achive the same, which will require substantial work. However, you may not need it in the 3D view, in which case it is a simple slice intersection, which could already work with your changes.
Thoughts @gregsharp @lassoan ?

@MichaelColonel
Copy link
Collaborator Author

The picture (part of it) is taken from SlicerRtData.

@lassoan
Copy link
Member

lassoan commented Jan 9, 2020

About the XiO question: Is this visualization in the 3D view? If so, then special overlay would be needed to achive the same, which will require substantial work. However, you may not need it in the 3D view, in which case it is a simple slice intersection, which could already work with your changes.
Thoughts @gregsharp @lassoan ?

Since it is a beam's eye view, the camera position, orientation, and viewing angle has match the beam parameters and cannot be rotated. Since the camera cannot be rotated and viewing angle cannot be changed, it does not matter if you display the grid as a 2D or 3D actor. In 3D views it is very easy to display 3D (using model nodes), so I would just go with that. If you create a model that contains projection of the collimator leaves (their shadow) then you can use the exact same model in 2D views (as slice intersection) and in 3D view. Another advantage of this approach is that if for some reason the camera gets rotated or any way misaligned with the beam's eye view, it will still be correct (but you'll see 3D beams and not just a 2D grid). In beam's eye 3D views you can choose to disable camera rotation similarly to how it is done for slice views here.

MichaelColonel pushed a commit to MichaelColonel/SlicerRT that referenced this pull request Jan 13, 2020
MichaelColonel pushed a commit to MichaelColonel/SlicerRT that referenced this pull request Jan 13, 2020
MichaelColonel pushed a commit to MichaelColonel/SlicerRT that referenced this pull request Jan 13, 2020
MichaelColonel added a commit to MichaelColonel/SlicerRT that referenced this pull request Jan 13, 2020
@cpinter
Copy link
Member

cpinter commented Jan 13, 2020

@MichaelColonel The problem that made most of the tests fail has been fixed by @Sunderlandkyl, and the dashboard shows only one failing test. So I think if you can build this branch against the latest Slicer and only the same tests fails (py_DicomRtImportTest, which tests importing/loading DICOM but not ion plan obviously - it may be added to it though), then I'll integrate this. Thanks again!

MichaelColonel pushed a commit to MichaelColonel/SlicerRT that referenced this pull request Jan 13, 2020
@MichaelColonel
Copy link
Collaborator Author

MichaelColonel commented Jan 13, 2020

All tests have passed except py_DicomRtImportTest. It failed because number of loaded beam nodes, and total number of nodes in hierarchy had increased (each control point is a separated beam node).

After some minor changes:

  1. self.assertEqual( len( slicer.util.getNodes('vtkMRMLModelHierarchyNode*') ), 11 )
  2. self.assertEqual( shNode.GetNumberOfItems(), 42 )

it also passed.

These changes are not in pull request.

@cpinter
Copy link
Member

cpinter commented Jan 14, 2020

@MichaelColonel you are great :) Now that the tests pass, I'll integrate this change, but not before you give me the green light, because I have seen pushes recently, and not sure if you want to add more improvements.

I'll make the changes in py_DicomRtImportTest and close the related ticket. Thanks again!

@MichaelColonel
Copy link
Collaborator Author

The pull request is ready to be merged, latest pushes were minor API style changes - GetBeamControlPoint* instead of GetControlPoint*.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants