Commit ac47aa77eea981a7abd7e4a94dff04c74bb2e16c

Authored by Andrey Zhdanov
1 parent 23bc2c04
Exists in master

- Added new class for storing markers

- General marker code cleanup
- Marker's label decoupled from the target status
invesalius/constants.py
... ... @@ -828,5 +828,4 @@ TREKKER_CONFIG = {'seed_max': 1, 'step_size': 0.1, 'min_fod': 0.1, 'probe_qualit
828 828  
829 829 MARKER_FILE_MAGICK_STRING = "INVESALIUS3_MARKER_FILE_"
830 830 CURRENT_MARKER_FILE_VERSION = 0
831   -WILDCARD_MARKER_FILES = _("Marker scanner coord files (*.mkss)|*.mkss") + "|" +\
832   - _("Marker files (*.mks)|*.mks")
  831 +WILDCARD_MARKER_FILES = _("Marker scanner coord files (*.mkss)|*.mkss")
... ...
invesalius/data/viewer_volume.py
... ... @@ -280,7 +280,7 @@ class Viewer(wx.Panel):
280 280 Publisher.subscribe(self.HideAllMarkers, 'Hide all markers')
281 281 Publisher.subscribe(self.ShowAllMarkers, 'Show all markers')
282 282 Publisher.subscribe(self.RemoveAllMarkers, 'Remove all markers')
283   - Publisher.subscribe(self.RemoveMarker, 'Remove marker')
  283 + Publisher.subscribe(self.RemoveMultipleMarkers, 'Remove multiple markers')
284 284 Publisher.subscribe(self.BlinkMarker, 'Blink Marker')
285 285 Publisher.subscribe(self.StopBlinkMarker, 'Stop Blink Marker')
286 286 Publisher.subscribe(self.SetNewColor, 'Set new color')
... ... @@ -676,7 +676,7 @@ class Viewer(wx.Panel):
676 676 self.staticballs = []
677 677 self.UpdateRender()
678 678  
679   - def RemoveMarker(self, index):
  679 + def RemoveMultipleMarkers(self, index):
680 680 for i in reversed(index):
681 681 self.ren.RemoveActor(self.staticballs[i])
682 682 del self.staticballs[i]
... ...
invesalius/gui/task_navigator.py
... ... @@ -17,6 +17,7 @@
17 17 # detalhes.
18 18 #--------------------------------------------------------------------------
19 19  
  20 +import dataclasses
20 21 from functools import partial
21 22 import itertools
22 23 import csv
... ... @@ -1078,6 +1079,76 @@ class ObjectRegistrationPanel(wx.Panel):
1078 1079  
1079 1080  
1080 1081 class MarkersPanel(wx.Panel):
  1082 + @dataclasses.dataclass
  1083 + class Marker:
  1084 + """Class for storing markers. @dataclass decorator simplifies
  1085 + setting default values, serialization, etc."""
  1086 + x : float = 0
  1087 + y : float = 0
  1088 + z : float = 0
  1089 + alpha : float = 0
  1090 + beta : float = 0
  1091 + gamma : float = 0
  1092 + r : float = 0
  1093 + g : float = 1
  1094 + b : float = 0
  1095 + size : int = 2
  1096 + label : str = '*'
  1097 + x_seed : float = 0
  1098 + y_seed : float = 0
  1099 + z_seed : float = 0
  1100 + is_target : int = 0 # is_target is int instead of boolean to avoid
  1101 + # problems with CSV export
  1102 +
  1103 + # x, y, z, alpha, beta, gamma can be jointly accessed as coord
  1104 + @property
  1105 + def coord(self):
  1106 + return list((self.x, self.y, self.z, self.alpha, self.beta, self.gamma),)
  1107 +
  1108 + @coord.setter
  1109 + def coord(self, new_coord):
  1110 + self.x, self.y, self.z, self.alpha, self.beta, self.gamma = new_coord
  1111 +
  1112 + # r, g, b can be jointly accessed as colour
  1113 + @property
  1114 + def colour(self):
  1115 + return list((self.r, self.g, self.b),)
  1116 +
  1117 + @colour.setter
  1118 + def colour(self, new_colour):
  1119 + self.r, self.g, self.b = new_colour
  1120 +
  1121 + # x_seed, y_seed, z_seed can be jointly accessed as seed
  1122 + @property
  1123 + def seed(self):
  1124 + return list((self.x_seed, self.y_seed, self.z_seed),)
  1125 +
  1126 + @seed.setter
  1127 + def seed(self, new_seed):
  1128 + self.x_seed, self.y_seed, self.z_seed = new_seed
  1129 +
  1130 + @classmethod
  1131 + def get_headers(cls):
  1132 + """Return the list of field names (headers) for exporting to csv."""
  1133 + res = [field.name for field in dataclasses.fields(cls)]
  1134 + res.extend(['x_world', 'y_world', 'z_world', 'alpha_world', 'beta_world', 'gamma_world'])
  1135 + return res
  1136 +
  1137 + def get_values(self):
  1138 + """Return the list of values for exporting to csv."""
  1139 + res = []
  1140 + res.extend(dataclasses.astuple(self))
  1141 +
  1142 + # Add world coordinates (in addition to the internal ones).
  1143 + position_world, orientation_world = imagedata_utils.convert_invesalius_to_world(
  1144 + position=[self.x, self.y, self.z],
  1145 + orientation=[self.alpha, self.beta, self.gamma],
  1146 + )
  1147 + res.extend(position_world)
  1148 + res.extend(orientation_world)
  1149 +
  1150 + return res
  1151 +
1081 1152 def __init__(self, parent):
1082 1153 wx.Panel.__init__(self, parent)
1083 1154 try:
... ... @@ -1093,8 +1164,7 @@ class MarkersPanel(wx.Panel):
1093 1164 self.current_coord = 0, 0, 0, 0, 0, 0
1094 1165 self.current_angle = 0, 0, 0
1095 1166 self.current_seed = 0, 0, 0
1096   - self.list_coord = []
1097   - self.tgt_flag = self.tgt_index = None
  1167 + self.markers = []
1098 1168 self.nav_status = False
1099 1169  
1100 1170 self.marker_colour = const.MARKER_COLOUR
... ... @@ -1155,11 +1225,15 @@ class MarkersPanel(wx.Panel):
1155 1225 self.lc.InsertColumn(2, 'Y')
1156 1226 self.lc.InsertColumn(3, 'Z')
1157 1227 self.lc.InsertColumn(4, 'ID')
  1228 + self.lc.InsertColumn(5, 'Target')
  1229 +
1158 1230 self.lc.SetColumnWidth(0, 28)
1159 1231 self.lc.SetColumnWidth(1, 50)
1160 1232 self.lc.SetColumnWidth(2, 50)
1161 1233 self.lc.SetColumnWidth(3, 50)
1162 1234 self.lc.SetColumnWidth(4, 60)
  1235 + self.lc.SetColumnWidth(5, 60)
  1236 +
1163 1237 self.lc.Bind(wx.EVT_LIST_ITEM_RIGHT_CLICK, self.OnMouseRightDown)
1164 1238 self.lc.Bind(wx.EVT_LIST_ITEM_ACTIVATED, self.OnItemBlink)
1165 1239 self.lc.Bind(wx.EVT_LIST_ITEM_DESELECTED, self.OnStopItemBlink)
... ... @@ -1184,6 +1258,70 @@ class MarkersPanel(wx.Panel):
1184 1258 Publisher.subscribe(self.UpdateNavigationStatus, 'Navigation status')
1185 1259 Publisher.subscribe(self.UpdateSeedCoordinates, 'Update tracts')
1186 1260  
  1261 + def __find_target_marker(self):
  1262 + """Return the index of the marker currently selected as target (there
  1263 + should be at most one). If there is no such marker, return -1."""
  1264 + for i in range(len(self.markers)):
  1265 + if self.markers[i].is_target:
  1266 + return i
  1267 +
  1268 + return -1
  1269 +
  1270 + def __get_selected_items(self):
  1271 + """
  1272 + Returns a (possibly empty) list of the selected items in the list control.
  1273 + """
  1274 + selection = []
  1275 +
  1276 + next = self.lc.GetFirstSelected()
  1277 +
  1278 + while next != -1:
  1279 + selection.append(next)
  1280 + next = self.lc.GetNextSelected(next)
  1281 +
  1282 + return selection
  1283 +
  1284 + def __delete_multiple_markers(self, index):
  1285 + """ Delete multiple markers indexed by index. index must be sorted in
  1286 + the ascending order.
  1287 + """
  1288 + for i in reversed(index):
  1289 + del self.markers[i]
  1290 + self.lc.DeleteItem(i)
  1291 + for n in range(0, self.lc.GetItemCount()):
  1292 + self.lc.SetItem(n, 0, str(n+1))
  1293 + Publisher.sendMessage('Remove multiple markers', index=index)
  1294 +
  1295 + def __set_marker_as_target(self, idx):
  1296 + """Set marker indexed by idx as the new target. idx must be a valid index."""
  1297 + # Find the previous target
  1298 + prev_idx = self.__find_target_marker()
  1299 +
  1300 + # If the new target is same as the previous do nothing.
  1301 + if prev_idx == idx:
  1302 + return
  1303 +
  1304 + # Unset the previous target
  1305 + if prev_idx != -1:
  1306 + self.markers[prev_idx].is_target = 0
  1307 + self.lc.SetItemBackgroundColour(prev_idx, 'white')
  1308 + Publisher.sendMessage('Set target transparency', status=False, index=prev_idx)
  1309 + self.lc.SetItem(prev_idx, 5, "")
  1310 +
  1311 + # Set the new target
  1312 + self.markers[idx].is_target = 1
  1313 + self.lc.SetItemBackgroundColour(idx, 'RED')
  1314 + self.lc.SetItem(idx, 5, _("Yes"))
  1315 +
  1316 + Publisher.sendMessage('Update target', coord=self.markers[idx].coord)
  1317 + Publisher.sendMessage('Set target transparency', status=True, index=idx)
  1318 + wx.MessageBox(_("New target selected."), _("InVesalius 3"))
  1319 +
  1320 + @staticmethod
  1321 + def __list_fiducial_labels():
  1322 + """Return the list of marker labels denoting fucials."""
  1323 + return list(itertools.chain(*(const.BTNS_IMG_MARKERS[i].values() for i in const.BTNS_IMG_MARKERS)))
  1324 +
1187 1325 def UpdateCurrentCoord(self, position):
1188 1326 self.current_coord = position
1189 1327 #self.current_angle = pubsub_evt.data[1][3:]
... ... @@ -1203,7 +1341,7 @@ class MarkersPanel(wx.Panel):
1203 1341 # TODO: Enable the "Set as target" only when target is created with registered object
1204 1342 menu_id = wx.Menu()
1205 1343 edit_id = menu_id.Append(0, _('Edit ID'))
1206   - menu_id.Bind(wx.EVT_MENU, self.OnMenuEditMarkerId, edit_id)
  1344 + menu_id.Bind(wx.EVT_MENU, self.OnMenuEditMarkerLabel, edit_id)
1207 1345 color_id = menu_id.Append(2, _('Edit color'))
1208 1346 menu_id.Bind(wx.EVT_MENU, self.OnMenuSetColor, color_id)
1209 1347 menu_id.AppendSeparator()
... ... @@ -1223,54 +1361,29 @@ class MarkersPanel(wx.Panel):
1223 1361 def OnStopItemBlink(self, evt):
1224 1362 Publisher.sendMessage('Stop Blink Marker')
1225 1363  
1226   - def OnMenuEditMarkerId(self, evt):
  1364 + def OnMenuEditMarkerLabel(self, evt):
1227 1365 list_index = self.lc.GetFocusedItem()
1228   - if evt == 'TARGET':
1229   - id_label = evt
1230   - else:
1231   - id_label = dlg.ShowEnterMarkerID(self.lc.GetItemText(list_index, 4))
1232   - if id_label == 'TARGET':
1233   - id_label = '*'
1234   - wx.MessageBox(_("Invalid TARGET ID."), _("InVesalius 3"))
1235   -
1236   - # Add the new ID to exported list
1237   - if len(self.list_coord[list_index]) > 8:
1238   - self.list_coord[list_index][10] = str(id_label)
  1366 + if list_index != -1:
  1367 + new_label = dlg.ShowEnterMarkerID(self.lc.GetItemText(list_index, 4))
  1368 + self.markers[list_index].label = str(new_label)
  1369 + self.lc.SetItem(list_index, 4, new_label)
1239 1370 else:
1240   - self.list_coord[list_index][7] = str(id_label)
1241   -
1242   - self.lc.SetItem(list_index, 4, id_label)
  1371 + wx.MessageBox(_("No data selected."), _("InVesalius 3"))
1243 1372  
1244 1373 def OnMenuSetTarget(self, evt):
1245   - if isinstance(evt, int):
1246   - self.lc.Focus(evt)
1247   -
1248   - if self.tgt_flag:
1249   - marker_id = '*'
1250   -
1251   - self.lc.SetItemBackgroundColour(self.tgt_index, 'white')
1252   - Publisher.sendMessage('Set target transparency', status=False, index=self.tgt_index)
1253   - self.lc.SetItem(self.tgt_index, 4, marker_id)
1254   -
1255   - # Add the new ID to exported list
1256   - if len(self.list_coord[self.tgt_index]) > 8:
1257   - self.list_coord[self.tgt_index][10] = marker_id
1258   - else:
1259   - self.list_coord[self.tgt_index][7] = marker_id
1260   -
1261   - self.tgt_index = self.lc.GetFocusedItem()
1262   - self.lc.SetItemBackgroundColour(self.tgt_index, 'RED')
1263   -
1264   - Publisher.sendMessage('Update target', coord=self.list_coord[self.tgt_index][:6])
1265   - Publisher.sendMessage('Set target transparency', status=True, index=self.tgt_index)
1266   - self.OnMenuEditMarkerId('TARGET')
1267   - self.tgt_flag = True
1268   - wx.MessageBox(_("New target selected."), _("InVesalius 3"))
  1374 + idx = self.lc.GetFocusedItem()
  1375 + if idx != -1:
  1376 + self.__set_marker_as_target(idx)
  1377 + else:
  1378 + wx.MessageBox(_("No data selected."), _("InVesalius 3"))
1269 1379  
1270 1380 def OnMenuSetColor(self, evt):
1271 1381 index = self.lc.GetFocusedItem()
  1382 + if index == -1:
  1383 + wx.MessageBox(_("No data selected."), _("InVesalius 3"))
  1384 + return
1272 1385  
1273   - color_current = [self.list_coord[index][n] * 255 for n in range(6, 9)]
  1386 + color_current = [ch * 255 for ch in self.markers[index].colour]
1274 1387  
1275 1388 color_new = dlg.ShowColorDialog(color_current=color_current)
1276 1389  
... ... @@ -1280,29 +1393,28 @@ class MarkersPanel(wx.Panel):
1280 1393 # XXX: Seems like a slightly too early point for rounding; better to round only when the value
1281 1394 # is printed to the screen or file.
1282 1395 #
1283   - self.list_coord[index][6:9] = [round(s/255.0, 3) for s in color_new]
  1396 + self.markers[index].colour = [round(s/255.0, 3) for s in color_new]
1284 1397  
1285 1398 Publisher.sendMessage('Set new color', index=index, color=color_new)
1286 1399  
1287 1400 def OnDeleteAllMarkers(self, evt=None):
1288   - if self.list_coord:
1289   - if evt is None:
1290   - result = wx.ID_OK
1291   - else:
1292   - # result = dlg.DeleteAllMarkers()
1293   - result = dlg.ShowConfirmationDialog(msg=_("Remove all markers? Cannot be undone."))
  1401 + if evt is None:
  1402 + result = wx.ID_OK
  1403 + else:
  1404 + result = dlg.ShowConfirmationDialog(msg=_("Remove all markers? Cannot be undone."))
1294 1405  
1295   - if result == wx.ID_OK:
1296   - self.list_coord = []
1297   - Publisher.sendMessage('Remove all markers', indexes=self.lc.GetItemCount())
1298   - self.lc.DeleteAllItems()
1299   - Publisher.sendMessage('Stop Blink Marker', index='DeleteAll')
  1406 + if result != wx.ID_OK:
  1407 + return
  1408 +
  1409 + if self.__find_target_marker() != -1:
  1410 + Publisher.sendMessage('Disable or enable coil tracker', status=False)
  1411 + if evt is not None:
  1412 + wx.MessageBox(_("Target deleted."), _("InVesalius 3"))
1300 1413  
1301   - if self.tgt_flag:
1302   - self.tgt_flag = self.tgt_index = None
1303   - Publisher.sendMessage('Disable or enable coil tracker', status=False)
1304   - if not hasattr(evt, 'data'):
1305   - wx.MessageBox(_("Target deleted."), _("InVesalius 3"))
  1414 + self.markers = []
  1415 + Publisher.sendMessage('Remove all markers', indexes=self.lc.GetItemCount())
  1416 + self.lc.DeleteAllItems()
  1417 + Publisher.sendMessage('Stop Blink Marker', index='DeleteAll')
1306 1418  
1307 1419 def OnDeleteMultipleMarkers(self, evt=None, label=None):
1308 1420 # OnDeleteMultipleMarkers is used for both pubsub and button click events
... ... @@ -1310,9 +1422,8 @@ class MarkersPanel(wx.Panel):
1310 1422  
1311 1423 if not evt: # called through pubsub
1312 1424 index = []
1313   - allowed_labels = itertools.chain(*(const.BTNS_IMG_MARKERS[i].values() for i in const.BTNS_IMG_MARKERS))
1314   -
1315   - if label and (label in allowed_labels):
  1425 +
  1426 + if label and (label in self.__list_fiducial_labels()):
1316 1427 for id_n in range(self.lc.GetItemCount()):
1317 1428 item = self.lc.GetItem(id_n, 4)
1318 1429 if item.GetText() == label:
... ... @@ -1320,49 +1431,32 @@ class MarkersPanel(wx.Panel):
1320 1431 index = [self.lc.GetFocusedItem()]
1321 1432  
1322 1433 else: # called from button click
1323   - index = self.__getSelectedItems()
  1434 + index = self.__get_selected_items()
1324 1435  
1325   - #TODO: Bug - when deleting multiple markers and target is not the first marker
1326 1436 if index:
1327   - if self.tgt_flag and self.tgt_index == index[0]:
1328   - self.tgt_flag = self.tgt_index = None
  1437 + if self.__find_target_marker() in index:
1329 1438 Publisher.sendMessage('Disable or enable coil tracker', status=False)
1330 1439 wx.MessageBox(_("Target deleted."), _("InVesalius 3"))
1331 1440  
1332   - self.__deleteMultipleMarkers(index)
  1441 + self.__delete_multiple_markers(index)
1333 1442 else:
1334   - wx.MessageBox(_("No data selected."), _("InVesalius 3"))
1335   -
1336   - def __deleteMultipleMarkers(self, index):
1337   - """ Delete multiple markers indexed by index. index must be sorted in
1338   - the ascending order.
1339   - """
1340   - for i in reversed(index):
1341   - del self.list_coord[i]
1342   - self.lc.DeleteItem(i)
1343   - for n in range(0, self.lc.GetItemCount()):
1344   - self.lc.SetItem(n, 0, str(n+1))
1345   - Publisher.sendMessage('Remove marker', index=index)
  1443 + if evt: # Don't show the warning if called through pubsub
  1444 + wx.MessageBox(_("No data selected."), _("InVesalius 3"))
1346 1445  
1347 1446 def OnCreateMarker(self, evt):
1348 1447 self.CreateMarker()
1349 1448  
1350 1449 def OnLoadMarkers(self, evt):
  1450 + """Loads markers from file and appends them to the current marker list.
  1451 + The file should contain no more than a single target marker. Also the
  1452 + file should not contain any fiducials already in the list."""
1351 1453 filename = dlg.ShowLoadSaveDialog(message=_(u"Load markers"),
1352 1454 wildcard=const.WILDCARD_MARKER_FILES)
1353 1455  
1354 1456 if not filename:
1355 1457 return
1356   -
1357   - if filename.lower().endswith('.mks'):
1358   - wx.MessageBox(_(".mks files are no longer supported. Convert them to .mkss with the conversion tool."), _("InVesalius 3"))
1359   - return
1360 1458  
1361   - # Treat any extension othjer than .mks as 'new' format that has magick
1362   - # string and version number
1363 1459 try:
1364   - count_line = self.lc.GetItemCount()
1365   -
1366 1460 with open(filename, 'r') as file:
1367 1461 magick_line = file.readline()
1368 1462 assert magick_line.startswith(const.MARKER_FILE_MAGICK_STRING)
... ... @@ -1371,39 +1465,22 @@ class MarkersPanel(wx.Panel):
1371 1465 wx.MessageBox(_("Unknown version of the markers file."), _("InVesalius 3"))
1372 1466 return
1373 1467  
1374   - # read lines from the file
1375 1468 reader = csv.reader(file, dialect='markers_dialect')
1376 1469 next(reader) # skip the header line
1377   - content = [row for row in reader]
1378   -
1379   - # parse the lines and update the markers list
1380   - for line in content:
1381   - target = None
1382   -
1383   - coord = [float(s) for s in line[:6]]
1384   - colour = [float(s) for s in line[12:15]]
1385   - size = float(line[15])
1386   - marker_id = line[16]
1387   -
1388   - seed = [float(s) for s in line[17:20]]
1389   -
1390   - for i in const.BTNS_IMG_MARKERS:
1391   - if marker_id in list(const.BTNS_IMG_MARKERS[i].values())[0]:
1392   - Publisher.sendMessage('Load image fiducials', marker_id=marker_id, coord=coord)
1393   - elif marker_id == 'TARGET':
1394   - target = count_line
1395   -
1396   - target_id = line[20]
1397   -
1398   - self.CreateMarker(coord=coord, colour=colour, size=size,
1399   - label=marker_id, target_id=target_id, seed=seed)
1400   -
1401   - # if there are multiple TARGETS will set the last one
1402   - if target:
1403   - self.OnMenuSetTarget(target)
1404   -
1405   - count_line += 1
1406   -
  1470 +
  1471 + # Read the data lines and create markers
  1472 + for line in reader:
  1473 + marker = self.Marker(*line[:-6]) # Discard the last 6 fields (the world coordinates)
  1474 + self.CreateMarker(coord=marker.coord, colour=marker.colour, size=marker.size,
  1475 + label=marker.label, is_target=0, seed=marker.seed)
  1476 +
  1477 + if marker.label in self.__list_fiducial_labels():
  1478 + Publisher.sendMessage('Load image fiducials', label=marker.label, coord=marker.coord)
  1479 +
  1480 + # If the new marker has is_target=1 (True), we first create
  1481 + # a marker with is_target=0 (False), and then call __set_marker_as_target
  1482 + if marker.is_target:
  1483 + self.__set_marker_as_target(len(self.markers)-1)
1407 1484 except:
1408 1485 wx.MessageBox(_("Invalid markers file."), _("InVesalius 3"))
1409 1486  
... ... @@ -1430,82 +1507,51 @@ class MarkersPanel(wx.Panel):
1430 1507 style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT,
1431 1508 default_filename=default_filename)
1432 1509  
1433   - header_titles = ['x', 'y', 'z', 'alpha', 'beta', 'gamma',
1434   - 'x_world', 'y_world', 'z_world', 'alpha_world', 'beta_world', 'gamma_world',
1435   - 'r', 'g', 'b', 'size', 'marker_id', 'x_seed', 'y_seed', 'z_seed', 'target_id']
1436   -
1437   - if filename:
1438   - if self.list_coord:
1439   - with open(filename, 'w', newline='') as file:
1440   - file.writelines(['%s%i\n' % (const.MARKER_FILE_MAGICK_STRING, const.CURRENT_MARKER_FILE_VERSION)])
1441   - writer = csv.writer(file, dialect='markers_dialect')
1442   - writer.writerow(header_titles)
  1510 + if not filename:
  1511 + return
