VisPyCanvas.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. # ##########################################################
  2. # FlatCAM: 2D Post-processing for Manufacturing #
  3. # http://flatcam.org #
  4. # File Author: Dennis Hayrullin #
  5. # Date: 2/5/2016 #
  6. # MIT Licence #
  7. # ##########################################################
  8. from PyQt5.QtGui import QPalette
  9. from PyQt5.QtCore import QSettings
  10. import numpy as np
  11. import vispy.scene as scene
  12. from vispy.scene.cameras.base_camera import BaseCamera
  13. from vispy.color import Color
  14. import time
  15. white = Color("#ffffff")
  16. black = Color("#000000")
  17. class VisPyCanvas(scene.SceneCanvas):
  18. def __init__(self, config=None):
  19. print("vp_1")
  20. try:
  21. # scene.SceneCanvas.__init__(self, keys=None, config=config)
  22. super().__init__(config=config, keys=None)
  23. except Exception as e:
  24. print("VisPyCanvas.__init__() -> %s" % str(e))
  25. print("vp_2")
  26. self.unfreeze()
  27. print("vp_3")
  28. settings = QSettings("Open Source", "FlatCAM")
  29. if settings.contains("axis_font_size"):
  30. a_fsize = settings.value('axis_font_size', type=int)
  31. else:
  32. a_fsize = 8
  33. print("vp_4")
  34. if settings.contains("theme"):
  35. theme = settings.value('theme', type=str)
  36. else:
  37. theme = 'white'
  38. if theme == 'white':
  39. theme_color = Color('#FFFFFF')
  40. tick_color = Color('#000000')
  41. back_color = str(QPalette().color(QPalette.Window).name())
  42. else:
  43. theme_color = Color('#000000')
  44. tick_color = Color('gray')
  45. back_color = Color('#000000')
  46. # back_color = Color('#272822') # darker
  47. # back_color = Color('#3c3f41') # lighter
  48. print("vp_5")
  49. self.central_widget.bgcolor = back_color
  50. self.central_widget.border_color = back_color
  51. self.grid_widget = self.central_widget.add_grid(margin=10)
  52. self.grid_widget.spacing = 0
  53. top_padding = self.grid_widget.add_widget(row=0, col=0, col_span=2)
  54. top_padding.height_max = 0
  55. print("vp_6")
  56. self.yaxis = scene.AxisWidget(
  57. orientation='left', axis_color=tick_color, text_color=tick_color, font_size=a_fsize, axis_width=1
  58. )
  59. self.yaxis.width_max = 55
  60. self.grid_widget.add_widget(self.yaxis, row=1, col=0)
  61. self.xaxis = scene.AxisWidget(
  62. orientation='bottom', axis_color=tick_color, text_color=tick_color, font_size=a_fsize, axis_width=1,
  63. anchors=['center', 'bottom']
  64. )
  65. self.xaxis.height_max = 30
  66. self.grid_widget.add_widget(self.xaxis, row=2, col=1)
  67. right_padding = self.grid_widget.add_widget(row=0, col=2, row_span=2)
  68. # right_padding.width_max = 24
  69. right_padding.width_max = 0
  70. print("vp_7")
  71. view = self.grid_widget.add_view(row=1, col=1, border_color=tick_color, bgcolor=theme_color)
  72. view.camera = Camera(aspect=1, rect=(-25, -25, 150, 150))
  73. print("vp_8")
  74. # Following function was removed from 'prepare_draw()' of 'Grid' class by patch,
  75. # it is necessary to call manually
  76. self.grid_widget._update_child_widget_dim()
  77. self.xaxis.link_view(view)
  78. self.yaxis.link_view(view)
  79. # grid1 = scene.GridLines(parent=view.scene, color='dimgray')
  80. # grid1.set_gl_state(depth_test=False)
  81. settings = QSettings("Open Source", "FlatCAM")
  82. if settings.contains("theme"):
  83. theme = settings.value('theme', type=str)
  84. else:
  85. theme = 'white'
  86. self.view = view
  87. if theme == 'white':
  88. self.grid = scene.GridLines(parent=self.view.scene, color='dimgray')
  89. else:
  90. self.grid = scene.GridLines(parent=self.view.scene, color='#dededeff')
  91. print("vp_9")
  92. self.grid.set_gl_state(depth_test=False)
  93. print("vp_10")
  94. self.freeze()
  95. # self.measure_fps()
  96. def translate_coords(self, pos):
  97. """
  98. Translate pixels to FlatCAM units.
  99. """
  100. tr = self.grid.get_transform('canvas', 'visual')
  101. return tr.map(pos)
  102. def translate_coords_2(self, pos):
  103. """
  104. Translate FlatCAM units to pixels.
  105. """
  106. tr = self.grid.get_transform('visual', 'document')
  107. return tr.map(pos)
  108. class Camera(scene.PanZoomCamera):
  109. def __init__(self, **kwargs):
  110. super(Camera, self).__init__(**kwargs)
  111. self.minimum_scene_size = 0.01
  112. self.maximum_scene_size = 10000
  113. self.last_event = None
  114. self.last_time = 0
  115. # Default mouse button for panning is RMB
  116. self.pan_button_setting = "2"
  117. def zoom(self, factor, center=None):
  118. center = center if (center is not None) else self.center
  119. super(Camera, self).zoom(factor, center)
  120. def viewbox_mouse_event(self, event):
  121. """
  122. The SubScene received a mouse event; update transform
  123. accordingly.
  124. Parameters
  125. ----------
  126. event : instance of Event
  127. The event.
  128. """
  129. if event.handled or not self.interactive:
  130. return
  131. # key modifiers
  132. modifiers = event.mouse_event.modifiers
  133. # Limit mouse move events
  134. last_event = event.last_event
  135. t = time.time()
  136. if t - self.last_time > 0.015:
  137. self.last_time = t
  138. if self.last_event:
  139. last_event = self.last_event
  140. self.last_event = None
  141. else:
  142. if not self.last_event:
  143. self.last_event = last_event
  144. event.handled = True
  145. return
  146. # ################### Scrolling ##########################
  147. BaseCamera.viewbox_mouse_event(self, event)
  148. if event.type == 'mouse_wheel':
  149. if not modifiers:
  150. center = self._scene_transform.imap(event.pos)
  151. scale = (1 + self.zoom_factor) ** (-event.delta[1] * 30)
  152. self.limited_zoom(scale, center)
  153. event.handled = True
  154. elif event.type == 'mouse_move':
  155. if event.press_event is None:
  156. return
  157. # ################ Panning ############################
  158. # self.pan_button_setting is actually self.FlatCAM.APP.defaults['global_pan_button']
  159. if event.button == int(self.pan_button_setting) and not modifiers:
  160. # Translate
  161. p1 = np.array(last_event.pos)[:2]
  162. p2 = np.array(event.pos)[:2]
  163. p1s = self._transform.imap(p1)
  164. p2s = self._transform.imap(p2)
  165. self.pan(p1s-p2s)
  166. event.handled = True
  167. elif event.button in [2, 3] and 'Shift' in modifiers:
  168. # Zoom
  169. p1c = np.array(last_event.pos)[:2]
  170. p2c = np.array(event.pos)[:2]
  171. scale = ((1 + self.zoom_factor) **
  172. ((p1c-p2c) * np.array([1, -1])))
  173. center = self._transform.imap(event.press_event.pos[:2])
  174. self.limited_zoom(scale, center)
  175. event.handled = True
  176. else:
  177. event.handled = False
  178. elif event.type == 'mouse_press':
  179. # accept the event if it is button 1 or 2.
  180. # This is required in order to receive future events
  181. event.handled = event.button in [1, 2, 3]
  182. else:
  183. event.handled = False
  184. def limited_zoom(self, scale, center):
  185. try:
  186. zoom_in = scale[1] < 1
  187. except IndexError:
  188. zoom_in = scale < 1
  189. if (not zoom_in and self.rect.width < self.maximum_scene_size) \
  190. or (zoom_in and self.rect.width > self.minimum_scene_size):
  191. self.zoom(scale, center)