Commit a2350755deb300f540a1088388803108d1b714f1

Authored by tfmoraes
1 parent dd2cd7d0

Improved cursor_actors, better handlings and more accurate

invesalius/data/cursor_actors.py
@@ -17,127 +17,174 @@ @@ -17,127 +17,174 @@
17 # detalhes. 17 # detalhes.
18 #-------------------------------------------------------------------------- 18 #--------------------------------------------------------------------------
19 19
20 -from math import * 20 +import math
21 21
22 import numpy 22 import numpy
23 import vtk 23 import vtk
24 -import wx.lib.pubsub as ps 24 +import imagedata_utils
25 from project import Project 25 from project import Project
26 import constants as const 26 import constants as const
27 -import utils  
28 27
29 -class CursorCircle:  
30 - # TODO: Think and try to change this class to an actor  
31 - # CursorCircleActor(vtk.vtkActor) 28 +from vtk.util import numpy_support
  29 +
  30 +ORIENTATION = {'AXIAL': 2,
  31 + 'CORONAL': 1,
  32 + 'SAGITAL': 0}
  33 +
  34 +def to_vtk(n_array, spacing, slice_number, orientation):
  35 + """
  36 + It transforms a numpy array into a vtkImageData.
  37 + """
  38 + # TODO Merge this function with imagedata_utils.to_vtk to eliminate
  39 + # duplicated code
  40 + try:
  41 + dz, dy, dx = n_array.shape
  42 + except ValueError:
  43 + dy, dx = n_array.shape
  44 + dz = 1
  45 +
  46 + v_image = numpy_support.numpy_to_vtk(n_array.flat)
  47 +
  48 + if orientation == 'AXIAL':
  49 + extent = (0, dx -1, 0, dy -1, slice_number, slice_number + dz - 1)
  50 + elif orientation == 'SAGITAL':
  51 + extent = (slice_number, slice_number + dx - 1, 0, dy - 1, 0, dz - 1)
  52 + elif orientation == 'CORONAL':
  53 + extent = (0, dx - 1, slice_number, slice_number + dy - 1, 0, dz - 1)
  54 +
  55 + image = vtk.vtkImageData()
  56 + image.SetOrigin(0, 0, 0)
  57 + image.SetSpacing(spacing)
  58 + image.SetNumberOfScalarComponents(1)
  59 + image.SetDimensions(dx, dy, dz)
  60 + image.SetExtent(extent)
  61 + image.SetScalarType(numpy_support.get_vtk_array_type(n_array.dtype))
  62 + image.AllocateScalars()
  63 + image.Update()
  64 + image.GetCellData().SetScalars(v_image)
  65 + image.GetPointData().SetScalars(v_image)
  66 + image.Update()
  67 +
  68 + image_copy = vtk.vtkImageData()
  69 + image_copy.DeepCopy(image)
  70 + image_copy.Update()
  71 +
  72 + return image_copy
  73 +
  74 +class CursorBase(object):
