Commit 9de6858764937e33dd2090be46587d1b9659d8b2

Authored by sotodela
Committed by GitHub
1 parent 85de3a6a
Exists in master

Coil projection on peel (#308)

* add add_object_orientation_disk and add_addobjectArrow functions, add orientation disk and projection arrow actors

* add getCenter and getNormal functions, create locator and add self.peel_centers and self.peel_normals variables, add to calculate normals and centers when calling getPeelActor (new peel)

* add GetPeelCenters and Initlocator_viewer and corresponding publisher call

* add in  OnLinkBrain and TractographyPanel class (OnSelectPeelingDepth) call to get peel centers and normals and initiator)

* remove print on GetPeelCenters and Initlocator_viewer

* add objectArrowlocation to calculate coil norms and directions

* Add UpdateObjectArrowOrientation and Getcellintersection

  - getcellintersection function calculates the intersection between the
  coil normal and the peel center
  -calculates the angle between the coil normal and the normal of the
  center of the intersected cell
  -shows the coil projected with arrow and disk
  -Color of the disk and arrow change according to the value of the
  angle between the normal of the coil and the peel center mesh
  intersected.
  -updateobjectarroworientation is used to show and update the position
  of the projected arrow and disk

* add comments, removed not used code on class def, modify currentPeel as local variable

* modify getPeelActor removing input currentPeel

* add affine_vtk matrix as input to getPeelActor, add change position of curent peel

* add case when not intersection found in getcellintersection function

* add remove arrow and disk actor only when intersecting with the peel

* add comments to getcellintersection function, remove TODO

* add comment to getcellintersection

* add transformpeelposition function

* add setvisibility to arrow and disk actor on OnNavigationStatus

* add tangent lines for debuggint at getcellintersection function

* add coil_dir from coordinates from tracker to objectArrowlocation

* modify visibility of disk and coil projection arrow, to be shown when coil is not shown

* comment tangent lines for debuggin on getcellintersection

* modify names of functions to invesalius naming convention

* correct mispelling error when calling GetCellIntersection

* add angle threshold for projectio arrow in constansts

* add angle threshold for arrow projection in constants

* change size of disk and arrow in coil projection

* add normal lines for debugging arrow projection

* Modify function names to invensalius convention

* add condition for track if peel is loaded or not

* fix removing arrow and disk projection when distance is larger than set value, removing normal lines for debugging

* clean comments

* add self.peel_loaded to vis_components

* Modify UpdatePeelVisualization to pass peel_loaded from navigation class

* change color disk and arrow
invesalius/constants.py
... ... @@ -781,6 +781,7 @@ ARROW_UPPER_LIMIT = 15
781 781 COIL_ANGLES_THRESHOLD = 3
782 782 COIL_COORD_THRESHOLD = 3
783 783 TIMESTAMP = 2.0
  784 +COIL_ANGLE_ARROW_PROJECTION_THRESHOLD = 10
784 785  
785 786 CAM_MODE = True
786 787  
... ...
invesalius/data/brainmesh_handler.py
... ... @@ -8,34 +8,33 @@ import pyvista
8 8  
9 9 class Brain:
10 10 def __init__(self, img_path, mask_path, n_peels, affine_vtk):
  11 + # Create arrays to access the peel data and peel Actors
11 12 self.peel = []
12 13 self.peelActors = []
13   -
  14 + # Read the image
14 15 T1_reader = vtk.vtkNIFTIImageReader()
15 16 T1_reader.SetFileName(img_path)
16 17 T1_reader.Update()
17   -
18   - # self.refImage = vtk.vtkImageData()
  18 + # Image
19 19 self.refImage = T1_reader.GetOutput()
20   -
  20 + # Read the mask
21 21 mask_reader = vtk.vtkNIFTIImageReader()
22 22 mask_reader.SetFileName(mask_path)
23 23 mask_reader.Update()
24   -
  24 + # Use the mask to create isosurface
25 25 mc = vtk.vtkContourFilter()
26 26 mc.SetInputConnection(mask_reader.GetOutputPort())
27 27 mc.SetValue(0, 1)
28 28 mc.Update()
29 29  
30   - refSurface = vtk.vtkPolyData()
  30 + # Mask isosurface
31 31 refSurface = mc.GetOutput()
32   -
33   - tmpPeel = vtk.vtkPolyData()
  32 + # Create a uniformly meshed surface
34 33 tmpPeel = downsample(refSurface)
35   -
36   - mask_sFormMatrix = vtk.vtkMatrix4x4()
  34 + # Standard space coordinates
