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) | ... | ... |