32 def __init__(self): 75 def __init__(self):
33 self.colour = (0.0, 0.0, 1.0) 76 self.colour = (0.0, 0.0, 1.0)
34 self.opacity = 1 77 self.opacity = 1
35 - self.radius = 15.0  
36 - #self.position = (0.5,0.5, 1)  
37 - self.points = [] 78 + self.size = 15.0
38 self.orientation = "AXIAL" 79 self.orientation = "AXIAL"
39 self.spacing = (1, 1, 1) 80 self.spacing = (1, 1, 1)
40 -  
41 - self.mapper = vtk.vtkPolyDataMapper()  
42 - self.actor = vtk.vtkActor()  
43 - self.property = vtk.vtkProperty()  
44 -  
45 - self.__build_actor()  
46 - self.__calculate_area_pixels()  
47 -  
48 - def __build_actor(self):  
49 - """  
50 - Function to plot the circle  
51 - """  
52 - print "Building circle cursor", self.orientation  
53 - r = self.radius  
54 - t = 0  
55 -  
56 - self.posc_a = 0  
57 - self.posc_b = 0  
58 -  
59 - self.segment = vtk.vtkAppendPolyData()  
60 -  
61 - self.xa = self.posc_a + r * cos(t)  
62 - self.ya = self.posc_a + r * sin(t)  
63 -  
64 - while(t <= 2 * pi):  
65 - self.GenerateCicleSegment(t)  
66 - t = t + 0.05  
67 -  
68 - self.GenerateCicleSegment(0)  
69 -  
70 - self.mapper.SetInputConnection(self.segment.GetOutputPort())  
71 - self.actor.SetMapper(self.mapper)  
72 - self.actor.GetProperty().SetOpacity(self.opacity)  
73 - self.actor.GetProperty().SetColor(self.colour)  
74 - self.actor.PickableOff()  
75 -  
76 - def GenerateCicleSegment(self, t):  
77 - """  
78 - Generate cicle segment  
79 - """  
80 - x = self.posc_a + self.radius * cos(t)  
81 - y = self.posc_b + self.radius * sin(t)  
82 -  
83 - ls = vtk.vtkLineSource()  
84 - ls.SetPoint1(self.xa, self.ya, 0)  
85 - ls.SetPoint2(x, y, 0)  
86 -  
87 - self.segment.AddInput(ls.GetOutput())  
88 - self.xa, self.ya = x, y  
89 -  
90 - def __calculate_area_pixels(self):  
91 - """  
92 - Return the cursor's pixels.  
93 - """  
94 - radius = self.radius  
95 - if self.orientation == 'AXIAL':  
96 - sx = self.spacing[0]  
97 - sy = self.spacing[1]  
98 - elif self.orientation == 'CORONAL':  
99 - sx = self.spacing[0]  
100 - sy = self.spacing[2]  
101 - elif self.orientation == 'SAGITAL':  
102 - sx = self.spacing[1]  
103 - sy = self.spacing[2]  
104 -  
105 - y,x = numpy.ogrid[-radius/sy:+radius/sy,  
106 - -radius/sx:+radius/sx]  
107 -  
108 - index = (y*sy)**2 + (x*sx)**2 <= radius**2  
109 - self.points = index 81 + if vtk.vtkVersion().GetVTKVersion() > '5.8.0':
  82 + self.mapper = vtk.vtkImageSliceMapper()
  83 + cursor_property = vtk.vtkImageProperty()
  84 + cursor_property.SetInterpolationTypeToNearest()
  85 + self.actor = vtk.vtkImageSlice()
  86 + self.actor.SetMapper(self.mapper)
  87 + self.actor.SetProperty(cursor_property)
  88 + else:
  89 + self.actor = vtk.vtkImageActor()
  90 + self.mapper = None
  91 + self._build_actor()
  92 + self._calculate_area_pixels()
110 93
111 def SetSize(self, diameter): 94 def SetSize(self, diameter):
112 - radius = self.radius = diameter/2.0  
113 - #self.disk.SetInnerRadius(radius-1) # filled = self.radius  
114 - #self.disk.SetOuterRadius(radius) # filled = 0  
115 - self.__build_actor()  
116 - self.__calculate_area_pixels() 95 + self.radius = diameter/2.0
  96 + self._build_actor()
  97 + self._calculate_area_pixels()
117 98
118 def SetColour(self, colour): 99 def SetColour(self, colour):
119 self.colour = colour 100 self.colour = colour
120 - self.actor.GetProperty().SetColor(colour) 101 + self._build_actor()
121 102
122 def SetOrientation(self, orientation): 103 def SetOrientation(self, orientation):
123 self.orientation = orientation 104 self.orientation = orientation
124 - proj = Project()  
125 - orig_orien = proj.original_orientation  
126 - if orientation == "CORONAL":  
127 - self.actor.RotateX(90)  
128 - if orientation == "SAGITAL":  
129 - self.actor.RotateY(90) 105 + self._build_actor()
  106 + self._calculate_area_pixels()
