diff --git a/BoneReconstructionPlanner/BoneReconstructionPlanner.py b/BoneReconstructionPlanner/BoneReconstructionPlanner.py index 1d30611..457dc97 100644 --- a/BoneReconstructionPlanner/BoneReconstructionPlanner.py +++ b/BoneReconstructionPlanner/BoneReconstructionPlanner.py @@ -250,12 +250,15 @@ def setup(self): ) updateVSPButtonsLayout = self.ui.updateVSPButtonsFrame.layout() - updateVSPButtonsLayout.setWidget(0, 0, generateFibulaPlanesFibulaBonePiecesAndTransformThemToMandibleButton) + updateVSPButtonsLayout.insertWidget(0, generateFibulaPlanesFibulaBonePiecesAndTransformThemToMandibleButton) self.ui.generateFibulaPlanesFibulaBonePiecesAndTransformThemToMandibleButton = generateFibulaPlanesFibulaBonePiecesAndTransformThemToMandibleButton recycleIconPath = os.path.join(os.path.dirname(__file__), 'Resources/Icons/recycle_48.svg') self.ui.hardVSPUpdateButton.setIcon(qt.QIcon(recycleIconPath)) + + lockIconPath = os.path.join(os.path.dirname(__file__), 'Resources/Icons/lock_48.svg') + self.ui.lockVSPButton.setIcon(qt.QIcon(lockIconPath)) booleanOperationsIconPath = os.path.join(os.path.dirname(__file__), 'Resources/Icons/construction_48.svg') self.ui.create3DModelOfTheReconstructionButton.setIcon(qt.QIcon(booleanOperationsIconPath)) @@ -350,6 +353,7 @@ def setup(self): self.ui.createPlateCurveButton.connect('clicked(bool)', self.onCreatePlateCurveButton) self.ui.createCustomPlateButton.connect('clicked(bool)', self.onCreateCustomPlateButton) self.ui.hardVSPUpdateButton.connect('clicked(bool)', self.onHardVSPUpdateButton) + self.ui.lockVSPButton.connect('toggled(bool)', self.onLockVSPButton) self.ui.makeAllMandiblePlanesRotateTogetherCheckBox.connect('stateChanged(int)', self.updateParameterNodeFromGUI) self.ui.useMoreExactVersionOfPositioningAlgorithmCheckBox.connect('stateChanged(int)', self.updateParameterNodeFromGUI) self.ui.useNonDecimatedBoneModelsForPreviewCheckBox.connect('stateChanged(int)', self.updateParameterNodeFromGUI) @@ -671,6 +675,37 @@ def updateGUIFromParameterNode(self, caller=None, event=None): self.ui.customTitaniumPlateGenerationCollapsibleButton.hide() + shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene) + mandibularPlanesFolder = shNode.GetItemByName("Mandibular planes") + mandibularPlanesList = createListFromFolderID(mandibularPlanesFolder) + if self._parameterNode.GetParameter("lockVSP") == "True": + self.logic.setInteractiveHandlesVisibilityOfMarkups( + mandibularPlanesList, + visibility=False + ) + self.logic.setMarkupsListLocked(mandibularPlanesList,locked=True) + self.logic.removeMandiblePlaneObservers() + # + self.ui.lockVSPButton.checked = True + self.ui.parametersOfVSPFrame.enabled = False + self.ui.updateVSPButtonsFrame.enabled = False + self.ui.create3DModelOfTheReconstructionButton.enabled = False + + else: + self.logic.setInteractiveHandlesVisibilityOfMarkups( + mandibularPlanesList, + visibility=True + ) + self.logic.setMarkupsListLocked(mandibularPlanesList,locked=False) + self.logic.removeMandiblePlaneObservers() # in case they already exist + self.logic.addMandiblePlaneObservers() + # + self.ui.lockVSPButton.checked = False + self.ui.parametersOfVSPFrame.enabled = True + self.ui.updateVSPButtonsFrame.enabled = True + self.ui.create3DModelOfTheReconstructionButton.enabled = True + + if self._parameterNode.GetParameter("updateOnMandiblePlanesMovement") == "True": self.ui.generateFibulaPlanesFibulaBonePiecesAndTransformThemToMandibleButton.checkState = 2 else: @@ -924,6 +959,9 @@ def onCenterFibulaLineButton(self): def onHardVSPUpdateButton(self): self.logic.hardVSPUpdate() + + def onLockVSPButton(self,checked): + self.logic.lockVSP(checked) def setBiggerSawBoxesInteractionHandlesVisibility(self, visibility): shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene) @@ -1037,6 +1075,8 @@ def setDefaultParameters(self, parameterNode): parameterNode.SetParameter("showBiggerSawBoxesInteractionHandles","False") if not parameterNode.GetParameter("showMandiblePlanesInteractionHandles"): parameterNode.SetParameter("showMandiblePlanesInteractionHandles","True") + if not parameterNode.GetParameter("lockVSP"): + parameterNode.SetParameter("lockVSP","False") def getParentFolderItemID(self): shNode = slicer.vtkMRMLSubjectHierarchyNode.GetSubjectHierarchyNode(slicer.mrmlScene) @@ -1228,6 +1268,12 @@ def onPlaneModifiedTimer(self,sourceNode,event): self.generateFibulaPlanesTimer.start() def onGenerateFibulaPlanesTimerTimeout(self): + parameterNode = self.getParameterNode() + lockVSPChecked = parameterNode.GetParameter("lockVSP") == "True" + if lockVSPChecked: + logging.info('VSP updates are locked. Please set "lockVSP" parameter to "False".') + return + import time startTime = time.time() logging.info('Processing started') @@ -2136,6 +2182,10 @@ def hardVSPUpdate(self): self.resetPlan() self.onGenerateFibulaPlanesTimerTimeout() + def lockVSP(self, doLock): + parameterNode = self.getParameterNode() + parameterNode.SetParameter("lockVSP", str(doLock)) + def generateFibulaPlanesFibulaBonePiecesAndTransformThemToMandible(self): parameterNode = self.getParameterNode() useNonDecimatedBoneModelsForPreviewChecked = parameterNode.GetParameter("useNonDecimatedBoneModelsForPreview") == "True" diff --git a/BoneReconstructionPlanner/Resources/Icons/lock_48.svg b/BoneReconstructionPlanner/Resources/Icons/lock_48.svg new file mode 100644 index 0000000..4c1938b --- /dev/null +++ b/BoneReconstructionPlanner/Resources/Icons/lock_48.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/BoneReconstructionPlanner/Resources/UI/BoneReconstructionPlanner.ui b/BoneReconstructionPlanner/Resources/UI/BoneReconstructionPlanner.ui index b500c77..768ae8d 100644 --- a/BoneReconstructionPlanner/Resources/UI/BoneReconstructionPlanner.ui +++ b/BoneReconstructionPlanner/Resources/UI/BoneReconstructionPlanner.ui @@ -6,8 +6,8 @@ 0 0 - 642 - 3288 + 686 + 3625 @@ -18,445 +18,552 @@ - - - Qt::AlignCenter - - - 0 - - - - - Current Scalar Volume - - - - - - - true - - - - vtkMRMLScalarVolumeNode - - - - false - - - false - - - - - - - Right side leg - - - - - - - (tick if fibula is the one from the right leg) - - - false - - - - - - - Select mandibular segmentation - - - - - - - true - - - - vtkMRMLSegmentationNode - - - - false - - - false - - - - - - - Select fibula segmentation - - - - - - - true - - - - vtkMRMLSegmentationNode - - - - false - - - false - - - - - - - Place mandibular curve - - - Qt::AlignCenter - - - - - - - Add mandibular curve - - - - - - - Place fibula line - - - Qt::AlignCenter - - - - - - - Add fibula line - - - - - - - Place mandibular planes - - - - - - - Add cut plane - - - - - - - Initial space (mm) - - - - - - - 1 - - - - - - - Intersection distance multiplier - - - - - - - 1 - - - 30.000000000000000 - - - 0.100000000000000 - - - 1.000000000000000 - - - - - - - Between space (mm) - - - - - - - 1 - - - 1.000000000000000 - - - - - - - Security margin (mm) - - - - - - - 1 - - - 30.000000000000000 - - - 0.100000000000000 - - - 1.000000000000000 - - - - - - - Select mandible curve - - - - - - - true - - - - vtkMRMLMarkupsCurveNode - - - - false - - - false - - - - - - - Select fibula line - - - - - - - true - - - - vtkMRMLMarkupsLineNode - - - - false - - - false - - - - - - - - - Create bone models from segmentations - - - - - - - Center fibula line using fibula model - - - - - - - Show mandible planes interaction handles - - - - - - - Show original mandible model + + + + 0 + 0 + - - - - - - 0 + + QFrame::NoFrame - - 0 + + QFrame::Plain - - - - Show fibula segments lengths - - - - - - - - 0 - 0 - - - - Fibula segment measurement mode. Needs update - - - QComboBox::AdjustToMinimumContentsLength - - - - center2center + + + + + 0 + + + 0 - - + + + + Current Scalar Volume + + + + + + + true + + + + vtkMRMLScalarVolumeNode + + + + false + + + false + + + + + + + Right side leg + + + + + + + (tick if fibula is the one from the right leg) + + + false + + + + + + + Select mandibular segmentation + + + + + + + true + + + + vtkMRMLSegmentationNode + + + + false + + + false + + + + + + + Select fibula segmentation + + + + + + + true + + + + vtkMRMLSegmentationNode + + + + false + + + false + + + + + + + Place mandibular curve + + + Qt::AlignCenter + + + + + + + Add mandibular curve + + + + + + + Place fibula line + + + Qt::AlignCenter + + + + + + + Add fibula line + + + + + + + Place mandibular planes + + + + + + + Add cut plane + + + + + + + Initial space (mm) + + + + + + + 1 + + + + + + + Intersection distance multiplier + + + + + + + 1 + + + 30.000000000000000 + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + Between space (mm) + + + + + + + 1 + + + 1.000000000000000 + + + + + + + Security margin (mm) + + + + + + + 1 + + + 30.000000000000000 + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + Select mandible curve + + + + + + + true + + + + vtkMRMLMarkupsCurveNode + + + + false + + + false + + + + + + + Select fibula line + + + + + + + true + + + + vtkMRMLMarkupsLineNode + + + + false + + + false + + + + + + + - proximal2proximal + Create bone models from segmentations - - + + + + - distal2distal + Center fibula line using fibula model - - - - - - - - - 0 - - - 0 - - - - + + + + + + 0 + + + 0 + + + + + Fibula segment lengths measurements + + + + + + + + 0 + 0 + + + + Fibula segment measurement mode. Needs update + + + QComboBox::AdjustToMinimumContentsLength + + + + center2center + + + + + proximal2proximal + + + + + distal2distal + + + + + + + + + + 0 + + + 0 + + + + + + Segmental Mandibulectomy + + + + + Hemimandibulectomy + + + + + + + + + Removing right side + + + + + Removing left side + + + + + + + + + + + + + - Segmental Mandibulectomy + Automatic mandibular planes positioning for maximum bones contact area - - + + + + - Hemimandibulectomy + Make all mandible planes rotate together + + + + + + + Use when you have finished editing - - - - - - - Removing right side + Use more exact version of the positioning algorithm (takes more time) - - + + + + - Removing left side + Use non-decimated bone models for preview (takes more time) - - + + + + - + Fix cut goes through the mandible twice - - - - - - - - - Automatic mandibular planes positioning for maximum bones contact area - - - - - - - Make all mandible planes rotate together - + + + - - - Use when you have finished editing - - - Use more exact version of the positioning algorithm (takes more time) + + + + 100 + 100 + - - - - - - Use non-decimated bone models for preview (takes more time) + + QFrame::NoFrame - - - - - - Fix cut goes through the mandible twice + + QFrame::Plain + + + + + 0 + + + 0 + + + + + + 0 + 0 + + + + QFrame::NoFrame + + + QFrame::Plain + + + + + + + 0 + 0 + + + + Hard-update (use when normal update does not work correctly) + + + true + + + + + + + + + + + + + QFrame::NoFrame + + + QFrame::Plain + + + + + + + 0 + 0 + + + + Lock updates to VSP + + + + + + true + + + + + + + + + + + + Create 3D model of the reconstruction for 3D printing + + + + - + - 0 - 0 + 100 + 100 @@ -465,36 +572,69 @@ QFrame::Plain - - - - - - 0 - 0 - - - - Hard-update (use when normal update does not work correctly) + + + + + Show mandible planes interaction handles - - true + + + + + + Show original mandible model + + + + - + Show fibula segments lengths + + + + 0 + + + + + Lights rendering: + + + + + + + + Lamp + + + + + Lamp and Shadows + + + + + MultiLamp + + + + + MultiLamp and Shadows + + + + + + - - - - Create 3D model of the reconstruction for 3D printing - - - @@ -952,14 +1092,14 @@ - + Miter box direction line - + false @@ -1426,37 +1566,6 @@ Desing - - - - Lights rendering: - - - - - - - - Lamp - - - - - Lamp and Shadows - - - - - MultiLamp - - - - - MultiLamp and Shadows - - - -