vispy 0.15.0__cp313-cp313-macosx_10_13_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of vispy might be problematic. Click here for more details.

Files changed (521) hide show
  1. vispy/__init__.py +33 -0
  2. vispy/app/__init__.py +15 -0
  3. vispy/app/_default_app.py +76 -0
  4. vispy/app/_detect_eventloop.py +148 -0
  5. vispy/app/application.py +263 -0
  6. vispy/app/backends/__init__.py +52 -0
  7. vispy/app/backends/_egl.py +264 -0
  8. vispy/app/backends/_glfw.py +513 -0
  9. vispy/app/backends/_jupyter_rfb.py +278 -0
  10. vispy/app/backends/_offscreen_util.py +121 -0
  11. vispy/app/backends/_osmesa.py +235 -0
  12. vispy/app/backends/_pyglet.py +451 -0
  13. vispy/app/backends/_pyqt4.py +36 -0
  14. vispy/app/backends/_pyqt5.py +36 -0
  15. vispy/app/backends/_pyqt6.py +40 -0
  16. vispy/app/backends/_pyside.py +37 -0
  17. vispy/app/backends/_pyside2.py +52 -0
  18. vispy/app/backends/_pyside6.py +53 -0
  19. vispy/app/backends/_qt.py +1003 -0
  20. vispy/app/backends/_sdl2.py +444 -0
  21. vispy/app/backends/_template.py +244 -0
  22. vispy/app/backends/_test.py +8 -0
  23. vispy/app/backends/_tk.py +800 -0
  24. vispy/app/backends/_wx.py +476 -0
  25. vispy/app/backends/tests/__init__.py +0 -0
  26. vispy/app/backends/tests/test_offscreen_util.py +52 -0
  27. vispy/app/backends/tests/test_rfb.py +77 -0
  28. vispy/app/base.py +294 -0
  29. vispy/app/canvas.py +828 -0
  30. vispy/app/qt.py +92 -0
  31. vispy/app/tests/__init__.py +0 -0
  32. vispy/app/tests/qt-designer.ui +58 -0
  33. vispy/app/tests/test_app.py +442 -0
  34. vispy/app/tests/test_backends.py +164 -0
  35. vispy/app/tests/test_canvas.py +122 -0
  36. vispy/app/tests/test_context.py +92 -0
  37. vispy/app/tests/test_qt.py +47 -0
  38. vispy/app/tests/test_simultaneous.py +134 -0
  39. vispy/app/timer.py +174 -0
  40. vispy/color/__init__.py +17 -0
  41. vispy/color/_color_dict.py +193 -0
  42. vispy/color/color_array.py +447 -0
  43. vispy/color/color_space.py +181 -0
  44. vispy/color/colormap.py +1213 -0
  45. vispy/color/tests/__init__.py +0 -0
  46. vispy/color/tests/test_color.py +378 -0
  47. vispy/conftest.py +12 -0
  48. vispy/ext/__init__.py +0 -0
  49. vispy/ext/cocoapy.py +1522 -0
  50. vispy/ext/cubehelix.py +138 -0
  51. vispy/ext/egl.py +375 -0
  52. vispy/ext/fontconfig.py +118 -0
  53. vispy/ext/gdi32plus.py +206 -0
  54. vispy/ext/osmesa.py +105 -0
  55. vispy/geometry/__init__.py +23 -0
  56. vispy/geometry/_triangulation_debugger.py +171 -0
  57. vispy/geometry/calculations.py +162 -0
  58. vispy/geometry/curves.py +399 -0
  59. vispy/geometry/generation.py +643 -0
  60. vispy/geometry/isocurve.py +175 -0
  61. vispy/geometry/isosurface.py +465 -0
  62. vispy/geometry/meshdata.py +700 -0
  63. vispy/geometry/normals.py +78 -0
  64. vispy/geometry/parametric.py +56 -0
  65. vispy/geometry/polygon.py +137 -0
  66. vispy/geometry/rect.py +210 -0
  67. vispy/geometry/tests/__init__.py +0 -0
  68. vispy/geometry/tests/test_calculations.py +23 -0
  69. vispy/geometry/tests/test_generation.py +56 -0
  70. vispy/geometry/tests/test_meshdata.py +106 -0
  71. vispy/geometry/tests/test_triangulation.py +594 -0
  72. vispy/geometry/torusknot.py +142 -0
  73. vispy/geometry/triangulation.py +876 -0
  74. vispy/gloo/__init__.py +56 -0
  75. vispy/gloo/buffer.py +505 -0
  76. vispy/gloo/context.py +272 -0
  77. vispy/gloo/framebuffer.py +257 -0
  78. vispy/gloo/gl/__init__.py +234 -0
  79. vispy/gloo/gl/_constants.py +332 -0
  80. vispy/gloo/gl/_es2.py +986 -0
  81. vispy/gloo/gl/_gl2.py +1365 -0
  82. vispy/gloo/gl/_proxy.py +499 -0
  83. vispy/gloo/gl/_pyopengl2.py +362 -0
  84. vispy/gloo/gl/dummy.py +24 -0
  85. vispy/gloo/gl/es2.py +62 -0
  86. vispy/gloo/gl/gl2.py +98 -0
  87. vispy/gloo/gl/glplus.py +168 -0
  88. vispy/gloo/gl/pyopengl2.py +97 -0
  89. vispy/gloo/gl/tests/__init__.py +0 -0
  90. vispy/gloo/gl/tests/test_basics.py +282 -0
  91. vispy/gloo/gl/tests/test_functionality.py +568 -0
  92. vispy/gloo/gl/tests/test_names.py +246 -0
  93. vispy/gloo/gl/tests/test_use.py +71 -0
  94. vispy/gloo/glir.py +1824 -0
  95. vispy/gloo/globject.py +101 -0
  96. vispy/gloo/preprocessor.py +67 -0
  97. vispy/gloo/program.py +543 -0
  98. vispy/gloo/tests/__init__.py +0 -0
  99. vispy/gloo/tests/test_buffer.py +558 -0
  100. vispy/gloo/tests/test_context.py +119 -0
  101. vispy/gloo/tests/test_framebuffer.py +195 -0
  102. vispy/gloo/tests/test_glir.py +307 -0
  103. vispy/gloo/tests/test_globject.py +35 -0
  104. vispy/gloo/tests/test_program.py +302 -0
  105. vispy/gloo/tests/test_texture.py +732 -0
  106. vispy/gloo/tests/test_use_gloo.py +187 -0
  107. vispy/gloo/tests/test_util.py +60 -0
  108. vispy/gloo/tests/test_wrappers.py +261 -0
  109. vispy/gloo/texture.py +1046 -0
  110. vispy/gloo/util.py +129 -0
  111. vispy/gloo/wrappers.py +762 -0
  112. vispy/glsl/__init__.py +42 -0
  113. vispy/glsl/antialias/antialias.glsl +7 -0
  114. vispy/glsl/antialias/cap-butt.glsl +31 -0
  115. vispy/glsl/antialias/cap-round.glsl +29 -0
  116. vispy/glsl/antialias/cap-square.glsl +30 -0
  117. vispy/glsl/antialias/cap-triangle-in.glsl +30 -0
  118. vispy/glsl/antialias/cap-triangle-out.glsl +30 -0
  119. vispy/glsl/antialias/cap.glsl +67 -0
  120. vispy/glsl/antialias/caps.glsl +67 -0
  121. vispy/glsl/antialias/filled.glsl +50 -0
  122. vispy/glsl/antialias/outline.glsl +40 -0
  123. vispy/glsl/antialias/stroke.glsl +43 -0
  124. vispy/glsl/arrowheads/angle.glsl +99 -0
  125. vispy/glsl/arrowheads/arrowheads.frag +60 -0
  126. vispy/glsl/arrowheads/arrowheads.glsl +12 -0
  127. vispy/glsl/arrowheads/arrowheads.vert +83 -0
  128. vispy/glsl/arrowheads/curved.glsl +48 -0
  129. vispy/glsl/arrowheads/inhibitor.glsl +26 -0
  130. vispy/glsl/arrowheads/stealth.glsl +46 -0
  131. vispy/glsl/arrowheads/triangle.glsl +97 -0
  132. vispy/glsl/arrowheads/util.glsl +13 -0
  133. vispy/glsl/arrows/angle-30.glsl +12 -0
  134. vispy/glsl/arrows/angle-60.glsl +12 -0
  135. vispy/glsl/arrows/angle-90.glsl +12 -0
  136. vispy/glsl/arrows/arrow.frag +39 -0
  137. vispy/glsl/arrows/arrow.vert +49 -0
  138. vispy/glsl/arrows/arrows.glsl +17 -0
  139. vispy/glsl/arrows/common.glsl +187 -0
  140. vispy/glsl/arrows/curved.glsl +63 -0
  141. vispy/glsl/arrows/stealth.glsl +50 -0
  142. vispy/glsl/arrows/triangle-30.glsl +12 -0
  143. vispy/glsl/arrows/triangle-60.glsl +12 -0
  144. vispy/glsl/arrows/triangle-90.glsl +12 -0
  145. vispy/glsl/arrows/util.glsl +98 -0
  146. vispy/glsl/build_spatial_filters.py +660 -0
  147. vispy/glsl/collections/agg-fast-path.frag +20 -0
  148. vispy/glsl/collections/agg-fast-path.vert +78 -0
  149. vispy/glsl/collections/agg-glyph.frag +60 -0
  150. vispy/glsl/collections/agg-glyph.vert +33 -0
  151. vispy/glsl/collections/agg-marker.frag +35 -0
  152. vispy/glsl/collections/agg-marker.vert +48 -0
  153. vispy/glsl/collections/agg-path.frag +55 -0
  154. vispy/glsl/collections/agg-path.vert +166 -0
  155. vispy/glsl/collections/agg-point.frag +21 -0
  156. vispy/glsl/collections/agg-point.vert +35 -0
  157. vispy/glsl/collections/agg-segment.frag +32 -0
  158. vispy/glsl/collections/agg-segment.vert +75 -0
  159. vispy/glsl/collections/marker.frag +38 -0
  160. vispy/glsl/collections/marker.vert +48 -0
  161. vispy/glsl/collections/raw-path.frag +15 -0
  162. vispy/glsl/collections/raw-path.vert +24 -0
  163. vispy/glsl/collections/raw-point.frag +14 -0
  164. vispy/glsl/collections/raw-point.vert +31 -0
  165. vispy/glsl/collections/raw-segment.frag +18 -0
  166. vispy/glsl/collections/raw-segment.vert +26 -0
  167. vispy/glsl/collections/raw-triangle.frag +13 -0
  168. vispy/glsl/collections/raw-triangle.vert +26 -0
  169. vispy/glsl/collections/sdf-glyph-ticks.vert +69 -0
  170. vispy/glsl/collections/sdf-glyph.frag +80 -0
  171. vispy/glsl/collections/sdf-glyph.vert +59 -0
  172. vispy/glsl/collections/tick-labels.vert +71 -0
  173. vispy/glsl/colormaps/autumn.glsl +20 -0
  174. vispy/glsl/colormaps/blues.glsl +20 -0
  175. vispy/glsl/colormaps/color-space.glsl +17 -0
  176. vispy/glsl/colormaps/colormaps.glsl +24 -0
  177. vispy/glsl/colormaps/cool.glsl +20 -0
  178. vispy/glsl/colormaps/fire.glsl +21 -0
  179. vispy/glsl/colormaps/gray.glsl +20 -0
  180. vispy/glsl/colormaps/greens.glsl +20 -0
  181. vispy/glsl/colormaps/hot.glsl +22 -0
  182. vispy/glsl/colormaps/ice.glsl +20 -0
  183. vispy/glsl/colormaps/icefire.glsl +23 -0
  184. vispy/glsl/colormaps/parse.py +40 -0
  185. vispy/glsl/colormaps/reds.glsl +20 -0
  186. vispy/glsl/colormaps/spring.glsl +20 -0
  187. vispy/glsl/colormaps/summer.glsl +20 -0
  188. vispy/glsl/colormaps/user.glsl +22 -0
  189. vispy/glsl/colormaps/util.glsl +41 -0
  190. vispy/glsl/colormaps/wheel.glsl +21 -0
  191. vispy/glsl/colormaps/winter.glsl +20 -0
  192. vispy/glsl/lines/agg.frag +320 -0
  193. vispy/glsl/lines/agg.vert +241 -0
  194. vispy/glsl/markers/arrow.glsl +12 -0
  195. vispy/glsl/markers/asterisk.glsl +16 -0
  196. vispy/glsl/markers/chevron.glsl +14 -0
  197. vispy/glsl/markers/clover.glsl +20 -0
  198. vispy/glsl/markers/club.glsl +31 -0
  199. vispy/glsl/markers/cross.glsl +17 -0
  200. vispy/glsl/markers/diamond.glsl +12 -0
  201. vispy/glsl/markers/disc.glsl +9 -0
  202. vispy/glsl/markers/ellipse.glsl +67 -0
  203. vispy/glsl/markers/hbar.glsl +9 -0
  204. vispy/glsl/markers/heart.glsl +15 -0
  205. vispy/glsl/markers/infinity.glsl +15 -0
  206. vispy/glsl/markers/marker-sdf.frag +74 -0
  207. vispy/glsl/markers/marker-sdf.vert +41 -0
  208. vispy/glsl/markers/marker.frag +36 -0
  209. vispy/glsl/markers/marker.vert +46 -0
  210. vispy/glsl/markers/markers.glsl +24 -0
  211. vispy/glsl/markers/pin.glsl +18 -0
  212. vispy/glsl/markers/ring.glsl +11 -0
  213. vispy/glsl/markers/spade.glsl +28 -0
  214. vispy/glsl/markers/square.glsl +10 -0
  215. vispy/glsl/markers/tag.glsl +11 -0
  216. vispy/glsl/markers/triangle.glsl +14 -0
  217. vispy/glsl/markers/vbar.glsl +9 -0
  218. vispy/glsl/math/circle-through-2-points.glsl +30 -0
  219. vispy/glsl/math/constants.glsl +48 -0
  220. vispy/glsl/math/double.glsl +114 -0
  221. vispy/glsl/math/functions.glsl +20 -0
  222. vispy/glsl/math/point-to-line-distance.glsl +31 -0
  223. vispy/glsl/math/point-to-line-projection.glsl +29 -0
  224. vispy/glsl/math/signed-line-distance.glsl +27 -0
  225. vispy/glsl/math/signed-segment-distance.glsl +30 -0
  226. vispy/glsl/misc/regular-grid.frag +244 -0
  227. vispy/glsl/misc/spatial-filters.frag +1407 -0
  228. vispy/glsl/misc/viewport-NDC.glsl +20 -0
  229. vispy/glsl/transforms/azimuthal-equal-area.glsl +32 -0
  230. vispy/glsl/transforms/azimuthal-equidistant.glsl +38 -0
  231. vispy/glsl/transforms/hammer.glsl +44 -0
  232. vispy/glsl/transforms/identity.glsl +6 -0
  233. vispy/glsl/transforms/identity_forward.glsl +23 -0
  234. vispy/glsl/transforms/identity_inverse.glsl +23 -0
  235. vispy/glsl/transforms/linear-scale.glsl +127 -0
  236. vispy/glsl/transforms/log-scale.glsl +126 -0
  237. vispy/glsl/transforms/mercator-transverse-forward.glsl +40 -0
  238. vispy/glsl/transforms/mercator-transverse-inverse.glsl +40 -0
  239. vispy/glsl/transforms/panzoom.glsl +10 -0
  240. vispy/glsl/transforms/polar.glsl +41 -0
  241. vispy/glsl/transforms/position.glsl +44 -0
  242. vispy/glsl/transforms/power-scale.glsl +139 -0
  243. vispy/glsl/transforms/projection.glsl +7 -0
  244. vispy/glsl/transforms/pvm.glsl +13 -0
  245. vispy/glsl/transforms/rotate.glsl +45 -0
  246. vispy/glsl/transforms/trackball.glsl +15 -0
  247. vispy/glsl/transforms/translate.glsl +35 -0
  248. vispy/glsl/transforms/transverse_mercator.glsl +38 -0
  249. vispy/glsl/transforms/viewport-clipping.glsl +14 -0
  250. vispy/glsl/transforms/viewport-transform.glsl +16 -0
  251. vispy/glsl/transforms/viewport.glsl +50 -0
  252. vispy/glsl/transforms/x.glsl +24 -0
  253. vispy/glsl/transforms/y.glsl +19 -0
  254. vispy/glsl/transforms/z.glsl +14 -0
  255. vispy/io/__init__.py +20 -0
  256. vispy/io/_data/spatial-filters.npy +0 -0
  257. vispy/io/datasets.py +94 -0
  258. vispy/io/image.py +231 -0
  259. vispy/io/mesh.py +122 -0
  260. vispy/io/stl.py +167 -0
  261. vispy/io/tests/__init__.py +0 -0
  262. vispy/io/tests/test_image.py +47 -0
  263. vispy/io/tests/test_io.py +121 -0
  264. vispy/io/wavefront.py +350 -0
  265. vispy/plot/__init__.py +36 -0
  266. vispy/plot/fig.py +58 -0
  267. vispy/plot/plotwidget.py +522 -0
  268. vispy/plot/tests/__init__.py +0 -0
  269. vispy/plot/tests/test_plot.py +46 -0
  270. vispy/scene/__init__.py +43 -0
  271. vispy/scene/cameras/__init__.py +27 -0
  272. vispy/scene/cameras/_base.py +38 -0
  273. vispy/scene/cameras/arcball.py +105 -0
  274. vispy/scene/cameras/base_camera.py +551 -0
  275. vispy/scene/cameras/fly.py +474 -0
  276. vispy/scene/cameras/magnify.py +163 -0
  277. vispy/scene/cameras/panzoom.py +311 -0
  278. vispy/scene/cameras/perspective.py +338 -0
  279. vispy/scene/cameras/tests/__init__.py +0 -0
  280. vispy/scene/cameras/tests/test_cameras.py +27 -0
  281. vispy/scene/cameras/tests/test_link.py +53 -0
  282. vispy/scene/cameras/tests/test_perspective.py +122 -0
  283. vispy/scene/cameras/turntable.py +183 -0
  284. vispy/scene/canvas.py +639 -0
  285. vispy/scene/events.py +85 -0
  286. vispy/scene/node.py +644 -0
  287. vispy/scene/subscene.py +20 -0
  288. vispy/scene/tests/__init__.py +0 -0
  289. vispy/scene/tests/test_canvas.py +119 -0
  290. vispy/scene/tests/test_node.py +142 -0
  291. vispy/scene/tests/test_visuals.py +141 -0
  292. vispy/scene/visuals.py +276 -0
  293. vispy/scene/widgets/__init__.py +18 -0
  294. vispy/scene/widgets/anchor.py +25 -0
  295. vispy/scene/widgets/axis.py +88 -0
  296. vispy/scene/widgets/colorbar.py +176 -0
  297. vispy/scene/widgets/console.py +351 -0
  298. vispy/scene/widgets/grid.py +509 -0
  299. vispy/scene/widgets/label.py +50 -0
  300. vispy/scene/widgets/tests/__init__.py +0 -0
  301. vispy/scene/widgets/tests/test_colorbar.py +47 -0
  302. vispy/scene/widgets/viewbox.py +199 -0
  303. vispy/scene/widgets/widget.py +478 -0
  304. vispy/testing/__init__.py +51 -0
  305. vispy/testing/_runners.py +448 -0
  306. vispy/testing/_testing.py +416 -0
  307. vispy/testing/image_tester.py +494 -0
  308. vispy/testing/rendered_array_tester.py +85 -0
  309. vispy/testing/tests/__init__.py +0 -0
  310. vispy/testing/tests/test_testing.py +20 -0
  311. vispy/util/__init__.py +32 -0
  312. vispy/util/bunch.py +15 -0
  313. vispy/util/check_environment.py +57 -0
  314. vispy/util/config.py +490 -0
  315. vispy/util/dpi/__init__.py +19 -0
  316. vispy/util/dpi/_linux.py +69 -0
  317. vispy/util/dpi/_quartz.py +26 -0
  318. vispy/util/dpi/_win32.py +34 -0
  319. vispy/util/dpi/tests/__init__.py +0 -0
  320. vispy/util/dpi/tests/test_dpi.py +16 -0
  321. vispy/util/eq.py +41 -0
  322. vispy/util/event.py +774 -0
  323. vispy/util/fetching.py +276 -0
  324. vispy/util/filter.py +44 -0
  325. vispy/util/fonts/__init__.py +14 -0
  326. vispy/util/fonts/_freetype.py +73 -0
  327. vispy/util/fonts/_quartz.py +192 -0
  328. vispy/util/fonts/_triage.py +36 -0
  329. vispy/util/fonts/_vispy_fonts.py +20 -0
  330. vispy/util/fonts/_win32.py +105 -0
  331. vispy/util/fonts/data/OpenSans-Bold.ttf +0 -0
  332. vispy/util/fonts/data/OpenSans-BoldItalic.ttf +0 -0
  333. vispy/util/fonts/data/OpenSans-Italic.ttf +0 -0
  334. vispy/util/fonts/data/OpenSans-Regular.ttf +0 -0
  335. vispy/util/fonts/tests/__init__.py +0 -0
  336. vispy/util/fonts/tests/test_font.py +45 -0
  337. vispy/util/fourier.py +69 -0
  338. vispy/util/frozen.py +25 -0
  339. vispy/util/gallery_scraper.py +268 -0
  340. vispy/util/keys.py +91 -0
  341. vispy/util/logs.py +358 -0
  342. vispy/util/osmesa_gl.py +17 -0
  343. vispy/util/profiler.py +135 -0
  344. vispy/util/ptime.py +16 -0
  345. vispy/util/quaternion.py +229 -0
  346. vispy/util/svg/__init__.py +18 -0
  347. vispy/util/svg/base.py +20 -0
  348. vispy/util/svg/color.py +219 -0
  349. vispy/util/svg/element.py +51 -0
  350. vispy/util/svg/geometry.py +478 -0
  351. vispy/util/svg/group.py +66 -0
  352. vispy/util/svg/length.py +81 -0
  353. vispy/util/svg/number.py +25 -0
  354. vispy/util/svg/path.py +332 -0
  355. vispy/util/svg/shapes.py +57 -0
  356. vispy/util/svg/style.py +59 -0
  357. vispy/util/svg/svg.py +40 -0
  358. vispy/util/svg/transform.py +223 -0
  359. vispy/util/svg/transformable.py +28 -0
  360. vispy/util/svg/viewport.py +73 -0
  361. vispy/util/tests/__init__.py +0 -0
  362. vispy/util/tests/test_config.py +58 -0
  363. vispy/util/tests/test_docstring_parameters.py +123 -0
  364. vispy/util/tests/test_emitter_group.py +262 -0
  365. vispy/util/tests/test_event_emitter.py +743 -0
  366. vispy/util/tests/test_fourier.py +35 -0
  367. vispy/util/tests/test_gallery_scraper.py +112 -0
  368. vispy/util/tests/test_import.py +127 -0
  369. vispy/util/tests/test_key.py +22 -0
  370. vispy/util/tests/test_logging.py +45 -0
  371. vispy/util/tests/test_run.py +14 -0
  372. vispy/util/tests/test_transforms.py +42 -0
  373. vispy/util/tests/test_vispy.py +48 -0
  374. vispy/util/transforms.py +201 -0
  375. vispy/util/wrappers.py +155 -0
  376. vispy/version.py +21 -0
  377. vispy/visuals/__init__.py +50 -0
  378. vispy/visuals/_scalable_textures.py +487 -0
  379. vispy/visuals/axis.py +678 -0
  380. vispy/visuals/border.py +208 -0
  381. vispy/visuals/box.py +79 -0
  382. vispy/visuals/collections/__init__.py +30 -0
  383. vispy/visuals/collections/agg_fast_path_collection.py +219 -0
  384. vispy/visuals/collections/agg_path_collection.py +197 -0
  385. vispy/visuals/collections/agg_point_collection.py +52 -0
  386. vispy/visuals/collections/agg_segment_collection.py +142 -0
  387. vispy/visuals/collections/array_list.py +401 -0
  388. vispy/visuals/collections/base_collection.py +482 -0
  389. vispy/visuals/collections/collection.py +253 -0
  390. vispy/visuals/collections/path_collection.py +23 -0
  391. vispy/visuals/collections/point_collection.py +19 -0
  392. vispy/visuals/collections/polygon_collection.py +25 -0
  393. vispy/visuals/collections/raw_path_collection.py +119 -0
  394. vispy/visuals/collections/raw_point_collection.py +113 -0
  395. vispy/visuals/collections/raw_polygon_collection.py +77 -0
  396. vispy/visuals/collections/raw_segment_collection.py +112 -0
  397. vispy/visuals/collections/raw_triangle_collection.py +78 -0
  398. vispy/visuals/collections/segment_collection.py +19 -0
  399. vispy/visuals/collections/triangle_collection.py +16 -0
  400. vispy/visuals/collections/util.py +168 -0
  401. vispy/visuals/colorbar.py +699 -0
  402. vispy/visuals/cube.py +41 -0
  403. vispy/visuals/ellipse.py +162 -0
  404. vispy/visuals/filters/__init__.py +10 -0
  405. vispy/visuals/filters/base_filter.py +242 -0
  406. vispy/visuals/filters/clipper.py +60 -0
  407. vispy/visuals/filters/clipping_planes.py +122 -0
  408. vispy/visuals/filters/color.py +181 -0
  409. vispy/visuals/filters/markers.py +28 -0
  410. vispy/visuals/filters/mesh.py +801 -0
  411. vispy/visuals/filters/picking.py +60 -0
  412. vispy/visuals/filters/tests/__init__.py +3 -0
  413. vispy/visuals/filters/tests/test_primitive_picking_filters.py +70 -0
  414. vispy/visuals/filters/tests/test_wireframe_filter.py +16 -0
  415. vispy/visuals/glsl/__init__.py +1 -0
  416. vispy/visuals/glsl/antialiasing.py +133 -0
  417. vispy/visuals/glsl/color.py +63 -0
  418. vispy/visuals/graphs/__init__.py +1 -0
  419. vispy/visuals/graphs/graph.py +240 -0
  420. vispy/visuals/graphs/layouts/__init__.py +55 -0
  421. vispy/visuals/graphs/layouts/circular.py +49 -0
  422. vispy/visuals/graphs/layouts/force_directed.py +211 -0
  423. vispy/visuals/graphs/layouts/networkx_layout.py +87 -0
  424. vispy/visuals/graphs/layouts/random.py +52 -0
  425. vispy/visuals/graphs/tests/__init__.py +1 -0
  426. vispy/visuals/graphs/tests/test_layouts.py +139 -0
  427. vispy/visuals/graphs/tests/test_networkx_layout.py +47 -0
  428. vispy/visuals/graphs/util.py +120 -0
  429. vispy/visuals/gridlines.py +161 -0
  430. vispy/visuals/gridmesh.py +98 -0
  431. vispy/visuals/histogram.py +58 -0
  432. vispy/visuals/image.py +701 -0
  433. vispy/visuals/image_complex.py +130 -0
  434. vispy/visuals/infinite_line.py +199 -0
  435. vispy/visuals/instanced_mesh.py +152 -0
  436. vispy/visuals/isocurve.py +213 -0
  437. vispy/visuals/isoline.py +241 -0
  438. vispy/visuals/isosurface.py +113 -0
  439. vispy/visuals/line/__init__.py +6 -0
  440. vispy/visuals/line/arrow.py +289 -0
  441. vispy/visuals/line/dash_atlas.py +90 -0
  442. vispy/visuals/line/line.py +545 -0
  443. vispy/visuals/line_plot.py +135 -0
  444. vispy/visuals/linear_region.py +199 -0
  445. vispy/visuals/markers.py +819 -0
  446. vispy/visuals/mesh.py +373 -0
  447. vispy/visuals/mesh_normals.py +159 -0
  448. vispy/visuals/plane.py +54 -0
  449. vispy/visuals/polygon.py +145 -0
  450. vispy/visuals/rectangle.py +196 -0
  451. vispy/visuals/regular_polygon.py +56 -0
  452. vispy/visuals/scrolling_lines.py +197 -0
  453. vispy/visuals/shaders/__init__.py +17 -0
  454. vispy/visuals/shaders/compiler.py +206 -0
  455. vispy/visuals/shaders/expression.py +99 -0
  456. vispy/visuals/shaders/function.py +788 -0
  457. vispy/visuals/shaders/multiprogram.py +145 -0
  458. vispy/visuals/shaders/parsing.py +140 -0
  459. vispy/visuals/shaders/program.py +161 -0
  460. vispy/visuals/shaders/shader_object.py +162 -0
  461. vispy/visuals/shaders/tests/__init__.py +0 -0
  462. vispy/visuals/shaders/tests/test_function.py +486 -0
  463. vispy/visuals/shaders/tests/test_multiprogram.py +78 -0
  464. vispy/visuals/shaders/tests/test_parsing.py +57 -0
  465. vispy/visuals/shaders/variable.py +272 -0
  466. vispy/visuals/spectrogram.py +169 -0
  467. vispy/visuals/sphere.py +80 -0
  468. vispy/visuals/surface_plot.py +192 -0
  469. vispy/visuals/tests/__init__.py +0 -0
  470. vispy/visuals/tests/test_arrows.py +109 -0
  471. vispy/visuals/tests/test_axis.py +120 -0
  472. vispy/visuals/tests/test_collections.py +15 -0
  473. vispy/visuals/tests/test_colorbar.py +179 -0
  474. vispy/visuals/tests/test_colormap.py +97 -0
  475. vispy/visuals/tests/test_ellipse.py +122 -0
  476. vispy/visuals/tests/test_gridlines.py +30 -0
  477. vispy/visuals/tests/test_histogram.py +24 -0
  478. vispy/visuals/tests/test_image.py +392 -0
  479. vispy/visuals/tests/test_image_complex.py +36 -0
  480. vispy/visuals/tests/test_infinite_line.py +53 -0
  481. vispy/visuals/tests/test_instanced_mesh.py +50 -0
  482. vispy/visuals/tests/test_isosurface.py +22 -0
  483. vispy/visuals/tests/test_linear_region.py +152 -0
  484. vispy/visuals/tests/test_markers.py +54 -0
  485. vispy/visuals/tests/test_mesh.py +261 -0
  486. vispy/visuals/tests/test_mesh_normals.py +218 -0
  487. vispy/visuals/tests/test_polygon.py +112 -0
  488. vispy/visuals/tests/test_rectangle.py +163 -0
  489. vispy/visuals/tests/test_regular_polygon.py +111 -0
  490. vispy/visuals/tests/test_scalable_textures.py +196 -0
  491. vispy/visuals/tests/test_sdf.py +73 -0
  492. vispy/visuals/tests/test_spectrogram.py +42 -0
  493. vispy/visuals/tests/test_surface_plot.py +57 -0
  494. vispy/visuals/tests/test_text.py +95 -0
  495. vispy/visuals/tests/test_volume.py +542 -0
  496. vispy/visuals/tests/test_windbarb.py +33 -0
  497. vispy/visuals/text/__init__.py +7 -0
  498. vispy/visuals/text/_sdf_cpu.cpython-313-darwin.so +0 -0
  499. vispy/visuals/text/_sdf_cpu.pyx +112 -0
  500. vispy/visuals/text/_sdf_gpu.py +316 -0
  501. vispy/visuals/text/text.py +675 -0
  502. vispy/visuals/transforms/__init__.py +34 -0
  503. vispy/visuals/transforms/_util.py +191 -0
  504. vispy/visuals/transforms/base_transform.py +233 -0
  505. vispy/visuals/transforms/chain.py +300 -0
  506. vispy/visuals/transforms/interactive.py +98 -0
  507. vispy/visuals/transforms/linear.py +564 -0
  508. vispy/visuals/transforms/nonlinear.py +398 -0
  509. vispy/visuals/transforms/tests/__init__.py +0 -0
  510. vispy/visuals/transforms/tests/test_transforms.py +243 -0
  511. vispy/visuals/transforms/transform_system.py +339 -0
  512. vispy/visuals/tube.py +173 -0
  513. vispy/visuals/visual.py +923 -0
  514. vispy/visuals/volume.py +1366 -0
  515. vispy/visuals/windbarb.py +291 -0
  516. vispy/visuals/xyz_axis.py +34 -0
  517. vispy-0.15.0.dist-info/METADATA +243 -0
  518. vispy-0.15.0.dist-info/RECORD +521 -0
  519. vispy-0.15.0.dist-info/WHEEL +6 -0
  520. vispy-0.15.0.dist-info/licenses/LICENSE.txt +36 -0
  521. vispy-0.15.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,311 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (c) Vispy Development Team. All Rights Reserved.