130 107
131 def SetPosition(self, position): 108 def SetPosition(self, position):
132 - self.position = position  
133 - self.actor.SetPosition(position) 109 + # Overriding SetPosition method because in rectangles with odd
  110 + # dimensions there is no half position.
  111 + px, py, pz = position
  112 + sx, sy, sz = self.spacing
  113 + tx = self.actor.GetXRange()[1] - self.actor.GetXRange()[0]
  114 + ty = self.actor.GetYRange()[1] - self.actor.GetYRange()[0]
  115 + tz = self.actor.GetZRange()[1] - self.actor.GetZRange()[0]
  116 +
  117 + if self.orientation == 'AXIAL':
  118 + if self.points.shape[0] % 2:
  119 + y = py - ty / 2.0
  120 + else:
  121 + y = py - ty / 2.0 + self.spacing[1] / 2.0
  122 +
  123 + if self.points.shape[1] % 2:
  124 + x = px - tx / 2.0
  125 + else:
  126 + x = px - tx / 2.0 + self.spacing[0] / 2.0
  127 + z = pz
  128 +
  129 + if self.mapper:
  130 + x += sx / 2.0
  131 + y += sy / 2.0
  132 +
  133 + elif self.orientation == 'CORONAL':
  134 + if self.points.shape[0] % 2:
  135 + z = pz - tz / 2.0
  136 + else:
  137 + z = pz - tz / 2.0 + self.spacing[2] / 2.0
  138 +
  139 + if self.points.shape[1] % 2:
  140 + x = px - tx / 2.0
  141 + else:
  142 + x = px - tx / 2.0 + self.spacing[0] / 2.0
  143 + y = py
  144 +
  145 + if self.mapper:
  146 + x += sx / 2.0
  147 + z += sz / 2.0
134 148
135 - def SetEditionPosition(self, position):  
136 - self.edition_position = position 149 + elif self.orientation == 'SAGITAL':
  150 + # height shape is odd
  151 + if self.points.shape[1] % 2:
  152 + y = py - ty / 2.0
  153 + else:
  154 + y = py - ty / 2.0 + self.spacing[1] / 2.0
  155 +
  156 + if self.points.shape[0] % 2:
  157 + z = pz - tz / 2.0
  158 + else:
  159 + z = pz - tz / 2.0 + self.spacing[2] / 2.0
  160 + x = px
  161 +
  162 + if self.mapper:
  163 + y += sy / 2.0
  164 + z += sz / 2.0
  165 +
  166 + else:
  167 + if self.points.shape[0] % 2:
  168 + y = py - ty / 2.0
  169 + else:
  170 + y = py - ty / 2.0 + self.spacing[1] / 2.0
  171 +
  172 + if self.points.shape[1] % 2:
  173 + x = px - tx / 2.0
  174 + else:
  175 + x = px - tx / 2.0 + self.spacing[0] / 2.0
  176 + z = pz
  177 +
  178 + if self.mapper:
  179 + x += sx / 2.0
  180 + y += sy / 2.0
  181 +
  182 + self.actor.SetPosition(x, y, z)
137 183
138 def SetSpacing(self, spacing): 184 def SetSpacing(self, spacing):
139 self.spacing = spacing 185 self.spacing = spacing
140 - self.__calculate_area_pixels() 186 + self._build_actor()
  187 + self._calculate_area_pixels()
141 188
142 def Show(self, value=1): 189 def Show(self, value=1):
143 if value: 190 if value:
@@ -148,90 +195,104 @@ class CursorCircle: @@ -148,90 +195,104 @@ class CursorCircle:
148 def GetPixels(self): 195 def GetPixels(self):
149 return self.points 196 return self.points
150 197
  198 + def _build_actor(self):
  199 + pass
  200 +
  201 + def _calculate_area_pixels(self):
  202 + pass