37 35 mask_sFormMatrix = mask_reader.GetSFormMatrix()
38 36  
  37 + # Apply coordinate transform to the meshed mask
39 38 mask_ijk2xyz = vtk.vtkTransform()
40 39 mask_ijk2xyz.SetMatrix(mask_sFormMatrix)
41 40  
... ... @@ -44,17 +43,21 @@ class Brain:
44 43 mask_ijk2xyz_filter.SetTransform(mask_ijk2xyz)
45 44 mask_ijk2xyz_filter.Update()
46 45  
  46 + # Smooth the mesh
47 47 tmpPeel = smooth(mask_ijk2xyz_filter.GetOutput())
  48 + # Configure calculation of normals
48 49 tmpPeel = fixMesh(tmpPeel)
  50 + # Remove duplicate points etc
49 51 tmpPeel = cleanMesh(tmpPeel)
  52 + # Generate triangles
50 53 tmpPeel = upsample(tmpPeel)
  54 +
51 55 tmpPeel = smooth(tmpPeel)
52 56 tmpPeel = fixMesh(tmpPeel)
53 57 tmpPeel = cleanMesh(tmpPeel)
54 58  
55   - # sFormMatrix = vtk.vtkMatrix4x4()
  59 + # Scanner coordinates from image
56 60 qFormMatrix = T1_reader.GetQFormMatrix()
57   - # sFormMatrix = T1_reader.GetSFormMatrix()
58 61  
59 62 refImageSpace2_xyz_transform = vtk.vtkTransform()
60 63 refImageSpace2_xyz_transform.SetMatrix(qFormMatrix)
... ... @@ -69,29 +72,32 @@ class Brain:
69 72 self.xyz2_refImageSpace = vtk.vtkTransformPolyDataFilter()
70 73 self.xyz2_refImageSpace.SetTransform(xyz2_refImageSpace_transform)
71 74  
72   - # self.currentPeel = vtk.vtkPolyData()
73   - self.currentPeel = tmpPeel
  75 + currentPeel = tmpPeel
74 76 self.currentPeelNo = 0
75   - self.mapImageOnCurrentPeel()
  77 + currentPeel= self.MapImageOnCurrentPeel(currentPeel)
76 78  
77 79 newPeel = vtk.vtkPolyData()
78   - newPeel.DeepCopy(self.currentPeel)
  80 + newPeel.DeepCopy(currentPeel)
  81 + newPeel.DeepCopy(currentPeel)
  82 + self.peel_normals = vtk.vtkFloatArray()
  83 + self.peel_centers = vtk.vtkFloatArray()
79 84 self.peel.append(newPeel)
80 85 self.currentPeelActor = vtk.vtkActor()
81 86 self.currentPeelActor.SetUserMatrix(affine_vtk)
82   - self.getCurrentPeelActor()
  87 + self.GetCurrentPeelActor(currentPeel)
83 88 self.peelActors.append(self.currentPeelActor)
84   -
  89 + # locator will later find the triangle on the peel surface where the coil's normal intersect
  90 + self.locator = vtk.vtkCellLocator()
85 91 self.numberOfPeels = n_peels
86   - self.peelDown()
  92 + self.PeelDown(currentPeel)
87 93  
88   - def get_actor(self, n):
89   - return self.getPeelActor(n)
  94 + def get_actor(self, n, affine_vtk):
  95 + return self.GetPeelActor(n, affine_vtk)
90 96  
91   - def sliceDown(self):
  97 + def SliceDown(self, currentPeel):
92 98 # Warp using the normals
93 99 warp = vtk.vtkWarpVector()
94   - warp.SetInputData(fixMesh(downsample(self.currentPeel))) # fixMesh here updates normals needed for warping
  100 + warp.SetInputData(fixMesh(downsample(currentPeel))) # fixMesh here updates normals needed for warping
95 101 warp.SetInputArrayToProcess(0, 0, 0, vtk.vtkDataObject().FIELD_ASSOCIATION_POINTS,
96 102 vtk.vtkDataSetAttributes().NORMALS)
97 103 warp.SetScaleFactor(-1)
... ... @@ -103,8 +109,8 @@ class Brain:
103 109 out = fixMesh(out)
104 110 out = cleanMesh(out)
105 111  
106   - self.currentPeel = out
107   -
  112 + currentPeel = out
  113 + return currentPeel
