simview 3.4__tar.gz → 3.6__tar.gz
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.
- simview-3.6/PKG-INFO +136 -0
- simview-3.6/README.md +103 -0
- {simview-3.4 → simview-3.6}/pyproject.toml +7 -2
- {simview-3.4 → simview-3.6}/simview/__main__.py +217 -44
- {simview-3.4 → simview-3.6}/simview/diff.py +58 -24
- {simview-3.4 → simview-3.6}/simview/info.py +7 -0
- {simview-3.4 → simview-3.6}/simview/model.py +47 -4
- simview-3.6/simview/render.py +141 -0
- {simview-3.4 → simview-3.6}/simview/scene.py +30 -7
- {simview-3.4 → simview-3.6}/simview/static/js/SimView.js +22 -1
- {simview-3.4 → simview-3.6}/simview/static/js/components/BatchManager.js +1 -0
- {simview-3.4 → simview-3.6}/simview/static/js/components/InteractionController.js +77 -6
- {simview-3.4 → simview-3.6}/simview/static/js/config.js +1 -0
- {simview-3.4 → simview-3.6}/simview/static/js/objects/Terrain.js +123 -11
- {simview-3.4 → simview-3.6}/simview/static/js/ui/AnalysisPanel.js +46 -25
- {simview-3.4 → simview-3.6}/simview/static/js/ui/Controls.js +91 -0
- {simview-3.4 → simview-3.6}/simview/static/js/ui/ErrorMetrics.js +8 -2
- {simview-3.4 → simview-3.6}/simview/static/js/ui/Legend.js +18 -2
- {simview-3.4 → simview-3.6}/simview/static/js/ui/ScalarPlotter.js +6 -2
- simview-3.6/simview/static/js/ui/TerrainProfile.js +544 -0
- simview-3.6/simview/static/js/utils/batchPresets.js +28 -0
- simview-3.6/simview/static/js/utils/terrainSample.js +92 -0
- {simview-3.4 → simview-3.6}/simview/terrain.py +505 -3
- simview-3.6/simview.egg-info/PKG-INFO +136 -0
- {simview-3.4 → simview-3.6}/simview.egg-info/SOURCES.txt +4 -0
- {simview-3.4 → simview-3.6}/simview.egg-info/requires.txt +3 -0
- {simview-3.4 → simview-3.6}/tests/test_cli.py +473 -2
- {simview-3.4 → simview-3.6}/tests/test_diff.py +55 -0
- {simview-3.4 → simview-3.6}/tests/test_info.py +26 -0
- {simview-3.4 → simview-3.6}/tests/test_roundtrip.py +13 -0
- {simview-3.4 → simview-3.6}/tests/test_scene.py +18 -0
- simview-3.6/tests/test_terrain_query.py +659 -0
- simview-3.4/PKG-INFO +0 -626
- simview-3.4/README.md +0 -595
- simview-3.4/simview.egg-info/PKG-INFO +0 -626
- simview-3.4/tests/test_terrain_query.py +0 -333
- {simview-3.4 → simview-3.6}/LICENSE +0 -0
- {simview-3.4 → simview-3.6}/MANIFEST.in +0 -0
- {simview-3.4 → simview-3.6}/setup.cfg +0 -0
- {simview-3.4 → simview-3.6}/simview/__init__.py +0 -0
- {simview-3.4 → simview-3.6}/simview/launcher.py +0 -0
- {simview-3.4 → simview-3.6}/simview/live.py +0 -0
- {simview-3.4 → simview-3.6}/simview/merge.py +0 -0
- {simview-3.4 → simview-3.6}/simview/py.typed +0 -0
- {simview-3.4 → simview-3.6}/simview/server.py +0 -0
- {simview-3.4 → simview-3.6}/simview/state.py +0 -0
- {simview-3.4 → simview-3.6}/simview/static/css/controls.css +0 -0
- {simview-3.4 → simview-3.6}/simview/static/js/components/AnimationController.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/js/components/InteractionControls.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/js/components/Scene.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/js/components/StateStore.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/js/main.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/js/objects/Body.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/js/objects/StaticObject.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/js/objects/utils.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/js/ui/BatchLegend.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/js/ui/BodyStateWindow.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/js/ui/PlaybackControls.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/js/utils/blobCodec.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/js/utils/bodyTransforms.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/js/utils/csv.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/js/utils/errorMath.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/js/utils/injectStyles.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/js/utils/interpolate.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/js/utils/liveFollow.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/js/utils/loadRecordingLibs.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/js/utils/viewState.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/index.min.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/Color.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/chroma.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/colors/colorbrewer.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/colors/w3cx11.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/generator/average.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/generator/bezier.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/generator/blend.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/generator/cubehelix.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/generator/mix.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/generator/random.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/generator/scale.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/interpolator/_hsx.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/interpolator/hcg.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/interpolator/hsi.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/interpolator/hsl.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/interpolator/hsv.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/interpolator/index.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/interpolator/lab.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/interpolator/lch.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/interpolator/lrgb.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/interpolator/num.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/interpolator/oklab.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/interpolator/oklch.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/interpolator/rgb.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/cmyk/cmyk2rgb.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/cmyk/index.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/cmyk/rgb2cmyk.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/css/css2rgb.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/css/hsl2css.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/css/index.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/css/lab2css.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/css/lch2css.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/css/oklab2css.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/css/oklch2css.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/css/rgb2css.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/gl/index.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/hcg/hcg2rgb.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/hcg/index.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/hcg/rgb2hcg.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/hex/hex2rgb.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/hex/index.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/hex/rgb2hex.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/hsi/hsi2rgb.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/hsi/index.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/hsi/rgb2hsi.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/hsl/hsl2rgb.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/hsl/index.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/hsl/rgb2hsl.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/hsv/hsv2rgb.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/hsv/index.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/hsv/rgb2hsv.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/input.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/lab/index.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/lab/lab-constants.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/lab/lab2rgb.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/lab/rgb2lab.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/lch/hcl2rgb.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/lch/index.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/lch/lab2lch.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/lch/lch2lab.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/lch/lch2rgb.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/lch/rgb2lch.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/named/index.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/num/index.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/num/num2rgb.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/num/rgb2num.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/oklab/index.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/oklab/oklab2rgb.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/oklab/rgb2oklab.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/oklch/index.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/oklch/oklch2rgb.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/oklch/rgb2oklch.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/rgb/index.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/temp/index.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/temp/rgb2temperature.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/io/temp/temperature2rgb.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/ops/alpha.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/ops/clipped.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/ops/darken.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/ops/get.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/ops/luminance.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/ops/mix.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/ops/premultiply.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/ops/saturate.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/ops/set.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/ops/shade.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/utils/analyze.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/utils/clip_rgb.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/utils/contrast.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/utils/contrastAPCA.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/utils/delta-e.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/utils/distance.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/utils/index.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/utils/last.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/utils/limit.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/utils/multiply-matrices.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/utils/scales.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/utils/type.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/utils/unpack.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/utils/valid.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/chroma-js-3.1.2/src/version.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/download.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/js-colormaps.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/tar.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/three-0.174.0/addons/controls/OrbitControls.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/three-0.174.0/addons/libs/lil-gui.module.min.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/three-0.174.0/three.core.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/three-0.174.0/three.module.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/uPlot.esm.js +0 -0
- {simview-3.4 → simview-3.6}/simview/static/lib/uPlot.min.css +0 -0
- {simview-3.4 → simview-3.6}/simview/static/textures/contacts/red-cross0.png +0 -0
- {simview-3.4 → simview-3.6}/simview/static/textures/points/ball0.png +0 -0
- {simview-3.4 → simview-3.6}/simview/static/textures/points/ball1.png +0 -0
- {simview-3.4 → simview-3.6}/simview/templates/index.html +0 -0
- {simview-3.4 → simview-3.6}/simview/utils.py +0 -0
- {simview-3.4 → simview-3.6}/simview.egg-info/dependency_links.txt +0 -0
- {simview-3.4 → simview-3.6}/simview.egg-info/entry_points.txt +0 -0
- {simview-3.4 → simview-3.6}/simview.egg-info/top_level.txt +0 -0
- {simview-3.4 → simview-3.6}/tests/test_columnar_states.py +0 -0
- {simview-3.4 → simview-3.6}/tests/test_contacts.py +0 -0
- {simview-3.4 → simview-3.6}/tests/test_launcher.py +0 -0
- {simview-3.4 → simview-3.6}/tests/test_live.py +0 -0
- {simview-3.4 → simview-3.6}/tests/test_merge.py +0 -0
- {simview-3.4 → simview-3.6}/tests/test_server.py +0 -0
- {simview-3.4 → simview-3.6}/tests/test_show.py +0 -0
- {simview-3.4 → simview-3.6}/tests/test_terrain.py +0 -0
- {simview-3.4 → simview-3.6}/tests/test_trajectory.py +0 -0
- {simview-3.4 → simview-3.6}/tests/test_utils.py +0 -0
simview-3.6/PKG-INFO
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: simview
|
|
3
|
+
Version: 3.6
|
|
4
|
+
Summary: THREE.js-based simulation visualization tool
|
|
5
|
+
Author-email: Jan Vlk <vlkjan6@fel.cvut.cz>, Ales Kucera <kuceral4@fel.cvut.cz>, David Korcak <david.korcak@gmail.com>
|
|
6
|
+
License-Expression: BSD-3-Clause
|
|
7
|
+
Project-URL: Homepage, https://vlk-jan.github.io/simview/
|
|
8
|
+
Project-URL: Repository, https://github.com/vlk-jan/simview
|
|
9
|
+
Project-URL: Issues, https://github.com/vlk-jan/simview/issues
|
|
10
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
11
|
+
Classifier: Intended Audience :: Science/Research
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Visualization
|
|
17
|
+
Requires-Python: >=3.12
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: fastapi>=0.135.3
|
|
21
|
+
Requires-Dist: httptools>=0.7.1; sys_platform != "win32"
|
|
22
|
+
Requires-Dist: jinja2>=3.1.6
|
|
23
|
+
Requires-Dist: orjson>=3.11.8
|
|
24
|
+
Requires-Dist: uvicorn>=0.44.0
|
|
25
|
+
Requires-Dist: uvloop>=0.22.1; sys_platform != "win32"
|
|
26
|
+
Provides-Extra: authoring
|
|
27
|
+
Requires-Dist: torch; extra == "authoring"
|
|
28
|
+
Requires-Dist: einops; extra == "authoring"
|
|
29
|
+
Requires-Dist: numpy; extra == "authoring"
|
|
30
|
+
Provides-Extra: render
|
|
31
|
+
Requires-Dist: playwright>=1.40; extra == "render"
|
|
32
|
+
Dynamic: license-file
|
|
33
|
+
|
|
34
|
+
# SimView Visualizer
|
|
35
|
+
|
|
36
|
+
[](https://vlk-jan.github.io/simview/)
|
|
37
|
+
[](https://vlk-jan.github.io/assets/demos/simview/)
|
|
38
|
+
|
|
39
|
+
**SimView** is a powerful and interactive tool for visualizing 3D models and terrain data in simulations. It enables you to explore and analyze multiple simulation scenarios (batches) within a shared environment, all defined through an intuitive JSON format or a Python API.
|
|
40
|
+
|
|
41
|
+
Whether you're simulating physical objects or comparing different runs, SimView provides a flexible and efficient way to bring your data to life using a web-based interface powered by Three.js.
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Documentation
|
|
46
|
+
|
|
47
|
+
Full documentation — usage guides, CLI reference, the JSON format specification,
|
|
48
|
+
the API reference, and developer/architecture docs — is available at:
|
|
49
|
+
|
|
50
|
+
**[https://vlk-jan.github.io/simview/](https://vlk-jan.github.io/simview/)**
|
|
51
|
+
|
|
52
|
+
Want to try it without installing anything? There's a
|
|
53
|
+
[live browser demo](https://vlk-jan.github.io/assets/demos/simview/)
|
|
54
|
+
(static snapshot, no backend needed).
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Features
|
|
59
|
+
|
|
60
|
+
- **Batched Simulations**: Visualize multiple simulation instances side-by-side.
|
|
61
|
+
- **Shared Terrain**: Efficient rendering with shared terrain across all batches.
|
|
62
|
+
- **Interactive UI**: Web-based controls for playback, camera, and data inspection.
|
|
63
|
+
- **Python API**: Easy-to-use API for generating scenes and launching the visualizer directly from your code.
|
|
64
|
+
- **JSON Support**: Load and save simulation data using a portable JSON format.
|
|
65
|
+
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## Quick Start
|
|
69
|
+
|
|
70
|
+
The easiest way to get started is to run the provided example script:
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
python example.py
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
This script demonstrates how to use the Python API to create a simulation with wavy terrain, dynamic bodies, and time-series data.
|
|
77
|
+
|
|
78
|
+
The Python authoring API (`simview.scene`, `simview.state`, `simview.model`) depends on
|
|
79
|
+
`torch` and `einops`. Install them with the optional `authoring` extra shown below.
|
|
80
|
+
Only these are needed to *build* simulations; *viewing* an existing JSON file does not
|
|
81
|
+
require `torch`.
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## Installation
|
|
86
|
+
|
|
87
|
+
Requires **Python 3.12+**.
|
|
88
|
+
|
|
89
|
+
### From PyPI
|
|
90
|
+
|
|
91
|
+
To only view existing simulation JSON files:
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
pip install simview
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
To also author simulations from Python (installs `torch` and `einops`):
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
pip install "simview[authoring]"
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### From source
|
|
104
|
+
|
|
105
|
+
For working on SimView itself (or to track an unreleased commit), install an
|
|
106
|
+
editable checkout instead:
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
pip install -e . # viewing only
|
|
110
|
+
pip install -e ".[authoring]" # viewing + authoring
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
For independent use of this repository, use `venv` or `uv`:
|
|
114
|
+
|
|
115
|
+
```bash
|
|
116
|
+
python -m venv .venv
|
|
117
|
+
source .venv/bin/activate
|
|
118
|
+
pip install -e ".[authoring]"
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
```bash
|
|
122
|
+
uv sync --extra authoring
|
|
123
|
+
source .venv/bin/activate
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## License
|
|
129
|
+
|
|
130
|
+
SimView is distributed under the [BSD 3-Clause License](LICENSE). The web interface
|
|
131
|
+
vendors [uPlot](https://github.com/leeoniya/uPlot), [three.js](https://github.com/mrdoob/three.js),
|
|
132
|
+
and [chroma-js](https://github.com/gka/chroma.js) (all MIT licensed) under
|
|
133
|
+
`simview/static/lib/` so the viewer works fully offline — see the
|
|
134
|
+
[documentation](https://vlk-jan.github.io/simview/dev/architecture/#vendored-third-party-libraries)
|
|
135
|
+
for details. All third-party libraries used by SimView are permissively licensed
|
|
136
|
+
(MIT/BSD), so there are no licensing restrictions on commercial use.
|
simview-3.6/README.md
ADDED
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
# SimView Visualizer
|
|
2
|
+
|
|
3
|
+
[](https://vlk-jan.github.io/simview/)
|
|
4
|
+
[](https://vlk-jan.github.io/assets/demos/simview/)
|
|
5
|
+
|
|
6
|
+
**SimView** is a powerful and interactive tool for visualizing 3D models and terrain data in simulations. It enables you to explore and analyze multiple simulation scenarios (batches) within a shared environment, all defined through an intuitive JSON format or a Python API.
|
|
7
|
+
|
|
8
|
+
Whether you're simulating physical objects or comparing different runs, SimView provides a flexible and efficient way to bring your data to life using a web-based interface powered by Three.js.
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Documentation
|
|
13
|
+
|
|
14
|
+
Full documentation — usage guides, CLI reference, the JSON format specification,
|
|
15
|
+
the API reference, and developer/architecture docs — is available at:
|
|
16
|
+
|
|
17
|
+
**[https://vlk-jan.github.io/simview/](https://vlk-jan.github.io/simview/)**
|
|
18
|
+
|
|
19
|
+
Want to try it without installing anything? There's a
|
|
20
|
+
[live browser demo](https://vlk-jan.github.io/assets/demos/simview/)
|
|
21
|
+
(static snapshot, no backend needed).
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Features
|
|
26
|
+
|
|
27
|
+
- **Batched Simulations**: Visualize multiple simulation instances side-by-side.
|
|
28
|
+
- **Shared Terrain**: Efficient rendering with shared terrain across all batches.
|
|
29
|
+
- **Interactive UI**: Web-based controls for playback, camera, and data inspection.
|
|
30
|
+
- **Python API**: Easy-to-use API for generating scenes and launching the visualizer directly from your code.
|
|
31
|
+
- **JSON Support**: Load and save simulation data using a portable JSON format.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Quick Start
|
|
36
|
+
|
|
37
|
+
The easiest way to get started is to run the provided example script:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
python example.py
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
This script demonstrates how to use the Python API to create a simulation with wavy terrain, dynamic bodies, and time-series data.
|
|
44
|
+
|
|
45
|
+
The Python authoring API (`simview.scene`, `simview.state`, `simview.model`) depends on
|
|
46
|
+
`torch` and `einops`. Install them with the optional `authoring` extra shown below.
|
|
47
|
+
Only these are needed to *build* simulations; *viewing* an existing JSON file does not
|
|
48
|
+
require `torch`.
|
|
49
|
+
|
|
50
|
+
---
|
|
51
|
+
|
|
52
|
+
## Installation
|
|
53
|
+
|
|
54
|
+
Requires **Python 3.12+**.
|
|
55
|
+
|
|
56
|
+
### From PyPI
|
|
57
|
+
|
|
58
|
+
To only view existing simulation JSON files:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pip install simview
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
To also author simulations from Python (installs `torch` and `einops`):
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
pip install "simview[authoring]"
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### From source
|
|
71
|
+
|
|
72
|
+
For working on SimView itself (or to track an unreleased commit), install an
|
|
73
|
+
editable checkout instead:
|
|
74
|
+
|
|
75
|
+
```bash
|
|
76
|
+
pip install -e . # viewing only
|
|
77
|
+
pip install -e ".[authoring]" # viewing + authoring
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
For independent use of this repository, use `venv` or `uv`:
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
python -m venv .venv
|
|
84
|
+
source .venv/bin/activate
|
|
85
|
+
pip install -e ".[authoring]"
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
uv sync --extra authoring
|
|
90
|
+
source .venv/bin/activate
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## License
|
|
96
|
+
|
|
97
|
+
SimView is distributed under the [BSD 3-Clause License](LICENSE). The web interface
|
|
98
|
+
vendors [uPlot](https://github.com/leeoniya/uPlot), [three.js](https://github.com/mrdoob/three.js),
|
|
99
|
+
and [chroma-js](https://github.com/gka/chroma.js) (all MIT licensed) under
|
|
100
|
+
`simview/static/lib/` so the viewer works fully offline — see the
|
|
101
|
+
[documentation](https://vlk-jan.github.io/simview/dev/architecture/#vendored-third-party-libraries)
|
|
102
|
+
for details. All third-party libraries used by SimView are permissively licensed
|
|
103
|
+
(MIT/BSD), so there are no licensing restrictions on commercial use.
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "simview"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.6"
|
|
8
8
|
readme = "README.md"
|
|
9
9
|
requires-python = ">=3.12"
|
|
10
10
|
license = "BSD-3-Clause"
|
|
@@ -34,7 +34,7 @@ dependencies = [
|
|
|
34
34
|
]
|
|
35
35
|
|
|
36
36
|
[project.urls]
|
|
37
|
-
Homepage = "https://
|
|
37
|
+
Homepage = "https://vlk-jan.github.io/simview/"
|
|
38
38
|
Repository = "https://github.com/vlk-jan/simview"
|
|
39
39
|
Issues = "https://github.com/vlk-jan/simview/issues"
|
|
40
40
|
|
|
@@ -42,6 +42,10 @@ Issues = "https://github.com/vlk-jan/simview/issues"
|
|
|
42
42
|
# Needed only to author simulations via the Python API (simview.scene / state / model).
|
|
43
43
|
# Viewing an existing JSON file does not require these.
|
|
44
44
|
authoring = ["torch", "einops", "numpy"]
|
|
45
|
+
# Needed only for `simview render` (headless PNG screenshots, e.g. from a
|
|
46
|
+
# SLURM job with no display). Also requires a one-time `playwright install
|
|
47
|
+
# chromium` to fetch the browser binary itself.
|
|
48
|
+
render = ["playwright>=1.40"]
|
|
45
49
|
|
|
46
50
|
[project.scripts]
|
|
47
51
|
simview = "simview.__main__:main"
|
|
@@ -61,6 +65,7 @@ dev = [
|
|
|
61
65
|
"pyright>=1.1.411",
|
|
62
66
|
"websockets>=16.1",
|
|
63
67
|
]
|
|
68
|
+
docs = ["mkdocs>=1.6", "mkdocs-material>=9.5", "mkdocstrings[python]>=0.27"]
|
|
64
69
|
|
|
65
70
|
[tool.ruff]
|
|
66
71
|
target-version = "py312"
|
|
@@ -82,14 +82,18 @@ def run_info(path: Path, as_json: bool) -> None:
|
|
|
82
82
|
|
|
83
83
|
|
|
84
84
|
def run_terrain(path: Path, args: argparse.Namespace) -> None:
|
|
85
|
-
"""Print terrain value(s) at a point
|
|
86
|
-
at `path`, to stdout. With `--batches
|
|
87
|
-
of querying a single one
|
|
85
|
+
"""Print terrain value(s) at a point, over an area, or along a body's
|
|
86
|
+
trajectory, from the scene JSON at `path`, to stdout. With `--batches
|
|
87
|
+
A B`, compares two batches instead of querying a single one (for
|
|
88
|
+
`--along-body`, both batches' terrains are sampled along batch A's
|
|
89
|
+
trajectory -- see `query_along_body_diff`)."""
|
|
88
90
|
from simview import terrain as terrain_mod
|
|
89
91
|
|
|
90
|
-
|
|
92
|
+
mode_count = sum(v is not None for v in (args.point, args.area, args.along_body))
|
|
93
|
+
if mode_count != 1:
|
|
91
94
|
logger.error(
|
|
92
|
-
"Error: 'simview terrain' requires exactly one of --point
|
|
95
|
+
"Error: 'simview terrain' requires exactly one of --point, --area, "
|
|
96
|
+
"or --along-body."
|
|
93
97
|
)
|
|
94
98
|
sys.exit(1)
|
|
95
99
|
if args.area is not None and len(args.area) not in (0, 4):
|
|
@@ -106,40 +110,67 @@ def run_terrain(path: Path, args: argparse.Namespace) -> None:
|
|
|
106
110
|
diff_mode = args.batches is not None
|
|
107
111
|
|
|
108
112
|
try:
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
result = terrain_mod.
|
|
113
|
+
if args.along_body is not None:
|
|
114
|
+
model_data, states_data = terrain_mod.load_scene(path)
|
|
115
|
+
if diff_mode:
|
|
116
|
+
batch_a, batch_b = args.batches
|
|
117
|
+
result = terrain_mod.query_along_body_diff(
|
|
114
118
|
model_data,
|
|
115
|
-
|
|
116
|
-
args.
|
|
119
|
+
states_data,
|
|
120
|
+
args.along_body,
|
|
117
121
|
batch_a,
|
|
118
122
|
batch_b,
|
|
119
123
|
args.layer,
|
|
124
|
+
args.every,
|
|
120
125
|
)
|
|
121
|
-
text = terrain_mod.
|
|
122
|
-
csv_text = terrain_mod.
|
|
126
|
+
text = terrain_mod.format_along_diff_text(result)
|
|
127
|
+
csv_text = terrain_mod.format_along_diff_csv(result)
|
|
123
128
|
else:
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
129
|
+
result = terrain_mod.query_along_body(
|
|
130
|
+
model_data,
|
|
131
|
+
states_data,
|
|
132
|
+
args.along_body,
|
|
133
|
+
args.layer,
|
|
134
|
+
args.batch,
|
|
135
|
+
args.every,
|
|
127
136
|
)
|
|
128
|
-
text = terrain_mod.
|
|
129
|
-
csv_text = terrain_mod.
|
|
130
|
-
elif args.point is not None:
|
|
131
|
-
result = terrain_mod.query_point(
|
|
132
|
-
model_data, args.point[0], args.point[1], args.layer, args.batch
|
|
133
|
-
)
|
|
134
|
-
text = terrain_mod.format_point_text(result)
|
|
135
|
-
csv_text = terrain_mod.format_point_csv(result)
|
|
137
|
+
text = terrain_mod.format_along_text(result)
|
|
138
|
+
csv_text = terrain_mod.format_along_csv(result)
|
|
136
139
|
else:
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
140
|
+
model_data = terrain_mod.load_scene_model(path)
|
|
141
|
+
if diff_mode:
|
|
142
|
+
batch_a, batch_b = args.batches
|
|
143
|
+
if args.point is not None:
|
|
144
|
+
result = terrain_mod.query_point_diff(
|
|
145
|
+
model_data,
|
|
146
|
+
args.point[0],
|
|
147
|
+
args.point[1],
|
|
148
|
+
batch_a,
|
|
149
|
+
batch_b,
|
|
150
|
+
args.layer,
|
|
151
|
+
)
|
|
152
|
+
text = terrain_mod.format_point_diff_text(result)
|
|
153
|
+
csv_text = terrain_mod.format_point_diff_csv(result)
|
|
154
|
+
else:
|
|
155
|
+
bounds = tuple(args.area) if args.area else None
|
|
156
|
+
result = terrain_mod.query_area_diff(
|
|
157
|
+
model_data, bounds, batch_a, batch_b, args.layer, args.stride
|
|
158
|
+
)
|
|
159
|
+
text = terrain_mod.format_area_diff_text(result)
|
|
160
|
+
csv_text = terrain_mod.format_area_diff_csv(result)
|
|
161
|
+
elif args.point is not None:
|
|
162
|
+
result = terrain_mod.query_point(
|
|
163
|
+
model_data, args.point[0], args.point[1], args.layer, args.batch
|
|
164
|
+
)
|
|
165
|
+
text = terrain_mod.format_point_text(result)
|
|
166
|
+
csv_text = terrain_mod.format_point_csv(result)
|
|
167
|
+
else:
|
|
168
|
+
bounds = tuple(args.area) if args.area else None
|
|
169
|
+
result = terrain_mod.query_area(
|
|
170
|
+
model_data, bounds, args.layer, args.batch, args.stride
|
|
171
|
+
)
|
|
172
|
+
text = terrain_mod.format_area_text(result)
|
|
173
|
+
csv_text = terrain_mod.format_area_csv(result)
|
|
143
174
|
except (json.JSONDecodeError, ValueError, KeyError) as e:
|
|
144
175
|
logger.error("Error: %s", e)
|
|
145
176
|
sys.exit(1)
|
|
@@ -154,7 +185,10 @@ def run_terrain(path: Path, args: argparse.Namespace) -> None:
|
|
|
154
185
|
|
|
155
186
|
def run_diff(path: Path, args: argparse.Namespace) -> None:
|
|
156
187
|
"""Print a trajectory divergence report between two batches of the scene
|
|
157
|
-
JSON at `path`, to stdout.
|
|
188
|
+
JSON at `path`, to stdout. With `--fail-on-exceed`, additionally exits
|
|
189
|
+
with a non-zero code once printing is done: 0 = within thresholds, 1 =
|
|
190
|
+
usage/parse error, 2 = a threshold was exceeded (see `--fail-on-exceed`'s
|
|
191
|
+
help text)."""
|
|
158
192
|
from simview import diff as diff_mod
|
|
159
193
|
|
|
160
194
|
if args.batches is None:
|
|
@@ -166,6 +200,16 @@ def run_diff(path: Path, args: argparse.Namespace) -> None:
|
|
|
166
200
|
if args.json and args.csv:
|
|
167
201
|
logger.error("Error: --json and --csv are mutually exclusive.")
|
|
168
202
|
sys.exit(1)
|
|
203
|
+
if (
|
|
204
|
+
args.fail_on_exceed
|
|
205
|
+
and args.pos_threshold is None
|
|
206
|
+
and args.rot_threshold_deg is None
|
|
207
|
+
):
|
|
208
|
+
logger.error(
|
|
209
|
+
"Error: --fail-on-exceed requires --pos-threshold and/or "
|
|
210
|
+
"--rot-threshold-deg."
|
|
211
|
+
)
|
|
212
|
+
sys.exit(1)
|
|
169
213
|
|
|
170
214
|
try:
|
|
171
215
|
model_data, states_data = diff_mod.load_scene(path)
|
|
@@ -178,6 +222,7 @@ def run_diff(path: Path, args: argparse.Namespace) -> None:
|
|
|
178
222
|
every=args.every,
|
|
179
223
|
pos_threshold=args.pos_threshold,
|
|
180
224
|
rot_threshold_deg=args.rot_threshold_deg,
|
|
225
|
+
per_axis=args.per_axis,
|
|
181
226
|
)
|
|
182
227
|
text = diff_mod.format_diff_text(result)
|
|
183
228
|
csv_text = diff_mod.format_diff_csv(result)
|
|
@@ -192,6 +237,45 @@ def run_diff(path: Path, args: argparse.Namespace) -> None:
|
|
|
192
237
|
else:
|
|
193
238
|
print(text)
|
|
194
239
|
|
|
240
|
+
if args.fail_on_exceed:
|
|
241
|
+
exceeded = any(
|
|
242
|
+
body["summary"]["first_frame_exceeding_pos_threshold"] is not None
|
|
243
|
+
or body["summary"]["first_frame_exceeding_rot_threshold"] is not None
|
|
244
|
+
for body in result["bodies"].values()
|
|
245
|
+
)
|
|
246
|
+
if exceeded:
|
|
247
|
+
sys.exit(2)
|
|
248
|
+
|
|
249
|
+
|
|
250
|
+
def run_render(path: Path, args: argparse.Namespace) -> None:
|
|
251
|
+
"""Headlessly render one PNG screenshot of the scene JSON at `path`, for
|
|
252
|
+
generating figures from a display-less environment (e.g. a SLURM job)."""
|
|
253
|
+
from simview.render import render_screenshot
|
|
254
|
+
|
|
255
|
+
if args.output is None:
|
|
256
|
+
logger.error(
|
|
257
|
+
"Error: 'simview render' requires --output, e.g. 'simview render "
|
|
258
|
+
"scene.json --output frame.png'."
|
|
259
|
+
)
|
|
260
|
+
sys.exit(1)
|
|
261
|
+
|
|
262
|
+
try:
|
|
263
|
+
render_screenshot(
|
|
264
|
+
path,
|
|
265
|
+
args.output,
|
|
266
|
+
host=args.host,
|
|
267
|
+
port=args.port,
|
|
268
|
+
view=args.view,
|
|
269
|
+
width=args.width,
|
|
270
|
+
height=args.height,
|
|
271
|
+
)
|
|
272
|
+
except ImportError as e:
|
|
273
|
+
logger.error("Error: %s", e)
|
|
274
|
+
sys.exit(1)
|
|
275
|
+
except (RuntimeError, TimeoutError) as e:
|
|
276
|
+
logger.error("Error: 'simview render' failed: %s", e)
|
|
277
|
+
sys.exit(1)
|
|
278
|
+
|
|
195
279
|
|
|
196
280
|
def save_merged(paths: list[Path], out_path: Path) -> None:
|
|
197
281
|
"""Merge `paths` (must be >= 2) and write the result to `out_path`, gzipped
|
|
@@ -218,11 +302,13 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
218
302
|
help=(
|
|
219
303
|
"Path(s) to simulation JSON file(s) to visualize, 'clear' to clear "
|
|
220
304
|
"cache, 'info <file>' to print a structural summary of one scene "
|
|
221
|
-
"file, 'terrain <file>' to query terrain values at a point
|
|
222
|
-
"an area, or 'diff <file>' to compare
|
|
223
|
-
"
|
|
224
|
-
"
|
|
225
|
-
"
|
|
305
|
+
"file, 'terrain <file>' to query terrain values at a point, over "
|
|
306
|
+
"an area, or along a body's trajectory, 'diff <file>' to compare "
|
|
307
|
+
"two batches' trajectories, or 'render <file>' to headlessly save "
|
|
308
|
+
"a PNG screenshot (needs the 'render' extra). Multiple "
|
|
309
|
+
"visualize-mode files are merged into one scene, each file's "
|
|
310
|
+
"batches appended as extra batches (e.g. a real-world recording "
|
|
311
|
+
"plus a simulated rerun)."
|
|
226
312
|
),
|
|
227
313
|
)
|
|
228
314
|
parser.add_argument(
|
|
@@ -255,7 +341,7 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
255
341
|
help=(
|
|
256
342
|
"With 'simview terrain <file>', query terrain value(s) at a single "
|
|
257
343
|
"(x, y) point (bilinear-interpolated). Mutually exclusive with "
|
|
258
|
-
"--area."
|
|
344
|
+
"--area and --along-body."
|
|
259
345
|
),
|
|
260
346
|
)
|
|
261
347
|
parser.add_argument(
|
|
@@ -267,7 +353,23 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
267
353
|
"With 'simview terrain <file>', query terrain values over a "
|
|
268
354
|
"rectangular area: pass no values for the whole terrain extent, "
|
|
269
355
|
"or exactly 4 values 'XMIN XMAX YMIN YMAX' for a sub-box. Mutually "
|
|
270
|
-
"exclusive with --point."
|
|
356
|
+
"exclusive with --point and --along-body."
|
|
357
|
+
),
|
|
358
|
+
)
|
|
359
|
+
parser.add_argument(
|
|
360
|
+
"--along-body",
|
|
361
|
+
type=str,
|
|
362
|
+
default=None,
|
|
363
|
+
metavar="BODY",
|
|
364
|
+
help=(
|
|
365
|
+
"With 'simview terrain <file>', sample terrain value(s) "
|
|
366
|
+
"bilinear-interpolated at BODY's (x, y) position in every "
|
|
367
|
+
"sampled state (e.g. friction/stiffness under a robot's driven "
|
|
368
|
+
"path). BODY is matched the same way as 'simview diff' --body "
|
|
369
|
+
"(full label, or any single name inside a rigidly-grouped body). "
|
|
370
|
+
"With --batches A B, samples both batches' terrains along batch "
|
|
371
|
+
"A's trajectory instead and reports the delta per layer. "
|
|
372
|
+
"Mutually exclusive with --point and --area."
|
|
271
373
|
),
|
|
272
374
|
)
|
|
273
375
|
parser.add_argument(
|
|
@@ -301,10 +403,11 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
301
403
|
metavar=("A", "B"),
|
|
302
404
|
help=(
|
|
303
405
|
"Two batch indices to compare. Required by 'simview diff <file>'. "
|
|
304
|
-
"With 'simview terrain <file> --point|--area',
|
|
305
|
-
"cross-batch diff mode (value_a/value_b/delta per
|
|
306
|
-
"of a single-batch query, and takes precedence
|
|
307
|
-
"both are given."
|
|
406
|
+
"With 'simview terrain <file> --point|--area|--along-body', "
|
|
407
|
+
"switches into cross-batch diff mode (value_a/value_b/delta per "
|
|
408
|
+
"layer) instead of a single-batch query, and takes precedence "
|
|
409
|
+
"over --batch if both are given. For --along-body, both batches' "
|
|
410
|
+
"terrains are sampled along batch A's trajectory."
|
|
308
411
|
),
|
|
309
412
|
)
|
|
310
413
|
parser.add_argument(
|
|
@@ -323,7 +426,10 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
323
426
|
"--every",
|
|
324
427
|
type=int,
|
|
325
428
|
default=1,
|
|
326
|
-
help=
|
|
429
|
+
help=(
|
|
430
|
+
"With 'simview diff <file>' or 'simview terrain <file> "
|
|
431
|
+
"--along-body', sample every Nth frame (default: 1)."
|
|
432
|
+
),
|
|
327
433
|
)
|
|
328
434
|
parser.add_argument(
|
|
329
435
|
"--pos-threshold",
|
|
@@ -345,6 +451,27 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
345
451
|
"orientation error exceeds this many degrees."
|
|
346
452
|
),
|
|
347
453
|
)
|
|
454
|
+
parser.add_argument(
|
|
455
|
+
"--per-axis",
|
|
456
|
+
action="store_true",
|
|
457
|
+
help=(
|
|
458
|
+
"With 'simview diff <file>', also report signed per-axis "
|
|
459
|
+
"(err_x/err_y/err_z = batch_a - batch_b) position error, matching "
|
|
460
|
+
"the browser Error Metrics panel's per-axis toggle."
|
|
461
|
+
),
|
|
462
|
+
)
|
|
463
|
+
parser.add_argument(
|
|
464
|
+
"--fail-on-exceed",
|
|
465
|
+
action="store_true",
|
|
466
|
+
help=(
|
|
467
|
+
"With 'simview diff <file>', exit with code 2 (after printing the "
|
|
468
|
+
"normal output) if any diffed body's trajectory exceeds "
|
|
469
|
+
"--pos-threshold or --rot-threshold-deg; requires at least one of "
|
|
470
|
+
"them. Exit codes: 0 = within thresholds, 1 = usage/parse error, "
|
|
471
|
+
"2 = threshold exceeded -- lets scripts/CI tell divergence apart "
|
|
472
|
+
"from a broken invocation."
|
|
473
|
+
),
|
|
474
|
+
)
|
|
348
475
|
parser.add_argument(
|
|
349
476
|
"--host",
|
|
350
477
|
type=str,
|
|
@@ -365,6 +492,37 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
365
492
|
action="store_true",
|
|
366
493
|
help="Don't automatically open a browser tab once the server starts.",
|
|
367
494
|
)
|
|
495
|
+
parser.add_argument(
|
|
496
|
+
"--output",
|
|
497
|
+
type=str,
|
|
498
|
+
default=None,
|
|
499
|
+
metavar="PATH",
|
|
500
|
+
help="With 'simview render <file>', PNG file path to save the screenshot to.",
|
|
501
|
+
)
|
|
502
|
+
parser.add_argument(
|
|
503
|
+
"--view",
|
|
504
|
+
type=str,
|
|
505
|
+
default=None,
|
|
506
|
+
metavar="HASH",
|
|
507
|
+
help=(
|
|
508
|
+
"With 'simview render <file>', a shareable view-link hash (from "
|
|
509
|
+
"the viewer's 'Copy view link' button, with or without the "
|
|
510
|
+
"leading '#') to set the camera/playback/terrain state before "
|
|
511
|
+
"capturing. Default: the viewer's startup state."
|
|
512
|
+
),
|
|
513
|
+
)
|
|
514
|
+
parser.add_argument(
|
|
515
|
+
"--width",
|
|
516
|
+
type=int,
|
|
517
|
+
default=1280,
|
|
518
|
+
help="With 'simview render <file>', screenshot width in pixels (default: 1280).",
|
|
519
|
+
)
|
|
520
|
+
parser.add_argument(
|
|
521
|
+
"--height",
|
|
522
|
+
type=int,
|
|
523
|
+
default=720,
|
|
524
|
+
help="With 'simview render <file>', screenshot height in pixels (default: 720).",
|
|
525
|
+
)
|
|
368
526
|
parser.add_argument(
|
|
369
527
|
"--save-merged",
|
|
370
528
|
type=str,
|
|
@@ -437,6 +595,21 @@ def main():
|
|
|
437
595
|
run_diff(diff_path, args)
|
|
438
596
|
return
|
|
439
597
|
|
|
598
|
+
if args.inputs and args.inputs[0] == "render":
|
|
599
|
+
render_args = args.inputs[1:]
|
|
600
|
+
if len(render_args) != 1:
|
|
601
|
+
logger.error(
|
|
602
|
+
"Error: 'simview render' requires exactly one file argument, "
|
|
603
|
+
"e.g. 'simview render scene.json --output frame.png'."
|
|
604
|
+
)
|
|
605
|
+
sys.exit(1)
|
|
606
|
+
render_path = Path(render_args[0])
|
|
607
|
+
if not (render_path.exists() and render_path.is_file()):
|
|
608
|
+
logger.error("Error: File '%s' not found or is not a file.", render_path)
|
|
609
|
+
sys.exit(1)
|
|
610
|
+
run_render(render_path, args)
|
|
611
|
+
return
|
|
612
|
+
|
|
440
613
|
if args.inputs == ["clear"]:
|
|
441
614
|
clear_cache()
|
|
442
615
|
return
|