Skip to content

Commit

Permalink
Merge pull request #30 from JEHoctor/dev/issue-4
Browse files Browse the repository at this point in the history
Dev/issue 4
  • Loading branch information
jcfr authored Jun 9, 2020
2 parents 3b91e5f + 0fcbd16 commit 4452401
Show file tree
Hide file tree
Showing 4 changed files with 215 additions and 12 deletions.
1 change: 1 addition & 0 deletions Q3DC/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ set(MODULE_PYTHON_SCRIPTS
set(MODULE_PYTHON_RESOURCES
Resources/Icons/${MODULE_NAME}.png
Resources/UI/${MODULE_NAME}.ui
Resources/Data/base_fiducial_legend.csv
)

#-----------------------------------------------------------------------------
Expand Down
145 changes: 134 additions & 11 deletions Q3DC/Q3DC.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import vtk, qt, ctk, slicer
from slicer.ScriptedLoadableModule import *
from slicer.util import NodeModify
import csv, os
from collections import defaultdict
from pathlib import Path
import json
import time
import math
Expand Down Expand Up @@ -90,6 +93,27 @@ def setup(self):
self.ui.inputLandmarksSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.onLandmarksChanged)
self.ui.landmarkComboBox.connect('currentIndexChanged(QString)', self.UpdateInterface)
self.ui.surfaceDeplacementCheckBox.connect('stateChanged(int)', self.onSurfaceDeplacementStateChanged)

# --------------- anatomical legend --------------
self.suggested_landmarks = self.logic.load_suggested_landmarks()
self.anatomical_legend_space = self.ui.landmarkModifLayout
self.anatomical_radio_buttons_layout = qt.QHBoxLayout()
self.anatomical_legend_space.addLayout(self.anatomical_radio_buttons_layout)
self.init_anatomical_radio_buttons()

self.anatomical_legend = None
self.init_anatomical_legend()
self.anatomical_legend_view = slicer.qMRMLTableView()
self.anatomical_legend_view.setMRMLTableNode(self.anatomical_legend)
self.anatomical_legend_space.addWidget(self.anatomical_legend_view)
self.anatomical_legend_view.show()
self.anatomical_legend_view.setSelectionBehavior(
qt.QAbstractItemView.SelectRows
)
self.anatomical_legend_view.connect('selectionChanged()', self.on_legend_row_selected)

self.anatomical_radio_buttons[0].toggle()

# ----------------- Compute Mid Point -------------
self.ui.landmarkComboBox1.connect('currentIndexChanged(int)', self.UpdateInterface)
self.ui.landmarkComboBox2.connect('currentIndexChanged(int)', self.UpdateInterface)
Expand Down Expand Up @@ -313,6 +337,94 @@ def UpdateInterface(self):
self.ui.fidListComboBoxlineLB.currentNode())
self.logic.UpdateThreeDView(self.ui.landmarkComboBox.currentText)

def init_anatomical_legend(self):
if self.anatomical_legend is None:
for table_node in slicer.mrmlScene.GetNodesByClass('vtkMRMLTableNode'):
if table_node.GetAttribute('Q3DC.is_anatomical_legend') == 'True':
self.anatomical_legend = table_node
if self.anatomical_legend is None:
self.anatomical_legend = slicer.vtkMRMLTableNode()
self.anatomical_legend.SetSaveWithScene(False)
self.anatomical_legend.SetLocked(True)
slicer.mrmlScene.AddNode(self.anatomical_legend)
self.anatomical_legend.SetAttribute('Q3DC.is_anatomical_legend', 'True')

al = self.anatomical_legend
with NodeModify(al):
al.RemoveAllColumns()
al.AddColumn().SetName('Landmark')
al.AddColumn().SetName('Description')
al.SetUseColumnNameAsColumnHeader(True)

def init_anatomical_radio_buttons(self):
self.anatomical_radio_buttons = \
[qt.QRadioButton(region) for region in self.suggested_landmarks.keys()]
for i in range(self.anatomical_radio_buttons_layout.count()-1, -1, -1):
self.anatomical_radio_buttons_layout.itemAt[i].widget().setParent(None)
for radio_button in self.anatomical_radio_buttons:
self.anatomical_radio_buttons_layout.addWidget(radio_button)
radio_button.toggled.connect(
lambda state, _radio_button=radio_button:
self.on_anatomical_radio_button_toggled(state, _radio_button)
)

def on_anatomical_radio_button_toggled(self, state, radio_button):
if state:
self.init_anatomical_legend()
region = radio_button.text

al = self.anatomical_legend
with NodeModify(al):
for landmark, description in self.suggested_landmarks[region]:
new_row_index = al.AddEmptyRow()
al.SetCellText(new_row_index, 0, landmark)
al.SetCellText(new_row_index, 1, description)
self.anatomical_legend_view.resizeColumnsToContents()

