Commit 55ce120595561b4806a4aed610e1379d82ac69f6
1 parent
9d79c88d
Exists in
master
MOD: Refactor task_navigator.py
- Some steps towards decoupling GUI and domain logic, namely, by adding classes Navigation and Tracker, which take some of the responsibility previously handled by NeuronavigationPanel. - This is done to prepare to do some changes in the GUI, such as moving "Navigate" button elsewhere -- previously, it was hard to do due to the elements in the GUI being tightly coupled with the implementation of navigation. - Also some other minor clean-up and style improvements, such as using more consistent and more descriptive variable names
Showing
3 changed files
with
490 additions
and
432 deletions
Show diff stats
invesalius/constants.py
@@ -675,12 +675,12 @@ DEFAULT_TRACKER = SELECT | @@ -675,12 +675,12 @@ DEFAULT_TRACKER = SELECT | ||
675 | 675 | ||
676 | NDICOMPORT = b'COM1' | 676 | NDICOMPORT = b'COM1' |
677 | 677 | ||
678 | -TRACKER = [_("Select tracker:"), _("Claron MicronTracker"), | ||
679 | - _("Polhemus FASTRAK"), _("Polhemus ISOTRAK II"), | ||
680 | - _("Polhemus PATRIOT"), _("Camera tracker"), | ||
681 | - _("NDI Polaris"), _("NDI Polaris P4"), | ||
682 | - _("Optitrack"), _("Debug tracker (random)"), | ||
683 | - _("Debug tracker (approach)"), _("Disconnect tracker")] | 678 | +TRACKERS = [_("Claron MicronTracker"), |
679 | + _("Polhemus FASTRAK"), _("Polhemus ISOTRAK II"), | ||
680 | + _("Polhemus PATRIOT"), _("Camera tracker"), | ||
681 | + _("NDI Polaris"), _("NDI Polaris P4"), | ||
682 | + _("Optitrack"), _("Debug tracker (random)"), | ||
683 | + _("Debug tracker (approach)"), _("Disconnect tracker")] | ||
684 | 684 | ||
685 | STATIC_REF = 0 | 685 | STATIC_REF = 0 |
686 | DYNAMIC_REF = 1 | 686 | DYNAMIC_REF = 1 |
@@ -729,21 +729,21 @@ TRACKER_FIDUCIALS = [ | @@ -729,21 +729,21 @@ TRACKER_FIDUCIALS = [ | ||
729 | 'button_id': TR1, | 729 | 'button_id': TR1, |
730 | 'label': 'LET', | 730 | 'label': 'LET', |
731 | 'fiducial_name': 'LE', | 731 | 'fiducial_name': 'LE', |
732 | - 'fiducial_index': 3, | 732 | + 'fiducial_index': 0, |
733 | 'tip': _("Select left ear with spatial tracker"), | 733 | 'tip': _("Select left ear with spatial tracker"), |
734 | }, | 734 | }, |
735 | { | 735 | { |
736 | 'button_id': TR2, | 736 | 'button_id': TR2, |
737 | 'label': 'RET', | 737 | 'label': 'RET', |
738 | 'fiducial_name': 'RE', | 738 | 'fiducial_name': 'RE', |
739 | - 'fiducial_index': 4, | 739 | + 'fiducial_index': 1, |
740 | 'tip': _("Select right ear with spatial tracker"), | 740 | 'tip': _("Select right ear with spatial tracker"), |
741 | }, | 741 | }, |
742 | { | 742 | { |
743 | 'button_id': TR3, | 743 | 'button_id': TR3, |
744 | 'label': 'NAT', | 744 | 'label': 'NAT', |
745 | 'fiducial_name': 'NA', | 745 | 'fiducial_name': 'NA', |
746 | - 'fiducial_index': 5, | 746 | + 'fiducial_index': 2, |
747 | 'tip': _("Select nasion with spatial tracker"), | 747 | 'tip': _("Select nasion with spatial tracker"), |
748 | }, | 748 | }, |
749 | ] | 749 | ] |
invesalius/data/coregistration.py
@@ -171,10 +171,10 @@ def corregistrate_dynamic(inp, coord_raw, ref_mode_id, icp): | @@ -171,10 +171,10 @@ def corregistrate_dynamic(inp, coord_raw, ref_mode_id, icp): | ||
171 | 171 | ||
172 | 172 | ||
173 | class CoordinateCorregistrate(threading.Thread): | 173 | class CoordinateCorregistrate(threading.Thread): |
174 | - def __init__(self, ref_mode_id, trck_info, coreg_data, view_tracts, queues, event, sle, tracker_id, target): | 174 | + def __init__(self, ref_mode_id, tracker, coreg_data, view_tracts, queues, event, sle, tracker_id, target): |
175 | threading.Thread.__init__(self, name='CoordCoregObject') | 175 | threading.Thread.__init__(self, name='CoordCoregObject') |
176 | self.ref_mode_id = ref_mode_id | 176 | self.ref_mode_id = ref_mode_id |
177 | - self.trck_info = trck_info | 177 | + self.tracker = tracker |
178 | self.coreg_data = coreg_data | 178 | self.coreg_data = coreg_data |
179 | self.coord_queue = queues[0] | 179 | self.coord_queue = queues[0] |
180 | self.view_tracts = view_tracts | 180 | self.view_tracts = view_tracts |
@@ -198,11 +198,11 @@ class CoordinateCorregistrate(threading.Thread): | @@ -198,11 +198,11 @@ class CoordinateCorregistrate(threading.Thread): | ||
198 | self.target[1] = -self.target[1] | 198 | self.target[1] = -self.target[1] |
199 | 199 | ||
200 | def run(self): | 200 | def run(self): |
201 | - trck_info = self.trck_info | ||
202 | coreg_data = self.coreg_data | 201 | coreg_data = self.coreg_data |
203 | view_obj = 1 | 202 | view_obj = 1 |
204 | 203 | ||
205 | - trck_init, trck_id, trck_mode = trck_info | 204 | + trck_init, trck_id, trck_mode = self.tracker.GetTrackerInfo() |
205 | + | ||
206 | # print('CoordCoreg: event {}'.format(self.event.is_set())) | 206 | # print('CoordCoreg: event {}'.format(self.event.is_set())) |
207 | while not self.event.is_set(): | 207 | while not self.event.is_set(): |
208 | try: | 208 | try: |
@@ -258,10 +258,10 @@ class CoordinateCorregistrate(threading.Thread): | @@ -258,10 +258,10 @@ class CoordinateCorregistrate(threading.Thread): | ||
258 | 258 | ||
259 | 259 | ||
260 | class CoordinateCorregistrateNoObject(threading.Thread): | 260 | class CoordinateCorregistrateNoObject(threading.Thread): |
261 | - def __init__(self, ref_mode_id, trck_info, coreg_data, view_tracts, queues, event, sle): | 261 | + def __init__(self, ref_mode_id, tracker, coreg_data, view_tracts, queues, event, sle): |
262 | threading.Thread.__init__(self, name='CoordCoregNoObject') | 262 | threading.Thread.__init__(self, name='CoordCoregNoObject') |
263 | self.ref_mode_id = ref_mode_id | 263 | self.ref_mode_id = ref_mode_id |
264 | - self.trck_info = trck_info | 264 | + self.tracker = tracker |
265 | self.coreg_data = coreg_data | 265 | self.coreg_data = coreg_data |
266 | self.coord_queue = queues[0] | 266 | self.coord_queue = queues[0] |
267 | self.view_tracts = view_tracts | 267 | self.view_tracts = view_tracts |
@@ -273,11 +273,10 @@ class CoordinateCorregistrateNoObject(threading.Thread): | @@ -273,11 +273,10 @@ class CoordinateCorregistrateNoObject(threading.Thread): | ||
273 | self.m_icp = None | 273 | self.m_icp = None |
274 | 274 | ||
275 | def run(self): | 275 | def run(self): |
276 | - trck_info = self.trck_info | ||
277 | coreg_data = self.coreg_data | 276 | coreg_data = self.coreg_data |
278 | view_obj = 0 | 277 | view_obj = 0 |
279 | 278 | ||
280 | - trck_init, trck_id, trck_mode = trck_info | 279 | + trck_init, trck_id, trck_mode = self.tracker.GetTrackerInfo() |
281 | # print('CoordCoreg: event {}'.format(self.event.is_set())) | 280 | # print('CoordCoreg: event {}'.format(self.event.is_set())) |
282 | while not self.event.is_set(): | 281 | while not self.event.is_set(): |
283 | try: | 282 | try: |
invesalius/gui/task_navigator.py
@@ -300,39 +300,18 @@ class InnerFoldPanel(wx.Panel): | @@ -300,39 +300,18 @@ class InnerFoldPanel(wx.Panel): | ||
300 | Publisher.sendMessage('Update volume camera state', camera_state=self.checkcamera.GetValue()) | 300 | Publisher.sendMessage('Update volume camera state', camera_state=self.checkcamera.GetValue()) |
301 | 301 | ||
302 | 302 | ||
303 | -class NeuronavigationPanel(wx.Panel): | ||
304 | - def __init__(self, parent): | ||
305 | - wx.Panel.__init__(self, parent) | ||
306 | - try: | ||
307 | - default_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_MENUBAR) | ||
308 | - except AttributeError: | ||
309 | - default_colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_MENUBAR) | ||
310 | - self.SetBackgroundColour(default_colour) | ||
311 | - | ||
312 | - self.SetAutoLayout(1) | ||
313 | - | ||
314 | - self.__bind_events() | ||
315 | - | ||
316 | - # Initialize global variables | ||
317 | - self.pedal_connection = PedalConnection() if HAS_PEDAL_CONNECTION else None | ||
318 | - self.fiducials = np.full([6, 3], np.nan) | ||
319 | - self.fiducials_raw = np.zeros((6, 6)) | 303 | +class Navigation(): |
304 | + def __init__(self): | ||
305 | + self.image_fiducials = np.full([3, 3], np.nan) | ||
320 | self.correg = None | 306 | self.correg = None |
321 | self.current_coord = 0, 0, 0 | 307 | self.current_coord = 0, 0, 0 |
322 | - self.trk_init = None | ||
323 | - self.nav_status = False | ||
324 | self.target = None | 308 | self.target = None |
325 | self.trigger = None | 309 | self.trigger = None |
326 | self.trigger_state = False | 310 | self.trigger_state = False |
327 | self.obj_reg = None | 311 | self.obj_reg = None |
328 | - self.obj_reg_status = False | ||
329 | self.track_obj = False | 312 | self.track_obj = False |
330 | - self.m_icp = None | ||
331 | - self.fre = None | ||
332 | - self.icp_fre = None | ||
333 | - self.icp = False | ||
334 | - self.event = threading.Event() | ||
335 | 313 | ||
314 | + self.event = threading.Event() | ||
336 | self.coord_queue = QueueCustom(maxsize=1) | 315 | self.coord_queue = QueueCustom(maxsize=1) |
337 | self.icp_queue = QueueCustom(maxsize=1) | 316 | self.icp_queue = QueueCustom(maxsize=1) |
338 | # self.visualization_queue = QueueCustom(maxsize=1) | 317 | # self.visualization_queue = QueueCustom(maxsize=1) |
@@ -352,21 +331,400 @@ class NeuronavigationPanel(wx.Panel): | @@ -352,21 +331,400 @@ class NeuronavigationPanel(wx.Panel): | ||
352 | self.seed_radius = const.SEED_RADIUS | 331 | self.seed_radius = const.SEED_RADIUS |
353 | self.sleep_nav = const.SLEEP_NAVIGATION | 332 | self.sleep_nav = const.SLEEP_NAVIGATION |
354 | 333 | ||
334 | + # ICP related variables | ||
335 | + self.use_icp = False | ||
336 | + self.m_icp = None | ||
337 | + self.fre = None | ||
338 | + self.icp_fre = None | ||
339 | + | ||
340 | + def SetImageFiducial(self, fiducial_index, coord): | ||
341 | + self.image_fiducials[fiducial_index, :] = coord | ||
342 | + | ||
343 | + print("Set image fiducial {} to coordinates {}".format(fiducial_index, coord)) | ||
344 | + | ||
345 | + def AreImageFiducialsSet(self): | ||
346 | + return not np.isnan(self.image_fiducials).any() | ||
347 | + | ||
348 | + def UpdateFiducialRegistrationError(self, tracker): | ||
349 | + tracker_fiducials, tracker_fiducials_raw = tracker.GetTrackerFiducials() | ||
350 | + ref_mode_id = tracker.GetReferenceMode() | ||
351 | + | ||
352 | + all_fiducials = np.vstack([self.image_fiducials, tracker_fiducials]) | ||
353 | + | ||
354 | + # fiducials matrix | ||
355 | + m_change = tr.affine_matrix_from_points(all_fiducials[3:, :].T, all_fiducials[:3, :].T, | ||
356 | + shear=False, scale=False) | ||
357 | + | ||
358 | + self.fre = db.calculate_fre(tracker_fiducials_raw, all_fiducials, ref_mode_id, m_change) | ||
359 | + | ||
360 | + def GetFiducialRegistrationError(self): | ||
361 | + fre = self.icp_fre if self.use_icp else self.fre | ||
362 | + return fre, fre <= 3 | ||
363 | + | ||
364 | + def StartNavigation(self, tracker): | ||
365 | + tracker_fiducials, tracker_fiducials_raw = tracker.GetTrackerFiducials() | ||
366 | + ref_mode_id = tracker.GetReferenceMode() | ||
367 | + | ||
368 | + # initialize jobs list | ||
369 | + jobs_list = [] | ||
370 | + | ||
371 | + if self.event.is_set(): | ||
372 | + self.event.clear() | ||
373 | + | ||
374 | + vis_components = [self.trigger_state, self.view_tracts] | ||
375 | + vis_queues = [self.coord_queue, self.trigger_queue, self.tracts_queue, self.icp_queue] | ||
376 | + | ||
377 | + Publisher.sendMessage("Navigation status", nav_status=True, vis_status=vis_components) | ||
378 | + | ||
379 | + all_fiducials = np.vstack([self.image_fiducials, tracker_fiducials]) | ||
380 | + | ||
381 | + # fiducials matrix | ||
382 | + m_change = tr.affine_matrix_from_points(all_fiducials[3:, :].T, all_fiducials[:3, :].T, | ||
383 | + shear=False, scale=False) | ||
384 | + | ||
385 | + errors = False | ||
386 | + | ||
387 | + if self.track_obj: | ||
388 | + # if object tracking is selected | ||
389 | + if self.obj_reg is None: | ||
390 | + # check if object registration was performed | ||
391 | + wx.MessageBox(_("Perform coil registration before navigation."), _("InVesalius 3")) | ||
392 | + errors = True | ||
393 | + else: | ||
394 | + # if object registration was correctly performed continue with navigation | ||
395 | + # obj_reg[0] is object 3x3 fiducial matrix and obj_reg[1] is 3x3 orientation matrix | ||
396 | + obj_fiducials, obj_orients, obj_ref_mode, obj_name = self.obj_reg | ||
397 | + | ||
398 | + coreg_data = [m_change, obj_ref_mode] | ||
399 | + | ||
400 | + if ref_mode_id: | ||
401 | + coord_raw = dco.GetCoordinates(tracker.trk_init, tracker.tracker_id, ref_mode_id) | ||
402 | + else: | ||
403 | + coord_raw = np.array([None]) | ||
404 | + | ||
405 | + obj_data = db.object_registration(obj_fiducials, obj_orients, coord_raw, m_change) | ||
406 | + coreg_data.extend(obj_data) | ||
407 | + | ||
408 | + queues = [self.coord_queue, self.coord_tracts_queue, self.icp_queue] | ||
409 | + jobs_list.append(dcr.CoordinateCorregistrate(ref_mode_id, tracker, coreg_data, | ||
410 | + self.view_tracts, queues, | ||
411 | + self.event, self.sleep_nav, tracker.tracker_id, | ||
412 | + self.target)) | ||
413 | + else: | ||
414 | + coreg_data = (m_change, 0) | ||
415 | + queues = [self.coord_queue, self.coord_tracts_queue, self.icp_queue] | ||
416 | + jobs_list.append(dcr.CoordinateCorregistrateNoObject(ref_mode_id, tracker, coreg_data, | ||
417 | + self.view_tracts, queues, | ||
418 | + self.event, self.sleep_nav)) | ||
419 | + | ||
420 | + if not errors: | ||
421 | + #TODO: Test the trigger thread | ||
422 | + if self.trigger_state: | ||
423 | + # self.trigger = trig.Trigger(nav_id) | ||
424 | + jobs_list.append(trig.TriggerNew(self.trigger_queue, self.event, self.sleep_nav)) | ||
425 | + | ||
426 | + if self.view_tracts: | ||
427 | + # initialize Trekker parameters | ||
428 | + slic = sl.Slice() | ||
429 | + prj_data = prj.Project() | ||
430 | + matrix_shape = tuple(prj_data.matrix_shape) | ||
431 | + affine = slic.affine.copy() | ||
432 | + affine[1, -1] -= matrix_shape[1] | ||
433 | + affine_vtk = vtk_utils.numpy_to_vtkMatrix4x4(affine) | ||
434 | + Publisher.sendMessage("Update marker offset state", create=True) | ||
435 | + self.trk_inp = self.trekker, affine, self.seed_offset, self.n_tracts, self.seed_radius,\ | ||
436 | + self.n_threads, self.act_data, affine_vtk, matrix_shape[1] | ||
437 | + # print("Appending the tract computation thread!") | ||
438 | + queues = [self.coord_tracts_queue, self.tracts_queue] | ||
439 | + if self.enable_act: | ||
440 | + jobs_list.append(dti.ComputeTractsACTThread(self.trk_inp, queues, self.event, self.sleep_nav)) | ||
441 | + else: | ||
442 | + jobs_list.append(dti.ComputeTractsThread(self.trk_inp, queues, self.event, self.sleep_nav)) | ||
443 | + | ||
444 | + jobs_list.append(UpdateNavigationScene(vis_queues, vis_components, | ||
445 | + self.event, self.sleep_nav)) | ||
446 | + | ||
447 | + for jobs in jobs_list: | ||
448 | + # jobs.daemon = True | ||
449 | + jobs.start() | ||
450 | + # del jobs | ||
451 | + | ||
452 | + # TODO: Separate ICP-related code from Navigation class. The first step would be to have this stuff | ||
453 | + # in a separate function or so. | ||
454 | + # | ||
455 | + if not self.use_icp: | ||
456 | + if dlg.ICPcorregistration(self.fre): | ||
457 | + m_icp = self.OnICP(tracker, m_change) | ||
458 | + self.icp_fre = db.calculate_fre(tracker_fiducials_raw, all_fiducials, ref_mode_id, | ||
459 | + m_change, m_icp) | ||
460 | + self.SetICP(True) | ||
461 | + | ||
462 | + def StopNavigation(self): | ||
463 | + self.event.set() | ||
464 | + | ||
465 | + self.coord_queue.clear() | ||
466 | + self.coord_queue.join() | ||
467 | + | ||
468 | + if self.trigger_state: | ||
469 | + self.trigger_queue.clear() | ||
470 | + self.trigger_queue.join() | ||
471 | + if self.view_tracts: | ||
472 | + self.coord_tracts_queue.clear() | ||
473 | + self.coord_tracts_queue.join() | ||
474 | + | ||
475 | + self.tracts_queue.clear() | ||
476 | + self.tracts_queue.join() | ||
477 | + | ||
478 | + vis_components = [self.trigger_state, self.view_tracts] | ||
479 | + Publisher.sendMessage("Navigation status", nav_status=False, vis_status=vis_components) | ||
480 | + | ||
481 | + # ICP-related functions | ||
482 | + # | ||
483 | + # TODO: Refactor to preferably their own class. | ||
484 | + # | ||
485 | + def OnICP(self, tracker, m_change): | ||
486 | + ref_mode_id = tracker.GetReferenceMode() | ||
487 | + | ||
488 | + dialog = dlg.ICPCorregistrationDialog(nav_prop=(m_change, tracker.tracker_id, tracker.trk_init, ref_mode_id)) | ||
489 | + | ||
490 | + if dialog.ShowModal() == wx.ID_OK: | ||
491 | + self.m_icp, point_coord, transformed_points, prev_error, final_error = dialog.GetValue() | ||
492 | + # TODO: checkbox in the dialog to transfer the icp points to 3D viewer | ||
493 | + #create markers | ||
494 | + # for i in range(len(point_coord)): | ||
495 | + # img_coord = point_coord[i][0],-point_coord[i][1],point_coord[i][2], 0, 0, 0 | ||
496 | + # transf_coord = transformed_points[i][0],-transformed_points[i][1],transformed_points[i][2], 0, 0, 0 | ||
497 | + # Publisher.sendMessage('Create marker', coord=img_coord, marker_id=None, colour=(1,0,0)) | ||
498 | + # Publisher.sendMessage('Create marker', coord=transf_coord, marker_id=None, colour=(0,0,1)) | ||
499 | + if self.m_icp is not None: | ||
500 | + dlg.ReportICPerror(prev_error, final_error) | ||
501 | + self.use_icp = True | ||
502 | + else: | ||
503 | + self.use_icp = False | ||
504 | + | ||
505 | + return self.m_icp | ||
506 | + | ||
507 | + def SetICP(self, use_icp): | ||
508 | + self.use_icp = use_icp | ||
509 | + self.icp_queue.put_nowait([self.use_icp, self.m_icp]) | ||
510 | + | ||
511 | + def ResetICP(self): | ||
512 | + self.use_icp = False | ||
513 | + self.m_icp = None | ||
514 | + self.fre = None | ||
515 | + self.icp_fre = None | ||
516 | + | ||
517 | + | ||
518 | +class Tracker(): | ||
519 | + def __init__(self): | ||
520 | + self.trk_init = None | ||
355 | self.tracker_id = const.DEFAULT_TRACKER | 521 | self.tracker_id = const.DEFAULT_TRACKER |
356 | self.ref_mode_id = const.DEFAULT_REF_MODE | 522 | self.ref_mode_id = const.DEFAULT_REF_MODE |
357 | 523 | ||
524 | + self.tracker_fiducials = np.full([3, 3], np.nan) | ||
525 | + self.tracker_fiducials_raw = np.zeros((6, 6)) | ||
526 | + | ||
527 | + self.tracker_connected = False | ||
528 | + | ||
529 | + def SetTracker(self, new_tracker): | ||
530 | + if self.trk_init: | ||
531 | + trck = self.trk_init[0] | ||
532 | + else: | ||
533 | + trck = None | ||
534 | + | ||
535 | + # Conditions check if click was on current selection and if any other tracker | ||
536 | + # has been initialized before | ||
537 | + if new_tracker != const.DISCTRACK and trck: | ||
538 | + self.ResetTrackerFiducials() | ||
539 | + Publisher.sendMessage('Update status text in GUI', | ||
540 | + label=_("Disconnecting tracker...")) | ||
541 | + Publisher.sendMessage('Remove sensors ID') | ||
542 | + self.trk_init = dt.TrackerConnection(self.tracker_id, trck, 'disconnect') | ||
543 | + Publisher.sendMessage('Remove object data') | ||
544 | + | ||
545 | + if not self.trk_init[0] and new_tracker: | ||
546 | + Publisher.sendMessage('Update status text in GUI', | ||
547 | + label=_("Tracker disconnected successfully")) | ||
548 | + self.trk_init = dt.TrackerConnection(new_tracker, None, 'connect') | ||
549 | + if not self.trk_init[0]: | ||
550 | + self.tracked_connected = False | ||
551 | + self.tracker_id = 0 | ||
552 | + | ||
553 | + dlg.ShowNavigationTrackerWarning(self.tracker_id, self.trk_init[1]) | ||
554 | + print("Tracker not connected!") | ||
555 | + else: | ||
556 | + self.tracked_connected = True | ||
557 | + self.tracker_id = new_tracker | ||
558 | + | ||
559 | + print("Tracker connected!") | ||
560 | + | ||
561 | + # TODO: const.DISCTRACK is not a tracker, so discoupling it from the actual trackers | ||
562 | + # would make this cleaner. | ||
563 | + # | ||
564 | + elif new_tracker == const.DISCTRACK and trck: | ||
565 | + self.ResetTrackerFiducials() | ||
566 | + Publisher.sendMessage('Update status text in GUI', | ||
567 | + label=_("Disconnecting tracker ...")) | ||
568 | + Publisher.sendMessage('Remove sensors ID') | ||
569 | + Publisher.sendMessage('Remove object data') | ||
570 | + self.trk_init = dt.TrackerConnection(self.tracker_id, trck, 'disconnect') | ||
571 | + if not self.trk_init[0]: | ||
572 | + dlg.ShowNavigationTrackerWarning(self.tracker_id, 'disconnect') | ||
573 | + | ||
574 | + self.tracked_connected = False | ||
575 | + self.tracker_id = 0 | ||
576 | + | ||
577 | + Publisher.sendMessage('Update status text in GUI', | ||
578 | + label=_("Tracker disconnected")) | ||
579 | + | ||
580 | + print("Tracker disconnected!") | ||
581 | + else: | ||
582 | + Publisher.sendMessage('Update status text in GUI', | ||
583 | + label=_("Tracker still connected")) | ||
584 | + print("Tracker still connected!") | ||
585 | + | ||
586 | + else: | ||
587 | + # If trk_init is None try to connect. If doesn't succeed show dialog. | ||
588 | + if new_tracker: | ||
589 | + self.trk_init = dt.TrackerConnection(new_tracker, None, 'connect') | ||
590 | + if not self.trk_init[0]: | ||
591 | + dlg.ShowNavigationTrackerWarning(self.tracker_id, self.trk_init[1]) | ||
592 | + | ||
593 | + self.tracker_id = 0 | ||
594 | + self.tracker_connected = False | ||
595 | + else: | ||
596 | + self.tracker_id = new_tracker | ||
597 | + self.tracker_connected = True | ||
598 | + | ||
599 | + Publisher.sendMessage('Update tracker initializer', | ||
600 | + nav_prop=(self.tracker_id, self.trk_init, self.ref_mode_id)) | ||
601 | + | ||
602 | + def DisconnectTracker(self): | ||
603 | + if self.tracker_connected: | ||
604 | + self.ResetTrackerFiducials() | ||
605 | + Publisher.sendMessage('Update status text in GUI', | ||
606 | + label=_("Disconnecting tracker ...")) | ||
607 | + Publisher.sendMessage('Remove sensors ID') | ||
608 | + Publisher.sendMessage('Remove object data') | ||
609 | + self.trk_init = dt.TrackerConnection(self.tracker_id, self.tracker_connected, 'disconnect') | ||
610 | + if not self.trk_init[0]: | ||
611 | + self.tracker_connected = False | ||
612 | + self.tracker_id = 0 | ||
613 | + | ||
614 | + Publisher.sendMessage('Update status text in GUI', | ||
615 | + label=_("Tracker disconnected")) | ||
616 | + print("Tracker disconnected!") | ||
617 | + else: | ||
618 | + Publisher.sendMessage('Update status text in GUI', | ||
619 | + label=_("Tracker still connected")) | ||
620 | + print("Tracker still connected!") | ||
621 | + | ||
622 | + def IsTrackerInitialized(self): | ||
623 | + return self.trk_init and self.tracker_id and self.tracker_connected | ||
624 | + | ||
625 | + def AreTrackerFiducialsSet(self): | ||
626 | + return not np.isnan(self.tracker_fiducials).any() | ||
627 | + | ||
628 | + def SetTrackerFiducial(self, fiducial_index): | ||
629 | + coord = None | ||
630 | + | ||
631 | + coord_raw = dco.GetCoordinates(self.trk_init, self.tracker_id, self.ref_mode_id) | ||
632 | + | ||
633 | + if self.ref_mode_id: | ||
634 | + coord = dco.dynamic_reference_m(coord_raw[0, :], coord_raw[1, :]) | ||
635 | + else: | ||
636 | + coord = coord_raw[0, :] | ||
637 | + coord[2] = -coord[2] | ||
638 | + | ||
639 | + # Update tracker fiducial with tracker coordinates | ||
640 | + self.tracker_fiducials[fiducial_index, :] = coord[0:3] | ||
641 | + | ||
642 | + assert 0 <= fiducial_index <= 2, "Fiducial index out of range (0-2): {}".format(fiducial_index) | ||
643 | + | ||
644 | + self.tracker_fiducials_raw[2 * fiducial_index, :] = coord_raw[0, :] | ||
645 | + self.tracker_fiducials_raw[2 * fiducial_index + 1, :] = coord_raw[1, :] | ||
646 | + | ||
647 | + print("Set tracker fiducial {} to coordinates {}.".format(fiducial_index, coord[0:3])) | ||
648 | + | ||
649 | + def ResetTrackerFiducials(self): | ||
650 | + for m in range(3): | ||
651 | + self.tracker_fiducials[m, :] = [np.nan, np.nan, np.nan] | ||
652 | + | ||
653 | + def GetTrackerFiducials(self): | ||
654 | + return self.tracker_fiducials, self.tracker_fiducials_raw | ||
655 | + | ||
656 | + def GetTrackerInfo(self): | ||
657 | + return self.trk_init, self.tracker_id, self.ref_mode_id | ||
658 | + | ||
659 | + def SetReferenceMode(self, value): | ||
660 | + self.ref_mode_id = value | ||
661 | + | ||
662 | + # When ref mode is changed the tracker coordinates are set to zero | ||
663 | + self.ResetTrackerFiducials() | ||
664 | + | ||
665 | + # Some trackers do not accept restarting within this time window | ||
666 | + # TODO: Improve the restarting of trackers after changing reference mode | ||
667 | + Publisher.sendMessage('Update tracker initializer', | ||
668 | + nav_prop=(self.tracker_id, self.trk_init, self.ref_mode_id)) | ||
669 | + | ||
670 | + def GetReferenceMode(self): | ||
671 | + return self.ref_mode_id | ||
672 | + | ||
673 | + def UpdateUI(self, selection_ctrl, numctrls_coord, txtctrl_fre): | ||
674 | + if self.tracker_connected: | ||
675 | + selection_ctrl.SetSelection(self.tracker_id) | ||
676 | + else: | ||
677 | + selection_ctrl.SetSelection(0) | ||
678 | + | ||
679 | + # Update tracker location in the UI. | ||
680 | + for m in range(3): | ||
681 | + coord = self.tracker_fiducials[m, :] | ||
682 | + for n in range(0, 3): | ||
683 | + value = 0.0 if np.isnan(coord[n]) else float(coord[n]) | ||
684 | + numctrls_coord[m][n].SetValue(value) | ||
685 | + | ||
686 | + txtctrl_fre.SetValue('') | ||
687 | + txtctrl_fre.SetBackgroundColour('WHITE') | ||
688 | + | ||
689 | + def get_trackers(self): | ||
690 | + return const.TRACKERS | ||
691 | + | ||
692 | + | ||
693 | +class NeuronavigationPanel(wx.Panel): | ||
694 | + def __init__(self, parent): | ||
695 | + wx.Panel.__init__(self, parent) | ||
696 | + try: | ||
697 | + default_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_MENUBAR) | ||
698 | + except AttributeError: | ||
699 | + default_colour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_MENUBAR) | ||
700 | + self.SetBackgroundColour(default_colour) | ||
701 | + | ||
702 | + self.SetAutoLayout(1) | ||
703 | + | ||
704 | + self.__bind_events() | ||
705 | + | ||
706 | + # Initialize global variables | ||
707 | + self.pedal_connection = PedalConnection() if HAS_PEDAL_CONNECTION else None | ||
708 | + self.tracker = Tracker() | ||
709 | + self.navigation = Navigation() | ||
710 | + | ||
711 | + self.nav_status = False | ||
712 | + | ||
358 | # Initialize list of buttons and numctrls for wx objects | 713 | # Initialize list of buttons and numctrls for wx objects |
359 | self.btns_coord = [None, None, None, None, None, None] | 714 | self.btns_coord = [None, None, None, None, None, None] |
360 | self.numctrls_coord = [[], [], [], [], [], []] | 715 | self.numctrls_coord = [[], [], [], [], [], []] |
361 | 716 | ||
362 | # ComboBox for spatial tracker device selection | 717 | # ComboBox for spatial tracker device selection |
718 | + tracker_options = [_("Select tracker:")] + self.tracker.get_trackers() | ||
719 | + select_tracker_elem = wx.ComboBox(self, -1, "", | ||
720 | + choices=tracker_options, style=wx.CB_DROPDOWN|wx.CB_READONLY) | ||
721 | + | ||
363 | tooltip = wx.ToolTip(_("Choose the tracking device")) | 722 | tooltip = wx.ToolTip(_("Choose the tracking device")) |
364 | - choice_trck = wx.ComboBox(self, -1, "", | ||
365 | - choices=const.TRACKER, style=wx.CB_DROPDOWN|wx.CB_READONLY) | ||
366 | - choice_trck.SetToolTip(tooltip) | ||
367 | - choice_trck.SetSelection(const.DEFAULT_TRACKER) | ||
368 | - choice_trck.Bind(wx.EVT_COMBOBOX, partial(self.OnChoiceTracker, ctrl=choice_trck)) | ||
369 | - self.choice_trck = choice_trck | 723 | + select_tracker_elem.SetToolTip(tooltip) |
724 | + | ||
725 | + select_tracker_elem.SetSelection(const.DEFAULT_TRACKER) | ||
726 | + select_tracker_elem.Bind(wx.EVT_COMBOBOX, partial(self.OnChooseTracker, ctrl=select_tracker_elem)) | ||
727 | + self.select_tracker_elem = select_tracker_elem | ||
370 | 728 | ||
371 | # ComboBox for tracker reference mode | 729 | # ComboBox for tracker reference mode |
372 | tooltip = wx.ToolTip(_("Choose the navigation reference mode")) | 730 | tooltip = wx.ToolTip(_("Choose the navigation reference mode")) |
@@ -374,7 +732,7 @@ class NeuronavigationPanel(wx.Panel): | @@ -374,7 +732,7 @@ class NeuronavigationPanel(wx.Panel): | ||
374 | choices=const.REF_MODE, style=wx.CB_DROPDOWN|wx.CB_READONLY) | 732 | choices=const.REF_MODE, style=wx.CB_DROPDOWN|wx.CB_READONLY) |
375 | choice_ref.SetSelection(const.DEFAULT_REF_MODE) | 733 | choice_ref.SetSelection(const.DEFAULT_REF_MODE) |
376 | choice_ref.SetToolTip(tooltip) | 734 | choice_ref.SetToolTip(tooltip) |
377 | - choice_ref.Bind(wx.EVT_COMBOBOX, partial(self.OnChoiceRefMode, ctrl=choice_trck)) | 735 | + choice_ref.Bind(wx.EVT_COMBOBOX, partial(self.OnChooseReferenceMode, ctrl=select_tracker_elem)) |
378 | self.choice_ref = choice_ref | 736 | self.choice_ref = choice_ref |
379 | 737 | ||
380 | # Toggle buttons for image fiducials | 738 | # Toggle buttons for image fiducials |
@@ -422,12 +780,12 @@ class NeuronavigationPanel(wx.Panel): | @@ -422,12 +780,12 @@ class NeuronavigationPanel(wx.Panel): | ||
422 | btn_nav.Bind(wx.EVT_TOGGLEBUTTON, partial(self.OnNavigate, btn_nav=btn_nav)) | 780 | btn_nav.Bind(wx.EVT_TOGGLEBUTTON, partial(self.OnNavigate, btn_nav=btn_nav)) |
423 | 781 | ||
424 | tooltip = wx.ToolTip(_(u"Refine the coregistration")) | 782 | tooltip = wx.ToolTip(_(u"Refine the coregistration")) |
425 | - checkicp = wx.CheckBox(self, -1, _(' ')) | ||
426 | - checkicp.SetValue(False) | ||
427 | - checkicp.Enable(False) | ||
428 | - checkicp.Bind(wx.EVT_CHECKBOX, partial(self.Oncheckicp, ctrl=checkicp)) | ||
429 | - checkicp.SetToolTip(tooltip) | ||
430 | - self.checkicp = checkicp | 783 | + checkbox_icp = wx.CheckBox(self, -1, _(' ')) |
784 | + checkbox_icp.SetValue(False) | ||
785 | + checkbox_icp.Enable(False) | ||
786 | + checkbox_icp.Bind(wx.EVT_CHECKBOX, partial(self.OnCheckboxICP, ctrl=checkbox_icp)) | ||
787 | + checkbox_icp.SetToolTip(tooltip) | ||
788 | + self.checkbox_icp = checkbox_icp | ||
431 | 789 | ||
432 | # An indicator for pedal trigger | 790 | # An indicator for pedal trigger |
433 | if HAS_PEDAL_CONNECTION and self.pedal_connection.in_use: | 791 | if HAS_PEDAL_CONNECTION and self.pedal_connection.in_use: |
@@ -454,7 +812,7 @@ class NeuronavigationPanel(wx.Panel): | @@ -454,7 +812,7 @@ class NeuronavigationPanel(wx.Panel): | ||
454 | 812 | ||
455 | # Sizer to group all GUI objects | 813 | # Sizer to group all GUI objects |
456 | choice_sizer = wx.FlexGridSizer(rows=1, cols=2, hgap=5, vgap=5) | 814 | choice_sizer = wx.FlexGridSizer(rows=1, cols=2, hgap=5, vgap=5) |
457 | - choice_sizer.AddMany([(choice_trck, wx.LEFT), | 815 | + choice_sizer.AddMany([(select_tracker_elem, wx.LEFT), |
458 | (choice_ref, wx.RIGHT)]) | 816 | (choice_ref, wx.RIGHT)]) |
459 | 817 | ||
460 | coord_sizer = wx.GridBagSizer(hgap=5, vgap=5) | 818 | coord_sizer = wx.GridBagSizer(hgap=5, vgap=5) |
@@ -471,7 +829,7 @@ class NeuronavigationPanel(wx.Panel): | @@ -471,7 +829,7 @@ class NeuronavigationPanel(wx.Panel): | ||
471 | (txtctrl_fre, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL), | 829 | (txtctrl_fre, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL), |
472 | (btn_nav, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL), | 830 | (btn_nav, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL), |
473 | (txt_icp, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL), | 831 | (txt_icp, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL), |
474 | - (checkicp, 0, wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL)]) | 832 | + (checkbox_icp, 0, wx.ALIGN_CENTER_HORIZONTAL | wx.ALIGN_CENTER_VERTICAL)]) |
475 | 833 | ||
476 | pedal_sizer = wx.FlexGridSizer(rows=1, cols=2, hgap=5, vgap=5) | 834 | pedal_sizer = wx.FlexGridSizer(rows=1, cols=2, hgap=5, vgap=5) |
477 | if HAS_PEDAL_CONNECTION and self.pedal_connection.in_use: | 835 | if HAS_PEDAL_CONNECTION and self.pedal_connection.in_use: |
@@ -544,172 +902,87 @@ class NeuronavigationPanel(wx.Panel): | @@ -544,172 +902,87 @@ class NeuronavigationPanel(wx.Panel): | ||
544 | def SetImageFiducial(self, fiducial_name, coord): | 902 | def SetImageFiducial(self, fiducial_name, coord): |
545 | fiducial = self.GetFiducialByAttribute(const.IMAGE_FIDUCIALS, 'fiducial_name', fiducial_name) | 903 | fiducial = self.GetFiducialByAttribute(const.IMAGE_FIDUCIALS, 'fiducial_name', fiducial_name) |
546 | fiducial_index = fiducial['fiducial_index'] | 904 | fiducial_index = fiducial['fiducial_index'] |
547 | - self.fiducials[fiducial_index, :] = coord | ||
548 | 905 | ||
549 | - print("Set image fiducial {} to coordinates {}".format(fiducial_name, coord)) | 906 | + self.navigation.SetImageFiducial(fiducial_index, coord) |
550 | 907 | ||
551 | def SetTrackerFiducial(self, fiducial_name): | 908 | def SetTrackerFiducial(self, fiducial_name): |
552 | - fiducial = self.GetFiducialByAttribute(const.TRACKER_FIDUCIALS, 'fiducial_name', fiducial_name) | ||
553 | - fiducial_index = fiducial['fiducial_index'] | ||
554 | - | ||
555 | - coord = None | ||
556 | - | ||
557 | - if not(self.trk_init and self.tracker_id): | 909 | + if not self.tracker.IsTrackerInitialized(): |
558 | dlg.ShowNavigationTrackerWarning(0, 'choose') | 910 | dlg.ShowNavigationTrackerWarning(0, 'choose') |
559 | return | 911 | return |
560 | 912 | ||
561 | - # if self.tracker_id == const.DEBUGTRACK: | ||
562 | - # if btn_id == 3: | ||
563 | - # coord1 = np.array([-120., 0., 0., 0., 0., 0.]) | ||
564 | - # elif btn_id == 4: | ||
565 | - # coord1 = np.array([120., 0., 0., 0., 0., 0.]) | ||
566 | - # elif btn_id == 5: | ||
567 | - # coord1 = np.array([0., 120., 0., 0., 0., 0.]) | ||
568 | - # coord2 = np.zeros([3, 6]) | ||
569 | - # coord_raw = np.vstack([coord1, coord2]) | ||
570 | - # else: | ||
571 | - coord_raw = dco.GetCoordinates(self.trk_init, self.tracker_id, self.ref_mode_id) | ||
572 | - | ||
573 | - if self.ref_mode_id: | ||
574 | - coord = dco.dynamic_reference_m(coord_raw[0, :], coord_raw[1, :]) | ||
575 | - else: | ||
576 | - coord = coord_raw[0, :] | ||
577 | - coord[2] = -coord[2] | ||
578 | - | ||
579 | - # Update tracker fiducial with tracker coordinates | ||
580 | - self.fiducials[fiducial_index, :] = coord[0:3] | ||
581 | - | ||
582 | - if fiducial_index == 3: | ||
583 | - self.fiducials_raw[0, :] = coord_raw[0, :] | ||
584 | - self.fiducials_raw[1, :] = coord_raw[1, :] | ||
585 | - elif fiducial_index == 4: | ||
586 | - self.fiducials_raw[2, :] = coord_raw[0, :] | ||
587 | - self.fiducials_raw[3, :] = coord_raw[1, :] | ||
588 | - else: | ||
589 | - self.fiducials_raw[4, :] = coord_raw[0, :] | ||
590 | - self.fiducials_raw[5, :] = coord_raw[1, :] | ||
591 | - | ||
592 | - # Update tracker location in the UI. | ||
593 | - for n in [0, 1, 2]: | ||
594 | - self.numctrls_coord[fiducial_index][n].SetValue(float(coord[n])) | ||
595 | - | ||
596 | - print("Set tracker fiducial {} to coordinates {}.".format(fiducial_name, coord[0:3])) | ||
597 | - | ||
598 | - def UpdateNavigationStatus(self, nav_status, vis_status): | ||
599 | - self.nav_status = nav_status | ||
600 | - if nav_status and (self.m_icp is not None): | ||
601 | - self.checkicp.Enable(True) | ||
602 | - else: | ||
603 | - self.checkicp.Enable(False) | ||
604 | - #self.checkicp.SetValue(False) | ||
605 | - | ||
606 | - def UpdateFRE(self, fre): | ||
607 | - # TODO: Exhibit FRE in a warning dialog and only starts navigation after user clicks ok | ||
608 | - self.txtctrl_fre.SetValue(str(round(fre, 2))) | ||
609 | - if fre <= 3: | ||
610 | - self.txtctrl_fre.SetBackgroundColour('GREEN') | ||
611 | - else: | ||
612 | - self.txtctrl_fre.SetBackgroundColour('RED') | ||
613 | - | ||
614 | - def UpdateTrekkerObject(self, data): | ||
615 | - # self.trk_inp = data | ||
616 | - self.trekker = data | ||
617 | - | ||
618 | - def UpdateNumTracts(self, data): | ||
619 | - self.n_tracts = data | ||
620 | - | ||
621 | - def UpdateSeedOffset(self, data): | ||
622 | - self.seed_offset = data | ||
623 | - | ||
624 | - def UpdateSeedRadius(self, data): | ||
625 | - self.seed_radius = data | ||
626 | - | ||
627 | - def UpdateSleep(self, data): | ||
628 | - self.sleep_nav = data | ||
629 | - | ||
630 | - def UpdateNumberThreads(self, data): | ||
631 | - self.n_threads = data | 913 | + fiducial = self.GetFiducialByAttribute(const.TRACKER_FIDUCIALS, 'fiducial_name', fiducial_name) |
914 | + fiducial_index = fiducial['fiducial_index'] | ||
632 | 915 | ||
633 | - def UpdateTractsVisualization(self, data): | ||
634 | - self.view_tracts = data | 916 | + self.tracker.SetTrackerFiducial(fiducial_index) |
635 | 917 | ||
636 | - def UpdateACTData(self, data): | ||
637 | - self.act_data = data | 918 | + self.tracker.UpdateUI(self.select_tracker_elem, self.numctrls_coord[3:6], self.txtctrl_fre) |
638 | 919 | ||
639 | def UpdateNavigationStatus(self, nav_status, vis_status): | 920 | def UpdateNavigationStatus(self, nav_status, vis_status): |
640 | self.nav_status = nav_status | 921 | self.nav_status = nav_status |
641 | - if nav_status and (self.m_icp is not None): | ||
642 | - self.checkicp.Enable(True) | ||
643 | - else: | ||
644 | - self.checkicp.Enable(False) | ||
645 | - #self.checkicp.SetValue(False) | ||
646 | - | ||
647 | - def UpdateFRE(self, fre): | ||
648 | - # TODO: Exhibit FRE in a warning dialog and only starts navigation after user clicks ok | ||
649 | - self.txtctrl_fre.SetValue(str(round(fre, 2))) | ||
650 | - if fre <= 3: | ||
651 | - self.txtctrl_fre.SetBackgroundColour('GREEN') | 922 | + if nav_status and self.navigation.m_icp is not None: |
923 | + self.checkbox_icp.Enable(True) | ||
652 | else: | 924 | else: |
653 | - self.txtctrl_fre.SetBackgroundColour('RED') | 925 | + self.checkbox_icp.Enable(False) |
654 | 926 | ||
655 | def UpdateTrekkerObject(self, data): | 927 | def UpdateTrekkerObject(self, data): |
656 | # self.trk_inp = data | 928 | # self.trk_inp = data |
657 | - self.trekker = data | 929 | + self.navigation.trekker = data |
658 | 930 | ||
659 | def UpdateNumTracts(self, data): | 931 | def UpdateNumTracts(self, data): |
660 | - self.n_tracts = data | 932 | + self.navigation.n_tracts = data |
661 | 933 | ||
662 | def UpdateSeedOffset(self, data): | 934 | def UpdateSeedOffset(self, data): |
663 | - self.seed_offset = data | 935 | + self.navigation.seed_offset = data |
664 | 936 | ||
665 | def UpdateSeedRadius(self, data): | 937 | def UpdateSeedRadius(self, data): |
666 | - self.seed_radius = data | 938 | + self.navigation.seed_radius = data |
667 | 939 | ||
668 | def UpdateSleep(self, data): | 940 | def UpdateSleep(self, data): |
669 | - self.sleep_nav = data | 941 | + self.navigation.sleep_nav = data |
670 | 942 | ||
671 | def UpdateNumberThreads(self, data): | 943 | def UpdateNumberThreads(self, data): |
672 | - self.n_threads = data | 944 | + self.navigation.n_threads = data |
673 | 945 | ||
674 | def UpdateTractsVisualization(self, data): | 946 | def UpdateTractsVisualization(self, data): |
675 | - self.view_tracts = data | 947 | + self.navigation.view_tracts = data |
676 | 948 | ||
677 | def UpdateACTData(self, data): | 949 | def UpdateACTData(self, data): |
678 | - self.act_data = data | 950 | + self.navigation.act_data = data |
679 | 951 | ||
680 | def UpdateTarget(self, coord): | 952 | def UpdateTarget(self, coord): |
681 | - self.target = coord | 953 | + self.navigation.target = coord |
682 | 954 | ||
683 | def EnableACT(self, data): | 955 | def EnableACT(self, data): |
684 | - self.enable_act = data | 956 | + self.navigation.enable_act = data |
685 | 957 | ||
686 | def UpdateImageCoordinates(self, position): | 958 | def UpdateImageCoordinates(self, position): |
687 | # TODO: Change from world coordinates to matrix coordinates. They are better for multi software communication. | 959 | # TODO: Change from world coordinates to matrix coordinates. They are better for multi software communication. |
688 | - self.current_coord = position | 960 | + self.navigation.current_coord = position |
961 | + | ||
689 | for m in [0, 1, 2]: | 962 | for m in [0, 1, 2]: |
690 | if not self.btns_coord[m].GetValue(): | 963 | if not self.btns_coord[m].GetValue(): |
691 | for n in [0, 1, 2]: | 964 | for n in [0, 1, 2]: |
692 | - self.numctrls_coord[m][n].SetValue(float(self.current_coord[n])) | 965 | + self.numctrls_coord[m][n].SetValue(float(position[n])) |
693 | 966 | ||
694 | def UpdateObjectRegistration(self, data=None): | 967 | def UpdateObjectRegistration(self, data=None): |
695 | - if data: | ||
696 | - self.obj_reg = data | ||
697 | - self.obj_reg_status = True | ||
698 | - else: | ||
699 | - self.obj_reg = None | ||
700 | - self.obj_reg_status = False | 968 | + self.navigation.obj_reg = data |
701 | 969 | ||
702 | def UpdateTrackObjectState(self, evt=None, flag=None, obj_name=None, polydata=None): | 970 | def UpdateTrackObjectState(self, evt=None, flag=None, obj_name=None, polydata=None): |
703 | - self.track_obj = flag | 971 | + self.navigation.track_obj = flag |
704 | 972 | ||
705 | def UpdateTriggerState(self, trigger_state): | 973 | def UpdateTriggerState(self, trigger_state): |
706 | - self.trigger_state = trigger_state | 974 | + self.navigation.trigger_state = trigger_state |
975 | + | ||
976 | + def ResetICP(self): | ||
977 | + self.navigation.ResetICP() | ||
978 | + self.checkbox_icp.Enable(False) | ||
979 | + self.checkbox_icp.SetValue(False) | ||
707 | 980 | ||
708 | def OnDisconnectTracker(self): | 981 | def OnDisconnectTracker(self): |
709 | - if self.tracker_id: | ||
710 | - dt.TrackerConnection(self.tracker_id, self.trk_init[0], 'disconnect') | 982 | + self.tracker.DisconnectTracker() |
983 | + self.ResetICP() | ||
711 | 984 | ||
712 | - def OnChoiceTracker(self, evt, ctrl): | 985 | + def OnChooseTracker(self, evt, ctrl): |
713 | Publisher.sendMessage('Update status text in GUI', | 986 | Publisher.sendMessage('Update status text in GUI', |
714 | label=_("Configuring tracker ...")) | 987 | label=_("Configuring tracker ...")) |
715 | if hasattr(evt, 'GetSelection'): | 988 | if hasattr(evt, 'GetSelection'): |
@@ -717,81 +990,16 @@ class NeuronavigationPanel(wx.Panel): | @@ -717,81 +990,16 @@ class NeuronavigationPanel(wx.Panel): | ||
717 | else: | 990 | else: |
718 | choice = const.DISCTRACK | 991 | choice = const.DISCTRACK |
719 | 992 | ||
720 | - if self.trk_init: | ||
721 | - trck = self.trk_init[0] | ||
722 | - else: | ||
723 | - trck = None | ||
724 | - | ||
725 | - # Conditions check if click was on current selection and if any other tracker | ||
726 | - # has been initialized before | ||
727 | - if trck and choice != const.DISCTRACK: | ||
728 | - self.ResetTrackerFiducials() | ||
729 | - self.ResetIcp() | ||
730 | - Publisher.sendMessage('Update status text in GUI', | ||
731 | - label=_("Disconnecting tracker...")) | ||
732 | - Publisher.sendMessage('Remove sensors ID') | ||
733 | - self.trk_init = dt.TrackerConnection(self.tracker_id, trck, 'disconnect') | ||
734 | - Publisher.sendMessage('Remove object data') | ||
735 | - self.tracker_id = choice | ||
736 | - if not self.trk_init[0] and choice: | ||
737 | - Publisher.sendMessage('Update status text in GUI', | ||
738 | - label=_("Tracker disconnected successfully")) | ||
739 | - self.trk_init = dt.TrackerConnection(self.tracker_id, None, 'connect') | ||
740 | - if not self.trk_init[0]: | ||
741 | - dlg.ShowNavigationTrackerWarning(self.tracker_id, self.trk_init[1]) | ||
742 | - ctrl.SetSelection(0) | ||
743 | - print("Tracker not connected!") | ||
744 | - else: | ||
745 | - ctrl.SetSelection(self.tracker_id) | ||
746 | - print("Tracker connected!") | ||
747 | - elif choice == const.DISCTRACK: | ||
748 | - if trck: | ||
749 | - self.ResetTrackerFiducials() | ||
750 | - self.ResetIcp() | ||
751 | - Publisher.sendMessage('Update status text in GUI', | ||
752 | - label=_("Disconnecting tracker ...")) | ||
753 | - Publisher.sendMessage('Remove sensors ID') | ||
754 | - Publisher.sendMessage('Remove object data') | ||
755 | - self.trk_init = dt.TrackerConnection(self.tracker_id, trck, 'disconnect') | ||
756 | - if not self.trk_init[0]: | ||
757 | - if evt is not False: | ||
758 | - dlg.ShowNavigationTrackerWarning(self.tracker_id, 'disconnect') | ||
759 | - self.tracker_id = 0 | ||
760 | - ctrl.SetSelection(self.tracker_id) | ||
761 | - Publisher.sendMessage('Update status text in GUI', | ||
762 | - label=_("Tracker disconnected")) | ||
763 | - print("Tracker disconnected!") | ||
764 | - else: | ||
765 | - Publisher.sendMessage('Update status text in GUI', | ||
766 | - label=_("Tracker still connected")) | ||
767 | - print("Tracker still connected!") | ||
768 | - else: | ||
769 | - ctrl.SetSelection(self.tracker_id) | ||
770 | - | ||
771 | - else: | ||
772 | - # If trk_init is None try to connect. If doesn't succeed show dialog. | ||
773 | - if choice: | ||
774 | - self.tracker_id = choice | ||
775 | - self.trk_init = dt.TrackerConnection(self.tracker_id, None, 'connect') | ||
776 | - if not self.trk_init[0]: | ||
777 | - dlg.ShowNavigationTrackerWarning(self.tracker_id, self.trk_init[1]) | ||
778 | - self.tracker_id = 0 | ||
779 | - ctrl.SetSelection(self.tracker_id) | 993 | + self.tracker.SetTracker(choice) |
994 | + self.ResetICP() | ||
995 | + self.tracker.UpdateUI(ctrl, self.numctrls_coord[3:6], self.txtctrl_fre) | ||
780 | 996 | ||
781 | Publisher.sendMessage('Update status text in GUI', label=_("Ready")) | 997 | Publisher.sendMessage('Update status text in GUI', label=_("Ready")) |
782 | - Publisher.sendMessage('Update tracker initializer', | ||
783 | - nav_prop=(self.tracker_id, self.trk_init, self.ref_mode_id)) | ||
784 | 998 | ||
785 | - def OnChoiceRefMode(self, evt, ctrl): | ||
786 | - # When ref mode is changed the tracker coordinates are set to zero | ||
787 | - self.ref_mode_id = evt.GetSelection() | ||
788 | - self.ResetTrackerFiducials() | ||
789 | - self.ResetIcp() | ||
790 | - # Some trackers do not accept restarting within this time window | ||
791 | - # TODO: Improve the restarting of trackers after changing reference mode | ||
792 | - # self.OnChoiceTracker(None, ctrl) | ||
793 | - Publisher.sendMessage('Update tracker initializer', | ||
794 | - nav_prop=(self.tracker_id, self.trk_init, self.ref_mode_id)) | 999 | + def OnChooseReferenceMode(self, evt, ctrl): |
1000 | + self.tracker.SetReferenceMode(evt.GetSelection()) | ||
1001 | + self.ResetICP() | ||
1002 | + | ||
795 | print("Reference mode changed!") | 1003 | print("Reference mode changed!") |
796 | 1004 | ||
797 | def OnImageFiducials(self, n, evt): | 1005 | def OnImageFiducials(self, n, evt): |
@@ -818,205 +1026,69 @@ class NeuronavigationPanel(wx.Panel): | @@ -818,205 +1026,69 @@ class NeuronavigationPanel(wx.Panel): | ||
818 | fiducial_name = const.TRACKER_FIDUCIALS[n]['fiducial_name'] | 1026 | fiducial_name = const.TRACKER_FIDUCIALS[n]['fiducial_name'] |
819 | Publisher.sendMessage('Set tracker fiducial', fiducial_name=fiducial_name) | 1027 | Publisher.sendMessage('Set tracker fiducial', fiducial_name=fiducial_name) |
820 | 1028 | ||
821 | - def OnICP(self, m_change): | ||
822 | - dialog = dlg.ICPCorregistrationDialog(nav_prop=(m_change, self.tracker_id, self.trk_init, self.ref_mode_id)) | ||
823 | - if dialog.ShowModal() == wx.ID_OK: | ||
824 | - self.m_icp, point_coord, transformed_points, prev_error, final_error = dialog.GetValue() | ||
825 | - #TODO: checkbox in the dialog to transfer the icp points to 3D viewer | ||
826 | - #create markers | ||
827 | - # for i in range(len(point_coord)): | ||
828 | - # img_coord = point_coord[i][0],-point_coord[i][1],point_coord[i][2], 0, 0, 0 | ||
829 | - # transf_coord = transformed_points[i][0],-transformed_points[i][1],transformed_points[i][2], 0, 0, 0 | ||
830 | - # Publisher.sendMessage('Create marker', coord=img_coord, marker_id=None, colour=(1,0,0)) | ||
831 | - # Publisher.sendMessage('Create marker', coord=transf_coord, marker_id=None, colour=(0,0,1)) | ||
832 | - if self.m_icp is not None: | ||
833 | - dlg.ReportICPerror(prev_error, final_error) | ||
834 | - self.checkicp.Enable(True) | ||
835 | - self.checkicp.SetValue(True) | ||
836 | - self.icp = True | ||
837 | - else: | ||
838 | - self.checkicp.Enable(False) | ||
839 | - self.checkicp.SetValue(False) | ||
840 | - self.icp = False | ||
841 | - | ||
842 | - return self.m_icp | ||
843 | - | ||
844 | - def Oncheckicp(self, evt, ctrl): | ||
845 | - if ctrl.GetValue() and evt and (self.m_icp is not None): | ||
846 | - self.icp = True | ||
847 | - else: | ||
848 | - self.icp = False | ||
849 | - self.ctrl_icp() | ||
850 | - | ||
851 | - def ctrl_icp(self): | ||
852 | - if self.icp: | ||
853 | - self.UpdateFRE(self.icp_fre) | ||
854 | - else: | ||
855 | - self.UpdateFRE(self.fre) | ||
856 | - self.icp_queue.put_nowait([self.icp, self.m_icp]) | ||
857 | - #print(self.icp, self.m_icp) | ||
858 | - | ||
859 | def onStopNavigation(self): | 1029 | def onStopNavigation(self): |
860 | - choice_trck = self.choice_trck | 1030 | + select_tracker_elem = self.select_tracker_elem |
861 | choice_ref = self.choice_ref | 1031 | choice_ref = self.choice_ref |
862 | 1032 | ||
863 | - self.event.set() | ||
864 | - | ||
865 | - # print("coord unfinished: {}, queue {}", self.coord_queue.unfinished_tasks, self.coord_queue.qsize()) | ||
866 | - # print("coord_tracts unfinished: {}, queue {}", self.coord_tracts_queue.unfinished_tasks, self.coord_tracts_queue.qsize()) | ||
867 | - # print("tracts unfinished: {}, queue {}", self.tracts_queue.unfinished_tasks, self.tracts_queue.qsize()) | ||
868 | - self.coord_queue.clear() | ||
869 | - # self.visualization_queue.clear() | ||
870 | - if self.trigger_state: | ||
871 | - self.trigger_queue.clear() | ||
872 | - if self.view_tracts: | ||
873 | - self.coord_tracts_queue.clear() | ||
874 | - self.tracts_queue.clear() | ||
875 | - | ||
876 | - # print("coord after unfinished: {}, queue {}", self.coord_queue.unfinished_tasks, self.coord_queue.qsize()) | ||
877 | - # print("coord_tracts after unfinished: {}, queue {}", self.coord_tracts_queue.unfinished_tasks, self.coord_tracts_queue.qsize()) | ||
878 | - # print("tracts after unfinished: {}, queue {}", self.tracts_queue.unfinished_tasks, self.tracts_queue.qsize()) | ||
879 | - self.coord_queue.join() | ||
880 | - # self.visualization_queue.join() | ||
881 | - if self.trigger_state: | ||
882 | - self.trigger_queue.join() | ||
883 | - if self.view_tracts: | ||
884 | - self.coord_tracts_queue.join() | ||
885 | - self.tracts_queue.join() | ||
886 | - | ||
887 | - # print("coord join unfinished: {}, queue {}", self.coord_queue.unfinished_tasks, self.coord_queue.qsize()) | ||
888 | - # print("vis join unfinished: {}, queue {}", self.visualization_queue.unfinished_tasks, self.visualization_queue.qsize()) | 1033 | + self.navigation.StopNavigation() |
889 | 1034 | ||
890 | # Enable all navigation buttons | 1035 | # Enable all navigation buttons |
891 | choice_ref.Enable(True) | 1036 | choice_ref.Enable(True) |
892 | - choice_trck.Enable(True) | 1037 | + select_tracker_elem.Enable(True) |
1038 | + | ||
893 | for btn_c in self.btns_coord: | 1039 | for btn_c in self.btns_coord: |
894 | btn_c.Enable(True) | 1040 | btn_c.Enable(True) |
895 | 1041 | ||
896 | - # if self.trigger_state: | ||
897 | - # self.trigger.stop() | 1042 | + def UpdateFiducialRegistrationError(self): |
1043 | + self.navigation.UpdateFiducialRegistrationError(self.tracker) | ||
1044 | + fre, fre_ok = self.navigation.GetFiducialRegistrationError() | ||
898 | 1045 | ||
899 | - vis_components = [self.trigger_state, self.view_tracts] | ||
900 | - Publisher.sendMessage("Navigation status", nav_status=False, vis_status=vis_components) | 1046 | + self.txtctrl_fre.SetValue(str(round(fre, 2))) |
1047 | + if fre_ok: | ||
1048 | + self.txtctrl_fre.SetBackgroundColour('GREEN') | ||
1049 | + else: | ||
1050 | + self.txtctrl_fre.SetBackgroundColour('RED') | ||
1051 | + | ||
1052 | + return fre_ok | ||
901 | 1053 | ||
902 | def onStartNavigation(self): | 1054 | def onStartNavigation(self): |
903 | - choice_trck = self.choice_trck | 1055 | + select_tracker_elem = self.select_tracker_elem |
904 | choice_ref = self.choice_ref | 1056 | choice_ref = self.choice_ref |
905 | 1057 | ||
906 | - errors = False | ||
907 | - | ||
908 | - # initialize jobs list | ||
909 | - jobs_list = [] | ||
910 | - vis_components = [self.trigger_state, self.view_tracts] | ||
911 | - vis_queues = [self.coord_queue, self.trigger_queue, self.tracts_queue, self.icp_queue] | ||
912 | - | ||
913 | - if np.isnan(self.fiducials).any(): | 1058 | + if not self.tracker.AreTrackerFiducialsSet() or not self.navigation.AreImageFiducialsSet(): |
914 | wx.MessageBox(_("Invalid fiducials, select all coordinates."), _("InVesalius 3")) | 1059 | wx.MessageBox(_("Invalid fiducials, select all coordinates."), _("InVesalius 3")) |
915 | 1060 | ||
916 | - elif not self.trk_init[0] or not self.tracker_id: | 1061 | + elif not self.tracker.IsTrackerInitialized(): |
917 | dlg.ShowNavigationTrackerWarning(0, 'choose') | 1062 | dlg.ShowNavigationTrackerWarning(0, 'choose') |
918 | errors = True | 1063 | errors = True |
919 | 1064 | ||
920 | else: | 1065 | else: |
921 | - if self.event.is_set(): | ||
922 | - self.event.clear() | 1066 | + if not self.UpdateFiducialRegistrationError(): |
1067 | + # TODO: Exhibit FRE in a warning dialog and only starts navigation after user clicks ok | ||
1068 | + print("WARNING: Fiducial registration error too large.") | ||
923 | 1069 | ||
924 | - # prepare GUI for navigation | ||
925 | - Publisher.sendMessage("Navigation status", nav_status=True, vis_status=vis_components) | 1070 | + # Prepare GUI for navigation. |
926 | Publisher.sendMessage("Toggle Cross", id=const.SLICE_STATE_CROSS) | 1071 | Publisher.sendMessage("Toggle Cross", id=const.SLICE_STATE_CROSS) |
927 | Publisher.sendMessage("Hide current mask") | 1072 | Publisher.sendMessage("Hide current mask") |
928 | 1073 | ||
929 | - # disable all navigation buttons | 1074 | + # Disable all navigation buttons. |
930 | choice_ref.Enable(False) | 1075 | choice_ref.Enable(False) |
931 | - choice_trck.Enable(False) | 1076 | + select_tracker_elem.Enable(False) |
932 | for btn_c in self.btns_coord: | 1077 | for btn_c in self.btns_coord: |
933 | btn_c.Enable(False) | 1078 | btn_c.Enable(False) |
934 | 1079 | ||
935 | - # fiducials matrix | ||
936 | - m_change = tr.affine_matrix_from_points(self.fiducials[3:, :].T, self.fiducials[:3, :].T, | ||
937 | - shear=False, scale=False) | ||
938 | - # initialize spatial tracker parameters | ||
939 | - tracker_mode = self.trk_init, self.tracker_id, self.ref_mode_id | ||
940 | - | ||
941 | - # compute fiducial registration error (FRE) | ||
942 | - if not self.icp_fre: | ||
943 | - self.fre = db.calculate_fre(self.fiducials_raw, self.fiducials, self.ref_mode_id, m_change) | ||
944 | - self.UpdateFRE(self.fre) | ||
945 | - | ||
946 | - if self.track_obj: | ||
947 | - # if object tracking is selected | ||
948 | - if not self.obj_reg_status: | ||
949 | - # check if object registration was performed | ||
950 | - wx.MessageBox(_("Perform coil registration before navigation."), _("InVesalius 3")) | ||
951 | - errors = True | ||
952 | - else: | ||
953 | - # if object registration was correctly performed continue with navigation | ||
954 | - # obj_reg[0] is object 3x3 fiducial matrix and obj_reg[1] is 3x3 orientation matrix | ||
955 | - obj_fiducials, obj_orients, obj_ref_mode, obj_name = self.obj_reg | ||
956 | - | ||
957 | - coreg_data = [m_change, obj_ref_mode] | ||
958 | - | ||
959 | - if self.ref_mode_id: | ||
960 | - coord_raw = dco.GetCoordinates(self.trk_init, self.tracker_id, self.ref_mode_id) | ||
961 | - else: | ||
962 | - coord_raw = np.array([None]) | ||
963 | - | ||
964 | - obj_data = db.object_registration(obj_fiducials, obj_orients, coord_raw, m_change) | ||
965 | - coreg_data.extend(obj_data) | ||
966 | - | ||
967 | - queues = [self.coord_queue, self.coord_tracts_queue, self.icp_queue] | ||
968 | - jobs_list.append(dcr.CoordinateCorregistrate(self.ref_mode_id, tracker_mode, coreg_data, | ||
969 | - self.view_tracts, queues, | ||
970 | - self.event, self.sleep_nav, self.tracker_id, | ||
971 | - self.target)) | ||
972 | - else: | ||
973 | - coreg_data = (m_change, 0) | ||
974 | - queues = [self.coord_queue, self.coord_tracts_queue, self.icp_queue] | ||
975 | - jobs_list.append(dcr.CoordinateCorregistrateNoObject(self.ref_mode_id, tracker_mode, coreg_data, | ||
976 | - self.view_tracts, queues, | ||
977 | - self.event, self.sleep_nav)) | ||
978 | - | ||
979 | - if not errors: | ||
980 | - #TODO: Test the trigger thread | ||
981 | - if self.trigger_state: | ||
982 | - # self.trigger = trig.Trigger(nav_id) | ||
983 | - jobs_list.append(trig.TriggerNew(self.trigger_queue, self.event, self.sleep_nav)) | ||
984 | - | ||
985 | - if self.view_tracts: | ||
986 | - # initialize Trekker parameters | ||
987 | - slic = sl.Slice() | ||
988 | - prj_data = prj.Project() | ||
989 | - matrix_shape = tuple(prj_data.matrix_shape) | ||
990 | - affine = slic.affine.copy() | ||
991 | - affine[1, -1] -= matrix_shape[1] | ||
992 | - affine_vtk = vtk_utils.numpy_to_vtkMatrix4x4(affine) | ||
993 | - Publisher.sendMessage("Update marker offset state", create=True) | ||
994 | - self.trk_inp = self.trekker, affine, self.seed_offset, self.n_tracts, self.seed_radius,\ | ||
995 | - self.n_threads, self.act_data, affine_vtk, matrix_shape[1] | ||
996 | - # print("Appending the tract computation thread!") | ||
997 | - queues = [self.coord_tracts_queue, self.tracts_queue] | ||
998 | - if self.enable_act: | ||
999 | - jobs_list.append(dti.ComputeTractsACTThread(self.trk_inp, queues, self.event, self.sleep_nav)) | ||
1000 | - else: | ||
1001 | - jobs_list.append(dti.ComputeTractsThread(self.trk_inp, queues, self.event, self.sleep_nav)) | ||
1002 | - | ||
1003 | - jobs_list.append(UpdateNavigationScene(vis_queues, vis_components, | ||
1004 | - self.event, self.sleep_nav)) | 1080 | + self.navigation.StartNavigation(self.tracker) |
1005 | 1081 | ||
1006 | - for jobs in jobs_list: | ||
1007 | - # jobs.daemon = True | ||
1008 | - jobs.start() | ||
1009 | - # del jobs | 1082 | + # Update FRE once more after starting the navigation, due to the optional use of ICP, |
1083 | + # which improves FRE. | ||
1084 | + self.UpdateFiducialRegistrationError() | ||
1010 | 1085 | ||
1011 | - if not self.checkicp.GetValue(): | ||
1012 | - if dlg.ICPcorregistration(self.fre): | ||
1013 | - m_icp = self.OnICP(m_change) | ||
1014 | - self.icp_fre = db.calculate_fre(self.fiducials_raw, self.fiducials, self.ref_mode_id, | ||
1015 | - m_change, m_icp) | ||
1016 | - self.ctrl_icp() | 1086 | + if self.navigation.use_icp: |
1087 | + self.checkbox_icp.Enable(True) | ||
1088 | + self.checkbox_icp.SetValue(True) | ||
1017 | 1089 | ||
1018 | def OnNavigate(self, evt, btn_nav): | 1090 | def OnNavigate(self, evt, btn_nav): |
1019 | - choice_trck = self.choice_trck | 1091 | + select_tracker_elem = self.select_tracker_elem |
1020 | choice_ref = self.choice_ref | 1092 | choice_ref = self.choice_ref |
1021 | 1093 | ||
1022 | nav_id = btn_nav.GetValue() | 1094 | nav_id = btn_nav.GetValue() |
@@ -1041,28 +1113,15 @@ class NeuronavigationPanel(wx.Panel): | @@ -1041,28 +1113,15 @@ class NeuronavigationPanel(wx.Panel): | ||
1041 | for n in range(0, 3): | 1113 | for n in range(0, 3): |
1042 | self.numctrls_coord[m][n].SetValue(0.0) | 1114 | self.numctrls_coord[m][n].SetValue(0.0) |
1043 | 1115 | ||
1044 | - def ResetTrackerFiducials(self): | ||
1045 | - for m in range(3, 6): | ||
1046 | - self.fiducials[m, :] = [np.nan, np.nan, np.nan] | ||
1047 | - for n in range(0, 3): | ||
1048 | - self.numctrls_coord[m][n].SetValue(0.0) | ||
1049 | - | ||
1050 | - self.txtctrl_fre.SetValue('') | ||
1051 | - self.txtctrl_fre.SetBackgroundColour('WHITE') | ||
1052 | - | ||
1053 | - def ResetIcp(self): | ||
1054 | - self.m_icp = None | ||
1055 | - self.fre = None | ||
1056 | - self.icp_fre = None | ||
1057 | - self.icp = False | ||
1058 | - self.checkicp.Enable(False) | ||
1059 | - self.checkicp.SetValue(False) | 1116 | + def OnCheckboxICP(self, evt, ctrl): |
1117 | + self.navigation.SetICP(ctrl.GetValue()) | ||
1118 | + self.UpdateFiducialRegistrationError() | ||
1060 | 1119 | ||
1061 | def OnCloseProject(self): | 1120 | def OnCloseProject(self): |
1062 | self.ResetTrackerFiducials() | 1121 | self.ResetTrackerFiducials() |
1063 | self.ResetImageFiducials() | 1122 | self.ResetImageFiducials() |
1064 | - self.ResetIcp() | ||
1065 | - self.OnChoiceTracker(False, self.choice_trck) | 1123 | + self.navigation.ResetICP() |
1124 | + self.OnChooseTracker(False, self.select_tracker_elem) | ||
1066 | Publisher.sendMessage('Update object registration') | 1125 | Publisher.sendMessage('Update object registration') |
1067 | Publisher.sendMessage('Update track object state', flag=False, obj_name=False) | 1126 | Publisher.sendMessage('Update track object state', flag=False, obj_name=False) |
1068 | Publisher.sendMessage('Delete all markers') | 1127 | Publisher.sendMessage('Delete all markers') |