151 203
152 -class CursorRectangle: 204 + def _set_colour(self, imagedata, colour):
  205 + scalar_range = int(imagedata.GetScalarRange()[1])
  206 + r, g, b = colour
  207 +
  208 + # map scalar values into colors
  209 + lut_mask = vtk.vtkLookupTable()
  210 + lut_mask.SetNumberOfColors(256)
  211 + lut_mask.SetHueRange(const.THRESHOLD_HUE_RANGE)
  212 + lut_mask.SetSaturationRange(1, 1)
  213 + lut_mask.SetValueRange(0, 255)
  214 + lut_mask.SetRange(0, 255)
  215 + lut_mask.SetNumberOfTableValues(256)
  216 + lut_mask.SetTableValue(0, 0, 0, 0, 0.0)
  217 + lut_mask.SetTableValue(1.0, 1-r, 1-g, 1-b, 0.50)
  218 + lut_mask.SetRampToLinear()
  219 + lut_mask.Build()
  220 +
  221 + # map the input image through a lookup table
  222 + img_colours_mask = vtk.vtkImageMapToColors()
  223 + img_colours_mask.SetLookupTable(lut_mask)
  224 + img_colours_mask.SetOutputFormatToRGBA()
  225 + img_colours_mask.SetInput(imagedata)
  226 + img_colours_mask.Update()
  227 +
  228 + return img_colours_mask.GetOutput()
  229 +
  230 +
  231 +class CursorCircle(CursorBase):
  232 + # TODO: Think and try to change this class to an actor
  233 + # CursorCircleActor(vtk.vtkActor)
153 def __init__(self): 234 def __init__(self):
154 -  
155 - self.colour = (0.0, 0.0, 1.0)  
156 - self.opacity = 1  
157 -  
158 - self.x_length = 30  
159 - self.y_length = 30  
160 - self.radius = 15  
161 -  
162 - self.dimension = (self.x_length, self.y_length)  
163 - self.position = (0 ,0)  
164 - self.orientation = "AXIAL"  
165 - self.spacing = (1, 1, 1)  
166 -  
167 - self.__build_actor()  
168 - self.__calculate_area_pixels()  
169 -  
170 - def SetSize(self, size):  
171 - self.x_length = size  
172 - self.y_length = size  
173 - self.radius = size / 2  
174 - retangle = self.retangle  
175 - retangle.SetXLength(size)  
176 - retangle.SetYLength(size)  
177 - self.__calculate_area_pixels()  
178 -  
179 - def SetOrientation(self, orientation):  
180 - self.orientation = orientation  
181 -  
182 - def SetColour(self, colour):  
183 - self.colour = colour  
184 - self.actor.GetProperty().SetColor(colour) 235 + self.radius = 15.0
  236 + super(CursorCircle, self).__init__()
185 237
186 - def SetOrientation(self, orientation):  
187 - self.orientation = orientation  
188 - proj = Project()  
189 - orig_orien = proj.original_orientation  
190 - if orientation == "CORONAL":  
191 - self.actor.RotateX(90)  
192 - if orientation == "SAGITAL":  
193 - self.actor.RotateY(90) 238 + def _build_actor(self):
  239 + """
  240 + Function to plot the circle
  241 + """
  242 + print "Building circle cursor", self.orientation
  243 + r = self.radius
  244 + sx, sy, sz = self.spacing
  245 + if self.orientation == 'AXIAL':
  246 + xi = math.floor(-r/sx)
  247 + xf = math.ceil(r/sx) + 1
  248 + yi = math.floor(-r/sy)
  249 + yf = math.ceil(r/sy) + 1
  250 + zi = 0
  251 + zf = 1
  252 + elif self.orientation == 'CORONAL':
  253 + xi = math.floor(-r/sx)
  254 + xf = math.ceil(r/sx) + 1
  255 + yi = 0
  256 + yf = 1
  257 + zi = math.floor(-r/sz)
  258 + zf = math.ceil(r/sz) + 1
  259 + elif self.orientation == 'SAGITAL':
  260 + xi = 0
  261 + xf = 1
  262 + yi = math.floor(-r/sy)
  263 + yf = math.ceil(r/sy) + 1
  264 + zi = math.floor(-r/sz)
  265 + zf = math.ceil(r/sz) + 1