3
+ # Distributed under the (new) BSD License. See LICENSE.txt for more info.
4
+
5
+ from __future__ import division
6
+
7
+ import numpy as np
8
+
9
+ from .base_camera import BaseCamera
10
+ from ...geometry import Rect
11
+ from ...visuals.transforms import STTransform, MatrixTransform
12
+
13
+
14
+ DEFAULT_RECT_TUPLE = (0, 0, 1, 1)
15
+
16
+
17
+ class PanZoomCamera(BaseCamera):
18
+ """Camera implementing 2D pan/zoom mouse interaction.
19
+
20
+ For this camera, the ``scale_factor`` indicates the zoom level, and
21
+ the ``center`` indicates the center position of the view.
22
+
23
+ By default, this camera inverts the y axis of the scene. This usually
24
+ results in the scene +y axis pointing upward because widgets (including
25
+ ViewBox) have their +y axis pointing downward.
26
+
27
+ Parameters
28
+ ----------
29
+ rect : Rect
30
+ A Rect object or 4-element tuple that specifies the rectangular
31
+ area to show.
32
+ aspect : float | None
33
+ The aspect ratio (i.e. scaling) between x and y dimension of
34
+ the scene. E.g. to show a square image as square, the aspect
35
+ should be 1. If None (default) the x and y dimensions are scaled
36
+ independently.
37
+ **kwargs : dict
38
+ Keyword arguments to pass to `BaseCamera`.
39
+
40
+ Notes
41
+ -----
42
+ Interaction:
43
+
44
+ * LMB: pan the view
45
+ * RMB or scroll: zooms the view
46
+
47
+ """
48
+
49
+ _state_props = BaseCamera._state_props + ('rect', )
50
+
51
+ def __init__(self, rect=DEFAULT_RECT_TUPLE, aspect=None, **kwargs):
52
+ super(PanZoomCamera, self).__init__(**kwargs)
53
+
54
+ self.transform = STTransform()
55
+ self.tf_mat = MatrixTransform()
56
+
57
+ # Set camera attributes
58
+ self.aspect = aspect
59
+ self._rect = None
60
+ self.rect = rect
61
+
62
+ @property
63
+ def aspect(self):
64
+ """The ratio between the x and y dimension. E.g. to show a
65
+ square image as square, the aspect should be 1. If None, the
66
+ dimensions are scaled automatically, dependening on the
67
+ available space. Otherwise the ratio between the dimensions
68
+ is fixed.
69
+ """
70
+ return self._aspect
71
+
72
+ @aspect.setter
73
+ def aspect(self, value):
74
+ if value is None:
75
+ self._aspect = None
76
+ else:
77
+ self._aspect = float(value)
78
+ self.view_changed()
79
+
80
+ def zoom(self, factor, center=None):
81
+ """Zoom in (or out) at the given center
82
+
83
+ Parameters
84
+ ----------
85
+ factor : float or tuple
86
+ Fraction by which the scene should be zoomed (e.g. a factor of 2
87
+ causes the scene to appear twice as large).
88
+ center : tuple of 2-4 elements
89
+ The center of the view. If not given or None, use the
90
+ current center.
91
+ """
92
+ # Init some variables
93
+ center = center if (center is not None) else self.center
94
+ assert len(center) in (2, 3, 4)
95
+ # Get scale factor, take scale ratio into account
96
+ if np.isscalar(factor):
97
+ scale = [factor, factor]
98
+ else:
99
+ if len(factor) != 2:
100
+ raise TypeError("factor must be scalar or length-2 sequence.")
101
+ scale = list(factor)
102
+ if self.aspect is not None:
103
+ scale[0] = scale[1]
104
+
105
+ # Make a new object (copy), so that allocation will
106
+ # trigger view_changed:
107
+ rect = Rect(self.rect)
108
+ # Get space from given center to edges
109
+ left_space = center[0] - rect.left
110
+ right_space = rect.right - center[0]
111
+ bottom_space = center[1] - rect.bottom
112
+ top_space = rect.top - center[1]
113
+ # Scale these spaces
114
+ rect.left = center[0] - left_space * scale[0]
115
+ rect.right = center[0] + right_space * scale[0]
116
+ rect.bottom = center[1] - bottom_space * scale[1]
117
+ rect.top = center[1] + top_space * scale[1]
118
+ self.rect = rect
119
+
120
+ def pan(self, *pan):
121
+ """Pan the view.
122
+
123
+ Parameters
124
+ ----------
125
+ *pan : length-2 sequence
126
+ The distance to pan the view, in the coordinate system of the
127
+ scene.
128
+ """
129
+ if len(pan) == 1:
130
+ pan = pan[0]
131
+ self.rect = self.rect + pan
132
+
133
+ @property
134
+ def rect(self):
135
+ """The rectangular border of the ViewBox visible area.
136
+
137
+ This is expressed in the coordinate system of the scene.
138
+ See :class:`~vispy.geometry.rect.Rect` for different ways this can
139
+ be specified.
140
+
141
+ Note that the rectangle can have negative width or height, in
142
+ which case the corresponding dimension is flipped (this flipping
143
+ is independent from the camera's ``flip`` property).
144
+ """
145
+ return self._rect
146
+
147
+ @rect.setter
148
+ def rect(self, args):
149
+ if isinstance(args, tuple):
150
+ rect = Rect(*args)
151
+ else:
152
+ rect = Rect(args)
153
+
154
+ if self._rect != rect:
155
+ self._rect = rect
156
+ self.view_changed()
157
+
158
+ @property
159
+ def center(self):
160
+ rect = self._rect
161
+ return (*rect.center, 0)
162
+
163
+ @center.setter
164
+ def center(self, center):
165
+ if not (isinstance(center, (tuple, list)) and len(center) in (2, 3)):
166
+ raise ValueError('center must be a 2 or 3 element tuple')
167
+ rect = Rect(self.rect) or Rect(*DEFAULT_RECT_TUPLE) # make a copy of self.rect
168
+ rect.center = center[:2]
169
+ self.rect = rect
170
+
171
+ def _set_range(self, init):
172
+ if init and self._rect is not None:
173
+ return
174
+ # Convert limits to rect
175
+ w = self._xlim[1] - self._xlim[0]
176
+ h = self._ylim[1] - self._ylim[0]
177
+ self.rect = self._xlim[0], self._ylim[0], w, h
178
+
179
+ def viewbox_resize_event(self, event):
180
+ """Modify the data aspect and scale factor, to adjust to
181
+ the new window size.
182
+
183
+ Parameters
184
+ ----------
185
+ event : instance of Event
186
+ The event.
187
+ """
188
+ self.view_changed()
189
+
190
+ def viewbox_mouse_event(self, event):
191
+ """
192
+ The SubScene received a mouse event; update transform
193
+ accordingly.
194
+
195
+ Parameters
196
+ ----------
197
+ event : instance of Event
198
+ The event.
199
+ """
200
+ if event.handled or not self.interactive:
201
+ return
202
+
203
+ # Scrolling
204
+ BaseCamera.viewbox_mouse_event(self, event)
205
+
206
+ if event.type == 'mouse_wheel':
207
+ center = self._scene_transform.imap(event.pos)
208
+ self.zoom((1 + self.zoom_factor)**(-event.delta[1] * 30), center)
209
+ event.handled = True
210
+ elif event.type == 'gesture_zoom':
211
+ center = self._scene_transform.imap(event.pos)
212
+ self.zoom(1 - event.scale, center)
213
+ event.handled = True
214
+ elif event.type == 'mouse_move':
215
+ if event.press_event is None:
216
+ return
217
+
218
+ modifiers = event.mouse_event.modifiers
219
+ p1 = event.mouse_event.press_event.pos
220
+ p2 = event.mouse_event.pos
221
+
222
+ if 1 in event.buttons and not modifiers:
223
+ # Translate
224
+ p1 = np.array(event.last_event.pos)[:2]
225
+ p2 = np.array(event.pos)[:2]
226
+ p1s = self._transform.imap(p1)
227
+ p2s = self._transform.imap(p2)
228
+ self.pan(p1s - p2s)
229
+ event.handled = True
230
+ elif 2 in event.buttons and not modifiers:
231
+ # Zoom
232
+ p1c = np.array(event.last_event.pos)[:2]
233
+ p2c = np.array(event.pos)[:2]
234
+ scale = ((1 + self.zoom_factor)**((p1c - p2c) *
235
+ np.array([1, -1])))
236
+ center = self._transform.imap(event.press_event.pos[:2])
237
+ self.zoom(scale, center)
238
+ event.handled = True
239
+ else:
240
+ event.handled = False
241
+ elif event.type == 'mouse_press':
242
+ # accept the event if it is button 1 or 2.
243
+ # This is required in order to receive future events
244
+ event.handled = event.button in [1, 2]
245
+ else:
246
+ event.handled = False
247
+
248
+ def _update_transform(self):
249
+ if self._resetting: # base camera linking operation
250
+ return
251
+
252
+ rect = self.rect
253
+ self._real_rect = Rect(rect)
254
+ vbr = self._viewbox.rect.flipped(x=self.flip[0], y=(not self.flip[1]))
255
+ d = self.depth_value
256
+
257
+ # apply scale ratio constraint
258
+ if self._aspect is not None:
259
+ # Aspect ratio of the requested range
260
+ requested_aspect = (rect.width /
261
+ rect.height if rect.height != 0 else 1)
262
+ # Aspect ratio of the viewbox
263
+ view_aspect = vbr.width / vbr.height if vbr.height != 0 else 1
264
+ # View aspect ratio needed to obey the scale constraint
265
+ constrained_aspect = abs(view_aspect / self._aspect)
266
+
267
+ if requested_aspect > constrained_aspect:
268
+ # view range needs to be taller than requested
269
+ dy = 0.5 * (rect.width / constrained_aspect - rect.height)
270
+ self._real_rect.top += dy
271
+ self._real_rect.bottom -= dy
272
+ else:
273
+ # view range needs to be wider than requested
274
+ dx = 0.5 * (rect.height * constrained_aspect - rect.width)
275
+ self._real_rect.left -= dx
276
+ self._real_rect.right += dx
277
+
278
+ # Apply mapping between viewbox and cam view
279
+ self.transform.set_mapping(self._real_rect, vbr, update=False)
280
+ # Scale z, so that the clipping planes are between -alot and +alot
281
+ self.transform.zoom((1, 1, 1 / d))
282
+
283
+ # We've now set self.transform, which represents our 2D
284
+ # transform When up is +z this is all. In other cases,
285
+ # self.transform is now set up correctly to allow pan/zoom, but
286
+ # for the scene we need a different (3D) mapping. When there
287
+ # is a minus in up, we simply look at the scene from the other
288
+ # side (as if z was flipped).
289
+ if self.up == '+z':
290
+ self.tf_mat.matrix = self.transform.as_matrix().matrix
291
+ else:
292
+ rr = self._real_rect
293
+ d = d if (self.up[0] == '+') else -d
294
+ pp1 = [(vbr.left, vbr.bottom, 0), (vbr.left, vbr.top, 0),
295
+ (vbr.right, vbr.bottom, 0), (vbr.left, vbr.bottom, 1)]
296
+ # Get Mapping
297
+ if self.up[1] == 'z':
298
+ pp2 = [(rr.left, rr.bottom, 0), (rr.left, rr.top, 0),
299
+ (rr.right, rr.bottom, 0), (rr.left, rr.bottom, d)]
300
+ elif self.up[1] == 'y':
301
+ pp2 = [(rr.left, 0, rr.bottom), (rr.left, 0, rr.top),
302
+ (rr.right, 0, rr.bottom), (rr.left, d, rr.bottom)]
303
+ elif self.up[1] == 'x':
304
+ pp2 = [(0, rr.left, rr.bottom), (0, rr.left, rr.top),
305
+ (0, rr.right, rr.bottom), (d, rr.left, rr.bottom)]
306
+
307
+ # Apply
308
+ self.tf_mat.set_mapping(np.array(pp2), np.array(pp1))
309
+
310
+ # Set on viewbox
311
+ self._set_scene_transform(self.tf_mat)
@@ -0,0 +1,338 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Copyright (c) Vispy Development Team. All Rights Reserved.
3
+ # Distributed under the (new) BSD License. See LICENSE.txt for more info.
4
+
5
+ from __future__ import division
6
+
7
+ import math
8
+ import numpy as np
9
+
10
+ from .base_camera import BaseCamera
11
+ from ...util import keys, transforms
12
+ from ...visuals.transforms import MatrixTransform
13
+
14
+
15
+ class PerspectiveCamera(BaseCamera):
16
+ """Base class for 3D cameras supporting orthographic and
17
+ perspective projections.
18
+
19
+ Parameters
20
+ ----------
21
+ fov : float
22
+ Field of view. Default 60.0.
23
+ scale_factor : scalar
24
+ A measure for the scale/range of the scene that the camera
25
+ should show. The exact meaning differs per camera type.
26
+ **kwargs : dict
27
+ Keyword arguments to pass to `BaseCamera`.
28
+ """
29
+
30
+ _state_props = ('scale_factor', 'center', 'fov')
31
+
32
+ def __init__(self, fov=60.0, scale_factor=None, center=None, **kwargs):
33
+ super(PerspectiveCamera, self).__init__(**kwargs)
34
+ # Camera transform
35
+ self.transform = MatrixTransform()
36
+
37
+ # Set camera attributes
38
+ self.fov = fov
39
+ self._scale_factor = None
40
+ self._center = None
41
+
42
+ # Only set if they are given. They're set during _set_range if None
43
+ if scale_factor is not None:
44
+ self.scale_factor = scale_factor
45
+ if center is not None:
46
+ self.center = center
47
+
48
+ def viewbox_mouse_event(self, event):
49
+ """The ViewBox received a mouse event; update transform
50
+ accordingly.
51
+ Default implementation adjusts scale factor when scolling.
52
+
53
+ Parameters
54
+ ----------
55
+ event : instance of Event
56
+ The event.
57
+ """
58
+ BaseCamera.viewbox_mouse_event(self, event)
59
+ if event.type == 'mouse_wheel':
60
+ s = 1.1 ** - event.delta[1]
61
+ self._scale_factor *= s
62
+ if self._distance is not None:
63
+ self._distance *= s
64
+ self.view_changed()
65
+ elif event.type == 'gesture_zoom':
66
+ s = 1 - event.scale
67
+ self._scale_factor *= s
68
+ if self._distance is not None:
69
+ self._distance *= s
70
+ self.view_changed()
71
+
72
+ @property
73
+ def scale_factor(self):
74
+ """The measure for the scale or range that the camera should cover
75
+
76
+ For the PanZoomCamera and TurnTableCamera this translates to
77
+ zooming: set to smaller values to zoom in.
78
+ """
79
+ return self._scale_factor
80
+
81
+ @scale_factor.setter
82
+ def scale_factor(self, value):
83
+ value = abs(float(value))
84
+ if value == self._scale_factor:
85
+ return
86
+ self._scale_factor = value
87
+ self.view_changed()
88
+
89
+ @property
90
+ def near_clip_distance(self):
91
+ """The distance of the near clipping plane from the camera's position."""
92
+ return self._near_clip_distance
93
+
94
+ def _set_range(self, init):
95
+ """Reset the camera view using the known limits."""
96
+ if init and (self._scale_factor is not None):
97
+ return # We don't have to set our scale factor
98
+
99
+ # Get window size (and store factor now to sync with resizing)
100
+ w, h = self._viewbox.size
101
+ w, h = float(w), float(h)
102
+
103
+ if (w == 0) or (h == 0):
104
+ return
105
+
106
+ # Get range and translation for x and y
107
+ x1, y1, z1 = self._xlim[0], self._ylim[0], self._zlim[0]
108
+ x2, y2, z2 = self._xlim[1], self._ylim[1], self._zlim[1]
109
+ rx, ry, rz = (x2 - x1), (y2 - y1), (z2 - z1)
110
+
111
+ # Correct ranges for window size. Note that the window width
112
+ # influences the x and y data range, while the height influences
113
+ # the z data range.
114
+ if w / h > 1:
115
+ rx /= w / h
116
+ ry /= w / h
117
+ else:
118
+ rz /= h / w
119
+
120
+ # Convert to screen coordinates. In screen x, only x and y have effect.
121
+ # In screen y, all three dimensions have effect. The idea of the lines
122
+ # below is to calculate the range on screen when that will fit the
123
+ # data under any rotation.
124
+ rxs = (rx**2 + ry**2)**0.5
125
+ rys = (rx**2 + ry**2 + rz**2)**0.5
126
+
127
+ self.scale_factor = max(rxs, rys) * 1.04 # 4% extra space
128
+
129
+ def viewbox_resize_event(self, event):
130
+ """The ViewBox resize handler to update the transform
131
+
132
+ Parameters
133
+ ----------
134
+ event : instance of Event
135
+ The event.
136
+ """
137
+ self.view_changed()
138
+
139
+ def _update_transform(self, event=None):
140
+ # Do we have a viewbox
141
+ if self._viewbox is None:
142
+ return
143
+ if self._resetting: # base camera linking operation
144
+ return
145
+
146
+ # Calculate viewing range for x and y
147
+ fx = fy = self._scale_factor
148
+
149
+ # Correct for window size
150
+ w, h = self._viewbox.size
151
+
152
+ if (w == 0) or (h == 0):
153
+ return
154
+
155
+ if w / h > 1:
156
+ fx *= w / h
157
+ else:
158
+ fy *= h / w
159
+
160
+ self._update_projection_transform(fx, fy)
161
+
162
+ # assemble complete transform mapping to viewbox bounds
163
+ unit = [[-1, 1], [1, -1]]
164
+ vrect = [[0, 0], self._viewbox.size]
165
+ self._viewbox_tr.set_mapping(unit, vrect)
166
+ transforms = [n.transform for n in
167
+ self._viewbox.scene.node_path_to_child(self)[1:]]
168
+ camera_tr = self._transform_cache.get(transforms).inverse
169
+ full_tr = self._transform_cache.get([self._viewbox_tr,
170
+ self._projection,
171
+ camera_tr])
172
+ self._transform_cache.roll()
173
+ self._set_scene_transform(full_tr)
174
+
175
+ def _update_projection_transform(self, fx, fy):
176
+ d = self.depth_value
177
+ fov = max(0.01, self._fov)
178
+ dist = fy / (2 * math.tan(math.radians(fov)/2))
179
+ val = math.sqrt(d)
180
+ self._projection.set_perspective(fov, fx/fy, dist/val, dist*val)
181
+
182
+
183
+ class Base3DRotationCamera(PerspectiveCamera):
184
+ """Base class for TurntableCamera and ArcballCamera"""
185
+
186
+ def __init__(self, fov=0.0, **kwargs):
187
+ super(Base3DRotationCamera, self).__init__(fov=fov, **kwargs)
188
+ self._actual_distance = 0.0
189
+ self._event_value = None
190
+
191
+ @property
192
+ def distance(self):
193
+ """The user-set distance. If None (default), the distance is
194
+ internally calculated from the scale factor and fov.
195
+ """
196
+ return self._distance
197
+
198
+ @distance.setter
199
+ def distance(self, distance):
200
+ if distance is None:
201
+ self._distance = None
202
+ else:
203
+ self._distance = float(distance)
204
+ self.view_changed()
205
+
206
+ def viewbox_mouse_event(self, event):
207
+ """
208
+ The viewbox received a mouse event; update transform
209
+ accordingly.
210
+
211
+ Parameters
212
+ ----------
213
+ event : instance of Event
214
+ The event.
215
+ """
216
+ if event.handled or not self.interactive:
217
+ return
218
+
219
+ PerspectiveCamera.viewbox_mouse_event(self, event)
220
+
221
+ if event.type == 'mouse_release':
222
+ self._event_value = None # Reset
223
+ elif event.type == 'mouse_press':
224
+ event.handled = True
225
+ elif event.type == 'mouse_move':
226
+ if event.press_event is None:
227
+ return
228
+ if 1 in event.buttons and 2 in event.buttons:
229
+ return
230
+
231
+ modifiers = event.mouse_event.modifiers
232
+ p1 = event.mouse_event.press_event.pos
233
+ p2 = event.mouse_event.pos
234
+ d = p2 - p1
235
+
236
+ if 1 in event.buttons and not modifiers:
237
+ # Rotate
238
+ self._update_rotation(event)
239
+
240
+ elif 2 in event.buttons and not modifiers:
241
+ # Zoom
242
+ if self._event_value is None:
243
+ self._event_value = (self._scale_factor, self._distance)
244
+ zoomy = (1 + self.zoom_factor) ** d[1]
245
+
246
+ self.scale_factor = self._event_value[0] * zoomy
247
+ # Modify distance if its given
248
+ if self._distance is not None:
249
+ self._distance = self._event_value[1] * zoomy
250
+ self.view_changed()
251
+
252
+ elif 1 in event.buttons and keys.SHIFT in modifiers:
253
+ # Translate
254
+ norm = np.mean(self._viewbox.size)
255
+ if self._event_value is None or len(self._event_value) == 2:
256
+ self._event_value = self.center
257
+ dist = (p1 - p2) / norm * self._scale_factor
258
+ dist[1] *= -1
259
+ # Black magic part 1: turn 2D into 3D translations
260
+ dx, dy, dz = self._dist_to_trans(dist)
261
+ # Black magic part 2: take up-vector and flipping into account
262
+ ff = self._flip_factors
263
+ up, forward, right = self._get_dim_vectors()
264
+ dx, dy, dz = right * dx + forward * dy + up * dz
265
+ dx, dy, dz = ff[0] * dx, ff[1] * dy, dz * ff[2]
266
+ c = self._event_value
267
+ self.center = c[0] + dx, c[1] + dy, c[2] + dz
268
+
269
+ elif 2 in event.buttons and keys.SHIFT in modifiers:
270
+ # Change fov
271
+ if self._event_value is None:
272
+ self._event_value = self._fov
273
+ fov = self._event_value - d[1] / 5.0
274
+ self.fov = min(180.0, max(0.0, fov))
275
+
276
+ def _update_camera_pos(self):
277
+ """Set the camera position and orientation"""
278
+ # transform will be updated several times; do not update camera
279
+ # transform until we are done.
280
+ ch_em = self.events.transform_change
281
+ with ch_em.blocker(self._update_transform):
282
+ up, forward, right = self._get_dim_vectors()
283
+
284
+ # Create mapping so correct dim is up
285
+ pp1 = np.array([(0, 0, 0), (0, 0, -1), (1, 0, 0), (0, 1, 0)])
286
+ pp2 = np.array([(0, 0, 0), forward, right, up])
287
+ pos = -self._actual_distance * forward
288
+ scale = [1.0/a for a in self._flip_factors]
289
+
290
+ self.transform.matrix = np.linalg.multi_dot((
291
+ transforms.affine_map(pp1, pp2).T,
292
+ transforms.translate(pos),
293
+ self._get_rotation_tr(),
294
+ transforms.scale(scale),
295
+ transforms.translate(self.center)
296
+ ))
297
+
298
+ def _get_dim_vectors(self):
299
+ # Specify up and forward vector
300
+ M = {'+z': [(0, 0, +1), (0, 1, 0)],
301
+ '-z': [(0, 0, -1), (0, 1, 0)],
302
+ '+y': [(0, +1, 0), (1, 0, 0)],
303
+ '-y': [(0, -1, 0), (1, 0, 0)],
304
+ '+x': [(+1, 0, 0), (0, 0, 1)],
305
+ '-x': [(-1, 0, 0), (0, 0, 1)],
306
+ }
307
+ up, forward = M[self.up]
308
+ right = np.cross(forward, up)
309
+ return np.array(up), np.array(forward), right
310
+
311
+ def _update_projection_transform(self, fx, fy):
312
+ d = self.depth_value
313
+ if self._fov == 0:
314
+ self._projection.set_ortho(-0.5*fx, 0.5*fx, -0.5*fy, 0.5*fy, -d, d)
315
+ self._actual_distance = self._distance or 0.0
316
+ else:
317
+ # Figure distance to center in order to have correct FoV and fy.
318
+ # Use that auto-distance, or the given distance (if not None).
319
+ fov = max(0.01, self._fov)
320
+ dist = fy / (2 * math.tan(math.radians(fov)/2))
321
+ self._actual_distance = dist = self._distance or dist
322
+ val = math.sqrt(d*10)
323
+ self._projection.set_perspective(fov, fx/fy, dist/val, dist*val)
324
+ # Update camera pos, which will use our calculated _distance to offset
325
+ # the camera
326
+ self._update_camera_pos()
327
+
328
+ def _update_rotation(self, event):
329
+ """Update rotation parmeters based on mouse movement"""
330
+ raise NotImplementedError
331
+
332
+ def _rotate_tr(self):
333
+ """Rotate the transformation matrix based on camera parameters"""
334
+ raise NotImplementedError
335
+
336
+ def _dist_to_trans(self, dist):
337
+ """Convert mouse x, y movement into x, y, z translations"""
338
+ raise NotImplementedError
File without changes
@@ -0,0 +1,27 @@
1
+ # -*- coding: utf-8 -*-
2
+ # -----------------------------------------------------------------------------
3
+ # Copyright (c) Vispy Development Team. All Rights Reserved.
4
+ # Distributed under the (new) BSD License. See LICENSE.txt for more info.
5
+ # -----------------------------------------------------------------------------
6
+ import numpy as np
7
+ import pytest
8
+ from vispy.scene.cameras import TurntableCamera
9
+ from vispy.testing import run_tests_if_main
10
+
11
+
12
+ @pytest.mark.parametrize(
13
+ "elevation, azimuth, roll, expected",
14
+ [
15
+ [0, 0, 0, np.eye(4)],
16
+ [90, 0, 0, [[1, 0, 0, 0], [0, 0, -1, 0], [0, 1, 0, 0], [0, 0, 0, 1]]],
17
+ [0, 90, 0, [[0, 1, 0, 0], [-1, 0, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]],
18
+ [0, 0, 90, [[0, 0, -1, 0], [0, 1, 0, 0], [1, 0, 0, 0], [0, 0, 0, 1]]],
19
+ ],
20
+ )
21
+ def test_turntable_camera_transform(elevation, azimuth, roll, expected):
22
+ camera = TurntableCamera(elevation=elevation, azimuth=azimuth, roll=roll)
23
+ matrix = camera._get_rotation_tr()
24
+ np.testing.assert_allclose(matrix, expected, atol=1e-5)
25
+
26
+
27
+ run_tests_if_main()