def on_legend_row_selected(self):
# Calculate the index of the selected point.
fidList = self.logic.selectedFidList
if not fidList:
return
selectedFidReflID = self.logic.findIDFromLabel(
fidList,
self.ui.landmarkComboBox.currentText
)
if selectedFidReflID is None:
# code would run correctly if we continued but wouldn't do anything
return
fid_index = fidList.GetNthControlPointIndexByID(selectedFidReflID)
old_name = fidList.GetNthControlPointLabel(fid_index)

# Look in the legend for the info from the selected row.
selected_indices = self.anatomical_legend_view.selectedIndexes()
if len(selected_indices) != 2:
return
name_index, description_index = selected_indices
row_index = name_index.row()
name = self.anatomical_legend.GetCellText(row_index, 0)
description = self.anatomical_legend.GetCellText(row_index, 1)

# Refuse to create multiple fiducials with the same name.
for i in range(fidList.GetNumberOfControlPoints()):
if name == fidList.GetNthControlPointLabel(i):
return

# Set the name and description of the selected point.
fidList.SetNthControlPointLabel(fid_index, name)
fidList.SetNthControlPointDescription(fid_index, description)

# Update the landmark combo boxes to reflect the name change.
self.logic.updateLandmarkComboBox(fidList, self.ui.landmarkComboBox, False)
self.ui.landmarkComboBox.setCurrentText(name)
for box in (self.ui.landmarkComboBox1, self.ui.landmarkComboBox2):
new_selection = box.currentText
if new_selection == old_name:
new_selection = name
self.logic.updateLandmarkComboBox(fidList, box)
box.setCurrentText(new_selection)
self.UpdateInterface()

def onModelChanged(self):
print("-------Model Changed--------")
if self.logic.selectedModel:
Expand Down Expand Up @@ -541,6 +653,20 @@ def __init__(self, interface):
self.decimalPoint = chr(system.decimalPoint())
self.comboboxdict = dict()

@staticmethod
def load_suggested_landmarks():
suggested_landmarks = defaultdict(list)
suggestions_path = \
Path(__file__).parent / 'Resources' / 'Data' / 'base_fiducial_legend.csv'
with suggestions_path.open(newline='') as suggestions_file:
reader = csv.DictReader(suggestions_file)
for row in reader:
region = row['Region'].title()
landmark = row['Landmark']
name = row['Name']
suggested_landmarks[region].append((landmark, name))
return suggested_landmarks

def initComboboxdict(self):
self.comboboxdict[self.interface.landmarkComboBoxA] = None
self.comboboxdict[self.interface.landmarkComboBoxB] = None
Expand Down Expand Up @@ -1100,14 +1226,12 @@ def deleteLandmark(self, fidList, label):
if value is fidList:
key.removeItem(key.findText(label))

def findIDFromLabel(self, fidList, landmarkLabel):
@staticmethod
def findIDFromLabel(fidList, landmarkLabel):
# find the ID of the markupsNode from the label of a landmark!
landmarkDescription = self.decodeJSON(fidList.GetAttribute("landmarkDescription"))
if not landmarkDescription:
return None
for ID, value in landmarkDescription.items():
if value["landmarkLabel"] == landmarkLabel:
return ID
for i in range(fidList.GetNumberOfFiducials()):
if landmarkLabel == fidList.GetNthFiducialLabel(i):
return fidList.GetNthMarkupID(i)
return None

def getClosestPointIndex(self, fidNode, inputPolyData, landmarkID):
Expand Down Expand Up @@ -1768,10 +1892,9 @@ def displayROI(self, inputModelNode, scalarName):
PolyData.Modified()
displayNode = inputModelNode.GetModelDisplayNode()
displayNode.SetScalarVisibility(False)
disabledModify = displayNode.StartModify()
displayNode.SetActiveScalarName(scalarName)
displayNode.SetScalarVisibility(True)
displayNode.EndModify(disabledModify)
with NodeModify(displayNode):
displayNode.SetActiveScalarName(scalarName)
displayNode.SetScalarVisibility(True)