194 266
195 - def SetPosition(self, position):  
196 - x,y,z = position  
197 - self.position = position  
198 - self.actor.SetPosition(x,y,z)  
199 -  
200 - def SetEditionPosition(self, position):  
201 - self.edition_position = position 267 + z,y,x = numpy.ogrid[zi:zf,yi:yf, xi:xf]
202 268
203 - def SetSpacing(self, spacing):  
204 - self.spacing = spacing 269 + circle_m = (z*sz)**2 + (y*sy)**2 + (x*sx)**2 <= r**2
  270 + circle_i = to_vtk(circle_m.astype('uint8'),
  271 + self.spacing, 0, self.orientation)
  272 + circle_ci = self._set_colour(circle_i, self.colour)
205 273
206 - def Show(self, value=1):  
207 - if value:  
208 - self.actor.VisibilityOn() 274 + if self.mapper is None:
  275 + self.actor.SetInput(circle_ci)
  276 + self.actor.InterpolateOff()
  277 + self.actor.PickableOff()
  278 + self.actor.SetDisplayExtent(circle_ci.GetExtent())
209 else: 279 else:
210 - self.actor.VisibilityOff() 280 + self.mapper.SetInput(circle_ci)
  281 + self.mapper.BorderOn()
  282 +
  283 + self.mapper.SetOrientation(ORIENTATION[self.orientation])
211 284
212 - def __build_actor(self): 285 + print '===================================='
  286 + print self.orientation
  287 + print circle_ci.GetSpacing()
  288 + print xi, xf, yi, yf, zi, zf
  289 + print '===================================='
  290 +
  291 + def _calculate_area_pixels(self):
213 """ 292 """
214 - Function to plot the Retangle 293 + Return the cursor's pixels.
215 """ 294 """
216 - print "Building rectangle cursor", self.orientation  
217 - mapper = vtk.vtkPolyDataMapper()  
218 - self.retangle = vtk.vtkCubeSource()  
219 - self.actor = actor = vtk.vtkActor()  
220 -  
221 - prop = vtk.vtkProperty()  
222 - prop.SetRepresentationToWireframe()  
223 - self.actor.SetProperty(prop)  
224 -  
225 - mapper.SetInput(self.retangle.GetOutput())  
226 - actor.SetPosition(self.position[0] - self.x_length,\  
227 - self.position[1] - self.y_length, 1)  
228 -  
229 - actor.SetMapper(mapper)  
230 - actor.GetProperty().SetOpacity(self.opacity)  
231 - actor.GetProperty().SetColor(self.colour)  
232 - actor.SetVisibility(0)  
233 -  
234 - def __calculate_area_pixels(self): 295 + r = self.radius
235 if self.orientation == 'AXIAL': 296 if self.orientation == 'AXIAL':
236 sx = self.spacing[0] 297 sx = self.spacing[0]
237 sy = self.spacing[1] 298 sy = self.spacing[1]
@@ -241,12 +302,71 @@ class CursorRectangle: @@ -241,12 +302,71 @@ class CursorRectangle:
241 elif self.orientation == 'SAGITAL': 302 elif self.orientation == 'SAGITAL':
242 sx = self.spacing[1] 303 sx = self.spacing[1]
243 sy = self.spacing[2] 304 sy = self.spacing[2]
244 - shape = (self.y_length/sy, self.x_length/sx)  
245 - self.points = numpy.empty(shape, dtype='bool')  
246 - self.points.fill(True)  
247 305
248 - def GetPixels(self): 306 + xi = math.floor(-r/sx)
  307 + xf = math.ceil(r/sx) + 1
  308 + yi = math.floor(-r/sy)
  309 + yf = math.ceil(r/sy) + 1
  310 +
  311 + y,x = numpy.ogrid[yi:yf, xi:xf]
  312 +
  313 + print "AREA", x
  314 +
  315 + index = (y*sy)**2 + (x*sx)**2 <= r**2
  316 + self.points = index
  317 +
  318 +
  319 +class CursorRectangle(CursorBase):
  320 + def __init__(self):
  321 + self.radius = 15.0
  322 + super(CursorRectangle, self).__init__()
  323 +
  324 +
  325 + def _build_actor(self):
