Commit 9ab9d4847b311144cbf72bb0ddd8cb08b21c4382

Authored by Thiago Franco de Moraes
Committed by GitHub
1 parent f6b001eb

Using Canvas to render text over the vtkrenderer

* Using wx to show slice number

* Setting weight to bold

* Orientation renderer text using wx

* Improvements

Author:    Thiago Franco de Moraes <totonixsame@gmail.com>

* Improvements

* Better cleaning on closing project

* Using antialising in mac
invesalius/data/measures.py
@@ -66,6 +66,13 @@ class MeasureData: @@ -66,6 +66,13 @@ class MeasureData:
66 66
67 self._list_measures.append(m) 67 self._list_measures.append(m)
68 68
  69 + def clean(self):
  70 + self.measures = {const.SURFACE: {},
  71 + const.AXIAL: {},
  72 + const.CORONAL: {},
  73 + const.SAGITAL: {}}
  74 + self._list_measures = []
  75 +
69 def get(self, location, slice_number): 76 def get(self, location, slice_number):
70 return self.measures[map_locations_id[location]].get(slice_number, []) 77 return self.measures[map_locations_id[location]].get(slice_number, [])
71 78
@@ -110,6 +117,7 @@ class MeasurementManager(object): @@ -110,6 +117,7 @@ class MeasurementManager(object):
110 Publisher.subscribe(self._rm_incomplete_measurements, 117 Publisher.subscribe(self._rm_incomplete_measurements,
111 "Remove incomplete measurements") 118 "Remove incomplete measurements")
112 Publisher.subscribe(self._change_measure_point_pos, 'Change measurement point position') 119 Publisher.subscribe(self._change_measure_point_pos, 'Change measurement point position')
  120 + Publisher.subscribe(self.OnCloseProject, 'Close project data')
113 121
114 def _load_measurements(self, pubsub_evt): 122 def _load_measurements(self, pubsub_evt):
115 try: 123 try:
@@ -340,6 +348,9 @@ class MeasurementManager(object): @@ -340,6 +348,9 @@ class MeasurementManager(object):
340 # self.measures.pop() 348 # self.measures.pop()
341 self.current = None 349 self.current = None
342 350
  351 + def OnCloseProject(self, pubsub_evt):
  352 + self.measures.clean()
  353 +
343 354
344 class Measurement(): 355 class Measurement():
345 general_index = -1 356 general_index = -1
invesalius/data/slice_data.py
@@ -17,6 +17,7 @@ @@ -17,6 +17,7 @@
17 # detalhes. 17 # detalhes.
18 #-------------------------------------------------------------------------- 18 #--------------------------------------------------------------------------
19 import vtk 19 import vtk
  20 +import wx
20 21
21 import invesalius.constants as const 22 import invesalius.constants as const
22 import invesalius.data.vtk_utils as vu 23 import invesalius.data.vtk_utils as vu
@@ -50,6 +51,7 @@ class SliceData(object): @@ -50,6 +51,7 @@ class SliceData(object):
50 text.SetColour(colour) 51 text.SetColour(colour)
51 text.SetSize(const.TEXT_SIZE_LARGE) 52 text.SetSize(const.TEXT_SIZE_LARGE)
52 text.SetPosition(const.TEXT_POS_LEFT_DOWN_ZERO) 53 text.SetPosition(const.TEXT_POS_LEFT_DOWN_ZERO)
  54 + text.SetSymbolicSize(wx.FONTSIZE_LARGE)
53 #text.SetVerticalJustificationToBottom() 55 #text.SetVerticalJustificationToBottom()
54 text.SetValue(self.number) 56 text.SetValue(self.number)
55 self.text = text 57 self.text = text
invesalius/data/styles.py
@@ -272,12 +272,14 @@ class WWWLInteractorStyle(DefaultInteractorStyle): @@ -272,12 +272,14 @@ class WWWLInteractorStyle(DefaultInteractorStyle):
272 272
273 def SetUp(self): 273 def SetUp(self):
274 self.viewer.on_wl = True 274 self.viewer.on_wl = True
275 - self.viewer.wl_text.Show() 275 + self.viewer.canvas.draw_list.append(self.viewer.wl_text)
  276 + self.viewer.UpdateCanvas()