108 114 # def sliceUp(self):
109 115 # # Warp using the normals
110 116 # warp = vtk.vtkWarpVector()
... ... @@ -122,8 +128,8 @@ class Brain:
122 128 #
123 129 # currentPeel = out
124 130  
125   - def mapImageOnCurrentPeel(self):
126   - self.xyz2_refImageSpace.SetInputData(self.currentPeel)
  131 + def MapImageOnCurrentPeel(self, currentPeel):
  132 + self.xyz2_refImageSpace.SetInputData(currentPeel)
127 133 self.xyz2_refImageSpace.Update()
128 134  
129 135 probe = vtk.vtkProbeFilter()
... ... @@ -134,25 +140,36 @@ class Brain:
134 140 self.refImageSpace2_xyz.SetInputData(probe.GetOutput())
135 141 self.refImageSpace2_xyz.Update()
136 142  
137   - self.currentPeel = self.refImageSpace2_xyz.GetOutput()
  143 + currentPeel = self.refImageSpace2_xyz.GetOutput()
  144 + return currentPeel
138 145  
139   - def peelDown(self):
  146 + def PeelDown(self, currentPeel):
140 147 for i in range(0, self.numberOfPeels):
141   - self.sliceDown()
142   - self.mapImageOnCurrentPeel()
  148 + currentPeel = self.SliceDown(currentPeel)
  149 + currentPeel = self.MapImageOnCurrentPeel(currentPeel)
143 150  
144 151 newPeel = vtk.vtkPolyData()
145   - newPeel.DeepCopy(self.currentPeel)
  152 + newPeel.DeepCopy(currentPeel)
146 153 self.peel.append(newPeel)
147 154  
148   - # getCurrentPeelActor()
  155 + # GetCurrentPeelActor()
149 156 # newPeelActor = vtk.vtkActor()
150 157 # newPeelActor = currentPeelActor
151 158 # peelActors.push_back(newPeelActor)
152 159  
153 160 self.currentPeelNo += 1
154 161  
155   - def getPeelActor(self, p):
  162 + def TransformPeelPosition(self, p, affine_vtk):
  163 + peel_transform = vtk.vtkTransform()
  164 + peel_transform.SetMatrix(affine_vtk)
  165 + refpeelspace = vtk.vtkTransformPolyDataFilter()
  166 + refpeelspace.SetInputData(self.peel[p])
  167 + refpeelspace.SetTransform(peel_transform)
  168 + refpeelspace.Update()
  169 + currentPeel = refpeelspace.GetOutput()
  170 + return currentPeel
  171 +
  172 + def GetPeelActor(self, p, affine_vtk):
156 173 colors = vtk.vtkNamedColors()
157 174 # Create the color map
158 175 colorLookupTable = vtk.vtkLookupTable()
... ... @@ -179,9 +196,16 @@ class Brain:
179 196 # Set actor
180 197 self.currentPeelActor.SetMapper(mapper)
181 198  
  199 + currentPeel = self.TransformPeelPosition(p, affine_vtk)
  200 +
  201 + self.locator.SetDataSet(currentPeel)
  202 + self.locator.BuildLocator()
  203 + self.GetCenters(currentPeel)
  204 + self.GetNormals(currentPeel)
  205 +
182 206 return self.currentPeelActor
183 207  
184   - def getCurrentPeelActor(self):
  208 + def GetCurrentPeelActor(self, currentPeel):
185 209 colors = vtk.vtkNamedColors()
186 210  
187 211 # Create the color map
... ... @@ -198,7 +222,7 @@ class Brain:
198 222  
199 223 # Set mapper auto
200 224 mapper = vtk.vtkOpenGLPolyDataMapper()
201   - mapper.SetInputData(self.currentPeel)
  225 + mapper.SetInputData(currentPeel)
202 226 # mapper.SetScalarRange(0, 1000)
203 227 # mapper.SetScalarRange(0, 250)
204 228 mapper.SetScalarRange(0, 200)
... ... @@ -213,6 +237,26 @@ class Brain:
213 237  
214 238 return self.currentPeelActor
215 239  
  240 + def GetCenters(self, currentPeel):
  241 + # Compute centers of triangles
  242 + centerComputer = vtk.vtkCellCenters() # This computes centers of the triangles on the peel
  243 + centerComputer.SetInputData(currentPeel)
  244 + centerComputer.Update()
  245 + # This stores the centers for easy access
  246 + peel_centers = centerComputer.GetOutput()
  247 + self.peel_centers = peel_centers
  248 +
  249 + def GetNormals(self, currentPeel):
  250 + # Compute normals of triangles
  251 + normalComputer = vtk.vtkPolyDataNormals() # This computes normals of the triangles on the peel
  252 + normalComputer.SetInputData(currentPeel)
  253 + normalComputer.ComputePointNormalsOff()
  254 + normalComputer.ComputeCellNormalsOn()
  255 + normalComputer.Update()
  256 + # This converts to the normals to an array for easy access
  257 + peel_normals = normalComputer.GetOutput().GetCellData().GetNormals()
  258 + self.peel_normals = peel_normals
  259 +