249 """ 326 """
250 - Return the points of the rectangle 327 + Function to plot the Retangle
251 """ 328 """
252 - return self.points 329 + print "Building rectangle cursor", self.orientation
  330 + r = self.radius
  331 + sx, sy, sz = self.spacing
  332 + if self.orientation == 'AXIAL':
  333 + x = math.floor(2*r/sx)
  334 + y = math.floor(2*r/sy)
  335 + z = 1
  336 + elif self.orientation == 'CORONAL':
  337 + x = math.floor(r/sx)
  338 + y = 1
  339 + z = math.floor(r/sz)
  340 + elif self.orientation == 'SAGITAL':
  341 + x = 1
  342 + y = math.floor(r/sy)
  343 + z = math.floor(r/sz)
  344 +
  345 + rectangle_m = numpy.ones((z, y, x), dtype='uint8')
  346 + rectangle_i = to_vtk(rectangle_m, self.spacing, 0, self.orientation)
  347 + rectangle_ci = self._set_colour(rectangle_i, self.colour)
  348 +
  349 + if self.mapper is None:
  350 + self.actor.SetInput(rectangle_ci)
  351 + self.actor.InterpolateOff()
  352 + self.actor.PickableOff()
  353 + self.actor.SetDisplayExtent(rectangle_ci.GetExtent())
  354 + else:
  355 + self.mapper.SetInput(rectangle_ci)
  356 + self.mapper.BorderOn()
  357 + self.mapper.SetOrientation(ORIENTATION[self.orientation])
  358 +
  359 + def _calculate_area_pixels(self):
  360 + r = self.radius
  361 + sx, sy, sz = self.spacing
  362 + if self.orientation == 'AXIAL':
  363 + x = math.floor(2*r/sx)
  364 + y = math.floor(2*r/sy)
  365 + elif self.orientation == 'CORONAL':
  366 + x = math.floor(r/sx)
  367 + y = math.floor(r/sz)
  368 + elif self.orientation == 'SAGITAL':
  369 + x = math.floor(r/sy)
  370 + y = math.floor(r/sz)
  371 +
  372 + self.points = numpy.ones((y, x), dtype='bool')
invesalius/data/imagedata_utils.py
@@ -545,5 +545,3 @@ def analyze2mmap(analyze): @@ -545,5 +545,3 @@ def analyze2mmap(analyze):
545 545
546 matrix.flush() 546 matrix.flush()
547 return matrix, temp_file 547 return matrix, temp_file
548 -  
549 -  
invesalius/data/slice_.py
@@ -294,8 +294,8 @@ class Slice(object): @@ -294,8 +294,8 @@ class Slice(object):
294 sx = self.spacing[0] 294 sx = self.spacing[0]
295 sy = self.spacing[2] 295 sy = self.spacing[2]
296 elif orientation == 'SAGITAL': 296 elif orientation == 'SAGITAL':
297 - sx = self.spacing[1]  
298 - sy = self.spacing[2] 297 + sx = self.spacing[2]
  298 + sy = self.spacing[1]
299 299
300 else: 300 else:
301 if orientation == 'AXIAL': 301 if orientation == 'AXIAL':
@@ -309,15 +309,17 @@ class Slice(object): @@ -309,15 +309,17 @@ class Slice(object):
309 py = position / mask.shape[1] 309 py = position / mask.shape[1]
310 px = position % mask.shape[1] 310 px = position % mask.shape[1]
311 elif orientation == 'SAGITAL': 311 elif orientation == 'SAGITAL':
312 - sx = self.spacing[1]  
313 - sy = self.spacing[2] 312 + sx = self.spacing[2]
  313 + sy = self.spacing[1]
314 py = position / mask.shape[1] 314 py = position / mask.shape[1]
315 px = position % mask.shape[1] 315 px = position % mask.shape[1]
316 316
317 - xi = px - math.ceil(radius/sx)  
318 - xf = px + math.ceil(radius/sx)  
319 - yi = py - math.ceil(radius/sy)  
320 - yf = py + math.ceil(radius/sy) 317 + cx = index.shape[1] / 2 + 1
  318 + cy = index.shape[0] / 2 + 1
  319 + xi = px - index.shape[1] + cx
  320 + xf = xi + index.shape[1]
  321 + yi = py - index.shape[0] + cy
  322 + yf = yi + index.shape[0]