276 277
277 def CleanUp(self): 278 def CleanUp(self):
278 self.viewer.on_wl = False 279 self.viewer.on_wl = False
279 if self.viewer.wl_text is not None: 280 if self.viewer.wl_text is not None:
280 - self.viewer.wl_text.Hide() 281 + self.viewer.canvas.draw_list.remove(self.viewer.wl_text)
  282 + self.viewer.UpdateCanvas()
281 283
282 def OnWindowLevelMove(self, obj, evt): 284 def OnWindowLevelMove(self, obj, evt):
283 if (self.left_pressed): 285 if (self.left_pressed):
invesalius/data/viewer_slice.py
@@ -212,6 +212,10 @@ class CanvasRendererCTX: @@ -212,6 +212,10 @@ class CanvasRendererCTX:
212 212
213 self.modified = True 213 self.modified = True
214 214
  215 + def remove_from_renderer(self):
  216 + self.canvas_renderer.RemoveActor(self.actor)
  217 + self.evt_renderer.RemoveObservers("StartEvent")
  218 +
215 def OnPaint(self, evt, obj): 219 def OnPaint(self, evt, obj):
216 size = self.canvas_renderer.GetSize() 220 size = self.canvas_renderer.GetSize()
217 w, h = size 221 w, h = size
@@ -233,7 +237,8 @@ class CanvasRendererCTX: @@ -233,7 +237,8 @@ class CanvasRendererCTX:
233 self.image.SetAlphaBuffer(self.alpha) 237 self.image.SetAlphaBuffer(self.alpha)
234 self.image.Clear() 238 self.image.Clear()
235 gc = wx.GraphicsContext.Create(self.image) 239 gc = wx.GraphicsContext.Create(self.image)
236 - gc.SetAntialiasMode(0) 240 + if sys.platform != 'darwin':
  241 + gc.SetAntialiasMode(0)
237 242
238 self.gc = gc 243 self.gc = gc
239 244
@@ -428,6 +433,8 @@ class CanvasRendererCTX: @@ -428,6 +433,8 @@ class CanvasRendererCTX:
428 gc.SetFont(font) 433 gc.SetFont(font)
429 434
430 px, py = pos 435 px, py = pos
  436 + py = -py
  437 +
431 gc.DrawText(text, px, py) 438 gc.DrawText(text, px, py)
432 self._drawn = True 439 self._drawn = True
433 440
@@ -455,14 +462,13 @@ class CanvasRendererCTX: @@ -455,14 +462,13 @@ class CanvasRendererCTX:
455 w, h = gc.GetTextExtent(text) 462 w, h = gc.GetTextExtent(text)
456 463
457 px, py = pos 464 px, py = pos
458 - py = -py  
459 465
460 # Drawing the box 466 # Drawing the box
461 cw, ch = w + border * 2, h + border * 2 467 cw, ch = w + border * 2, h + border * 2
462 - self.draw_rectangle((px, py), cw, ch, bg_colour, bg_colour) 468 + self.draw_rectangle((px, -py), cw, ch, bg_colour, bg_colour)
463 469
464 # Drawing the text 470 # Drawing the text
465 - tpx, tpy = px + border, py + border 471 + tpx, tpy = px + border, py - border
466 self.draw_text(text, (tpx, tpy), font, txt_colour) 472 self.draw_text(text, (tpx, tpy), font, txt_colour)
467 self._drawn = True 473 self._drawn = True
468 474
@@ -532,10 +538,12 @@ class Viewer(wx.Panel): @@ -532,10 +538,12 @@ class Viewer(wx.Panel):
532 # All renderers and image actors in this viewer 538 # All renderers and image actors in this viewer
533 self.slice_data_list = [] 539 self.slice_data_list = []
534 self.slice_data = None 540 self.slice_data = None
535 - 541 +
536 self.slice_actor = None 542 self.slice_actor = None
537 self.interpolation_slice_status = True 543 self.interpolation_slice_status = True
538 544
  545 + self.canvas = None
  546 +