216 260  
217 261 def cleanMesh(inp):
218 262 cleaned = vtk.vtkCleanPolyData()
... ...
invesalius/data/viewer_volume.py
... ... @@ -173,6 +173,8 @@ class Viewer(wx.Panel):
173 173 self.y_actor = None
174 174 self.z_actor = None
175 175 self.mark_actor = None
  176 + self.obj_projection_arrow_actor = None
  177 + self.object_orientation_disk_actor = None
176 178  
177 179 self._mode_cross = False
178 180 self._to_show_ball = 0
... ... @@ -192,6 +194,7 @@ class Viewer(wx.Panel):
192 194 self.polydata = None
193 195 self.anglethreshold = const.COIL_ANGLES_THRESHOLD
194 196 self.distthreshold = const.COIL_COORD_THRESHOLD
  197 + self.angle_arrow_projection_threshold = const.COIL_ANGLE_ARROW_PROJECTION_THRESHOLD
195 198  
196 199 self.actor_tracts = None
197 200 self.actor_peel = None
... ... @@ -293,6 +296,7 @@ class Viewer(wx.Panel):
293 296 # Related to object tracking during neuronavigation
294 297 Publisher.subscribe(self.OnNavigationStatus, 'Navigation status')
295 298 Publisher.subscribe(self.UpdateObjectOrientation, 'Update object matrix')
  299 + Publisher.subscribe(self.UpdateObjectArrowOrientation, 'Update object arrow matrix')
296 300 Publisher.subscribe(self.UpdateTrackObjectState, 'Update track object state')
297 301 Publisher.subscribe(self.UpdateShowObjectState, 'Update show object state')
298 302  
... ... @@ -310,6 +314,8 @@ class Viewer(wx.Panel):
310 314 Publisher.subscribe(self.UpdateMarkerOffsetState, 'Update marker offset state')
311 315 Publisher.subscribe(self.UpdateMarkerOffsetPosition, 'Update marker offset')
312 316 Publisher.subscribe(self.AddPeeledSurface, 'Update peel')
  317 + Publisher.subscribe(self.GetPeelCenters, 'Get peel centers and normals')
  318 + Publisher.subscribe(self.Initlocator_viewer, 'Get init locator')
313 319  
314 320 Publisher.subscribe(self.load_mask_preview, 'Load mask preview')
315 321 Publisher.subscribe(self.remove_mask_preview, 'Remove mask preview')
... ... @@ -1320,11 +1326,18 @@ class Viewer(wx.Panel):
1320 1326 self.y_actor = self.add_line([0., 0., 0.], [0., 1., 0.], color=[.0, 1.0, .0])
1321 1327 self.z_actor = self.add_line([0., 0., 0.], [0., 0., 1.], color=[1.0, .0, .0])
1322 1328  
  1329 + self.obj_projection_arrow_actor = self.Add_ObjectArrow([0., 0., 0.], [0., 0., 0.], vtk_colors.GetColor3d('Red'),
  1330 + 15)
  1331 + self.object_orientation_disk_actor = self.Add_Object_Orientation_Disk([0., 0., 0.], [0., 0., 0.],
  1332 + vtk_colors.GetColor3d('Red'))
  1333 + #self.obj_projection_arrow_actor.SetVisibility(False)
  1334 + #self.object_orientation_disk_actor.SetVisibility(False)
1323 1335 self.ren.AddActor(self.obj_actor)
1324 1336 self.ren.AddActor(self.x_actor)
1325 1337 self.ren.AddActor(self.y_actor)
1326 1338 self.ren.AddActor(self.z_actor)
1327   -
  1339 + #self.ren.AddActor(self.obj_projection_arrow_actor)
  1340 + #self.ren.AddActor(self.object_orientation_disk_actor)