1443 1512  
1444   - writer.writerows(self.list_coord)
  1513 + try:
  1514 + with open(filename, 'w', newline='') as file:
  1515 + file.writelines(['%s%i\n' % (const.MARKER_FILE_MAGICK_STRING, const.CURRENT_MARKER_FILE_VERSION)])
  1516 + writer = csv.writer(file, dialect='markers_dialect')
  1517 + writer.writerow(self.Marker.get_headers())
  1518 + writer.writerows(marker.get_values() for marker in self.markers)
  1519 + file.close()
  1520 + except:
  1521 + wx.MessageBox(_("Error writing markers file."), _("InVesalius 3"))
1445 1522  
1446 1523 def OnSelectColour(self, evt, ctrl):
1447   - self.marker_colour = [colour/255.0 for colour in ctrl.GetValue()]
  1524 + #TODO: Make sure GetValue returns 3 numbers (without alpha)
  1525 + self.marker_colour = [colour/255.0 for colour in ctrl.GetValue()][:3]
1448 1526  
1449 1527 def OnSelectSize(self, evt, ctrl):
1450 1528 self.marker_size = ctrl.GetValue()
1451 1529  
1452   - def CreateMarker(self, coord=None, colour=None, size=None, label='*', target_id='*', seed=None):
1453   - coord = coord or self.current_coord
1454   - colour = colour or self.marker_colour
1455   - size = size or self.marker_size
1456   - seed = seed or self.current_seed
1457   -
1458   - position_world, orientation_world = imagedata_utils.convert_invesalius_to_world(
1459   - position=coord[:3],
1460   - orientation=coord[3:],
1461   - )
1462   -
1463   - # TODO: Use matrix coordinates and not world coordinates as current method.
1464   - # This makes easier for inter-software comprehension.
1465   -
1466   - Publisher.sendMessage('Add marker', ball_id=len(self.list_coord), size=size, colour=colour, coord=coord[0:3])
1467   -
1468   - # List of lists with coordinates and properties of a marker
1469   - line = []
1470   - line.extend(coord)
1471   - line.extend(position_world)
1472   - line.extend(orientation_world)
1473   - line.extend(colour)
1474   - line.append(size)
1475   - line.append(label)
1476   - line.extend(seed)
1477   - line.append(target_id)
1478   -
1479   - # Adding current line to a list of all markers already created
1480   - if not self.list_coord:
1481   - self.list_coord = [line]
1482   - else:
1483   - self.list_coord.append(line)
  1530 + def CreateMarker(self, coord=None, colour=None, size=None, label='*', is_target=0, seed=None):
  1531 + new_marker = self.Marker()
  1532 + new_marker.coord = coord or self.current_coord
  1533 + new_marker.colour = colour or self.marker_colour
  1534 + new_marker.size = size or self.marker_size
  1535 + new_marker.label = label
  1536 + new_marker.is_target = is_target
  1537 + new_marker.seed = seed or self.current_seed
  1538 +
  1539 + # Note that ball_id is zero-based, so we assign it len(self.markers) before the new marker is added
  1540 + Publisher.sendMessage('Add marker', ball_id=len(self.markers),
  1541 + size=new_marker.size,
  1542 + colour=new_marker.colour,
  1543 + coord=new_marker.coord[:3])
  1544 + self.markers.append(new_marker)