321 323
322 if yi < 0: 324 if yi < 0:
323 index = index[abs(yi):,:] 325 index = index[abs(yi):,:]
@@ -341,6 +343,12 @@ class Slice(object): @@ -341,6 +343,12 @@ class Slice(object):
341 roi_m = mask[yi:yf,xi:xf] 343 roi_m = mask[yi:yf,xi:xf]
342 roi_i = image[yi:yf, xi:xf] 344 roi_i = image[yi:yf, xi:xf]
343 345
  346 + print
  347 + print"IMAGE", roi_m.shape
  348 + print "BRUSH", index.shape
  349 + print "IMAGE[BRUSH]", roi_m[index].shape
  350 + print
  351 +
344 if operation == const.BRUSH_THRESH: 352 if operation == const.BRUSH_THRESH:
345 # It's a trick to make points between threshold gets value 254 353 # It's a trick to make points between threshold gets value 254
346 # (1 * 253 + 1) and out ones gets value 1 (0 * 253 + 1). 354 # (1 * 253 + 1) and out ones gets value 1 (0 * 253 + 1).
invesalius/data/slice_data.py
@@ -38,6 +38,7 @@ class SliceData(object): @@ -38,6 +38,7 @@ class SliceData(object):
38 self.number = 0 38 self.number = 0
39 self.orientation = 'AXIAL' 39 self.orientation = 'AXIAL'
40 self.renderer = None 40 self.renderer = None
  41 + self.overlay_renderer = None
41 self.__create_text() 42 self.__create_text()
42 self.__create_box() 43 self.__create_box()
43 44
@@ -131,8 +132,8 @@ class SliceData(object): @@ -131,8 +132,8 @@ class SliceData(object):
131 132
132 def SetCursor(self, cursor): 133 def SetCursor(self, cursor):
133 if self.cursor: 134 if self.cursor:
134 - self.renderer.RemoveActor(self.cursor.actor)  
135 - self.renderer.AddActor(cursor.actor) 135 + self.overlay_renderer.RemoveActor(self.cursor.actor)
  136 + self.overlay_renderer.AddActor(cursor.actor)
136 self.cursor = cursor 137 self.cursor = cursor
137 138
138 def SetNumber(self, number): 139 def SetNumber(self, number):
@@ -166,7 +167,7 @@ class SliceData(object): @@ -166,7 +167,7 @@ class SliceData(object):
166 self.line_r.SetPoint2((xf, yf, 0)) 167 self.line_r.SetPoint2((xf, yf, 0))
167 168
168 def Hide(self): 169 def Hide(self):
169 - self.renderer.RemoveActor(self.actor) 170 + self.overlay_renderer.RemoveActor(self.actor)
170 self.renderer.RemoveActor(self.text.actor) 171 self.renderer.RemoveActor(self.text.actor)
171 172
172 def Show(self): 173 def Show(self):
invesalius/data/viewer_slice.py
@@ -725,13 +725,13 @@ class Viewer(wx.Panel): @@ -725,13 +725,13 @@ class Viewer(wx.Panel):
725 self.pick.Pick(mouse_x, mouse_y, 0, render) 725 self.pick.Pick(mouse_x, mouse_y, 0, render)
726 726
727 coord = self.get_coordinate_cursor() 727 coord = self.get_coordinate_cursor()
728 - slice_data.cursor.SetPosition(coord)  
729 - slice_data.cursor.SetEditionPosition(  
730 - self.get_coordinate_cursor_edition(slice_data))  
731 - self.__update_cursor_position(slice_data, coord) 728 + position = self.slice_data.actor.GetInput().FindPoint(coord)
  729 +
  730 + if position != -1:
  731 + coord = self.slice_data.actor.GetInput().GetPoint(position)
732 732
  733 + slice_data.cursor.SetPosition(coord)