539 # The layout from slice_data, the first is number of cols, the second 547 # The layout from slice_data, the first is number of cols, the second
540 # is the number of rows 548 # is the number of rows
541 self.layout = (1, 1) 549 self.layout = (1, 1)
@@ -617,19 +625,23 @@ class Viewer(wx.Panel): @@ -617,19 +625,23 @@ class Viewer(wx.Panel):
617 self.__configure_scroll() 625 self.__configure_scroll()
618 626
619 def HideTextActors(self, change_status=True): 627 def HideTextActors(self, change_status=True):
620 - if self.wl_text:  
621 - self.wl_text.Hide()  
622 - [t.Hide() for t in self.orientation_texts]  
623 - self.interactor.Render() 628 + try:
  629 + self.canvas.draw_list.remove(self.wl_text)
  630 + except (ValueError, AttributeError):
  631 + pass
  632 +
  633 + [self.canvas.draw_list.remove(t) for t in self.orientation_texts]
  634 + self.UpdateCanvas()
624 if change_status: 635 if change_status:
625 self.on_text = False 636 self.on_text = False
626 637
627 def ShowTextActors(self): 638 def ShowTextActors(self):
628 if self.on_wl and self.wl_text: 639 if self.on_wl and self.wl_text:
629 - self.wl_text.Show()  
630 - [t.Show() for t in self.orientation_texts]  
631 - self.Update()  
632 - self.interactor.Render() 640 + self.canvas.draw_list.append(self.wl_text)
  641 + print "Canvas", self.canvas.draw_list
  642 + print "text ori", self.orientation_texts
  643 + [self.canvas.draw_list.append(t) for t in self.orientation_texts]
  644 + self.UpdateCanvas()
633 self.on_text = True 645 self.on_text = True
634 646
635 def __set_layout(self, pubsub_evt): 647 def __set_layout(self, pubsub_evt):
@@ -689,6 +701,7 @@ class Viewer(wx.Panel): @@ -689,6 +701,7 @@ class Viewer(wx.Panel):
689 value = STR_WL%(window_level, window_width) 701 value = STR_WL%(window_level, window_width)
690 if (self.wl_text): 702 if (self.wl_text):
691 self.wl_text.SetValue(value) 703 self.wl_text.SetValue(value)
  704 + self.canvas.modified = True
692 #self.interactor.Render() 705 #self.interactor.Render()
693 706
694 def EnableText(self): 707 def EnableText(self):
@@ -697,8 +710,11 @@ class Viewer(wx.Panel): @@ -697,8 +710,11 @@ class Viewer(wx.Panel):
697 colour = const.ORIENTATION_COLOUR[self.orientation] 710 colour = const.ORIENTATION_COLOUR[self.orientation]
698 711
699 # Window & Level text 712 # Window & Level text
700 - self.wl_text = vtku.Text() 713 + self.wl_text = vtku.TextZero()
  714 + self.wl_text.SetPosition(const.TEXT_POS_LEFT_UP)
  715 + self.wl_text.SetSymbolicSize(wx.FONTSIZE_LARGE)
701 self.SetWLText(proj.level, proj.window) 716 self.SetWLText(proj.level, proj.window)
  717 +