1484 1545  
1485 1546 # Add item to list control in panel
1486 1547 num_items = self.lc.GetItemCount()
1487 1548 self.lc.InsertItem(num_items, str(num_items + 1))
1488   - self.lc.SetItem(num_items, 1, str(round(coord[0], 2)))
1489   - self.lc.SetItem(num_items, 2, str(round(coord[1], 2)))
1490   - self.lc.SetItem(num_items, 3, str(round(coord[2], 2)))
1491   - self.lc.SetItem(num_items, 4, str(label))
  1549 + self.lc.SetItem(num_items, 1, str(round(new_marker.x, 2)))
  1550 + self.lc.SetItem(num_items, 2, str(round(new_marker.y, 2)))
  1551 + self.lc.SetItem(num_items, 3, str(round(new_marker.z, 2)))
  1552 + self.lc.SetItem(num_items, 4, str(new_marker.label))
1492 1553 self.lc.EnsureVisible(num_items)
1493 1554  
1494   - def __getSelectedItems(self):
1495   - """
1496   - Returns a (possibly empty) list of the selected items in the list control.
1497   - """
1498   - selection = []
1499   -
1500   - next = self.lc.GetFirstSelected()
1501   -
1502   - while next != -1:
1503   - selection.append(next)
1504   - next = self.lc.GetNextSelected(next)
1505   -
1506   - return selection
1507   -
1508   -
1509 1555 class DbsPanel(wx.Panel):
1510 1556 def __init__(self, parent):
1511 1557 wx.Panel.__init__(self, parent)
... ...