Commit e971a69900d0f036bd49404d0c75b65f5ca0e116

Authored by Olli-Pekka Kahilakoski
Committed by GitHub
1 parent df0e6ca1
Exists in master

ADD: Send coil mesh using NeuronavigationApi (#418)

* ADD: Send coil mesh using NeuronavigationApi

* Review comments, some tweaks to save memory and speed up
invesalius/gui/task_navigator.py
@@ -201,7 +201,12 @@ class InnerFoldPanel(wx.Panel): @@ -201,7 +201,12 @@ class InnerFoldPanel(wx.Panel):
201 201
202 # Fold 2 - Object registration panel 202 # Fold 2 - Object registration panel
203 item = fold_panel.AddFoldPanel(_("Object registration"), collapsed=True) 203 item = fold_panel.AddFoldPanel(_("Object registration"), collapsed=True)
204 - otw = ObjectRegistrationPanel(item, tracker, pedal_connection) 204 + otw = ObjectRegistrationPanel(
  205 + parent=item,
  206 + tracker=tracker,
  207 + pedal_connection=pedal_connection,
  208 + neuronavigation_api=neuronavigation_api,
  209 + )
205 210
206 fold_panel.ApplyCaptionStyle(item, style) 211 fold_panel.ApplyCaptionStyle(item, style)
207 fold_panel.AddFoldPanelWindow(item, otw, spacing=0, 212 fold_panel.AddFoldPanelWindow(item, otw, spacing=0,
@@ -889,7 +894,7 @@ class NeuronavigationPanel(wx.Panel): @@ -889,7 +894,7 @@ class NeuronavigationPanel(wx.Panel):
889 894
890 895
891 class ObjectRegistrationPanel(wx.Panel): 896 class ObjectRegistrationPanel(wx.Panel):
892 - def __init__(self, parent, tracker, pedal_connection): 897 + def __init__(self, parent, tracker, pedal_connection, neuronavigation_api):
893 wx.Panel.__init__(self, parent) 898 wx.Panel.__init__(self, parent)
894 try: 899 try:
895 default_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_MENUBAR) 900 default_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_MENUBAR)
@@ -901,6 +906,7 @@ class ObjectRegistrationPanel(wx.Panel): @@ -901,6 +906,7 @@ class ObjectRegistrationPanel(wx.Panel):
901 906
902 self.tracker = tracker 907 self.tracker = tracker
903 self.pedal_connection = pedal_connection 908 self.pedal_connection = pedal_connection
  909 + self.neuronavigation_api = neuronavigation_api
904 910
905 self.nav_prop = None 911 self.nav_prop = None
906 self.obj_fiducials = None 912 self.obj_fiducials = None
@@ -917,7 +923,7 @@ class ObjectRegistrationPanel(wx.Panel): @@ -917,7 +923,7 @@ class ObjectRegistrationPanel(wx.Panel):
917 btn_new = wx.Button(self, -1, _("New"), size=wx.Size(65, 23)) 923 btn_new = wx.Button(self, -1, _("New"), size=wx.Size(65, 23))
918 btn_new.SetToolTip(tooltip) 924 btn_new.SetToolTip(tooltip)
919 btn_new.Enable(1) 925 btn_new.Enable(1)
920 - btn_new.Bind(wx.EVT_BUTTON, self.OnLinkCreate) 926 + btn_new.Bind(wx.EVT_BUTTON, self.OnCreateNewCoil)
921 self.btn_new = btn_new 927 self.btn_new = btn_new
922 928
923 # Button for import config coil file 929 # Button for import config coil file
@@ -1060,13 +1066,16 @@ class ObjectRegistrationPanel(wx.Panel): @@ -1060,13 +1066,16 @@ class ObjectRegistrationPanel(wx.Panel):
1060 coil_index = evt.GetSelection() 1066 coil_index = evt.GetSelection()
1061 Publisher.sendMessage('Change selected coil', self.coil_list[coil_index][1]) 1067 Publisher.sendMessage('Change selected coil', self.coil_list[coil_index][1])
1062 1068
1063 - def OnLinkCreate(self, event=None): 1069 + def OnCreateNewCoil(self, event=None):
1064 1070
1065 if self.tracker.IsTrackerInitialized(): 1071 if self.tracker.IsTrackerInitialized():
1066 dialog = dlg.ObjectCalibrationDialog(self.tracker, self.pedal_connection) 1072 dialog = dlg.ObjectCalibrationDialog(self.tracker, self.pedal_connection)
1067 try: 1073 try:
1068 if dialog.ShowModal() == wx.ID_OK: 1074 if dialog.ShowModal() == wx.ID_OK:
1069 self.obj_fiducials, self.obj_orients, self.obj_ref_mode, self.obj_name, polydata, use_default_object = dialog.GetValue() 1075 self.obj_fiducials, self.obj_orients, self.obj_ref_mode, self.obj_name, polydata, use_default_object = dialog.GetValue()
  1076 +
  1077 + self.neuronavigation_api.update_coil_mesh(polydata)
  1078 +
1070 if np.isfinite(self.obj_fiducials).all() and np.isfinite(self.obj_orients).all(): 1079 if np.isfinite(self.obj_fiducials).all() and np.isfinite(self.obj_orients).all():
1071 self.checktrack.Enable(1) 1080 self.checktrack.Enable(1)
1072 Publisher.sendMessage('Update object registration', 1081 Publisher.sendMessage('Update object registration',
invesalius/net/neuronavigation_api.py
@@ -20,6 +20,9 @@ @@ -20,6 +20,9 @@
20 from invesalius.pubsub import pub as Publisher 20 from invesalius.pubsub import pub as Publisher
21 from invesalius.utils import Singleton 21 from invesalius.utils import Singleton
22 22
  23 +import numpy as np
  24 +from vtk.numpy_interface import dataset_adapter
  25 +
23 class NeuronavigationApi(metaclass=Singleton): 26 class NeuronavigationApi(metaclass=Singleton):
24 """ 27 """
25 An API used internally in InVesalius to communicate with the 28 An API used internally in InVesalius to communicate with the
@@ -34,6 +37,8 @@ class NeuronavigationApi(metaclass=Singleton): @@ -34,6 +37,8 @@ class NeuronavigationApi(metaclass=Singleton):
34 37
35 If connection object is not given or it is None, skip doing the updates. 38 If connection object is not given or it is None, skip doing the updates.
36 """ 39 """
  40 + N_VERTICES_IN_POLYGON = 3
  41 +
37 def __init__(self, connection=None): 42 def __init__(self, connection=None):
38 if connection is not None: 43 if connection is not None:
39 assert self._hasmethod(connection, 'update_coil_pose') 44 assert self._hasmethod(connection, 'update_coil_pose')
@@ -65,3 +70,28 @@ class NeuronavigationApi(metaclass=Singleton): @@ -65,3 +70,28 @@ class NeuronavigationApi(metaclass=Singleton):
65 position=position, 70 position=position,
66 orientation=orientation, 71 orientation=orientation,
67 ) 72 )
  73 +
  74 + def update_coil_mesh(self, polydata):
  75 + wrapped = dataset_adapter.WrapDataObject(polydata)
  76 +
  77 + points = np.asarray(wrapped.Points)
  78 + polygons_raw = np.asarray(wrapped.Polygons)
  79 +
  80 + # The polygons are returned as 1d-array of the form
  81 + #
  82 + # [n_0, id_0(0), id_0(1), ..., id_0(n_0),
  83 + # n_1, id_1(0), id_1(1), ..., id_1(n_1),
  84 + # ...]
  85 + #
  86 + # where n_i is the number of vertices in polygon i, and id_i's are indices to the vertex list.
  87 + #
  88 + # Assert that all polygons have an equal number of vertices, reshape the array, and drop n_i's.
  89 + #
  90 + assert np.all(polygons_raw[0::self.N_VERTICES_IN_POLYGON + 1] == self.N_VERTICES_IN_POLYGON)
  91 +
  92 + polygons = polygons_raw.reshape(-1, self.N_VERTICES_IN_POLYGON + 1)[:, 1:]
  93 +
  94 + self.connection.update_coil_mesh(
  95 + points=points,
  96 + polygons=polygons,
  97 + )