702 # Orientation text 718 # Orientation text
703 if self.orientation == 'AXIAL': 719 if self.orientation == 'AXIAL':
704 values = [_('R'), _('L'), _('A'), _('P')] 720 values = [_('R'), _('L'), _('A'), _('P')]
@@ -713,6 +729,7 @@ class Viewer(wx.Panel): @@ -713,6 +729,7 @@ class Viewer(wx.Panel):
713 left_text.SetPosition(const.TEXT_POS_VCENTRE_LEFT) 729 left_text.SetPosition(const.TEXT_POS_VCENTRE_LEFT)
714 left_text.SetVerticalJustificationToCentered() 730 left_text.SetVerticalJustificationToCentered()
715 left_text.SetValue(values[0]) 731 left_text.SetValue(values[0])
  732 + left_text.SetSymbolicSize(wx.FONTSIZE_LARGE)
716 733
717 right_text = self.right_text = vtku.TextZero() 734 right_text = self.right_text = vtku.TextZero()
718 right_text.ShadowOff() 735 right_text.ShadowOff()
@@ -721,6 +738,7 @@ class Viewer(wx.Panel): @@ -721,6 +738,7 @@ class Viewer(wx.Panel):
721 right_text.SetVerticalJustificationToCentered() 738 right_text.SetVerticalJustificationToCentered()
722 right_text.SetJustificationToRight() 739 right_text.SetJustificationToRight()
723 right_text.SetValue(values[1]) 740 right_text.SetValue(values[1])
  741 + right_text.SetSymbolicSize(wx.FONTSIZE_LARGE)
724 742
725 up_text = self.up_text = vtku.TextZero() 743 up_text = self.up_text = vtku.TextZero()
726 up_text.ShadowOff() 744 up_text.ShadowOff()
@@ -728,6 +746,7 @@ class Viewer(wx.Panel): @@ -728,6 +746,7 @@ class Viewer(wx.Panel):
728 up_text.SetPosition(const.TEXT_POS_HCENTRE_UP) 746 up_text.SetPosition(const.TEXT_POS_HCENTRE_UP)
729 up_text.SetJustificationToCentered() 747 up_text.SetJustificationToCentered()
730 up_text.SetValue(values[2]) 748 up_text.SetValue(values[2])
  749 + up_text.SetSymbolicSize(wx.FONTSIZE_LARGE)
731 750
732 down_text = self.down_text = vtku.TextZero() 751 down_text = self.down_text = vtku.TextZero()
733 down_text.ShadowOff() 752 down_text.ShadowOff()
@@ -736,17 +755,11 @@ class Viewer(wx.Panel): @@ -736,17 +755,11 @@ class Viewer(wx.Panel):
736 down_text.SetJustificationToCentered() 755 down_text.SetJustificationToCentered()
737 down_text.SetVerticalJustificationToBottom() 756 down_text.SetVerticalJustificationToBottom()
738 down_text.SetValue(values[3]) 757 down_text.SetValue(values[3])
  758 + down_text.SetSymbolicSize(wx.FONTSIZE_LARGE)
739 759
740 self.orientation_texts = [left_text, right_text, up_text, 760 self.orientation_texts = [left_text, right_text, up_text,
741 down_text] 761 down_text]
742 762
743 -  
744 - self.slice_data.renderer.AddActor(self.wl_text.actor)  
745 - self.slice_data.renderer.AddActor(left_text.actor)  
746 - self.slice_data.renderer.AddActor(right_text.actor)  
747 - self.slice_data.renderer.AddActor(up_text.actor)  
748 - self.slice_data.renderer.AddActor(down_text.actor)  
749 -  
750 def RenderTextDirection(self, directions): 763 def RenderTextDirection(self, directions):
751 # Values are on ccw order, starting from the top: 764 # Values are on ccw order, starting from the top:
752 self.up_text.SetValue(directions[0]) 765 self.up_text.SetValue(directions[0])
@@ -1304,7 +1317,16 @@ class Viewer(wx.Panel): @@ -1304,7 +1317,16 @@ class Viewer(wx.Panel):
1304 1317
1305 self.slice_data_list = [] 1318 self.slice_data_list = []
1306 self.layout = (1, 1) 1319 self.layout = (1, 1)
  1320 +
  1321 + del self.slice_data
  1322 + self.slice_data = None
  1323 +
  1324 + self.canvas.draw_list = []
  1325 + self.canvas.remove_from_renderer()
  1326 + self.canvas = None
  1327 +