def findROI(self, fidList):
hardenModel = slicer.app.mrmlScene().GetNodeByID(fidList.GetAttribute("hardenModelID"))
Expand Down
72 changes: 72 additions & 0 deletions Q3DC/Resources/Data/base_fiducial_legend.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
Region,Landmark,Name
CRANIAL BASE,Ba,Basion
CRANIAL BASE,S,Sella
CRANIAL BASE,N,Nasion
NASOMAXILLARY COMPLEX,A,A-point
NASOMAXILLARY COMPLEX,ANS,Anterior Nasal Spine
NASOMAXILLARY COMPLEX,PNS,Posterior Nasal Spine
NASOMAXILLARY COMPLEX,OrR,Right Orbitale
NASOMAXILLARY COMPLEX,OrL,Left Orbitale
NASOMAXILLARY COMPLEX,ZygR,Right Zygomatic
NASOMAXILLARY COMPLEX,ZygL,Left Zygomatic
NASOMAXILLARY COMPLEX,NCR,Right Nasal Cavity
NASOMAXILLARY COMPLEX,NCL,Left Nasal Cavity
NASOMAXILLARY COMPLEX,PFR,Right Palatine Foramen
NASOMAXILLARY COMPLEX,PFL,Left Palatine Foramen
NASOMAXILLARY COMPLEX,IFr,Incisal Foramen
NASOMAXILLARY COMPLEX,UR6,Right Maxillary molar cusp tip
NASOMAXILLARY COMPLEX,UL6,Left Maxillary molar cusp tip
NASOMAXILLARY COMPLEX,UR’6,Right Maxillary molar root apex
NASOMAXILLARY COMPLEX,UL’6,Left Maxillary molar root apex
NASOMAXILLARY COMPLEX,UR6AB,Buccal Alveolar Bone Level at first molar
NASOMAXILLARY COMPLEX,UL6AB,Buccal Alveolar Bone Level at first molar
NASOMAXILLARY COMPLEX,UR5,Right Maxillary 2nd premolar cusp tip
NASOMAXILLARY COMPLEX,UL5,Left Maxillary 2nd premolar cusp tip
NASOMAXILLARY COMPLEX,UR’5,Right Maxillary 2nd premolar root apex
NASOMAXILLARY COMPLEX,UL’5,Left Maxillary 2nd premolar root apex
NASOMAXILLARY COMPLEX,UR4,Right Maxillary 1st premolar cusp tip
NASOMAXILLARY COMPLEX,UL4,Left Maxillary 1st premolar cusp tip
NASOMAXILLARY COMPLEX,UR’4,Right Maxillary 1st premolar root apex
NASOMAXILLARY COMPLEX,UL’4,Left Maxillary 1st premolar root apex
NASOMAXILLARY COMPLEX,UR3,Right Maxillary 1st premolar cusp tip
NASOMAXILLARY COMPLEX,UL3,Left Maxillary 1st premolar cusp tip
NASOMAXILLARY COMPLEX,UR’3,Right Maxillary 1st premolar root apex
NASOMAXILLARY COMPLEX,UL’3,Left Maxillary 1st premolar root apex
NASOMAXILLARY COMPLEX,U1,Maxillary incisor incisal edge
NASOMAXILLARY COMPLEX,U’1,Maxillary incisor root apex
MANDIBLE,B,B-point
MANDIBLE,Pog,Pogonion
MANDIBLE,Me,Menton
MANDIBLE,Gn,Gnathion
MANDIBLE,RGo,Right Gonion
MANDIBLE,LGo,Left Gonion
MANDIBLE,RSGo,Right Superior Gonion
MANDIBLE,RIGo,Right Inferior Gonion
MANDIBLE,LSGo,Left Superior Gonion
MANDIBLE,LIGo,Left Inferior Gonion
MANDIBLE,RCo,Right Condylion
MANDIBLE,LCo,Left Condylion
MANDIBLE,RLCP,Right Lateral Condylar pole
MANDIBLE,RMCP,Right Medial Condylar pole
MANDIBLE,LLCP,Left Lateral Condylar pole
MANDIBLE,LMCP,Left Medial Condylar pole
MANDIBLE,LR6,Right Mandibular molar cusp tip
MANDIBLE,LL6,Left Maxillary molar cusp tip
MANDIBLE,LR’6,Right Maxillary molar root apex
MANDIBLE,LL’6,Left Maxillary molar root apex
MANDIBLE,LR6AB,Buccal Alveolar Bone Level at first molar
MANDIBLE,LL6AB,Buccal Alveolar Bone Level at first molar
MANDIBLE,LR5,Right Maxillary 2nd premolar cusp tip
MANDIBLE,LL5,Left Maxillary 2nd premolar cusp tip
MANDIBLE,LR’5,Right Maxillary 2nd premolar root apex
MANDIBLE,LL’5,Left Maxillary 2nd premolar root apex
MANDIBLE,LR4,Right Maxillary 1st premolar cusp tip
MANDIBLE,LL4,Left Maxillary 1st premolar cusp tip
MANDIBLE,LR’4,Right Maxillary 1st premolar root apex
MANDIBLE,LL’4,Left Maxillary 1st premolar root apex
MANDIBLE,LR3,Right Maxillary 1st premolar cusp tip
MANDIBLE,LL3,Left Maxillary 1st premolar cusp tip
MANDIBLE,LR’3,Right Maxillary 1st premolar root apex
MANDIBLE,LL’3,Left Maxillary 1st premolar root apex
MANDIBLE,L1,Maxillary incisor incisal edge
MANDIBLE,L’1,Maxillary incisor root apex
9 changes: 8 additions & 1 deletion Q3DC/Resources/UI/Q3DC.ui
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
<property name="contentsFrameShape">
<enum>QFrame::StyledPanel</enum>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<layout class="QVBoxLayout" name="landmarkModifLayout">
<item>
<layout class="QHBoxLayout" name="inputModelLayout">
<item>
Expand Down Expand Up @@ -189,6 +189,13 @@
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="landmarkLegendLabel">
<property name="text">
<string>Landmark Legend</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
Expand Down

0 comments on commit 4452401

Please sign in to comment.