733 cursor = self.slice_data.cursor 734 cursor = self.slice_data.cursor
734 - position = self.slice_data.actor.GetInput().FindPoint(coord)  
735 radius = cursor.radius 735 radius = cursor.radius
736 736
737 if position < 0: 737 if position < 0:
@@ -771,9 +771,7 @@ class Viewer(wx.Panel): @@ -771,9 +771,7 @@ class Viewer(wx.Panel):
771 if position != -1: 771 if position != -1:
772 coord = self.slice_data.actor.GetInput().GetPoint(position) 772 coord = self.slice_data.actor.GetInput().GetPoint(position)
773 slice_data.cursor.SetPosition(coord) 773 slice_data.cursor.SetPosition(coord)
774 - slice_data.cursor.SetEditionPosition(  
775 - self.get_coordinate_cursor_edition(slice_data))  
776 - self.__update_cursor_position(slice_data, coord) 774 + #self.__update_cursor_position(slice_data, coord)
777 775
778 if (self.left_pressed): 776 if (self.left_pressed):
779 cursor = self.slice_data.cursor 777 cursor = self.slice_data.cursor
@@ -1280,12 +1278,25 @@ class Viewer(wx.Panel): @@ -1280,12 +1278,25 @@ class Viewer(wx.Panel):
1280 1278
1281 def create_slice_window(self): 1279 def create_slice_window(self):
1282 renderer = vtk.vtkRenderer() 1280 renderer = vtk.vtkRenderer()
  1281 + renderer.SetLayer(0)
  1282 + cam = renderer.GetActiveCamera()
  1283 +
  1284 + overlay_renderer = vtk.vtkRenderer()
  1285 + overlay_renderer.SetLayer(1)
  1286 + overlay_renderer.SetActiveCamera(cam)
  1287 + overlay_renderer.SetInteractive(0)
  1288 +
  1289 +
  1290 + self.interactor.GetRenderWindow().SetNumberOfLayers(2)
  1291 + self.interactor.GetRenderWindow().AddRenderer(overlay_renderer)
1283 self.interactor.GetRenderWindow().AddRenderer(renderer) 1292 self.interactor.GetRenderWindow().AddRenderer(renderer)
  1293 +
1284 actor = vtk.vtkImageActor() 1294 actor = vtk.vtkImageActor()
1285 actor.InterpolateOff() 1295 actor.InterpolateOff()
1286 slice_data = sd.SliceData() 1296 slice_data = sd.SliceData()
1287 slice_data.SetOrientation(self.orientation) 1297 slice_data.SetOrientation(self.orientation)
1288 slice_data.renderer = renderer 1298 slice_data.renderer = renderer
  1299 + slice_data.overlay_renderer = overlay_renderer
1289 slice_data.actor = actor 1300 slice_data.actor = actor
1290 slice_data.SetBorderStyle(sd.BORDER_ALL) 1301 slice_data.SetBorderStyle(sd.BORDER_ALL)
1291 renderer.AddActor(actor) 1302 renderer.AddActor(actor)
@@ -1301,7 +1312,7 @@ class Viewer(wx.Panel): @@ -1301,7 +1312,7 @@ class Viewer(wx.Panel):
1301 self.cam.SetFocalPoint(0, 0, 0) 1312 self.cam.SetFocalPoint(0, 0, 0)
1302 self.cam.SetViewUp(const.SLICE_POSITION[orig_orien][0][self.orientation]) 1313 self.cam.SetViewUp(const.SLICE_POSITION[orig_orien][0][self.orientation])
1303 self.cam.SetPosition(const.SLICE_POSITION[orig_orien][1][self.orientation]) 1314 self.cam.SetPosition(const.SLICE_POSITION[orig_orien][1][self.orientation])
1304 - self.cam.ComputeViewPlaneNormal() 1315 + #self.cam.ComputeViewPlaneNormal()
1305 #self.cam.OrthogonalizeViewUp() 1316 #self.cam.OrthogonalizeViewUp()
1306 self.cam.ParallelProjectionOn() 1317 self.cam.ParallelProjectionOn()
1307 1318