1307 self.orientation_texts = [] 1328 self.orientation_texts = []
  1329 +
1308 self.slice_number = 0 1330 self.slice_number = 0
1309 self.cursor = None 1331 self.cursor = None
1310 self.wl_text = None 1332 self.wl_text = None
@@ -1405,6 +1427,7 @@ class Viewer(wx.Panel): @@ -1405,6 +1427,7 @@ class Viewer(wx.Panel):
1405 self.__build_cross_lines() 1427 self.__build_cross_lines()
1406 1428
1407 self.canvas = CanvasRendererCTX(self.slice_data.renderer, self.slice_data.canvas_renderer, self.orientation) 1429 self.canvas = CanvasRendererCTX(self.slice_data.renderer, self.slice_data.canvas_renderer, self.orientation)
  1430 + self.canvas.draw_list.append(self.slice_data.text)
1408 1431
1409 # Set the slice number to the last slice to ensure the camera if far 1432 # Set the slice number to the last slice to ensure the camera if far
1410 # enough to show all slices. 1433 # enough to show all slices.
@@ -1502,7 +1525,7 @@ class Viewer(wx.Panel): @@ -1502,7 +1525,7 @@ class Viewer(wx.Panel):
1502 slice_data.actor = actor 1525 slice_data.actor = actor
1503 slice_data.SetBorderStyle(sd.BORDER_ALL) 1526 slice_data.SetBorderStyle(sd.BORDER_ALL)
1504 renderer.AddActor(actor) 1527 renderer.AddActor(actor)
1505 - renderer.AddActor(slice_data.text.actor) 1528 + # renderer.AddActor(slice_data.text.actor)
1506 renderer.AddViewProp(slice_data.box_actor) 1529 renderer.AddViewProp(slice_data.box_actor)
1507 1530
1508 return slice_data 1531 return slice_data
@@ -1547,21 +1570,22 @@ class Viewer(wx.Panel): @@ -1547,21 +1570,22 @@ class Viewer(wx.Panel):
1547 self.interactor.Render() 1570 self.interactor.Render()
1548 1571
1549 def UpdateCanvas(self, evt=None): 1572 def UpdateCanvas(self, evt=None):
1550 - cp_draw_list = self.canvas.draw_list[:]  
1551 - self.canvas.draw_list = [] 1573 + if self.canvas is not None:
  1574 + cp_draw_list = self.canvas.draw_list[:]
  1575 + self.canvas.draw_list = []
1552 1576
1553 - # Removing all measures  
1554 - for i in cp_draw_list:  
1555 - if not isinstance(i, (measures.AngularMeasure, measures.LinearMeasure)):  
1556 - self.canvas.draw_list.append(i) 1577 + # Removing all measures
  1578 + for i in cp_draw_list:
  1579 + if not isinstance(i, (measures.AngularMeasure, measures.LinearMeasure)):
  1580 + self.canvas.draw_list.append(i)
1557 1581
1558 - # Then add all needed measures  
1559 - for (m, mr) in self.measures.get(self.orientation, self.slice_data.number):  
1560 - if m.visible:  
1561 - self.canvas.draw_list.append(mr) 1582 + # Then add all needed measures
  1583 + for (m, mr) in self.measures.get(self.orientation, self.slice_data.number):
  1584 + if m.visible:
  1585 + self.canvas.draw_list.append(mr)
1562 1586
1563 - self.canvas.modified = True  
1564 - self.interactor.Render() 1587 + self.canvas.modified = True
  1588 + self.interactor.Render()
