vispy 0.15.0__cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.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.
- vispy/__init__.py +33 -0
- vispy/app/__init__.py +15 -0
- vispy/app/_default_app.py +76 -0
- vispy/app/_detect_eventloop.py +148 -0
- vispy/app/application.py +263 -0
- vispy/app/backends/__init__.py +52 -0
- vispy/app/backends/_egl.py +264 -0
- vispy/app/backends/_glfw.py +513 -0
- vispy/app/backends/_jupyter_rfb.py +278 -0
- vispy/app/backends/_offscreen_util.py +121 -0
- vispy/app/backends/_osmesa.py +235 -0
- vispy/app/backends/_pyglet.py +451 -0
- vispy/app/backends/_pyqt4.py +36 -0
- vispy/app/backends/_pyqt5.py +36 -0
- vispy/app/backends/_pyqt6.py +40 -0
- vispy/app/backends/_pyside.py +37 -0
- vispy/app/backends/_pyside2.py +52 -0
- vispy/app/backends/_pyside6.py +53 -0
- vispy/app/backends/_qt.py +1003 -0
- vispy/app/backends/_sdl2.py +444 -0
- vispy/app/backends/_template.py +244 -0
- vispy/app/backends/_test.py +8 -0
- vispy/app/backends/_tk.py +800 -0
- vispy/app/backends/_wx.py +476 -0
- vispy/app/backends/tests/__init__.py +0 -0
- vispy/app/backends/tests/test_offscreen_util.py +52 -0
- vispy/app/backends/tests/test_rfb.py +77 -0
- vispy/app/base.py +294 -0
- vispy/app/canvas.py +828 -0
- vispy/app/qt.py +92 -0
- vispy/app/tests/__init__.py +0 -0
- vispy/app/tests/qt-designer.ui +58 -0
- vispy/app/tests/test_app.py +442 -0
- vispy/app/tests/test_backends.py +164 -0
- vispy/app/tests/test_canvas.py +122 -0
- vispy/app/tests/test_context.py +92 -0
- vispy/app/tests/test_qt.py +47 -0
- vispy/app/tests/test_simultaneous.py +134 -0
- vispy/app/timer.py +174 -0
- vispy/color/__init__.py +17 -0
- vispy/color/_color_dict.py +193 -0
- vispy/color/color_array.py +447 -0
- vispy/color/color_space.py +181 -0
- vispy/color/colormap.py +1213 -0
- vispy/color/tests/__init__.py +0 -0
- vispy/color/tests/test_color.py +378 -0
- vispy/conftest.py +12 -0
- vispy/ext/__init__.py +0 -0
- vispy/ext/cocoapy.py +1522 -0
- vispy/ext/cubehelix.py +138 -0
- vispy/ext/egl.py +375 -0
- vispy/ext/fontconfig.py +118 -0
- vispy/ext/gdi32plus.py +206 -0
- vispy/ext/osmesa.py +105 -0
- vispy/geometry/__init__.py +23 -0
- vispy/geometry/_triangulation_debugger.py +171 -0
- vispy/geometry/calculations.py +162 -0
- vispy/geometry/curves.py +399 -0
- vispy/geometry/generation.py +643 -0
- vispy/geometry/isocurve.py +175 -0
- vispy/geometry/isosurface.py +465 -0
- vispy/geometry/meshdata.py +700 -0
- vispy/geometry/normals.py +78 -0
- vispy/geometry/parametric.py +56 -0
- vispy/geometry/polygon.py +137 -0
- vispy/geometry/rect.py +210 -0
- vispy/geometry/tests/__init__.py +0 -0
- vispy/geometry/tests/test_calculations.py +23 -0
- vispy/geometry/tests/test_generation.py +56 -0
- vispy/geometry/tests/test_meshdata.py +106 -0
- vispy/geometry/tests/test_triangulation.py +594 -0
- vispy/geometry/torusknot.py +142 -0
- vispy/geometry/triangulation.py +876 -0
- vispy/gloo/__init__.py +56 -0
- vispy/gloo/buffer.py +505 -0
- vispy/gloo/context.py +272 -0
- vispy/gloo/framebuffer.py +257 -0
- vispy/gloo/gl/__init__.py +234 -0
- vispy/gloo/gl/_constants.py +332 -0
- vispy/gloo/gl/_es2.py +986 -0
- vispy/gloo/gl/_gl2.py +1365 -0
- vispy/gloo/gl/_proxy.py +499 -0
- vispy/gloo/gl/_pyopengl2.py +362 -0
- vispy/gloo/gl/dummy.py +24 -0
- vispy/gloo/gl/es2.py +62 -0
- vispy/gloo/gl/gl2.py +98 -0
- vispy/gloo/gl/glplus.py +168 -0
- vispy/gloo/gl/pyopengl2.py +97 -0
- vispy/gloo/gl/tests/__init__.py +0 -0
- vispy/gloo/gl/tests/test_basics.py +282 -0
- vispy/gloo/gl/tests/test_functionality.py +568 -0
- vispy/gloo/gl/tests/test_names.py +246 -0
- vispy/gloo/gl/tests/test_use.py +71 -0
- vispy/gloo/glir.py +1824 -0
- vispy/gloo/globject.py +101 -0
- vispy/gloo/preprocessor.py +67 -0
- vispy/gloo/program.py +543 -0
- vispy/gloo/tests/__init__.py +0 -0
- vispy/gloo/tests/test_buffer.py +558 -0
- vispy/gloo/tests/test_context.py +119 -0
- vispy/gloo/tests/test_framebuffer.py +195 -0
- vispy/gloo/tests/test_glir.py +307 -0
- vispy/gloo/tests/test_globject.py +35 -0
- vispy/gloo/tests/test_program.py +302 -0
- vispy/gloo/tests/test_texture.py +732 -0
- vispy/gloo/tests/test_use_gloo.py +187 -0
- vispy/gloo/tests/test_util.py +60 -0
- vispy/gloo/tests/test_wrappers.py +261 -0
- vispy/gloo/texture.py +1046 -0
- vispy/gloo/util.py +129 -0
- vispy/gloo/wrappers.py +762 -0
- vispy/glsl/__init__.py +42 -0
- vispy/glsl/antialias/antialias.glsl +7 -0
- vispy/glsl/antialias/cap-butt.glsl +31 -0
- vispy/glsl/antialias/cap-round.glsl +29 -0
- vispy/glsl/antialias/cap-square.glsl +30 -0
- vispy/glsl/antialias/cap-triangle-in.glsl +30 -0
- vispy/glsl/antialias/cap-triangle-out.glsl +30 -0
- vispy/glsl/antialias/cap.glsl +67 -0
- vispy/glsl/antialias/caps.glsl +67 -0
- vispy/glsl/antialias/filled.glsl +50 -0
- vispy/glsl/antialias/outline.glsl +40 -0
- vispy/glsl/antialias/stroke.glsl +43 -0
- vispy/glsl/arrowheads/angle.glsl +99 -0
- vispy/glsl/arrowheads/arrowheads.frag +60 -0
- vispy/glsl/arrowheads/arrowheads.glsl +12 -0
- vispy/glsl/arrowheads/arrowheads.vert +83 -0
- vispy/glsl/arrowheads/curved.glsl +48 -0
- vispy/glsl/arrowheads/inhibitor.glsl +26 -0
- vispy/glsl/arrowheads/stealth.glsl +46 -0
- vispy/glsl/arrowheads/triangle.glsl +97 -0
- vispy/glsl/arrowheads/util.glsl +13 -0
- vispy/glsl/arrows/angle-30.glsl +12 -0
- vispy/glsl/arrows/angle-60.glsl +12 -0
- vispy/glsl/arrows/angle-90.glsl +12 -0
- vispy/glsl/arrows/arrow.frag +39 -0
- vispy/glsl/arrows/arrow.vert +49 -0
- vispy/glsl/arrows/arrows.glsl +17 -0
- vispy/glsl/arrows/common.glsl +187 -0
- vispy/glsl/arrows/curved.glsl +63 -0
- vispy/glsl/arrows/stealth.glsl +50 -0
- vispy/glsl/arrows/triangle-30.glsl +12 -0
- vispy/glsl/arrows/triangle-60.glsl +12 -0
- vispy/glsl/arrows/triangle-90.glsl +12 -0
- vispy/glsl/arrows/util.glsl +98 -0
- vispy/glsl/build_spatial_filters.py +660 -0
- vispy/glsl/collections/agg-fast-path.frag +20 -0
- vispy/glsl/collections/agg-fast-path.vert +78 -0
- vispy/glsl/collections/agg-glyph.frag +60 -0
- vispy/glsl/collections/agg-glyph.vert +33 -0
- vispy/glsl/collections/agg-marker.frag +35 -0
- vispy/glsl/collections/agg-marker.vert +48 -0
- vispy/glsl/collections/agg-path.frag +55 -0
- vispy/glsl/collections/agg-path.vert +166 -0
- vispy/glsl/collections/agg-point.frag +21 -0
- vispy/glsl/collections/agg-point.vert +35 -0
- vispy/glsl/collections/agg-segment.frag +32 -0
- vispy/glsl/collections/agg-segment.vert +75 -0
- vispy/glsl/collections/marker.frag +38 -0
- vispy/glsl/collections/marker.vert +48 -0
- vispy/glsl/collections/raw-path.frag +15 -0
- vispy/glsl/collections/raw-path.vert +24 -0
- vispy/glsl/collections/raw-point.frag +14 -0
- vispy/glsl/collections/raw-point.vert +31 -0
- vispy/glsl/collections/raw-segment.frag +18 -0
- vispy/glsl/collections/raw-segment.vert +26 -0
- vispy/glsl/collections/raw-triangle.frag +13 -0
- vispy/glsl/collections/raw-triangle.vert +26 -0
- vispy/glsl/collections/sdf-glyph-ticks.vert +69 -0
- vispy/glsl/collections/sdf-glyph.frag +80 -0
- vispy/glsl/collections/sdf-glyph.vert +59 -0
- vispy/glsl/collections/tick-labels.vert +71 -0
- vispy/glsl/colormaps/autumn.glsl +20 -0
- vispy/glsl/colormaps/blues.glsl +20 -0
- vispy/glsl/colormaps/color-space.glsl +17 -0
- vispy/glsl/colormaps/colormaps.glsl +24 -0
- vispy/glsl/colormaps/cool.glsl +20 -0
- vispy/glsl/colormaps/fire.glsl +21 -0
- vispy/glsl/colormaps/gray.glsl +20 -0
- vispy/glsl/colormaps/greens.glsl +20 -0
- vispy/glsl/colormaps/hot.glsl +22 -0
- vispy/glsl/colormaps/ice.glsl +20 -0
- vispy/glsl/colormaps/icefire.glsl +23 -0
- vispy/glsl/colormaps/parse.py +40 -0
- vispy/glsl/colormaps/reds.glsl +20 -0
- vispy/glsl/colormaps/spring.glsl +20 -0
- vispy/glsl/colormaps/summer.glsl +20 -0
- vispy/glsl/colormaps/user.glsl +22 -0
- vispy/glsl/colormaps/util.glsl +41 -0
- vispy/glsl/colormaps/wheel.glsl +21 -0
- vispy/glsl/colormaps/winter.glsl +20 -0
- vispy/glsl/lines/agg.frag +320 -0
- vispy/glsl/lines/agg.vert +241 -0
- vispy/glsl/markers/arrow.glsl +12 -0
- vispy/glsl/markers/asterisk.glsl +16 -0
- vispy/glsl/markers/chevron.glsl +14 -0
- vispy/glsl/markers/clover.glsl +20 -0
- vispy/glsl/markers/club.glsl +31 -0
- vispy/glsl/markers/cross.glsl +17 -0
- vispy/glsl/markers/diamond.glsl +12 -0
- vispy/glsl/markers/disc.glsl +9 -0
- vispy/glsl/markers/ellipse.glsl +67 -0
- vispy/glsl/markers/hbar.glsl +9 -0
- vispy/glsl/markers/heart.glsl +15 -0
- vispy/glsl/markers/infinity.glsl +15 -0
- vispy/glsl/markers/marker-sdf.frag +74 -0
- vispy/glsl/markers/marker-sdf.vert +41 -0
- vispy/glsl/markers/marker.frag +36 -0
- vispy/glsl/markers/marker.vert +46 -0
- vispy/glsl/markers/markers.glsl +24 -0
- vispy/glsl/markers/pin.glsl +18 -0
- vispy/glsl/markers/ring.glsl +11 -0
- vispy/glsl/markers/spade.glsl +28 -0
- vispy/glsl/markers/square.glsl +10 -0
- vispy/glsl/markers/tag.glsl +11 -0
- vispy/glsl/markers/triangle.glsl +14 -0
- vispy/glsl/markers/vbar.glsl +9 -0
- vispy/glsl/math/circle-through-2-points.glsl +30 -0
- vispy/glsl/math/constants.glsl +48 -0
- vispy/glsl/math/double.glsl +114 -0
- vispy/glsl/math/functions.glsl +20 -0
- vispy/glsl/math/point-to-line-distance.glsl +31 -0
- vispy/glsl/math/point-to-line-projection.glsl +29 -0
- vispy/glsl/math/signed-line-distance.glsl +27 -0
- vispy/glsl/math/signed-segment-distance.glsl +30 -0
- vispy/glsl/misc/regular-grid.frag +244 -0
- vispy/glsl/misc/spatial-filters.frag +1407 -0
- vispy/glsl/misc/viewport-NDC.glsl +20 -0
- vispy/glsl/transforms/azimuthal-equal-area.glsl +32 -0
- vispy/glsl/transforms/azimuthal-equidistant.glsl +38 -0
- vispy/glsl/transforms/hammer.glsl +44 -0
- vispy/glsl/transforms/identity.glsl +6 -0
- vispy/glsl/transforms/identity_forward.glsl +23 -0
- vispy/glsl/transforms/identity_inverse.glsl +23 -0
- vispy/glsl/transforms/linear-scale.glsl +127 -0
- vispy/glsl/transforms/log-scale.glsl +126 -0
- vispy/glsl/transforms/mercator-transverse-forward.glsl +40 -0
- vispy/glsl/transforms/mercator-transverse-inverse.glsl +40 -0
- vispy/glsl/transforms/panzoom.glsl +10 -0
- vispy/glsl/transforms/polar.glsl +41 -0
- vispy/glsl/transforms/position.glsl +44 -0
- vispy/glsl/transforms/power-scale.glsl +139 -0
- vispy/glsl/transforms/projection.glsl +7 -0
- vispy/glsl/transforms/pvm.glsl +13 -0
- vispy/glsl/transforms/rotate.glsl +45 -0
- vispy/glsl/transforms/trackball.glsl +15 -0
- vispy/glsl/transforms/translate.glsl +35 -0
- vispy/glsl/transforms/transverse_mercator.glsl +38 -0
- vispy/glsl/transforms/viewport-clipping.glsl +14 -0
- vispy/glsl/transforms/viewport-transform.glsl +16 -0
- vispy/glsl/transforms/viewport.glsl +50 -0
- vispy/glsl/transforms/x.glsl +24 -0
- vispy/glsl/transforms/y.glsl +19 -0
- vispy/glsl/transforms/z.glsl +14 -0
- vispy/io/__init__.py +20 -0
- vispy/io/_data/spatial-filters.npy +0 -0
- vispy/io/datasets.py +94 -0
- vispy/io/image.py +231 -0
- vispy/io/mesh.py +122 -0
- vispy/io/stl.py +167 -0
- vispy/io/tests/__init__.py +0 -0
- vispy/io/tests/test_image.py +47 -0
- vispy/io/tests/test_io.py +121 -0
- vispy/io/wavefront.py +350 -0
- vispy/plot/__init__.py +36 -0
- vispy/plot/fig.py +58 -0
- vispy/plot/plotwidget.py +522 -0
- vispy/plot/tests/__init__.py +0 -0
- vispy/plot/tests/test_plot.py +46 -0
- vispy/scene/__init__.py +43 -0
- vispy/scene/cameras/__init__.py +27 -0
- vispy/scene/cameras/_base.py +38 -0
- vispy/scene/cameras/arcball.py +105 -0
- vispy/scene/cameras/base_camera.py +551 -0
- vispy/scene/cameras/fly.py +474 -0
- vispy/scene/cameras/magnify.py +163 -0
- vispy/scene/cameras/panzoom.py +311 -0
- vispy/scene/cameras/perspective.py +338 -0
- vispy/scene/cameras/tests/__init__.py +0 -0
- vispy/scene/cameras/tests/test_cameras.py +27 -0
- vispy/scene/cameras/tests/test_link.py +53 -0
- vispy/scene/cameras/tests/test_perspective.py +122 -0
- vispy/scene/cameras/turntable.py +183 -0
- vispy/scene/canvas.py +639 -0
- vispy/scene/events.py +85 -0
- vispy/scene/node.py +644 -0
- vispy/scene/subscene.py +20 -0
- vispy/scene/tests/__init__.py +0 -0
- vispy/scene/tests/test_canvas.py +119 -0
- vispy/scene/tests/test_node.py +142 -0
- vispy/scene/tests/test_visuals.py +141 -0
- vispy/scene/visuals.py +276 -0
- vispy/scene/widgets/__init__.py +18 -0
- vispy/scene/widgets/anchor.py +25 -0
- vispy/scene/widgets/axis.py +88 -0
- vispy/scene/widgets/colorbar.py +176 -0
- vispy/scene/widgets/console.py +351 -0
- vispy/scene/widgets/grid.py +509 -0
- vispy/scene/widgets/label.py +50 -0
- vispy/scene/widgets/tests/__init__.py +0 -0
- vispy/scene/widgets/tests/test_colorbar.py +47 -0
- vispy/scene/widgets/viewbox.py +199 -0
- vispy/scene/widgets/widget.py +478 -0
- vispy/testing/__init__.py +51 -0
- vispy/testing/_runners.py +448 -0
- vispy/testing/_testing.py +416 -0
- vispy/testing/image_tester.py +494 -0
- vispy/testing/rendered_array_tester.py +85 -0
- vispy/testing/tests/__init__.py +0 -0
- vispy/testing/tests/test_testing.py +20 -0
- vispy/util/__init__.py +32 -0
- vispy/util/bunch.py +15 -0
- vispy/util/check_environment.py +57 -0
- vispy/util/config.py +490 -0
- vispy/util/dpi/__init__.py +19 -0
- vispy/util/dpi/_linux.py +69 -0
- vispy/util/dpi/_quartz.py +26 -0
- vispy/util/dpi/_win32.py +34 -0
- vispy/util/dpi/tests/__init__.py +0 -0
- vispy/util/dpi/tests/test_dpi.py +16 -0
- vispy/util/eq.py +41 -0
- vispy/util/event.py +774 -0
- vispy/util/fetching.py +276 -0
- vispy/util/filter.py +44 -0
- vispy/util/fonts/__init__.py +14 -0
- vispy/util/fonts/_freetype.py +73 -0
- vispy/util/fonts/_quartz.py +192 -0
- vispy/util/fonts/_triage.py +36 -0
- vispy/util/fonts/_vispy_fonts.py +20 -0
- vispy/util/fonts/_win32.py +105 -0
- vispy/util/fonts/data/OpenSans-Bold.ttf +0 -0
- vispy/util/fonts/data/OpenSans-BoldItalic.ttf +0 -0
- vispy/util/fonts/data/OpenSans-Italic.ttf +0 -0
- vispy/util/fonts/data/OpenSans-Regular.ttf +0 -0
- vispy/util/fonts/tests/__init__.py +0 -0
- vispy/util/fonts/tests/test_font.py +45 -0
- vispy/util/fourier.py +69 -0
- vispy/util/frozen.py +25 -0
- vispy/util/gallery_scraper.py +268 -0
- vispy/util/keys.py +91 -0
- vispy/util/logs.py +358 -0
- vispy/util/osmesa_gl.py +17 -0
- vispy/util/profiler.py +135 -0
- vispy/util/ptime.py +16 -0
- vispy/util/quaternion.py +229 -0
- vispy/util/svg/__init__.py +18 -0
- vispy/util/svg/base.py +20 -0
- vispy/util/svg/color.py +219 -0
- vispy/util/svg/element.py +51 -0
- vispy/util/svg/geometry.py +478 -0
- vispy/util/svg/group.py +66 -0
- vispy/util/svg/length.py +81 -0
- vispy/util/svg/number.py +25 -0
- vispy/util/svg/path.py +332 -0
- vispy/util/svg/shapes.py +57 -0
- vispy/util/svg/style.py +59 -0
- vispy/util/svg/svg.py +40 -0
- vispy/util/svg/transform.py +223 -0
- vispy/util/svg/transformable.py +28 -0
- vispy/util/svg/viewport.py +73 -0
- vispy/util/tests/__init__.py +0 -0
- vispy/util/tests/test_config.py +58 -0
- vispy/util/tests/test_docstring_parameters.py +123 -0
- vispy/util/tests/test_emitter_group.py +262 -0
- vispy/util/tests/test_event_emitter.py +743 -0
- vispy/util/tests/test_fourier.py +35 -0
- vispy/util/tests/test_gallery_scraper.py +112 -0
- vispy/util/tests/test_import.py +127 -0
- vispy/util/tests/test_key.py +22 -0
- vispy/util/tests/test_logging.py +45 -0
- vispy/util/tests/test_run.py +14 -0
- vispy/util/tests/test_transforms.py +42 -0
- vispy/util/tests/test_vispy.py +48 -0
- vispy/util/transforms.py +201 -0
- vispy/util/wrappers.py +155 -0
- vispy/version.py +21 -0
- vispy/visuals/__init__.py +50 -0
- vispy/visuals/_scalable_textures.py +487 -0
- vispy/visuals/axis.py +678 -0
- vispy/visuals/border.py +208 -0
- vispy/visuals/box.py +79 -0
- vispy/visuals/collections/__init__.py +30 -0
- vispy/visuals/collections/agg_fast_path_collection.py +219 -0
- vispy/visuals/collections/agg_path_collection.py +197 -0
- vispy/visuals/collections/agg_point_collection.py +52 -0
- vispy/visuals/collections/agg_segment_collection.py +142 -0
- vispy/visuals/collections/array_list.py +401 -0
- vispy/visuals/collections/base_collection.py +482 -0
- vispy/visuals/collections/collection.py +253 -0
- vispy/visuals/collections/path_collection.py +23 -0
- vispy/visuals/collections/point_collection.py +19 -0
- vispy/visuals/collections/polygon_collection.py +25 -0
- vispy/visuals/collections/raw_path_collection.py +119 -0
- vispy/visuals/collections/raw_point_collection.py +113 -0
- vispy/visuals/collections/raw_polygon_collection.py +77 -0
- vispy/visuals/collections/raw_segment_collection.py +112 -0
- vispy/visuals/collections/raw_triangle_collection.py +78 -0
- vispy/visuals/collections/segment_collection.py +19 -0
- vispy/visuals/collections/triangle_collection.py +16 -0
- vispy/visuals/collections/util.py +168 -0
- vispy/visuals/colorbar.py +699 -0
- vispy/visuals/cube.py +41 -0
- vispy/visuals/ellipse.py +162 -0
- vispy/visuals/filters/__init__.py +10 -0
- vispy/visuals/filters/base_filter.py +242 -0
- vispy/visuals/filters/clipper.py +60 -0
- vispy/visuals/filters/clipping_planes.py +122 -0
- vispy/visuals/filters/color.py +181 -0
- vispy/visuals/filters/markers.py +28 -0
- vispy/visuals/filters/mesh.py +801 -0
- vispy/visuals/filters/picking.py +60 -0
- vispy/visuals/filters/tests/__init__.py +3 -0
- vispy/visuals/filters/tests/test_primitive_picking_filters.py +70 -0
- vispy/visuals/filters/tests/test_wireframe_filter.py +16 -0
- vispy/visuals/glsl/__init__.py +1 -0
- vispy/visuals/glsl/antialiasing.py +133 -0
- vispy/visuals/glsl/color.py +63 -0
- vispy/visuals/graphs/__init__.py +1 -0
- vispy/visuals/graphs/graph.py +240 -0
- vispy/visuals/graphs/layouts/__init__.py +55 -0
- vispy/visuals/graphs/layouts/circular.py +49 -0
- vispy/visuals/graphs/layouts/force_directed.py +211 -0
- vispy/visuals/graphs/layouts/networkx_layout.py +87 -0
- vispy/visuals/graphs/layouts/random.py +52 -0
- vispy/visuals/graphs/tests/__init__.py +1 -0
- vispy/visuals/graphs/tests/test_layouts.py +139 -0
- vispy/visuals/graphs/tests/test_networkx_layout.py +47 -0
- vispy/visuals/graphs/util.py +120 -0
- vispy/visuals/gridlines.py +161 -0
- vispy/visuals/gridmesh.py +98 -0
- vispy/visuals/histogram.py +58 -0
- vispy/visuals/image.py +701 -0
- vispy/visuals/image_complex.py +130 -0
- vispy/visuals/infinite_line.py +199 -0
- vispy/visuals/instanced_mesh.py +152 -0
- vispy/visuals/isocurve.py +213 -0
- vispy/visuals/isoline.py +241 -0
- vispy/visuals/isosurface.py +113 -0
- vispy/visuals/line/__init__.py +6 -0
- vispy/visuals/line/arrow.py +289 -0
- vispy/visuals/line/dash_atlas.py +90 -0
- vispy/visuals/line/line.py +545 -0
- vispy/visuals/line_plot.py +135 -0
- vispy/visuals/linear_region.py +199 -0
- vispy/visuals/markers.py +819 -0
- vispy/visuals/mesh.py +373 -0
- vispy/visuals/mesh_normals.py +159 -0
- vispy/visuals/plane.py +54 -0
- vispy/visuals/polygon.py +145 -0
- vispy/visuals/rectangle.py +196 -0
- vispy/visuals/regular_polygon.py +56 -0
- vispy/visuals/scrolling_lines.py +197 -0
- vispy/visuals/shaders/__init__.py +17 -0
- vispy/visuals/shaders/compiler.py +206 -0
- vispy/visuals/shaders/expression.py +99 -0
- vispy/visuals/shaders/function.py +788 -0
- vispy/visuals/shaders/multiprogram.py +145 -0
- vispy/visuals/shaders/parsing.py +140 -0
- vispy/visuals/shaders/program.py +161 -0
- vispy/visuals/shaders/shader_object.py +162 -0
- vispy/visuals/shaders/tests/__init__.py +0 -0
- vispy/visuals/shaders/tests/test_function.py +486 -0
- vispy/visuals/shaders/tests/test_multiprogram.py +78 -0
- vispy/visuals/shaders/tests/test_parsing.py +57 -0
- vispy/visuals/shaders/variable.py +272 -0
- vispy/visuals/spectrogram.py +169 -0
- vispy/visuals/sphere.py +80 -0
- vispy/visuals/surface_plot.py +192 -0
- vispy/visuals/tests/__init__.py +0 -0
- vispy/visuals/tests/test_arrows.py +109 -0
- vispy/visuals/tests/test_axis.py +120 -0
- vispy/visuals/tests/test_collections.py +15 -0
- vispy/visuals/tests/test_colorbar.py +179 -0
- vispy/visuals/tests/test_colormap.py +97 -0
- vispy/visuals/tests/test_ellipse.py +122 -0
- vispy/visuals/tests/test_gridlines.py +30 -0
- vispy/visuals/tests/test_histogram.py +24 -0
- vispy/visuals/tests/test_image.py +392 -0
- vispy/visuals/tests/test_image_complex.py +36 -0
- vispy/visuals/tests/test_infinite_line.py +53 -0
- vispy/visuals/tests/test_instanced_mesh.py +50 -0
- vispy/visuals/tests/test_isosurface.py +22 -0
- vispy/visuals/tests/test_linear_region.py +152 -0
- vispy/visuals/tests/test_markers.py +54 -0
- vispy/visuals/tests/test_mesh.py +261 -0
- vispy/visuals/tests/test_mesh_normals.py +218 -0
- vispy/visuals/tests/test_polygon.py +112 -0
- vispy/visuals/tests/test_rectangle.py +163 -0
- vispy/visuals/tests/test_regular_polygon.py +111 -0
- vispy/visuals/tests/test_scalable_textures.py +196 -0
- vispy/visuals/tests/test_sdf.py +73 -0
- vispy/visuals/tests/test_spectrogram.py +42 -0
- vispy/visuals/tests/test_surface_plot.py +57 -0
- vispy/visuals/tests/test_text.py +95 -0
- vispy/visuals/tests/test_volume.py +542 -0
- vispy/visuals/tests/test_windbarb.py +33 -0
- vispy/visuals/text/__init__.py +7 -0
- vispy/visuals/text/_sdf_cpu.cpython-313-aarch64-linux-gnu.so +0 -0
- vispy/visuals/text/_sdf_cpu.pyx +112 -0
- vispy/visuals/text/_sdf_gpu.py +316 -0
- vispy/visuals/text/text.py +675 -0
- vispy/visuals/transforms/__init__.py +34 -0
- vispy/visuals/transforms/_util.py +191 -0
- vispy/visuals/transforms/base_transform.py +233 -0
- vispy/visuals/transforms/chain.py +300 -0
- vispy/visuals/transforms/interactive.py +98 -0
- vispy/visuals/transforms/linear.py +564 -0
- vispy/visuals/transforms/nonlinear.py +398 -0
- vispy/visuals/transforms/tests/__init__.py +0 -0
- vispy/visuals/transforms/tests/test_transforms.py +243 -0
- vispy/visuals/transforms/transform_system.py +339 -0
- vispy/visuals/tube.py +173 -0
- vispy/visuals/visual.py +923 -0
- vispy/visuals/volume.py +1366 -0
- vispy/visuals/windbarb.py +291 -0
- vispy/visuals/xyz_axis.py +34 -0
- vispy-0.15.0.dist-info/METADATA +243 -0
- vispy-0.15.0.dist-info/RECORD +521 -0
- vispy-0.15.0.dist-info/WHEEL +6 -0
- vispy-0.15.0.dist-info/licenses/LICENSE.txt +36 -0
- vispy-0.15.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,105 @@
|
|
|
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 ...util import transforms
|
|
10
|
+
from ...util.quaternion import Quaternion
|
|
11
|
+
from ...visuals.transforms import MatrixTransform
|
|
12
|
+
from .perspective import Base3DRotationCamera
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ArcballCamera(Base3DRotationCamera):
|
|
16
|
+
"""3D camera class that orbits around a center point while
|
|
17
|
+
maintaining a view on a center point.
|
|
18
|
+
|
|
19
|
+
For this camera, the ``scale_factor`` indicates the zoom level, and
|
|
20
|
+
the ``center`` indicates the position to put at the center of the
|
|
21
|
+
view.
|
|
22
|
+
|
|
23
|
+
Parameters
|
|
24
|
+
----------
|
|
25
|
+
fov : float
|
|
26
|
+
Field of view. Zero (default) means orthographic projection.
|
|
27
|
+
distance : float | None
|
|
28
|
+
The distance of the camera from the rotation point (only makes sense
|
|
29
|
+
if fov > 0). If None (default) the distance is determined from the
|
|
30
|
+
scale_factor and fov.
|
|
31
|
+
translate_speed : float
|
|
32
|
+
Scale factor on translation speed when moving the camera center point.
|
|
33
|
+
**kwargs : dict
|
|
34
|
+
Keyword arguments to pass to `BaseCamera`.
|
|
35
|
+
|
|
36
|
+
Notes
|
|
37
|
+
-----
|
|
38
|
+
Interaction:
|
|
39
|
+
|
|
40
|
+
* LMB: orbits the view around its center point.
|
|
41
|
+
* RMB or scroll: change scale_factor (i.e. zoom level)
|
|
42
|
+
* SHIFT + LMB: translate the center point
|
|
43
|
+
* SHIFT + RMB: change FOV
|
|
44
|
+
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
_state_props = Base3DRotationCamera._state_props + ('_quaternion',)
|
|
48
|
+
|
|
49
|
+
def __init__(self, fov=45.0, distance=None, translate_speed=1.0, **kwargs):
|
|
50
|
+
super(ArcballCamera, self).__init__(fov=fov, **kwargs)
|
|
51
|
+
|
|
52
|
+
# Set camera attributes
|
|
53
|
+
self._quaternion = Quaternion()
|
|
54
|
+
self.distance = distance # None means auto-distance
|
|
55
|
+
self.translate_speed = translate_speed
|
|
56
|
+
|
|
57
|
+
def _update_rotation(self, event):
|
|
58
|
+
"""Update rotation parmeters based on mouse movement"""
|
|
59
|
+
p2 = event.pos[:2]
|
|
60
|
+
if self._event_value is None:
|
|
61
|
+
self._event_value = p2
|
|
62
|
+
wh = self._viewbox.size
|
|
63
|
+
self._quaternion = (Quaternion(*_arcball(p2, wh)) *
|
|
64
|
+
Quaternion(*_arcball(self._event_value, wh)) *
|
|
65
|
+
self._quaternion)
|
|
66
|
+
self._event_value = p2
|
|
67
|
+
self.view_changed()
|
|
68
|
+
|
|
69
|
+
def _get_rotation_tr(self):
|
|
70
|
+
"""Return a rotation matrix based on camera parameters"""
|
|
71
|
+
rot, x, y, z = self._quaternion.get_axis_angle()
|
|
72
|
+
return transforms.rotate(180 * rot / np.pi, (x, z, y))
|
|
73
|
+
|
|
74
|
+
def _dist_to_trans(self, dist):
|
|
75
|
+
"""Convert mouse x, y movement into x, y, z translations"""
|
|
76
|
+
rot, x, y, z = self._quaternion.get_axis_angle()
|
|
77
|
+
tr = MatrixTransform()
|
|
78
|
+
tr.rotate(180 * rot / np.pi, (x, y, z))
|
|
79
|
+
dx, dz, dy = np.dot(tr.matrix[:3, :3],
|
|
80
|
+
(dist[0], dist[1], 0.)) * self.translate_speed
|
|
81
|
+
return dx, dy, dz
|
|
82
|
+
|
|
83
|
+
def _get_dim_vectors(self):
|
|
84
|
+
# Override vectors, camera has no sense of "up"
|
|
85
|
+
return np.eye(3)[::-1]
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
def _arcball(xy, wh):
|
|
89
|
+
"""Convert x,y coordinates to w,x,y,z Quaternion parameters
|
|
90
|
+
|
|
91
|
+
Adapted from:
|
|
92
|
+
|
|
93
|
+
linalg library
|
|
94
|
+
|
|
95
|
+
Copyright (c) 2010-2015, Renaud Blanch <rndblnch at gmail dot com>
|
|
96
|
+
Licence at your convenience:
|
|
97
|
+
GPLv3 or higher <http://www.gnu.org/licenses/gpl.html>
|
|
98
|
+
BSD new <http://opensource.org/licenses/BSD-3-Clause>
|
|
99
|
+
"""
|
|
100
|
+
x, y = xy
|
|
101
|
+
w, h = wh
|
|
102
|
+
r = (w + h) / 2.
|
|
103
|
+
x, y = -(2. * x - w) / r, (2. * y - h) / r
|
|
104
|
+
h = np.sqrt(x*x + y*y)
|
|
105
|
+
return (0., x/h, y/h, 0.) if h > 1. else (0., x, y, np.sqrt(1. - h*h))
|
|
@@ -0,0 +1,551 @@
|
|
|
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
|
+
from contextlib import contextmanager
|
|
7
|
+
|
|
8
|
+
from ...util import keys
|
|
9
|
+
from ..node import Node
|
|
10
|
+
from ...visuals.transforms import (STTransform, MatrixTransform,
|
|
11
|
+
NullTransform, TransformCache)
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def nested_getattr(obj, names):
|
|
15
|
+
for name in names:
|
|
16
|
+
obj = getattr(obj, name)
|
|
17
|
+
return obj
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def nested_setattr(obj, names, val):
|
|
21
|
+
target = nested_getattr(obj, names[:-1])
|
|
22
|
+
setattr(target, names[-1], val)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class BaseCamera(Node):
|
|
26
|
+
"""Base camera class.
|
|
27
|
+
|
|
28
|
+
The Camera describes the perspective from which a ViewBox views its
|
|
29
|
+
subscene, and the way that user interaction affects that perspective.
|
|
30
|
+
|
|
31
|
+
Most functionality is implemented in subclasses. This base class has
|
|
32
|
+
no user interaction and causes the subscene to use the same coordinate
|
|
33
|
+
system as the ViewBox.
|
|
34
|
+
|
|
35
|
+
Parameters
|
|
36
|
+
----------
|
|
37
|
+
interactive : bool
|
|
38
|
+
Whether the camera processes mouse and keyboard events.
|
|
39
|
+
flip : tuple of bools
|
|
40
|
+
For each dimension, specify whether it is flipped.
|
|
41
|
+
up : {'+z', '-z', '+y', '-y', '+x', '-x'}
|
|
42
|
+
The direction that is considered up. Default '+z'. Not all
|
|
43
|
+
camera's may support this (yet).
|
|
44
|
+
parent : Node
|
|
45
|
+
The parent of the camera.
|
|
46
|
+
name : str
|
|
47
|
+
Name used to identify the camera in the scene.
|
|
48
|
+
"""
|
|
49
|
+
|
|
50
|
+
# These define the state of the camera
|
|
51
|
+
_state_props = ()
|
|
52
|
+
|
|
53
|
+
# The fractional zoom to apply for a single pixel of mouse motion
|
|
54
|
+
zoom_factor = 0.007
|
|
55
|
+
|
|
56
|
+
def __init__(self, interactive=True, flip=None, up='+z', parent=None,
|
|
57
|
+
name=None):
|
|
58
|
+
super(BaseCamera, self).__init__(parent, name)
|
|
59
|
+
|
|
60
|
+
# The viewbox for which this camera is active
|
|
61
|
+
self._viewbox = None
|
|
62
|
+
|
|
63
|
+
# Linked cameras
|
|
64
|
+
self._linked_cameras = {}
|
|
65
|
+
self._linked_cameras_no_update = None
|
|
66
|
+
|
|
67
|
+
# Variables related to transforms
|
|
68
|
+
self.transform = NullTransform()
|
|
69
|
+
self._pre_transform = None
|
|
70
|
+
self._viewbox_tr = STTransform() # correction for viewbox
|
|
71
|
+
self._projection = MatrixTransform()
|
|
72
|
+
self._transform_cache = TransformCache()
|
|
73
|
+
|
|
74
|
+
# For internal use, to store event related information
|
|
75
|
+
self._event_value = None
|
|
76
|
+
|
|
77
|
+
# Flags
|
|
78
|
+
self._resetting = False # Avoid lots of updates during set_range
|
|
79
|
+
self._key_events_bound = False # Have we connected to key events
|
|
80
|
+
self._set_range_args = None # hold set_range() args
|
|
81
|
+
|
|
82
|
+
# Limits set in reset (interesting region of the scene)
|
|
83
|
+
self._xlim = None # None is flag that no reset has been performed
|
|
84
|
+
self._ylim = None
|
|
85
|
+
self._zlim = None
|
|
86
|
+
|
|
87
|
+
# Our default state to apply when resetting
|
|
88
|
+
self._default_state = None
|
|
89
|
+
|
|
90
|
+
# We initialize these parameters here, because we want these props
|
|
91
|
+
# available in all cameras. Note that PanZoom does not use _center
|
|
92
|
+
self._fov = 0.0
|
|
93
|
+
self._center = None
|
|
94
|
+
self._depth_value = 1e6 # bit+depth >= 24, otherwise should do 3e3
|
|
95
|
+
|
|
96
|
+
# Set parameters. These are all not part of the "camera state"
|
|
97
|
+
self.interactive = bool(interactive)
|
|
98
|
+
self.flip = flip if (flip is not None) else (False, False, False)
|
|
99
|
+
self.up = up
|
|
100
|
+
|
|
101
|
+
@property
|
|
102
|
+
def depth_value(self):
|
|
103
|
+
"""The depth value to use in orthographic and perspective projection
|
|
104
|
+
|
|
105
|
+
For orthographic projections, ``depth_value`` is the distance between
|
|
106
|
+
the near and far clipping planes. For perspective projections, it is
|
|
107
|
+
the ratio between the near and far clipping plane distances.
|
|
108
|
+
|
|
109
|
+
GL has a fixed amount of precision in the depth buffer, and a fixed
|
|
110
|
+
constant will not work for both a very large range and very high
|
|
111
|
+
precision. This property provides the user a way to override
|
|
112
|
+
the default value if necessary.
|
|
113
|
+
"""
|
|
114
|
+
return self._depth_value
|
|
115
|
+
|
|
116
|
+
@depth_value.setter
|
|
117
|
+
def depth_value(self, value):
|
|
118
|
+
value = float(value)
|
|
119
|
+
if value <= 0:
|
|
120
|
+
raise ValueError('depth value must be positive')
|
|
121
|
+
self._depth_value = value
|
|
122
|
+
self.view_changed()
|
|
123
|
+
|
|
124
|
+
def _depth_to_z(self, depth):
|
|
125
|
+
"""Get the z-coord, given the depth value."""
|
|
126
|
+
val = self.depth_value
|
|
127
|
+
return val - depth * 2 * val
|
|
128
|
+
|
|
129
|
+
def _viewbox_set(self, viewbox):
|
|
130
|
+
"""Friend method of viewbox to register itself."""
|
|
131
|
+
self._viewbox = viewbox
|
|
132
|
+
# Connect
|
|
133
|
+
viewbox.events.mouse_press.connect(self.viewbox_mouse_event)
|
|
134
|
+
viewbox.events.mouse_release.connect(self.viewbox_mouse_event)
|
|
135
|
+
viewbox.events.mouse_move.connect(self.viewbox_mouse_event)
|
|
136
|
+
viewbox.events.mouse_wheel.connect(self.viewbox_mouse_event)
|
|
137
|
+
viewbox.events.gesture_zoom.connect(self.viewbox_mouse_event)
|
|
138
|
+
viewbox.events.gesture_rotate.connect(self.viewbox_mouse_event)
|
|
139
|
+
viewbox.events.resize.connect(self.viewbox_resize_event)
|
|
140
|
+
# todo: also add key events! (and also on viewbox (they're missing)
|
|
141
|
+
|
|
142
|
+
def _viewbox_unset(self, viewbox):
|
|
143
|
+
"""Friend method of viewbox to unregister itself."""
|
|
144
|
+
self._viewbox = None
|
|
145
|
+
# Disconnect
|
|
146
|
+
viewbox.events.mouse_press.disconnect(self.viewbox_mouse_event)
|
|
147
|
+
viewbox.events.mouse_release.disconnect(self.viewbox_mouse_event)
|
|
148
|
+
viewbox.events.mouse_move.disconnect(self.viewbox_mouse_event)
|
|
149
|
+
viewbox.events.mouse_wheel.disconnect(self.viewbox_mouse_event)
|
|
150
|
+
viewbox.events.gesture_zoom.disconnect(self.viewbox_mouse_event)
|
|
151
|
+
viewbox.events.gesture_rotate.disconnect(self.viewbox_mouse_event)
|
|
152
|
+
viewbox.events.resize.disconnect(self.viewbox_resize_event)
|
|
153
|
+
|
|
154
|
+
@property
|
|
155
|
+
def viewbox(self):
|
|
156
|
+
"""The viewbox that this camera applies to."""
|
|
157
|
+
return self._viewbox
|
|
158
|
+
|
|
159
|
+
# Camera attributes
|
|
160
|
+
|
|
161
|
+
@property
|
|
162
|
+
def interactive(self):
|
|
163
|
+
"""Boolean describing whether the camera should enable or disable
|
|
164
|
+
user interaction.
|
|
165
|
+
"""
|
|
166
|
+
return self._interactive
|
|
167
|
+
|
|
168
|
+
@interactive.setter
|
|
169
|
+
def interactive(self, value):
|
|
170
|
+
self._interactive = bool(value)
|
|
171
|
+
|
|
172
|
+
@property
|
|
173
|
+
def flip(self):
|
|
174
|
+
return self._flip
|
|
175
|
+
|
|
176
|
+
@flip.setter
|
|
177
|
+
def flip(self, value):
|
|
178
|
+
if not isinstance(value, (list, tuple)):
|
|
179
|
+
raise ValueError('Flip must be a tuple or list.')
|
|
180
|
+
if len(value) == 2:
|
|
181
|
+
self._flip = bool(value[0]), bool(value[1]), False
|
|
182
|
+
elif len(value) == 3:
|
|
183
|
+
self._flip = bool(value[0]), bool(value[1]), bool(value[2])
|
|
184
|
+
else:
|
|
185
|
+
raise ValueError('Flip must have 2 or 3 elements.')
|
|
186
|
+
self._flip_factors = tuple([(1-x*2) for x in self._flip])
|
|
187
|
+
self.view_changed()
|
|
188
|
+
|
|
189
|
+
@property
|
|
190
|
+
def up(self):
|
|
191
|
+
"""The dimension that is considered up."""
|
|
192
|
+
return self._up
|
|
193
|
+
|
|
194
|
+
@up.setter
|
|
195
|
+
def up(self, value):
|
|
196
|
+
value = value.lower()
|
|
197
|
+
value = ('+' + value) if value in 'zyx' else value
|
|
198
|
+
if value not in ('+z', '-z', '+y', '-y', '+x', '-x'):
|
|
199
|
+
raise ValueError('Invalid value for up.')
|
|
200
|
+
self._up = value
|
|
201
|
+
self.view_changed()
|
|
202
|
+
|
|
203
|
+
@property
|
|
204
|
+
def center(self):
|
|
205
|
+
"""The center location for this camera
|
|
206
|
+
|
|
207
|
+
The exact meaning of this value differs per type of camera, but
|
|
208
|
+
generally means the point of interest or the rotation point.
|
|
209
|
+
"""
|
|
210
|
+
return self._center or (0, 0, 0)
|
|
211
|
+
|
|
212
|
+
@center.setter
|
|
213
|
+
def center(self, val):
|
|
214
|
+
if len(val) == 2:
|
|
215
|
+
center = float(val[0]), float(val[1]), 0.0
|
|
216
|
+
elif len(val) == 3:
|
|
217
|
+
center = float(val[0]), float(val[1]), float(val[2])
|
|
218
|
+
else:
|
|
219
|
+
raise ValueError('Center must be a 2 or 3 element tuple')
|
|
220
|
+
if center == self._center:
|
|
221
|
+
return
|
|
222
|
+
self._center = center
|
|
223
|
+
self.view_changed()
|
|
224
|
+
|
|
225
|
+
@property
|
|
226
|
+
def fov(self):
|
|
227
|
+
"""Field-of-view angle of the camera. If 0, the camera is in
|
|
228
|
+
orthographic mode.
|
|
229
|
+
"""
|
|
230
|
+
return self._fov
|
|
231
|
+
|
|
232
|
+
@fov.setter
|
|
233
|
+
def fov(self, fov):
|
|
234
|
+
fov = float(fov)
|
|
235
|
+
if fov < 0 or fov > 180:
|
|
236
|
+
raise ValueError("fov must be 0 <= fov <= 180.")
|
|
237
|
+
self._fov = fov
|
|
238
|
+
self.view_changed()
|
|
239
|
+
|
|
240
|
+
@contextmanager
|
|
241
|
+
def _block_updates(self):
|
|
242
|
+
prev, self._resetting = self._resetting, True
|
|
243
|
+
yield
|
|
244
|
+
self._resetting = prev
|
|
245
|
+
|
|
246
|
+
# Camera methods
|
|
247
|
+
|
|
248
|
+
def set_range(self, x=None, y=None, z=None, margin=0.05):
|
|
249
|
+
"""Set the range of the view region for the camera
|
|
250
|
+
|
|
251
|
+
Parameters
|
|
252
|
+
----------
|
|
253
|
+
x : tuple | None
|
|
254
|
+
X range.
|
|
255
|
+
y : tuple | None
|
|
256
|
+
Y range.
|
|
257
|
+
z : tuple | None
|
|
258
|
+
Z range.
|
|
259
|
+
margin : float
|
|
260
|
+
Margin to use.
|
|
261
|
+
|
|
262
|
+
Notes
|
|
263
|
+
-----
|
|
264
|
+
The view is set to the given range or to the scene boundaries
|
|
265
|
+
if ranges are not specified. The ranges should be 2-element
|
|
266
|
+
tuples specifying the min and max for each dimension.
|
|
267
|
+
|
|
268
|
+
For the PanZoomCamera the view is fully defined by the range.
|
|
269
|
+
For e.g. the TurntableCamera the elevation and azimuth are not
|
|
270
|
+
set. One should use reset() for that.
|
|
271
|
+
"""
|
|
272
|
+
# Flag to indicate that this is an initializing (not user-invoked)
|
|
273
|
+
init = self._xlim is None
|
|
274
|
+
|
|
275
|
+
# Collect given bounds
|
|
276
|
+
bounds = [None, None, None]
|
|
277
|
+
if x is not None:
|
|
278
|
+
bounds[0] = float(x[0]), float(x[1])
|
|
279
|
+
if y is not None:
|
|
280
|
+
bounds[1] = float(y[0]), float(y[1])
|
|
281
|
+
if z is not None:
|
|
282
|
+
bounds[2] = float(z[0]), float(z[1])
|
|
283
|
+
# If there is no viewbox, store given bounds in lim variables, and stop
|
|
284
|
+
if self._viewbox is None:
|
|
285
|
+
self._set_range_args = bounds[0], bounds[1], bounds[2], margin
|
|
286
|
+
return
|
|
287
|
+
|
|
288
|
+
# There is a viewbox, we're going to set the range for real
|
|
289
|
+
with self._block_updates():
|
|
290
|
+
|
|
291
|
+
# Get bounds from viewbox if not given
|
|
292
|
+
if all([(b is None) for b in bounds]):
|
|
293
|
+
bounds = self._viewbox.get_scene_bounds()
|
|
294
|
+
else:
|
|
295
|
+
for i in range(3):
|
|
296
|
+
if bounds[i] is None:
|
|
297
|
+
bounds[i] = self._viewbox.get_scene_bounds(i)
|
|
298
|
+
|
|
299
|
+
# Calculate ranges and margins
|
|
300
|
+
ranges = [b[1] - b[0] for b in bounds]
|
|
301
|
+
margins = [(r*margin or 0.1) for r in ranges]
|
|
302
|
+
# Assign limits for this camera
|
|
303
|
+
bounds_margins = [(b[0]-m, b[1]+m) for b, m in zip(bounds, margins)]
|
|
304
|
+
self._xlim, self._ylim, self._zlim = bounds_margins
|
|
305
|
+
# Store center location
|
|
306
|
+
if (not init) or (self._center is None):
|
|
307
|
+
self._center = [(b[0] + r / 2) for b, r in zip(bounds, ranges)]
|
|
308
|
+
|
|
309
|
+
# Let specific camera handle it
|
|
310
|
+
self._set_range(init)
|
|
311
|
+
|
|
312
|
+
# Finish
|
|
313
|
+
self.view_changed()
|
|
314
|
+
|
|
315
|
+
def _set_range(self, init):
|
|
316
|
+
pass
|
|
317
|
+
|
|
318
|
+
def reset(self):
|
|
319
|
+
"""Reset the view to the default state."""
|
|
320
|
+
self.set_state(self._default_state)
|
|
321
|
+
|
|
322
|
+
def set_default_state(self):
|
|
323
|
+
"""Set the current state to be the default state to be applied
|
|
324
|
+
when calling reset().
|
|
325
|
+
"""
|
|
326
|
+
self._default_state = self.get_state()
|
|
327
|
+
|
|
328
|
+
def get_state(self, props=None):
|
|
329
|
+
"""Get the current view state of the camera
|
|
330
|
+
|
|
331
|
+
Returns a dict of key-value pairs. The exact keys depend on the
|
|
332
|
+
camera. Can be passed to set_state() (of this or another camera
|
|
333
|
+
of the same type) to reproduce the state.
|
|
334
|
+
|
|
335
|
+
Parameters
|
|
336
|
+
----------
|
|
337
|
+
props : list of strings | None
|
|
338
|
+
List of properties to include in the returned dict. If None,
|
|
339
|
+
all of camera state is returned.
|
|
340
|
+
"""
|
|
341
|
+
if props is None:
|
|
342
|
+
props = self._state_props
|
|
343
|
+
state = {}
|
|
344
|
+
for key in props:
|
|
345
|
+
# We support tuple keys to accomodate camera linking.
|
|
346
|
+
if isinstance(key, tuple):
|
|
347
|
+
state[key] = nested_getattr(self, key)
|
|
348
|
+
else:
|
|
349
|
+
state[key] = getattr(self, key)
|
|
350
|
+
return state
|
|
351
|
+
|
|
352
|
+
def set_state(self, state=None, **kwargs):
|
|
353
|
+
"""Set the view state of the camera
|
|
354
|
+
|
|
355
|
+
Should be a dict (or kwargs) as returned by get_state. It can
|
|
356
|
+
be an incomlete dict, in which case only the specified
|
|
357
|
+
properties are set.
|
|
358
|
+
|
|
359
|
+
Parameters
|
|
360
|
+
----------
|
|
361
|
+
state : dict
|
|
362
|
+
The camera state.
|
|
363
|
+
**kwargs : dict
|
|
364
|
+
Unused keyword arguments.
|
|
365
|
+
"""
|
|
366
|
+
state = state or {}
|
|
367
|
+
state.update(kwargs)
|
|
368
|
+
|
|
369
|
+
with self._block_updates():
|
|
370
|
+
# In first pass, process tuple keys which select subproperties. This
|
|
371
|
+
# is an undocumented feature used for selective linking of camera state.
|
|
372
|
+
#
|
|
373
|
+
# Subproperties are handled by first copying old value of the root
|
|
374
|
+
# property, then setting the subproperty on this copy, and finally
|
|
375
|
+
# assigning the copied object back to the camera property. There needs
|
|
376
|
+
# to be an assignment of the root property so setters are called and
|
|
377
|
+
# update is triggered.
|
|
378
|
+
for key in list(state.keys()):
|
|
379
|
+
if isinstance(key, tuple):
|
|
380
|
+
key1 = key[0]
|
|
381
|
+
if key1 not in state:
|
|
382
|
+
root_prop = getattr(self, key1)
|
|
383
|
+
# We make copies by passing the old object to the type's
|
|
384
|
+
# constructor. This needs to be supported as is the case in
|
|
385
|
+
# e.g. the geometry.Rect class.
|
|
386
|
+
state[key1] = root_prop.__class__(root_prop)
|
|
387
|
+
nested_setattr(state[key1], key[1:], state[key])
|
|
388
|
+
|
|
389
|
+
# In second pass, assign the new root properties.
|
|
390
|
+
for key, val in state.items():
|
|
391
|
+
if isinstance(key, tuple):
|
|
392
|
+
continue
|
|
393
|
+
if key not in self._state_props:
|
|
394
|
+
raise KeyError('Not a valid camera state property %r' % key)
|
|
395
|
+
setattr(self, key, val)
|
|
396
|
+
self.view_changed()
|
|
397
|
+
|
|
398
|
+
def link(self, camera, props=None, axis=None):
|
|
399
|
+
"""Link this camera with another camera of the same type
|
|
400
|
+
|
|
401
|
+
Linked camera's keep each-others' state in sync.
|
|
402
|
+
|
|
403
|
+
Parameters
|
|
404
|
+
----------
|
|
405
|
+
camera : instance of Camera
|
|
406
|
+
The other camera to link.
|
|
407
|
+
props : list of strings | tuple of strings | None
|
|
408
|
+
List of camera state properties to keep in sync between
|
|
409
|
+
the two cameras. If None, all of camera state is kept in sync.
|
|
410
|
+
axis : "x" | "y" | None
|
|
411
|
+
An axis to link between two PanZoomCamera instances. If not None,
|
|
412
|
+
view limits in the selected axis only will be kept in sync between
|
|
413
|
+
the cameras.
|
|
414
|
+
"""
|
|
415
|
+
if axis is not None:
|
|
416
|
+
props = props or []
|
|
417
|
+
if axis == "x":
|
|
418
|
+
props += [("rect", "left"), ("rect", "right")]
|
|
419
|
+
elif axis == "y":
|
|
420
|
+
props += [("rect", "bottom"), ("rect", "top")]
|
|
421
|
+
else:
|
|
422
|
+
raise ValueError("Axis can be 'x' or 'y', not %r" % axis)
|
|
423
|
+
if props is None:
|
|
424
|
+
props = self._state_props
|
|
425
|
+
|
|
426
|
+
cam1, cam2 = self, camera
|
|
427
|
+
while cam1 in cam2._linked_cameras:
|
|
428
|
+
del cam2._linked_cameras[cam1]
|
|
429
|
+
while cam2 in cam1._linked_cameras:
|
|
430
|
+
del cam1._linked_cameras[cam2]
|
|
431
|
+
# Link both ways
|
|
432
|
+
cam1._linked_cameras[cam2] = props
|
|
433
|
+
cam2._linked_cameras[cam1] = props
|
|
434
|
+
|
|
435
|
+
# Event-related methods
|
|
436
|
+
|
|
437
|
+
def view_changed(self):
|
|
438
|
+
"""Called when this camera is changes its view. Also called
|
|
439
|
+
when its associated with a viewbox.
|
|
440
|
+
"""
|
|
441
|
+
if self._resetting:
|
|
442
|
+
return # don't update anything while resetting (are in set_range)
|
|
443
|
+
if self._viewbox:
|
|
444
|
+
# Set range if necessary
|
|
445
|
+
if self._xlim is None:
|
|
446
|
+
args = self._set_range_args or ()
|
|
447
|
+
self.set_range(*args)
|
|
448
|
+
# Store default state if we have not set it yet
|
|
449
|
+
if self._default_state is None:
|
|
450
|
+
self.set_default_state()
|
|
451
|
+
# Do the actual update
|
|
452
|
+
self._update_transform()
|
|
453
|
+
|
|
454
|
+
@property
|
|
455
|
+
def pre_transform(self):
|
|
456
|
+
"""A transform to apply to the beginning of the scene transform, in
|
|
457
|
+
addition to anything else provided by this Camera.
|
|
458
|
+
"""
|
|
459
|
+
return self._pre_transform
|
|
460
|
+
|
|
461
|
+
@pre_transform.setter
|
|
462
|
+
def pre_transform(self, tr):
|
|
463
|
+
self._pre_transform = tr
|
|
464
|
+
self.view_changed()
|
|
465
|
+
|
|
466
|
+
def viewbox_mouse_event(self, event):
|
|
467
|
+
"""Viewbox mouse event handler
|
|
468
|
+
|
|
469
|
+
Parameters
|
|
470
|
+
----------
|
|
471
|
+
event : instance of Event
|
|
472
|
+
The event.
|
|
473
|
+
"""
|
|
474
|
+
pass
|
|
475
|
+
|
|
476
|
+
def on_canvas_change(self, event):
|
|
477
|
+
"""Canvas change event handler
|
|
478
|
+
|
|
479
|
+
Parameters
|
|
480
|
+
----------
|
|
481
|
+
event : instance of Event
|
|
482
|
+
The event.
|
|
483
|
+
"""
|
|
484
|
+
# Connect key events from canvas to camera.
|
|
485
|
+
# TODO: canvas should keep track of a single node with keyboard focus.
|
|
486
|
+
if event.old is not None:
|
|
487
|
+
event.old.events.key_press.disconnect(self.viewbox_key_event)
|
|
488
|
+
event.old.events.key_release.disconnect(self.viewbox_key_event)
|
|
489
|
+
if event.new is not None:
|
|
490
|
+
event.new.events.key_press.connect(self.viewbox_key_event)
|
|
491
|
+
event.new.events.key_release.connect(self.viewbox_key_event)
|
|
492
|
+
|
|
493
|
+
def viewbox_key_event(self, event):
|
|
494
|
+
"""The ViewBox key event handler
|
|
495
|
+
|
|
496
|
+
Parameters
|
|
497
|
+
----------
|
|
498
|
+
event : instance of Event
|
|
499
|
+
The event.
|
|
500
|
+
"""
|
|
501
|
+
if event.key == keys.BACKSPACE:
|
|
502
|
+
self.reset()
|
|
503
|
+
|
|
504
|
+
def viewbox_resize_event(self, event):
|
|
505
|
+
"""The ViewBox resize handler to update the transform
|
|
506
|
+
|
|
507
|
+
Parameters
|
|
508
|
+
----------
|
|
509
|
+
event : instance of Event
|
|
510
|
+
The event.
|
|
511
|
+
"""
|
|
512
|
+
pass
|
|
513
|
+
|
|
514
|
+
def _update_transform(self):
|
|
515
|
+
"""Subclasses should reimplement this method to update the scene
|
|
516
|
+
transform by calling self._set_scene_transform.
|
|
517
|
+
"""
|
|
518
|
+
self._set_scene_transform(self.transform)
|
|
519
|
+
|
|
520
|
+
def _set_scene_transform(self, tr):
|
|
521
|
+
"""Called by subclasses to configure the viewbox scene transform."""
|
|
522
|
+
if self._resetting:
|
|
523
|
+
return
|
|
524
|
+
# todo: check whether transform has changed, connect to
|
|
525
|
+
# transform.changed event
|
|
526
|
+
pre_tr = self.pre_transform
|
|
527
|
+
if pre_tr is None:
|
|
528
|
+
self._scene_transform = tr
|
|
529
|
+
else:
|
|
530
|
+
self._transform_cache.roll()
|
|
531
|
+
self._scene_transform = self._transform_cache.get([pre_tr, tr])
|
|
532
|
+
|
|
533
|
+
# Mark the transform dynamic so that it will not be collapsed with
|
|
534
|
+
# others
|
|
535
|
+
self._scene_transform.dynamic = True
|
|
536
|
+
|
|
537
|
+
# Update scene
|
|
538
|
+
self._viewbox.scene.transform = self._scene_transform
|
|
539
|
+
self._viewbox.update()
|
|
540
|
+
|
|
541
|
+
# Apply same state to linked cameras, but prevent that camera
|
|
542
|
+
# to return the favor
|
|
543
|
+
for cam in self._linked_cameras:
|
|
544
|
+
if cam is self._linked_cameras_no_update:
|
|
545
|
+
continue
|
|
546
|
+
try:
|
|
547
|
+
cam._linked_cameras_no_update = self
|
|
548
|
+
linked_props = self._linked_cameras[cam]
|
|
549
|
+
cam.set_state(self.get_state(linked_props))
|
|
550
|
+
finally:
|
|
551
|
+
cam._linked_cameras_no_update = None
|