Commit 9ab9d4847b311144cbf72bb0ddd8cb08b21c4382
Committed by
GitHub
1 parent
f6b001eb
Exists in
master
and in
6 other branches
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
Showing
5 changed files
with
97 additions
and
38 deletions
Show diff stats
invesalius/data/measures.py
| ... | ... | @@ -66,6 +66,13 @@ class MeasureData: |
| 66 | 66 | |
| 67 | 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 | 76 | def get(self, location, slice_number): |
| 70 | 77 | return self.measures[map_locations_id[location]].get(slice_number, []) |
| 71 | 78 | |
| ... | ... | @@ -110,6 +117,7 @@ class MeasurementManager(object): |
| 110 | 117 | Publisher.subscribe(self._rm_incomplete_measurements, |
| 111 | 118 | "Remove incomplete measurements") |
| 112 | 119 | Publisher.subscribe(self._change_measure_point_pos, 'Change measurement point position') |
| 120 | + Publisher.subscribe(self.OnCloseProject, 'Close project data') | |
| 113 | 121 | |
| 114 | 122 | def _load_measurements(self, pubsub_evt): |
| 115 | 123 | try: |
| ... | ... | @@ -340,6 +348,9 @@ class MeasurementManager(object): |
| 340 | 348 | # self.measures.pop() |
| 341 | 349 | self.current = None |
| 342 | 350 | |
| 351 | + def OnCloseProject(self, pubsub_evt): | |
| 352 | + self.measures.clean() | |
| 353 | + | |
| 343 | 354 | |
| 344 | 355 | class Measurement(): |
| 345 | 356 | general_index = -1 | ... | ... |
invesalius/data/slice_data.py
| ... | ... | @@ -17,6 +17,7 @@ |
| 17 | 17 | # detalhes. |
| 18 | 18 | #-------------------------------------------------------------------------- |
| 19 | 19 | import vtk |
| 20 | +import wx | |
| 20 | 21 | |
| 21 | 22 | import invesalius.constants as const |
| 22 | 23 | import invesalius.data.vtk_utils as vu |
| ... | ... | @@ -50,6 +51,7 @@ class SliceData(object): |
| 50 | 51 | text.SetColour(colour) |
| 51 | 52 | text.SetSize(const.TEXT_SIZE_LARGE) |
| 52 | 53 | text.SetPosition(const.TEXT_POS_LEFT_DOWN_ZERO) |
| 54 | + text.SetSymbolicSize(wx.FONTSIZE_LARGE) | |
| 53 | 55 | #text.SetVerticalJustificationToBottom() |
| 54 | 56 | text.SetValue(self.number) |
| 55 | 57 | self.text = text | ... | ... |
invesalius/data/styles.py
| ... | ... | @@ -272,12 +272,14 @@ class WWWLInteractorStyle(DefaultInteractorStyle): |
| 272 | 272 | |
| 273 | 273 | def SetUp(self): |
| 274 | 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 | 278 | def CleanUp(self): |
| 278 | 279 | self.viewer.on_wl = False |
| 279 | 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 | 284 | def OnWindowLevelMove(self, obj, evt): |
| 283 | 285 | if (self.left_pressed): | ... | ... |
invesalius/data/viewer_slice.py
| ... | ... | @@ -212,6 +212,10 @@ class CanvasRendererCTX: |
| 212 | 212 | |
| 213 | 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 | 219 | def OnPaint(self, evt, obj): |
| 216 | 220 | size = self.canvas_renderer.GetSize() |
| 217 | 221 | w, h = size |
| ... | ... | @@ -233,7 +237,8 @@ class CanvasRendererCTX: |
| 233 | 237 | self.image.SetAlphaBuffer(self.alpha) |
| 234 | 238 | self.image.Clear() |
| 235 | 239 | gc = wx.GraphicsContext.Create(self.image) |
| 236 | - gc.SetAntialiasMode(0) | |
| 240 | + if sys.platform != 'darwin': | |
| 241 | + gc.SetAntialiasMode(0) | |
| 237 | 242 | |
| 238 | 243 | self.gc = gc |
| 239 | 244 | |
| ... | ... | @@ -428,6 +433,8 @@ class CanvasRendererCTX: |
| 428 | 433 | gc.SetFont(font) |
| 429 | 434 | |
| 430 | 435 | px, py = pos |
| 436 | + py = -py | |
| 437 | + | |
| 431 | 438 | gc.DrawText(text, px, py) |
| 432 | 439 | self._drawn = True |
| 433 | 440 | |
| ... | ... | @@ -455,14 +462,13 @@ class CanvasRendererCTX: |
| 455 | 462 | w, h = gc.GetTextExtent(text) |
| 456 | 463 | |
| 457 | 464 | px, py = pos |
| 458 | - py = -py | |
| 459 | 465 | |
| 460 | 466 | # Drawing the box |
| 461 | 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 | 470 | # Drawing the text |
| 465 | - tpx, tpy = px + border, py + border | |
| 471 | + tpx, tpy = px + border, py - border | |
| 466 | 472 | self.draw_text(text, (tpx, tpy), font, txt_colour) |
| 467 | 473 | self._drawn = True |
| 468 | 474 | |
| ... | ... | @@ -532,10 +538,12 @@ class Viewer(wx.Panel): |
| 532 | 538 | # All renderers and image actors in this viewer |
| 533 | 539 | self.slice_data_list = [] |
| 534 | 540 | self.slice_data = None |
| 535 | - | |
| 541 | + | |
| 536 | 542 | self.slice_actor = None |
| 537 | 543 | self.interpolation_slice_status = True |
| 538 | 544 | |
| 545 | + self.canvas = None | |
| 546 | + | |
| 539 | 547 | # The layout from slice_data, the first is number of cols, the second |
| 540 | 548 | # is the number of rows |
| 541 | 549 | self.layout = (1, 1) |
| ... | ... | @@ -617,19 +625,23 @@ class Viewer(wx.Panel): |
| 617 | 625 | self.__configure_scroll() |
| 618 | 626 | |
| 619 | 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 | 635 | if change_status: |
| 625 | 636 | self.on_text = False |
| 626 | 637 | |
| 627 | 638 | def ShowTextActors(self): |
| 628 | 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 | 645 | self.on_text = True |
| 634 | 646 | |
| 635 | 647 | def __set_layout(self, pubsub_evt): |
| ... | ... | @@ -689,6 +701,7 @@ class Viewer(wx.Panel): |
| 689 | 701 | value = STR_WL%(window_level, window_width) |
| 690 | 702 | if (self.wl_text): |
| 691 | 703 | self.wl_text.SetValue(value) |
| 704 | + self.canvas.modified = True | |
| 692 | 705 | #self.interactor.Render() |
| 693 | 706 | |
| 694 | 707 | def EnableText(self): |
| ... | ... | @@ -697,8 +710,11 @@ class Viewer(wx.Panel): |
| 697 | 710 | colour = const.ORIENTATION_COLOUR[self.orientation] |
| 698 | 711 | |
| 699 | 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 | 716 | self.SetWLText(proj.level, proj.window) |
| 717 | + | |
| 702 | 718 | # Orientation text |
| 703 | 719 | if self.orientation == 'AXIAL': |
| 704 | 720 | values = [_('R'), _('L'), _('A'), _('P')] |
| ... | ... | @@ -713,6 +729,7 @@ class Viewer(wx.Panel): |
| 713 | 729 | left_text.SetPosition(const.TEXT_POS_VCENTRE_LEFT) |
| 714 | 730 | left_text.SetVerticalJustificationToCentered() |
| 715 | 731 | left_text.SetValue(values[0]) |
| 732 | + left_text.SetSymbolicSize(wx.FONTSIZE_LARGE) | |
| 716 | 733 | |
| 717 | 734 | right_text = self.right_text = vtku.TextZero() |
| 718 | 735 | right_text.ShadowOff() |
| ... | ... | @@ -721,6 +738,7 @@ class Viewer(wx.Panel): |
| 721 | 738 | right_text.SetVerticalJustificationToCentered() |
| 722 | 739 | right_text.SetJustificationToRight() |
| 723 | 740 | right_text.SetValue(values[1]) |
| 741 | + right_text.SetSymbolicSize(wx.FONTSIZE_LARGE) | |
| 724 | 742 | |
| 725 | 743 | up_text = self.up_text = vtku.TextZero() |
| 726 | 744 | up_text.ShadowOff() |
| ... | ... | @@ -728,6 +746,7 @@ class Viewer(wx.Panel): |
| 728 | 746 | up_text.SetPosition(const.TEXT_POS_HCENTRE_UP) |
| 729 | 747 | up_text.SetJustificationToCentered() |
| 730 | 748 | up_text.SetValue(values[2]) |
| 749 | + up_text.SetSymbolicSize(wx.FONTSIZE_LARGE) | |
| 731 | 750 | |
| 732 | 751 | down_text = self.down_text = vtku.TextZero() |
| 733 | 752 | down_text.ShadowOff() |
| ... | ... | @@ -736,17 +755,11 @@ class Viewer(wx.Panel): |
| 736 | 755 | down_text.SetJustificationToCentered() |
| 737 | 756 | down_text.SetVerticalJustificationToBottom() |
| 738 | 757 | down_text.SetValue(values[3]) |
| 758 | + down_text.SetSymbolicSize(wx.FONTSIZE_LARGE) | |
| 739 | 759 | |
| 740 | 760 | self.orientation_texts = [left_text, right_text, up_text, |
| 741 | 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 | 763 | def RenderTextDirection(self, directions): |
| 751 | 764 | # Values are on ccw order, starting from the top: |
| 752 | 765 | self.up_text.SetValue(directions[0]) |
| ... | ... | @@ -1304,7 +1317,16 @@ class Viewer(wx.Panel): |
| 1304 | 1317 | |
| 1305 | 1318 | self.slice_data_list = [] |
| 1306 | 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 | 1328 | self.orientation_texts = [] |
| 1329 | + | |
| 1308 | 1330 | self.slice_number = 0 |
| 1309 | 1331 | self.cursor = None |
| 1310 | 1332 | self.wl_text = None |
| ... | ... | @@ -1405,6 +1427,7 @@ class Viewer(wx.Panel): |
| 1405 | 1427 | self.__build_cross_lines() |
| 1406 | 1428 | |
| 1407 | 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 | 1432 | # Set the slice number to the last slice to ensure the camera if far |
| 1410 | 1433 | # enough to show all slices. |
| ... | ... | @@ -1502,7 +1525,7 @@ class Viewer(wx.Panel): |
| 1502 | 1525 | slice_data.actor = actor |
| 1503 | 1526 | slice_data.SetBorderStyle(sd.BORDER_ALL) |
| 1504 | 1527 | renderer.AddActor(actor) |
| 1505 | - renderer.AddActor(slice_data.text.actor) | |
| 1528 | + # renderer.AddActor(slice_data.text.actor) | |
| 1506 | 1529 | renderer.AddViewProp(slice_data.box_actor) |
| 1507 | 1530 | |
| 1508 | 1531 | return slice_data |
| ... | ... | @@ -1547,21 +1570,22 @@ class Viewer(wx.Panel): |
| 1547 | 1570 | self.interactor.Render() |
| 1548 | 1571 | |
| 1549 | 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 | 1590 | def __configure_scroll(self): |
| 1567 | 1591 | actor = self.slice_data_list[0].actor | ... | ... |
invesalius/data/vtk_utils.py
| ... | ... | @@ -19,6 +19,7 @@ |
| 19 | 19 | import sys |
| 20 | 20 | |
| 21 | 21 | import vtk |
| 22 | +import wx | |
| 22 | 23 | from wx.lib.pubsub import pub as Publisher |
| 23 | 24 | import invesalius.constants as const |
| 24 | 25 | from invesalius.gui.dialogs import ProgressDialog |
| ... | ... | @@ -189,6 +190,10 @@ class TextZero(object): |
| 189 | 190 | actor.PickableOff() |
| 190 | 191 | self.actor = actor |
| 191 | 192 | |
| 193 | + self.text = '' | |
| 194 | + self.position = (0, 0) | |
| 195 | + self.symbolic_syze = wx.FONTSIZE_MEDIUM | |
| 196 | + | |
| 192 | 197 | def SetColour(self, colour): |
| 193 | 198 | self.property.SetColor(colour) |
| 194 | 199 | |
| ... | ... | @@ -198,6 +203,9 @@ class TextZero(object): |
| 198 | 203 | def SetSize(self, size): |
| 199 | 204 | self.property.SetFontSize(size) |
| 200 | 205 | |
| 206 | + def SetSymbolicSize(self, size): | |
| 207 | + self.symbolic_syze = size | |
| 208 | + | |
| 201 | 209 | def SetValue(self, value): |
| 202 | 210 | if isinstance(value, int) or isinstance(value, float): |
| 203 | 211 | value = str(value) |
| ... | ... | @@ -207,13 +215,15 @@ class TextZero(object): |
| 207 | 215 | # UnicodeEncodeError because they have non-ascii characters. To avoid |
| 208 | 216 | # that we encode in utf-8. |
| 209 | 217 | self.actor.SetInput(value.encode("cp1252")) |
| 218 | + self.text = value | |
| 210 | 219 | |
| 211 | 220 | def SetPosition(self, position): |
| 221 | + self.position = position | |
| 212 | 222 | self.actor.GetPositionCoordinate().SetValue(position[0], |
| 213 | 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 | 228 | def SetJustificationToRight(self): |
| 219 | 229 | self.property.SetJustificationToRight() |
| ... | ... | @@ -237,3 +247,13 @@ class TextZero(object): |
| 237 | 247 | def Hide(self): |
| 238 | 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) | ... | ... |