1328 1341 # self.obj_axes = vtk.vtkAxesActor()
1329 1342 # self.obj_axes.SetShaftTypeToCylinder()
1330 1343 # self.obj_axes.SetXAxisLabelText("x")
... ... @@ -1334,6 +1347,63 @@ class Viewer(wx.Panel):
1334 1347  
1335 1348 # self.ren.AddActor(self.obj_axes)
1336 1349  
  1350 + def Add_Object_Orientation_Disk(self, position, orientation, color=[0.0, 0.0, 1.0]):
  1351 + # Create a disk to show target
  1352 + disk = vtk.vtkDiskSource()
  1353 + disk.SetInnerRadius(5)
  1354 + disk.SetOuterRadius(15)
  1355 + disk.SetRadialResolution(100)
  1356 + disk.SetCircumferentialResolution(100)
  1357 + disk.Update()
  1358 +
  1359 + disk_mapper = vtk.vtkPolyDataMapper()
  1360 + disk_mapper.SetInputData(disk.GetOutput())
  1361 + disk_actor = vtk.vtkActor()
  1362 + disk_actor.SetMapper(disk_mapper)
  1363 + disk_actor.GetProperty().SetColor(color)
  1364 + disk_actor.GetProperty().SetOpacity(1)
  1365 + disk_actor.SetPosition(position)
  1366 + disk_actor.SetOrientation(orientation)
  1367 +
  1368 + return disk_actor
  1369 +
  1370 + def Add_ObjectArrow(self, direction, orientation, color=[0.0, 0.0, 1.0], size=2):
  1371 + vtk_colors = vtk.vtkNamedColors()
  1372 +
  1373 + arrow = vtk.vtkArrowSource()
  1374 +
  1375 + mapper = vtk.vtkPolyDataMapper()
  1376 + mapper.SetInputConnection(arrow.GetOutputPort())
  1377 +
  1378 + actor = vtk.vtkActor()
  1379 + actor.SetMapper(mapper)
  1380 + actor.GetProperty().SetColor(color)
  1381 + actor.GetProperty().SetLineWidth(5)
  1382 + actor.AddPosition(0, 0, 0)
  1383 + actor.SetScale(size)
  1384 + actor.SetPosition(direction)
  1385 + actor.SetOrientation(orientation)
  1386 +
  1387 + return actor
  1388 +
  1389 + def ObjectArrowLocation(self, m_img, coord):
  1390 + # m_img[:3, 0] is from posterior to anterior direction of the coil
  1391 + # m_img[:3, 1] is from left to right direction of the coil
  1392 + # m_img[:3, 2] is from bottom to up direction of the coil
  1393 + vec_length = 70
  1394 + m_img_flip = m_img.copy()
  1395 + m_img_flip[1, -1] = -m_img_flip[1, -1]
  1396 + p1 = m_img_flip[:-1, -1] # coil center
  1397 + coil_dir = m_img_flip[:-1, 0]
  1398 + coil_face = m_img_flip[:-1, 1]
  1399 +
  1400 + coil_norm = np.cross(coil_dir, coil_face)
  1401 + p2_norm = p1 - vec_length * coil_norm # point normal to the coil away from the center by vec_length
  1402 + coil_dir = np.array([coord[3], coord[4], coord[5]])
  1403 +
  1404 + return coil_dir, p2_norm, coil_norm, p1
  1405 +
  1406 +