1565 1589
1566 def __configure_scroll(self): 1590 def __configure_scroll(self):
1567 actor = self.slice_data_list[0].actor 1591 actor = self.slice_data_list[0].actor
invesalius/data/vtk_utils.py
@@ -19,6 +19,7 @@ @@ -19,6 +19,7 @@
19 import sys 19 import sys
20 20
21 import vtk 21 import vtk
  22 +import wx
22 from wx.lib.pubsub import pub as Publisher 23 from wx.lib.pubsub import pub as Publisher
23 import invesalius.constants as const 24 import invesalius.constants as const
24 from invesalius.gui.dialogs import ProgressDialog 25 from invesalius.gui.dialogs import ProgressDialog
@@ -189,6 +190,10 @@ class TextZero(object): @@ -189,6 +190,10 @@ class TextZero(object):
189 actor.PickableOff() 190 actor.PickableOff()
190 self.actor = actor 191 self.actor = actor
191 192
  193 + self.text = ''
  194 + self.position = (0, 0)
  195 + self.symbolic_syze = wx.FONTSIZE_MEDIUM
  196 +
192 def SetColour(self, colour): 197 def SetColour(self, colour):
193 self.property.SetColor(colour) 198 self.property.SetColor(colour)
194 199
@@ -198,6 +203,9 @@ class TextZero(object): @@ -198,6 +203,9 @@ class TextZero(object):
198 def SetSize(self, size): 203 def SetSize(self, size):
199 self.property.SetFontSize(size) 204 self.property.SetFontSize(size)
200 205
  206 + def SetSymbolicSize(self, size):
  207 + self.symbolic_syze = size
  208 +
201 def SetValue(self, value): 209 def SetValue(self, value):
202 if isinstance(value, int) or isinstance(value, float): 210 if isinstance(value, int) or isinstance(value, float):
203 value = str(value) 211 value = str(value)
@@ -207,13 +215,15 @@ class TextZero(object): @@ -207,13 +215,15 @@ class TextZero(object):
207 # UnicodeEncodeError because they have non-ascii characters. To avoid 215 # UnicodeEncodeError because they have non-ascii characters. To avoid
208 # that we encode in utf-8. 216 # that we encode in utf-8.
209 self.actor.SetInput(value.encode("cp1252")) 217 self.actor.SetInput(value.encode("cp1252"))
  218 + self.text = value
210 219
211 def SetPosition(self, position): 220 def SetPosition(self, position):
  221 + self.position = position
212 self.actor.GetPositionCoordinate().SetValue(position[0], 222 self.actor.GetPositionCoordinate().SetValue(position[0],
213 position[1]) 223 position[1])
214 224
215 - def GetPosition(self, position):  
216 - self.actor.GetPositionCoordinate().GetValue() 225 + def GetPosition(self):
  226 + return self.actor.GetPositionCoordinate().GetValue()
217 227
218 def SetJustificationToRight(self): 228 def SetJustificationToRight(self):
219 self.property.SetJustificationToRight() 229 self.property.SetJustificationToRight()
@@ -237,3 +247,13 @@ class TextZero(object): @@ -237,3 +247,13 @@ class TextZero(object):
237 def Hide(self): 247 def Hide(self):
238 self.actor.VisibilityOff() 248 self.actor.VisibilityOff()
239 249
  250 + def draw_to_canvas(self, gc, canvas):
  251 + coord = vtk.vtkCoordinate()
  252 + coord.SetCoordinateSystemToNormalizedDisplay()
  253 + coord.SetValue(*self.position)
  254 + x, y = coord.GetComputedDisplayValue(canvas.evt_renderer)
  255 +
  256 + font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
  257 + # font.SetWeight(wx.FONTWEIGHT_BOLD)
  258 + font.SetSymbolicSize(self.symbolic_syze)
  259 + canvas.draw_text(self.text, (x, y), font=font)