Commit f64959b98097c05e706e81faa74a9aa67820b144

Authored by Renan
2 parents e35fada3 e1b52082
Exists in master

Merge branch 'master' into multimodal_tracking

# Conflicts:
#	invesalius/constants.py
invesalius/constants.py
... ... @@ -830,11 +830,12 @@ TREKKER_CONFIG = {'seed_max': 1, 'step_size': 0.1, 'min_fod': 0.1, 'probe_qualit
830 830  
831 831 MARKER_FILE_MAGICK_STRING = "##INVESALIUS3_MARKER_FILE_"
832 832 CURRENT_MARKER_FILE_VERSION = 0
833   -WILDCARD_MARKER_FILES = _("Marker scanner coord files (*.mkss)|*.mkss")
  833 +WILDCARD_MARKER_FILES = _("Marker scanner coord files (*.mkss)|*.mkss")
834 834  
835 835 # Serial port
836 836 BAUD_RATES = [300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200]
837 837 BAUD_RATE_DEFAULT_SELECTION = 4
  838 +PULSE_DURATION_IN_MILLISECONDS = 0.2
838 839  
839 840 #Robot
840 841 ROBOT_ElFIN_IP = ['143.107.220.251', '169.254.153.251', '127.0.0.1']
... ... @@ -843,4 +844,3 @@ ROBOT_MOTIONS = {"normal": 0, "linear out": 1, "arc": 2}
843 844 ROBOT_HEAD_VELOCITY_THRESHOLD = 10
844 845 ROBOT_ARC_THRESHOLD_DISTANCE = 100
845 846 ROBOT_VERSOR_SCALE_FACTOR = 70
846   -
... ...
invesalius/data/serial_port_connection.py
... ... @@ -22,12 +22,12 @@ import threading
22 22 import time
23 23  
24 24 import wx
  25 +
  26 +from invesalius import constants
25 27 from invesalius.pubsub import pub as Publisher
26 28  
27 29  
28 30 class SerialPortConnection(threading.Thread):
29   - BINARY_PULSE = b'\x01'
30   -
31 31 def __init__(self, com_port, baud_rate, serial_port_queue, event, sleep_nav):
32 32 """
33 33 Thread created to communicate using the serial port to interact with software during neuronavigation.
... ... @@ -65,7 +65,7 @@ class SerialPortConnection(threading.Thread):
65 65  
66 66 def SendPulse(self):
67 67 try:
68   - self.connection.write(self.BINARY_PULSE)
  68 + self.connection.send_break(constants.PULSE_DURATION_IN_MILLISECONDS / 1000)
69 69 Publisher.sendMessage('Serial port pulse triggered')
70 70 except:
71 71 print("Error: Serial port could not be written into.")
... ...
invesalius/data/trackers.py
... ... @@ -301,9 +301,11 @@ def PlhSerialConnection(tracker_id):
301 301 trck_init = None
302 302 dlg_port = dlg.SetCOMPort(select_baud_rate=False)
303 303 if dlg_port.ShowModal() == ID_OK:
304   - com_port = dlg_port.GetValue()
  304 + com_port = dlg_port.GetCOMPort()
  305 + baud_rate = 115200
  306 +
305 307 try:
306   - trck_init = serial.Serial(com_port, baudrate=115200, timeout=0.03)
  308 + trck_init = serial.Serial(com_port, baudrate=baud_rate, timeout=0.03)
307 309  
308 310 if tracker_id == 2:
309 311 # Polhemus FASTRAK needs configurations first
... ...
invesalius/data/viewer_volume.py
... ... @@ -726,9 +726,13 @@ class Viewer(wx.Panel):
726 726 self.distthreshold = dist_threshold
727 727  
728 728 def ActivateTargetMode(self, evt=None, target_mode=None):
  729 +
729 730 vtk_colors = vtk.vtkNamedColors()
730 731 self.target_mode = target_mode
731 732 if self.target_coord and self.target_mode:
  733 + if self.actor_peel:
  734 + self.object_orientation_torus_actor.SetVisibility(0)
  735 + self.obj_projection_arrow_actor.SetVisibility(0)
732 736 self.CreateTargetAim()
733 737  
734 738 # Create a line
... ... @@ -831,6 +835,9 @@ class Viewer(wx.Panel):
831 835  
832 836 else:
833 837 self.DisableCoilTracker()
  838 + if self.actor_peel:
  839 + self.object_orientation_torus_actor.SetVisibility(1)
  840 + self.obj_projection_arrow_actor.SetVisibility(1)
834 841  
835 842 def OnUpdateObjectTargetGuide(self, m_img, coord):
836 843  
... ...
invesalius/gui/dialogs.py
... ... @@ -4809,15 +4809,16 @@ class SetCOMPort(wx.Dialog):
4809 4809  
4810 4810 self.CenterOnParent()
4811 4811  
4812   - def GetValue(self):
  4812 + def GetCOMPort(self):
4813 4813 com_port = self.com_port_dropdown.GetString(self.com_port_dropdown.GetSelection())
  4814 + return com_port
4814 4815  
4815   - if self.select_baud_rate:
4816   - baud_rate = self.baud_rate_dropdown.GetString(self.baud_rate_dropdown.GetSelection())
4817   - else:
4818   - baud_rate = None
  4816 + def GetBaudRate(self):
  4817 + if not self.select_baud_rate:
  4818 + return None
4819 4819  
4820   - return com_port, baud_rate
  4820 + baud_rate = self.baud_rate_dropdown.GetString(self.baud_rate_dropdown.GetSelection())
  4821 + return baud_rate
4821 4822  
4822 4823  
4823 4824 class ManualWWWLDialog(wx.Dialog):
... ...
invesalius/gui/task_navigator.py
... ... @@ -305,7 +305,7 @@ class InnerFoldPanel(wx.Panel):
305 305 ctrl.SetValue(False)
306 306 return
307 307  
308   - com_port = dlg_port.GetValue()
  308 + com_port = dlg_port.GetCOMPort()
309 309 baud_rate = 115200
310 310  
311 311 Publisher.sendMessage('Update serial port', serial_port_in_use=True, com_port=com_port, baud_rate=baud_rate)
... ... @@ -410,16 +410,10 @@ class NeuronavigationPanel(wx.Panel):
410 410  
411 411 self.btns_set_fiducial[n + 3] = ctrl
412 412  
413   - # TODO: Find a better allignment between FRE, text and navigate button
414   - txt_fre = wx.StaticText(self, -1, _('FRE:'))
415   - txt_icp = wx.StaticText(self, -1, _('Refine:'))
  413 + # TODO: Find a better alignment between FRE, text and navigate button
416 414  
417   - if pedal_connection is not None and pedal_connection.in_use:
418   - txt_pedal_pressed = wx.StaticText(self, -1, _('Pedal pressed:'))
419   - else:
420   - txt_pedal_pressed = None
421   -
422   - # Fiducial registration error text box
  415 + # Fiducial registration error text and checkbox
  416 + txt_fre = wx.StaticText(self, -1, _('FRE:'))
423 417 tooltip = wx.ToolTip(_("Fiducial registration error"))
424 418 txtctrl_fre = wx.TextCtrl(self, value="", size=wx.Size(60, -1), style=wx.TE_CENTRE)
425 419 txtctrl_fre.SetFont(wx.Font(9, wx.DEFAULT, wx.NORMAL, wx.BOLD))
... ... @@ -434,6 +428,8 @@ class NeuronavigationPanel(wx.Panel):
434 428 btn_nav.SetToolTip(tooltip)
435 429 btn_nav.Bind(wx.EVT_TOGGLEBUTTON, partial(self.OnNavigate, btn_nav=btn_nav))
436 430  
  431 + # "Refine" text and checkbox
  432 + txt_icp = wx.StaticText(self, -1, _('Refine:'))
437 433 tooltip = wx.ToolTip(_(u"Refine the coregistration"))
438 434 checkbox_icp = wx.CheckBox(self, -1, _(' '))
439 435 checkbox_icp.SetValue(False)
... ... @@ -442,8 +438,9 @@ class NeuronavigationPanel(wx.Panel):
442 438 checkbox_icp.SetToolTip(tooltip)
443 439 self.checkbox_icp = checkbox_icp
444 440  
445   - # An indicator for pedal trigger
  441 + # "Pedal pressed" text and an indicator (checkbox) for pedal press
446 442 if pedal_connection is not None and pedal_connection.in_use:
  443 + txt_pedal_pressed = wx.StaticText(self, -1, _('Pedal pressed:'))
447 444 tooltip = wx.ToolTip(_(u"Is the pedal pressed"))
448 445 checkbox_pedal_pressed = wx.CheckBox(self, -1, _(' '))
449 446 checkbox_pedal_pressed.SetValue(False)
... ... @@ -454,15 +451,27 @@ class NeuronavigationPanel(wx.Panel):
454 451  
455 452 self.checkbox_pedal_pressed = checkbox_pedal_pressed
456 453 else:
  454 + txt_pedal_pressed = None
457 455 self.checkbox_pedal_pressed = None
458 456  
  457 + # "Lock to target" text and checkbox
  458 + tooltip = wx.ToolTip(_(u"Allow triggering stimulation pulse only if the coil is at the target"))
  459 + lock_to_target_text = wx.StaticText(self, -1, _('Lock to target:'))
  460 + lock_to_target_checkbox = wx.CheckBox(self, -1, _(' '))
  461 + lock_to_target_checkbox.SetValue(False)
  462 + lock_to_target_checkbox.Enable(False)
  463 + lock_to_target_checkbox.Bind(wx.EVT_CHECKBOX, partial(self.OnLockToTargetCheckbox, ctrl=lock_to_target_checkbox))
  464 + lock_to_target_checkbox.SetToolTip(tooltip)
  465 +
  466 + self.lock_to_target_checkbox = lock_to_target_checkbox
  467 +
459 468 # Image and tracker coordinates number controls
460 469 for m in range(len(self.btns_set_fiducial)):
461 470 for n in range(3):
462 471 self.numctrls_fiducial[m].append(
463 472 wx.lib.masked.numctrl.NumCtrl(parent=self, integerWidth=4, fractionWidth=1))
464 473  
465   - # Sizer to group all GUI objects
  474 + # Sizers to group all GUI objects
466 475 choice_sizer = wx.FlexGridSizer(rows=1, cols=2, hgap=5, vgap=5)
467 476 choice_sizer.AddMany([(select_tracker_elem, wx.LEFT),
468 477 (choice_ref, wx.RIGHT)])
... ... @@ -483,10 +492,13 @@ class NeuronavigationPanel(wx.Panel):
483 492 (txt_icp, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL),
484 493 (checkbox_icp, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL)])
485 494  
486   - pedal_sizer = wx.FlexGridSizer(rows=1, cols=2, hgap=5, vgap=5)
487   - if HAS_PEDAL_CONNECTION and pedal_connection.in_use:
488   - pedal_sizer.AddMany([(txt_pedal_pressed, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL),
489   - (checkbox_pedal_pressed, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL)])
  495 + checkboxes_sizer = wx.FlexGridSizer(rows=1, cols=4, hgap=5, vgap=5)
  496 + checkboxes_sizer.AddMany([(lock_to_target_text, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL),
  497 + (lock_to_target_checkbox, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL)])
  498 +
  499 + if pedal_connection is not None and pedal_connection.in_use:
  500 + checkboxes_sizer.AddMany([(txt_pedal_pressed, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL),
  501 + (checkbox_pedal_pressed, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL)])
490 502  
491 503 group_sizer = wx.FlexGridSizer(rows=10, cols=1, hgap=5, vgap=5)
492 504 group_sizer.AddGrowableCol(0, 1)
... ... @@ -497,7 +509,7 @@ class NeuronavigationPanel(wx.Panel):
497 509 group_sizer.AddMany([(choice_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL),
498 510 (coord_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL),
499 511 (nav_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL),
500   - (pedal_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL)])
  512 + (checkboxes_sizer, 0, wx.ALIGN_CENTER_HORIZONTAL)])
501 513  
502 514 main_sizer = wx.BoxSizer(wx.HORIZONTAL)
503 515 main_sizer.Add(group_sizer, 1)# wx.ALIGN_CENTER_HORIZONTAL, 10)
... ... @@ -575,7 +587,6 @@ class NeuronavigationPanel(wx.Panel):
575 587 self.ResetICP()
576 588 self.tracker.UpdateUI(self.select_tracker_elem, self.numctrls_fiducial[3:6], self.txtctrl_fre)
577 589  
578   -
579 590 def UpdatePeelVisualization(self, data):
580 591 self.navigation.peel_loaded = data
581 592  
... ... @@ -614,6 +625,10 @@ class NeuronavigationPanel(wx.Panel):
614 625 def UpdateTarget(self, coord):
615 626 self.navigation.target = coord
616 627  
  628 + self.lock_to_target_checkbox.Enable(True)
  629 + self.lock_to_target_checkbox.SetValue(True)
  630 + self.navigation.SetLockToTarget(True)
  631 +
617 632 def EnableACT(self, data):
618 633 self.navigation.enable_act = data
619 634  
... ... @@ -644,6 +659,10 @@ class NeuronavigationPanel(wx.Panel):
644 659 self.ResetICP()
645 660 self.tracker.UpdateUI(self.select_tracker_elem, self.numctrls_fiducial[3:6], self.txtctrl_fre)
646 661  
  662 + def OnLockToTargetCheckbox(self, evt, ctrl):
  663 + value = ctrl.GetValue()
  664 + self.navigation.SetLockToTarget(value)
  665 +
647 666 def OnChooseTracker(self, evt, ctrl):
648 667 Publisher.sendMessage('Update status text in GUI',
649 668 label=_("Configuring tracker ..."))
... ... @@ -1394,7 +1413,7 @@ class MarkersPanel(wx.Panel):
1394 1413  
1395 1414 @staticmethod
1396 1415 def __list_fiducial_labels():
1397   - """Return the list of marker labels denoting fucials."""
  1416 + """Return the list of marker labels denoting fiducials."""
1398 1417 return list(itertools.chain(*(const.BTNS_IMG_MARKERS[i].values() for i in const.BTNS_IMG_MARKERS)))
1399 1418  
1400 1419 def UpdateCurrentCoord(self, position):
... ...
invesalius/navigation/navigation.py
... ... @@ -177,6 +177,7 @@ class Navigation():
177 177 self.serial_port_connection = None
178 178  
179 179 # During navigation
  180 + self.lock_to_target = False
180 181 self.coil_at_target = False
181 182  
182 183 self.__bind_events()
... ... @@ -197,6 +198,9 @@ class Navigation():
197 198 self.com_port = com_port
198 199 self.baud_rate = baud_rate
199 200  
  201 + def SetLockToTarget(self, value):
  202 + self.lock_to_target = value
  203 +
200 204 def SetReferenceMode(self, value):
201 205 self.ref_mode_id = value
202 206  
... ... @@ -223,7 +227,13 @@ class Navigation():
223 227 return fre, fre <= const.FIDUCIAL_REGISTRATION_ERROR_THRESHOLD
224 228  
225 229 def PedalStateChanged(self, state):
226   - if state is True and self.coil_at_target and self.serial_port_in_use:
  230 + if not self.serial_port_in_use:
  231 + return
  232 +
  233 + permission_to_stimulate = (self.lock_to_target and self.coil_at_target) or \
  234 + not self.lock_to_target
  235 +
  236 + if state and permission_to_stimulate:
227 237 self.serial_port_connection.SendPulse()
228 238  
229 239 def StartNavigation(self, tracker):
... ...