1337 1407 def add_line(self, p1, p2, color=[0.0, 0.0, 1.0]):
1338 1408 line = vtk.vtkLineSource()
1339 1409 line.SetPoint1(p1)
... ... @@ -1357,6 +1427,80 @@ class Viewer(wx.Panel):
1357 1427 self.actor_peel = actor
1358 1428 self.Refresh()
1359 1429  
  1430 + def GetPeelCenters(self, centers, normals):
  1431 + self.peel_centers = centers
  1432 + self.peel_normals = normals
  1433 +
  1434 + self.Refresh()
  1435 +
  1436 + def Initlocator_viewer(self, locator):
  1437 + self.locator = locator
  1438 + self.Refresh()
  1439 +
  1440 + def GetCellIntersection(self, p1, p2, coil_norm, coil_dir):
  1441 +
  1442 + vtk_colors = vtk.vtkNamedColors()
  1443 + # This find store the triangles that intersect the coil's normal
  1444 + intersectingCellIds = vtk.vtkIdList()
  1445 +
  1446 + #for debugging
  1447 + self.x_actor = self.add_line(p1,p2,vtk_colors.GetColor3d('Blue'))
  1448 + #self.ren.AddActor(self.x_actor) # remove comment for testing
  1449 +
  1450 + self.locator.FindCellsAlongLine(p1, p2, .001, intersectingCellIds)
  1451 +
  1452 + closestDist = 50
  1453 +
  1454 + #if find intersection , calculate angle and add actors
  1455 + if intersectingCellIds.GetNumberOfIds() != 0:
  1456 + for i in range(intersectingCellIds.GetNumberOfIds()):
  1457 + cellId = intersectingCellIds.GetId(i)
  1458 + point = np.array(self.peel_centers.GetPoint(cellId))
  1459 + distance = np.linalg.norm(point - p1)
  1460 +
  1461 + #print('distance:', distance, point - p1)
  1462 + self.ren.RemoveActor(self.y_actor)
  1463 +
  1464 + if distance < closestDist:
  1465 + closestDist = distance
  1466 + closestPoint = point
  1467 + pointnormal = np.array(self.peel_normals.GetTuple(cellId))
  1468 + angle = np.rad2deg(np.arccos(np.dot(pointnormal, coil_norm)))
  1469 + #print('the angle:', angle)
  1470 +
  1471 + #for debbuging
  1472 + self.y_actor = self.add_line(closestPoint, closestPoint + 75 * pointnormal,
  1473 + vtk_colors.GetColor3d('Yellow'))
  1474 +
  1475 + #self.ren.AddActor(self.y_actor)# remove comment for testing
  1476 +
  1477 +
  1478 + self.ren.AddActor(self.obj_projection_arrow_actor)
  1479 + self.ren.AddActor(self.object_orientation_disk_actor)
  1480 +
  1481 + self.obj_projection_arrow_actor.SetPosition(closestPoint)
  1482 + self.obj_projection_arrow_actor.SetOrientation(coil_dir)
  1483 +
  1484 + self.object_orientation_disk_actor.SetPosition(closestPoint)
  1485 + self.object_orientation_disk_actor.SetOrientation(coil_dir)
  1486 +
  1487 + # change color of arrow and disk according to angle
  1488 + if angle < self.angle_arrow_projection_threshold:
  1489 + self.object_orientation_disk_actor.GetProperty().SetColor(vtk_colors.GetColor3d('Green'))
  1490 + self.obj_projection_arrow_actor.GetProperty().SetColor(vtk_colors.GetColor3d('Green'))
  1491 + else:
  1492 + self.object_orientation_disk_actor.GetProperty().SetColor(vtk_colors.GetColor3d('indian_red'))
  1493 + self.obj_projection_arrow_actor.GetProperty().SetColor(vtk_colors.GetColor3d('indian_red'))
  1494 + else:
  1495 + self.ren.RemoveActor(self.y_actor)
  1496 +
  1497 + else:
  1498 + self.ren.RemoveActor(self.obj_projection_arrow_actor)
  1499 + self.ren.RemoveActor(self.object_orientation_disk_actor)
  1500 + self.ren.RemoveActor(self.x_actor)
  1501 + #self.ren.RemoveActor(self.y_actor)
  1502 + self.Refresh()
  1503 +
1360 1504 def OnNavigationStatus(self, nav_status, vis_status):
1361 1505 self.nav_status = nav_status
1362 1506 self.tracts_status = vis_status[1]
... ... @@ -1368,7 +1512,8 @@ class Viewer(wx.Panel):
1368 1512 self.x_actor.SetVisibility(self.obj_state)
1369 1513 self.y_actor.SetVisibility(self.obj_state)
1370 1514 self.z_actor.SetVisibility(self.obj_state)
1371   -
  1515 + #self.object_orientation_disk_actor.SetVisibility(self.obj_state)
  1516 + #self.obj_projection_arrow_actor.SetVisibility(self.obj_state)
1372 1517 self.Refresh()
1373 1518  
1374 1519 def UpdateSeedOffset(self, data):
... ... @@ -1419,6 +1564,19 @@ class Viewer(wx.Panel):
1419 1564  
1420 1565 self.Refresh()
1421 1566  
  1567 +
  1568 + def UpdateObjectArrowOrientation(self, m_img, coord, flag):
  1569 +
  1570 + [coil_dir, norm, coil_norm, p1 ]= self.ObjectArrowLocation(m_img,coord)
  1571 +
  1572 + if flag:
  1573 + self.ren.RemoveActor(self.x_actor)
  1574 + #self.ren.RemoveActor(self.y_actor)
  1575 + self.ren.RemoveActor(self.obj_projection_arrow_actor)
  1576 + self.ren.RemoveActor(self.object_orientation_disk_actor)
  1577 + self.GetCellIntersection(p1, norm, coil_norm, coil_dir)
  1578 + self.Refresh()
  1579 +
1422 1580 def UpdateTrackObjectState(self, evt=None, flag=None, obj_name=None, polydata=None):
1423 1581 if flag:
1424 1582 self.obj_name = obj_name
... ... @@ -1432,11 +1590,15 @@ class Viewer(wx.Panel):
1432 1590 self.ren.RemoveActor(self.y_actor)
1433 1591 self.ren.RemoveActor(self.z_actor)
1434 1592 self.ren.RemoveActor(self.mark_actor)
  1593 + self.ren.RemoveActor(self.obj_projection_arrow_actor)
  1594 + self.ren.RemoveActor(self.object_orientation_disk_actor)
1435 1595 self.obj_actor = None
1436 1596 self.x_actor = None
1437 1597 self.y_actor = None
1438 1598 self.z_actor = None
1439 1599 self.mark_actor = None
  1600 + self.obj_projection_arrow_actor = None
  1601 + self.object_orientation_disk_actor=None
1440 1602 self.Refresh()
1441 1603  
1442 1604 def UpdateShowObjectState(self, state):
... ...
invesalius/gui/task_navigator.py
... ... @@ -326,6 +326,7 @@ class Navigation():
326 326 self.trekker = None
327 327 self.n_threads = None
328 328 self.view_tracts = False
  329 + self.peel_loaded = False
329 330 self.enable_act = False
330 331 self.act_data = None
331 332 self.n_tracts = const.N_TRACTS
... ... @@ -363,7 +364,7 @@ class Navigation():
363 364 if self.event.is_set():
364 365 self.event.clear()
365 366  
366   - vis_components = [self.trigger_state, self.view_tracts]
  367 + vis_components = [self.trigger_state, self.view_tracts, self.peel_loaded]
367 368 vis_queues = [self.coord_queue, self.trigger_queue, self.tracts_queue, self.icp_queue]
368 369  
369 370 Publisher.sendMessage("Navigation status", nav_status=True, vis_status=vis_components)
... ... @@ -458,7 +459,7 @@ class Navigation():
458 459 self.tracts_queue.clear()
459 460 self.tracts_queue.join()
460 461  
461   - vis_components = [self.trigger_state, self.view_tracts]
  462 + vis_components = [self.trigger_state, self.view_tracts, self.peel_loaded]
462 463 Publisher.sendMessage("Navigation status", nav_status=False, vis_status=vis_components)
463 464  
464 465  
... ... @@ -870,6 +871,7 @@ class NeuronavigationPanel(wx.Panel):
870 871 Publisher.subscribe(self.UpdateSleep, 'Update sleep')
871 872 Publisher.subscribe(self.UpdateNumberThreads, 'Update number of threads')
872 873 Publisher.subscribe(self.UpdateTractsVisualization, 'Update tracts visualization')
  874 + Publisher.subscribe(self.UpdatePeelVisualization, 'Update peel visualization')
873 875 Publisher.subscribe(self.EnableACT, 'Enable ACT')
874 876 Publisher.subscribe(self.UpdateACTData, 'Update ACT data')
875 877 Publisher.subscribe(self.UpdateNavigationStatus, 'Navigation status')
... ... @@ -918,6 +920,10 @@ class NeuronavigationPanel(wx.Panel):
918 920 self.ResetICP()
919 921 self.tracker.UpdateUI(self.select_tracker_elem, self.numctrls_coord[3:6], self.txtctrl_fre)
920 922  
  923 +
  924 + def UpdatePeelVisualization(self, data):
  925 + self.navigation.peel_loaded = data
  926 +
921 927 def UpdateNavigationStatus(self, nav_status, vis_status):
922 928 self.nav_status = nav_status
923 929 if nav_status and self.icp.m_icp is not None:
... ... @@ -1044,6 +1050,7 @@ class NeuronavigationPanel(wx.Panel):
1044 1050 self.navigation.UpdateFiducialRegistrationError(self.tracker)
1045 1051 fre, fre_ok = self.navigation.GetFiducialRegistrationError(self.icp)
1046 1052  
  1053 +
1047 1054 self.txtctrl_fre.SetValue(str(round(fre, 2)))
1048 1055 if fre_ok:
1049 1056 self.txtctrl_fre.SetBackgroundColour('GREEN')
... ... @@ -1862,7 +1869,7 @@ class TractographyPanel(wx.Panel):
1862 1869 self.tracts_run = None
1863 1870 self.trekker_cfg = const.TREKKER_CONFIG
1864 1871 self.nav_status = False
1865   -
  1872 + self.peel_loaded = False
1866 1873 self.SetAutoLayout(1)
1867 1874 self.__bind_events()
1868 1875  
... ... @@ -2040,9 +2047,12 @@ class TractographyPanel(wx.Panel):
2040 2047 def OnSelectPeelingDepth(self, evt, ctrl):
2041 2048 self.peel_depth = ctrl.GetValue()
2042 2049 if self.checkpeeling.GetValue():
2043   - actor = self.brain_peel.get_actor(self.peel_depth)
  2050 + actor = self.brain_peel.get_actor(self.peel_depth, self.affine_vtk)
2044 2051 Publisher.sendMessage('Update peel', flag=True, actor=actor)
2045   -
  2052 + Publisher.sendMessage('Get peel centers and normals', centers=self.brain_peel.peel_centers,
  2053 + normals=self.brain_peel.peel_normals)
  2054 + Publisher.sendMessage('Get init locator', locator=self.brain_peel.locator)
  2055 + self.peel_loaded = True
2046 2056 def OnSelectNumTracts(self, evt, ctrl):
2047 2057 self.n_tracts = ctrl.GetValue()
2048 2058 # self.tract.n_tracts = ctrl.GetValue()
... ... @@ -2070,7 +2080,7 @@ class TractographyPanel(wx.Panel):
2070 2080 def OnShowPeeling(self, evt, ctrl):
2071 2081 # self.view_peeling = ctrl.GetValue()
2072 2082 if ctrl.GetValue():
2073   - actor = self.brain_peel.get_actor(self.peel_depth)
  2083 + actor = self.brain_peel.get_actor(self.peel_depth, self.affine_vtk)
2074 2084 else:
2075 2085 actor = None
2076 2086 Publisher.sendMessage('Update peel', flag=ctrl.GetValue(), actor=actor)
... ... @@ -2114,13 +2124,18 @@ class TractographyPanel(wx.Panel):
2114 2124  
2115 2125 try:
2116 2126 self.brain_peel = brain.Brain(img_path, mask_path, self.n_peels, self.affine_vtk)
2117   - self.brain_actor = self.brain_peel.get_actor(self.peel_depth)
  2127 + self.brain_actor = self.brain_peel.get_actor(self.peel_depth, self.affine_vtk)
2118 2128 self.brain_actor.GetProperty().SetOpacity(self.brain_opacity)
2119 2129 Publisher.sendMessage('Update peel', flag=True, actor=self.brain_actor)
  2130 + Publisher.sendMessage('Get peel centers and normals', centers=self.brain_peel.peel_centers,
  2131 + normals=self.brain_peel.peel_normals)
  2132 + Publisher.sendMessage('Get init locator', locator=self.brain_peel.locator)
2120 2133 self.checkpeeling.Enable(1)
2121 2134 self.checkpeeling.SetValue(True)
2122 2135 self.spin_opacity.Enable(1)
2123 2136 Publisher.sendMessage('Update status text in GUI', label=_("Brain model loaded"))
  2137 + self.peel_loaded = True
  2138 + Publisher.sendMessage('Update peel visualization', data= self.peel_loaded)
2124 2139 except:
2125 2140 wx.MessageBox(_("Unable to load brain mask."), _("InVesalius 3"))
2126 2141  
... ... @@ -2308,7 +2323,7 @@ class UpdateNavigationScene(threading.Thread):
2308 2323 """
2309 2324  
2310 2325 threading.Thread.__init__(self, name='UpdateScene')
2311   - self.trigger_state, self.view_tracts = vis_components
  2326 + self.trigger_state, self.view_tracts, self.peel_loaded = vis_components
2312 2327 self.coord_queue, self.trigger_queue, self.tracts_queue, self.icp_queue = vis_queues
2313 2328 self.sle = sle
2314 2329 self.event = event
... ... @@ -2347,7 +2362,7 @@ class UpdateNavigationScene(threading.Thread):
2347 2362  
2348 2363 if view_obj:
2349 2364 wx.CallAfter(Publisher.sendMessage, 'Update object matrix', m_img=m_img, coord=coord)
2350   -
  2365 + wx.CallAfter(Publisher.sendMessage, 'Update object arrow matrix',m_img=m_img, coord=coord, flag= self.peel_loaded)
2351 2366 self.coord_queue.task_done()
2352 2367 # print('UpdateScene: done {}'.format(count))
2353 2368 # count += 1
... ...