simview 3.4__tar.gz → 3.5__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.
Files changed (193) hide show
  1. simview-3.5/PKG-INFO +136 -0
  2. simview-3.5/README.md +103 -0
  3. {simview-3.4 → simview-3.5}/pyproject.toml +7 -2
  4. {simview-3.4 → simview-3.5}/simview/__main__.py +91 -4
  5. {simview-3.4 → simview-3.5}/simview/diff.py +58 -24
  6. simview-3.5/simview/render.py +141 -0
  7. {simview-3.4 → simview-3.5}/simview/static/js/components/InteractionController.js +77 -6
  8. {simview-3.4 → simview-3.5}/simview/static/js/objects/Terrain.js +123 -11
  9. {simview-3.4 → simview-3.5}/simview/static/js/ui/Controls.js +76 -0
  10. {simview-3.4 → simview-3.5}/simview/static/js/ui/ErrorMetrics.js +8 -2
  11. {simview-3.4 → simview-3.5}/simview/static/js/ui/Legend.js +18 -2
  12. simview-3.5/simview/static/js/utils/batchPresets.js +28 -0
  13. {simview-3.4 → simview-3.5}/simview/terrain.py +13 -2
  14. simview-3.5/simview.egg-info/PKG-INFO +136 -0
  15. {simview-3.4 → simview-3.5}/simview.egg-info/SOURCES.txt +2 -0
  16. {simview-3.4 → simview-3.5}/simview.egg-info/requires.txt +3 -0
  17. {simview-3.4 → simview-3.5}/tests/test_cli.py +118 -0
  18. {simview-3.4 → simview-3.5}/tests/test_diff.py +55 -0
  19. {simview-3.4 → simview-3.5}/tests/test_terrain_query.py +33 -0
  20. simview-3.4/PKG-INFO +0 -626
  21. simview-3.4/README.md +0 -595
  22. simview-3.4/simview.egg-info/PKG-INFO +0 -626
  23. {simview-3.4 → simview-3.5}/LICENSE +0 -0
  24. {simview-3.4 → simview-3.5}/MANIFEST.in +0 -0
  25. {simview-3.4 → simview-3.5}/setup.cfg +0 -0
  26. {simview-3.4 → simview-3.5}/simview/__init__.py +0 -0
  27. {simview-3.4 → simview-3.5}/simview/info.py +0 -0
  28. {simview-3.4 → simview-3.5}/simview/launcher.py +0 -0
  29. {simview-3.4 → simview-3.5}/simview/live.py +0 -0
  30. {simview-3.4 → simview-3.5}/simview/merge.py +0 -0
  31. {simview-3.4 → simview-3.5}/simview/model.py +0 -0
  32. {simview-3.4 → simview-3.5}/simview/py.typed +0 -0
  33. {simview-3.4 → simview-3.5}/simview/scene.py +0 -0
  34. {simview-3.4 → simview-3.5}/simview/server.py +0 -0
  35. {simview-3.4 → simview-3.5}/simview/state.py +0 -0
  36. {simview-3.4 → simview-3.5}/simview/static/css/controls.css +0 -0
  37. {simview-3.4 → simview-3.5}/simview/static/js/SimView.js +0 -0
  38. {simview-3.4 → simview-3.5}/simview/static/js/components/AnimationController.js +0 -0
  39. {simview-3.4 → simview-3.5}/simview/static/js/components/BatchManager.js +0 -0
  40. {simview-3.4 → simview-3.5}/simview/static/js/components/InteractionControls.js +0 -0
  41. {simview-3.4 → simview-3.5}/simview/static/js/components/Scene.js +0 -0
  42. {simview-3.4 → simview-3.5}/simview/static/js/components/StateStore.js +0 -0
  43. {simview-3.4 → simview-3.5}/simview/static/js/config.js +0 -0
  44. {simview-3.4 → simview-3.5}/simview/static/js/main.js +0 -0
  45. {simview-3.4 → simview-3.5}/simview/static/js/objects/Body.js +0 -0
  46. {simview-3.4 → simview-3.5}/simview/static/js/objects/StaticObject.js +0 -0
  47. {simview-3.4 → simview-3.5}/simview/static/js/objects/utils.js +0 -0
  48. {simview-3.4 → simview-3.5}/simview/static/js/ui/AnalysisPanel.js +0 -0
  49. {simview-3.4 → simview-3.5}/simview/static/js/ui/BatchLegend.js +0 -0
  50. {simview-3.4 → simview-3.5}/simview/static/js/ui/BodyStateWindow.js +0 -0
  51. {simview-3.4 → simview-3.5}/simview/static/js/ui/PlaybackControls.js +0 -0
  52. {simview-3.4 → simview-3.5}/simview/static/js/ui/ScalarPlotter.js +0 -0
  53. {simview-3.4 → simview-3.5}/simview/static/js/utils/blobCodec.js +0 -0
  54. {simview-3.4 → simview-3.5}/simview/static/js/utils/bodyTransforms.js +0 -0
  55. {simview-3.4 → simview-3.5}/simview/static/js/utils/csv.js +0 -0
  56. {simview-3.4 → simview-3.5}/simview/static/js/utils/errorMath.js +0 -0
  57. {simview-3.4 → simview-3.5}/simview/static/js/utils/injectStyles.js +0 -0
  58. {simview-3.4 → simview-3.5}/simview/static/js/utils/interpolate.js +0 -0
  59. {simview-3.4 → simview-3.5}/simview/static/js/utils/liveFollow.js +0 -0
  60. {simview-3.4 → simview-3.5}/simview/static/js/utils/loadRecordingLibs.js +0 -0
  61. {simview-3.4 → simview-3.5}/simview/static/js/utils/viewState.js +0 -0
  62. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/index.min.js +0 -0
  63. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/Color.js +0 -0
  64. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/chroma.js +0 -0
  65. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/colors/colorbrewer.js +0 -0
  66. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/colors/w3cx11.js +0 -0
  67. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/generator/average.js +0 -0
  68. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/generator/bezier.js +0 -0
  69. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/generator/blend.js +0 -0
  70. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/generator/cubehelix.js +0 -0
  71. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/generator/mix.js +0 -0
  72. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/generator/random.js +0 -0
  73. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/generator/scale.js +0 -0
  74. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/interpolator/_hsx.js +0 -0
  75. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/interpolator/hcg.js +0 -0
  76. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/interpolator/hsi.js +0 -0
  77. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/interpolator/hsl.js +0 -0
  78. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/interpolator/hsv.js +0 -0
  79. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/interpolator/index.js +0 -0
  80. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/interpolator/lab.js +0 -0
  81. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/interpolator/lch.js +0 -0
  82. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/interpolator/lrgb.js +0 -0
  83. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/interpolator/num.js +0 -0
  84. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/interpolator/oklab.js +0 -0
  85. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/interpolator/oklch.js +0 -0
  86. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/interpolator/rgb.js +0 -0
  87. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/cmyk/cmyk2rgb.js +0 -0
  88. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/cmyk/index.js +0 -0
  89. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/cmyk/rgb2cmyk.js +0 -0
  90. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/css/css2rgb.js +0 -0
  91. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/css/hsl2css.js +0 -0
  92. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/css/index.js +0 -0
  93. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/css/lab2css.js +0 -0
  94. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/css/lch2css.js +0 -0
  95. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/css/oklab2css.js +0 -0
  96. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/css/oklch2css.js +0 -0
  97. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/css/rgb2css.js +0 -0
  98. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/gl/index.js +0 -0
  99. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/hcg/hcg2rgb.js +0 -0
  100. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/hcg/index.js +0 -0
  101. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/hcg/rgb2hcg.js +0 -0
  102. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/hex/hex2rgb.js +0 -0
  103. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/hex/index.js +0 -0
  104. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/hex/rgb2hex.js +0 -0
  105. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/hsi/hsi2rgb.js +0 -0
  106. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/hsi/index.js +0 -0
  107. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/hsi/rgb2hsi.js +0 -0
  108. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/hsl/hsl2rgb.js +0 -0
  109. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/hsl/index.js +0 -0
  110. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/hsl/rgb2hsl.js +0 -0
  111. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/hsv/hsv2rgb.js +0 -0
  112. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/hsv/index.js +0 -0
  113. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/hsv/rgb2hsv.js +0 -0
  114. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/input.js +0 -0
  115. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/lab/index.js +0 -0
  116. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/lab/lab-constants.js +0 -0
  117. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/lab/lab2rgb.js +0 -0
  118. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/lab/rgb2lab.js +0 -0
  119. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/lch/hcl2rgb.js +0 -0
  120. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/lch/index.js +0 -0
  121. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/lch/lab2lch.js +0 -0
  122. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/lch/lch2lab.js +0 -0
  123. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/lch/lch2rgb.js +0 -0
  124. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/lch/rgb2lch.js +0 -0
  125. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/named/index.js +0 -0
  126. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/num/index.js +0 -0
  127. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/num/num2rgb.js +0 -0
  128. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/num/rgb2num.js +0 -0
  129. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/oklab/index.js +0 -0
  130. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/oklab/oklab2rgb.js +0 -0
  131. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/oklab/rgb2oklab.js +0 -0
  132. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/oklch/index.js +0 -0
  133. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/oklch/oklch2rgb.js +0 -0
  134. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/oklch/rgb2oklch.js +0 -0
  135. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/rgb/index.js +0 -0
  136. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/temp/index.js +0 -0
  137. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/temp/rgb2temperature.js +0 -0
  138. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/io/temp/temperature2rgb.js +0 -0
  139. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/ops/alpha.js +0 -0
  140. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/ops/clipped.js +0 -0
  141. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/ops/darken.js +0 -0
  142. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/ops/get.js +0 -0
  143. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/ops/luminance.js +0 -0
  144. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/ops/mix.js +0 -0
  145. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/ops/premultiply.js +0 -0
  146. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/ops/saturate.js +0 -0
  147. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/ops/set.js +0 -0
  148. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/ops/shade.js +0 -0
  149. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/utils/analyze.js +0 -0
  150. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/utils/clip_rgb.js +0 -0
  151. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/utils/contrast.js +0 -0
  152. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/utils/contrastAPCA.js +0 -0
  153. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/utils/delta-e.js +0 -0
  154. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/utils/distance.js +0 -0
  155. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/utils/index.js +0 -0
  156. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/utils/last.js +0 -0
  157. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/utils/limit.js +0 -0
  158. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/utils/multiply-matrices.js +0 -0
  159. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/utils/scales.js +0 -0
  160. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/utils/type.js +0 -0
  161. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/utils/unpack.js +0 -0
  162. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/utils/valid.js +0 -0
  163. {simview-3.4 → simview-3.5}/simview/static/lib/chroma-js-3.1.2/src/version.js +0 -0
  164. {simview-3.4 → simview-3.5}/simview/static/lib/download.js +0 -0
  165. {simview-3.4 → simview-3.5}/simview/static/lib/js-colormaps.js +0 -0
  166. {simview-3.4 → simview-3.5}/simview/static/lib/tar.js +0 -0
  167. {simview-3.4 → simview-3.5}/simview/static/lib/three-0.174.0/addons/controls/OrbitControls.js +0 -0
  168. {simview-3.4 → simview-3.5}/simview/static/lib/three-0.174.0/addons/libs/lil-gui.module.min.js +0 -0
  169. {simview-3.4 → simview-3.5}/simview/static/lib/three-0.174.0/three.core.js +0 -0
  170. {simview-3.4 → simview-3.5}/simview/static/lib/three-0.174.0/three.module.js +0 -0
  171. {simview-3.4 → simview-3.5}/simview/static/lib/uPlot.esm.js +0 -0
  172. {simview-3.4 → simview-3.5}/simview/static/lib/uPlot.min.css +0 -0
  173. {simview-3.4 → simview-3.5}/simview/static/textures/contacts/red-cross0.png +0 -0
  174. {simview-3.4 → simview-3.5}/simview/static/textures/points/ball0.png +0 -0
  175. {simview-3.4 → simview-3.5}/simview/static/textures/points/ball1.png +0 -0
  176. {simview-3.4 → simview-3.5}/simview/templates/index.html +0 -0
  177. {simview-3.4 → simview-3.5}/simview/utils.py +0 -0
  178. {simview-3.4 → simview-3.5}/simview.egg-info/dependency_links.txt +0 -0
  179. {simview-3.4 → simview-3.5}/simview.egg-info/entry_points.txt +0 -0
  180. {simview-3.4 → simview-3.5}/simview.egg-info/top_level.txt +0 -0
  181. {simview-3.4 → simview-3.5}/tests/test_columnar_states.py +0 -0
  182. {simview-3.4 → simview-3.5}/tests/test_contacts.py +0 -0
  183. {simview-3.4 → simview-3.5}/tests/test_info.py +0 -0
  184. {simview-3.4 → simview-3.5}/tests/test_launcher.py +0 -0
  185. {simview-3.4 → simview-3.5}/tests/test_live.py +0 -0
  186. {simview-3.4 → simview-3.5}/tests/test_merge.py +0 -0
  187. {simview-3.4 → simview-3.5}/tests/test_roundtrip.py +0 -0
  188. {simview-3.4 → simview-3.5}/tests/test_scene.py +0 -0
  189. {simview-3.4 → simview-3.5}/tests/test_server.py +0 -0
  190. {simview-3.4 → simview-3.5}/tests/test_show.py +0 -0
  191. {simview-3.4 → simview-3.5}/tests/test_terrain.py +0 -0
  192. {simview-3.4 → simview-3.5}/tests/test_trajectory.py +0 -0
  193. {simview-3.4 → simview-3.5}/tests/test_utils.py +0 -0
simview-3.5/PKG-INFO ADDED
@@ -0,0 +1,136 @@
1
+ Metadata-Version: 2.4
2
+ Name: simview
3
+ Version: 3.5
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
+ [![Documentation](https://img.shields.io/badge/docs-GitHub%20Pages-blue.svg)](https://vlk-jan.github.io/simview/)
37
+ [![Live Demo](https://img.shields.io/badge/demo-live-brightgreen.svg)](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.5/README.md ADDED
@@ -0,0 +1,103 @@
1
+ # SimView Visualizer
2
+
3
+ [![Documentation](https://img.shields.io/badge/docs-GitHub%20Pages-blue.svg)](https://vlk-jan.github.io/simview/)
4
+ [![Live Demo](https://img.shields.io/badge/demo-live-brightgreen.svg)](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.4"
7
+ version = "3.5"
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://github.com/vlk-jan/simview"
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"
@@ -178,6 +178,7 @@ def run_diff(path: Path, args: argparse.Namespace) -> None:
178
178
  every=args.every,
179
179
  pos_threshold=args.pos_threshold,
180
180
  rot_threshold_deg=args.rot_threshold_deg,
181
+ per_axis=args.per_axis,
181
182
  )
182
183
  text = diff_mod.format_diff_text(result)
183
184
  csv_text = diff_mod.format_diff_csv(result)
@@ -193,6 +194,36 @@ def run_diff(path: Path, args: argparse.Namespace) -> None:
193
194
  print(text)
194
195
 
195
196
 
197
+ def run_render(path: Path, args: argparse.Namespace) -> None:
198
+ """Headlessly render one PNG screenshot of the scene JSON at `path`, for
199
+ generating figures from a display-less environment (e.g. a SLURM job)."""
200
+ from simview.render import render_screenshot
201
+
202
+ if args.output is None:
203
+ logger.error(
204
+ "Error: 'simview render' requires --output, e.g. 'simview render "
205
+ "scene.json --output frame.png'."
206
+ )
207
+ sys.exit(1)
208
+
209
+ try:
210
+ render_screenshot(
211
+ path,
212
+ args.output,
213
+ host=args.host,
214
+ port=args.port,
215
+ view=args.view,
216
+ width=args.width,
217
+ height=args.height,
218
+ )
219
+ except ImportError as e:
220
+ logger.error("Error: %s", e)
221
+ sys.exit(1)
222
+ except (RuntimeError, TimeoutError) as e:
223
+ logger.error("Error: 'simview render' failed: %s", e)
224
+ sys.exit(1)
225
+
226
+
196
227
  def save_merged(paths: list[Path], out_path: Path) -> None:
197
228
  """Merge `paths` (must be >= 2) and write the result to `out_path`, gzipped
198
229
  if it ends in .gz, without starting the server."""
@@ -219,10 +250,11 @@ def build_parser() -> argparse.ArgumentParser:
219
250
  "Path(s) to simulation JSON file(s) to visualize, 'clear' to clear "
220
251
  "cache, 'info <file>' to print a structural summary of one scene "
221
252
  "file, 'terrain <file>' to query terrain values at a point or over "
222
- "an area, or 'diff <file>' to compare two batches' trajectories. "
223
- "Multiple visualize-mode files are merged into one scene, each "
224
- "file's batches appended as extra batches (e.g. a real-world "
225
- "recording plus a simulated rerun)."
253
+ "an area, 'diff <file>' to compare two batches' trajectories, or "
254
+ "'render <file>' to headlessly save a PNG screenshot (needs the "
255
+ "'render' extra). Multiple visualize-mode files are merged into "
256
+ "one scene, each file's batches appended as extra batches (e.g. a "
257
+ "real-world recording plus a simulated rerun)."
226
258
  ),
227
259
  )
228
260
  parser.add_argument(
@@ -345,6 +377,15 @@ def build_parser() -> argparse.ArgumentParser:
345
377
  "orientation error exceeds this many degrees."
346
378
  ),
347
379
  )
380
+ parser.add_argument(
381
+ "--per-axis",
382
+ action="store_true",
383
+ help=(
384
+ "With 'simview diff <file>', also report signed per-axis "
385
+ "(err_x/err_y/err_z = batch_a - batch_b) position error, matching "
386
+ "the browser Error Metrics panel's per-axis toggle."
387
+ ),
388
+ )
348
389
  parser.add_argument(
349
390
  "--host",
350
391
  type=str,
@@ -365,6 +406,37 @@ def build_parser() -> argparse.ArgumentParser:
365
406
  action="store_true",
366
407
  help="Don't automatically open a browser tab once the server starts.",
367
408
  )
409
+ parser.add_argument(
410
+ "--output",
411
+ type=str,
412
+ default=None,
413
+ metavar="PATH",
414
+ help="With 'simview render <file>', PNG file path to save the screenshot to.",
415
+ )
416
+ parser.add_argument(
417
+ "--view",
418
+ type=str,
419
+ default=None,
420
+ metavar="HASH",
421
+ help=(
422
+ "With 'simview render <file>', a shareable view-link hash (from "
423
+ "the viewer's 'Copy view link' button, with or without the "
424
+ "leading '#') to set the camera/playback/terrain state before "
425
+ "capturing. Default: the viewer's startup state."
426
+ ),
427
+ )
428
+ parser.add_argument(
429
+ "--width",
430
+ type=int,
431
+ default=1280,
432
+ help="With 'simview render <file>', screenshot width in pixels (default: 1280).",
433
+ )
434
+ parser.add_argument(
435
+ "--height",
436
+ type=int,
437
+ default=720,
438
+ help="With 'simview render <file>', screenshot height in pixels (default: 720).",
439
+ )
368
440
  parser.add_argument(
369
441
  "--save-merged",
370
442
  type=str,
@@ -437,6 +509,21 @@ def main():
437
509
  run_diff(diff_path, args)
438
510
  return
439
511
 
512
+ if args.inputs and args.inputs[0] == "render":
513
+ render_args = args.inputs[1:]
514
+ if len(render_args) != 1:
515
+ logger.error(
516
+ "Error: 'simview render' requires exactly one file argument, "
517
+ "e.g. 'simview render scene.json --output frame.png'."
518
+ )
519
+ sys.exit(1)
520
+ render_path = Path(render_args[0])
521
+ if not (render_path.exists() and render_path.is_file()):
522
+ logger.error("Error: File '%s' not found or is not a file.", render_path)
523
+ sys.exit(1)
524
+ run_render(render_path, args)
525
+ return
526
+
440
527
  if args.inputs == ["clear"]:
441
528
  clear_cache()
442
529
  return
@@ -180,19 +180,25 @@ def compute_trajectory_diff(
180
180
  every: int = 1,
181
181
  pos_threshold: float | None = None,
182
182
  rot_threshold_deg: float | None = None,
183
+ per_axis: bool = False,
183
184
  ) -> dict:
184
185
  """Per-frame positional/orientation divergence between batch `batch_a`
185
186
  and batch `batch_b`'s trajectories in `states_data`, for every body
186
187
  present in the states (or just `body` if given).
187
188
 
188
189
  Returns a JSON-serializable dict: `{"batch_a", "batch_b", "every",
189
- "pos_threshold", "rot_threshold_deg", "bodies": {label: {"frame_indices",
190
- "times", "position_error", "orientation_error_deg", "summary": {
191
- "frame_count", "position_error": {"mean","max","final"},
190
+ "pos_threshold", "rot_threshold_deg", "per_axis", "bodies": {label:
191
+ {"frame_indices", "times", "position_error", "orientation_error_deg",
192
+ "summary": {"frame_count", "position_error": {"mean","max","final"},
192
193
  "orientation_error_deg": {...}, "first_frame_exceeding_pos_threshold",
193
- "first_frame_exceeding_rot_threshold"}}}}`. Raises `ValueError` on
194
- invalid batch indices, `every < 1`, an unmatched/ambiguous `body`, or a
195
- scene with no diffable bodies.
194
+ "first_frame_exceeding_rot_threshold"}}}}`. When `per_axis` is set, each
195
+ body also gets `"err_x"`/`"err_y"`/`"err_z"` per-frame series (signed
196
+ `batch_a - batch_b`, matching the browser Error Metrics panel's
197
+ per-axis toggle -- see `static/js/utils/errorMath.js`'s
198
+ `positionAxisError`) and matching `"err_x"`/`"err_y"`/`"err_z"` entries
199
+ in `summary` (mean/max/final of the *signed* value, so directional bias
200
+ is visible). Raises `ValueError` on invalid batch indices, `every < 1`,
201
+ an unmatched/ambiguous `body`, or a scene with no diffable bodies.
196
202
  """
197
203
  batch_size = _resolve_batches(model_data, batch_a, batch_b)
198
204
  if every < 1:
@@ -223,6 +229,9 @@ def compute_trajectory_diff(
223
229
  times: list = []
224
230
  position_error: list[float] = []
225
231
  orientation_error_deg: list[float] = []
232
+ err_x: list[float] = []
233
+ err_y: list[float] = []
234
+ err_z: list[float] = []
226
235
 
227
236
  for idx, state in enumerate(states_data):
228
237
  if idx % every != 0:
@@ -245,24 +254,36 @@ def compute_trajectory_diff(
245
254
  times.append(state.get("time"))
246
255
  position_error.append(math.dist(row_a[:3], row_b[:3]))
247
256
  orientation_error_deg.append(_quat_angle_deg(row_a[3:], row_b[3:]))
248
-
257
+ if per_axis:
258
+ err_x.append(row_a[0] - row_b[0])
259
+ err_y.append(row_a[1] - row_b[1])
260
+ err_z.append(row_a[2] - row_b[2])
261
+
262
+ summary = {
263
+ "frame_count": len(frame_indices),
264
+ "position_error": _stats(position_error),
265
+ "orientation_error_deg": _stats(orientation_error_deg),
266
+ "first_frame_exceeding_pos_threshold": _first_exceeding(
267
+ frame_indices, position_error, pos_threshold
268
+ ),
269
+ "first_frame_exceeding_rot_threshold": _first_exceeding(
270
+ frame_indices, orientation_error_deg, rot_threshold_deg
271
+ ),
272
+ }
249
273
  bodies_out[label] = {
250
274
  "frame_indices": frame_indices,
251
275
  "times": times,
252
276
  "position_error": position_error,
253
277
  "orientation_error_deg": orientation_error_deg,
254
- "summary": {
255
- "frame_count": len(frame_indices),
256
- "position_error": _stats(position_error),
257
- "orientation_error_deg": _stats(orientation_error_deg),
258
- "first_frame_exceeding_pos_threshold": _first_exceeding(
259
- frame_indices, position_error, pos_threshold
260
- ),
261
- "first_frame_exceeding_rot_threshold": _first_exceeding(
262
- frame_indices, orientation_error_deg, rot_threshold_deg
263
- ),
264
- },
278
+ "summary": summary,
265
279
  }
280
+ if per_axis:
281
+ bodies_out[label]["err_x"] = err_x
282
+ bodies_out[label]["err_y"] = err_y
283
+ bodies_out[label]["err_z"] = err_z
284
+ summary["err_x"] = _stats(err_x)
285
+ summary["err_y"] = _stats(err_y)
286
+ summary["err_z"] = _stats(err_z)
266
287
 
267
288
  return {
268
289
  "batch_a": batch_a,
@@ -270,6 +291,7 @@ def compute_trajectory_diff(
270
291
  "every": every,
271
292
  "pos_threshold": pos_threshold,
272
293
  "rot_threshold_deg": rot_threshold_deg,
294
+ "per_axis": per_axis,
273
295
  "bodies": bodies_out,
274
296
  }
275
297
 
@@ -306,6 +328,13 @@ def format_diff_text(result: dict) -> str:
306
328
  f" rot_err (deg): mean={rot['mean']:.6g} max={rot['max']:.6g} "
307
329
  f"final={rot['final']:.6g}"
308
330
  )
331
+ if result.get("per_axis"):
332
+ for axis in ("err_x", "err_y", "err_z"):
333
+ a = summary[axis]
334
+ lines.append(
335
+ f" {axis} (m): mean={a['mean']:.6g} max={a['max']:.6g} "
336
+ f"final={a['final']:.6g}"
337
+ )
309
338
  if summary["first_frame_exceeding_pos_threshold"] is not None:
310
339
  lines.append(
311
340
  " first frame exceeding pos_threshold: "
@@ -344,17 +373,22 @@ def format_diff_csv(result: dict) -> str:
344
373
  (body, frame), full series (no truncation) -- CSV output is for scripts,
345
374
  matching the "just the numbers, in full" philosophy `--json` already
346
375
  uses everywhere in this CLI."""
376
+ per_axis = result.get("per_axis")
347
377
  buf = io.StringIO()
348
378
  writer = csv.writer(buf)
349
- writer.writerow(
350
- ["body", "frame", "time", "position_error", "orientation_error_deg"]
351
- )
379
+ header = ["body", "frame", "time", "position_error", "orientation_error_deg"]
380
+ if per_axis:
381
+ header += ["err_x", "err_y", "err_z"]
382
+ writer.writerow(header)
352
383
  for label, body in result["bodies"].items():
353
- for frame_idx, t, p, r in zip(
384
+ columns = [
354
385
  body["frame_indices"],
355
386
  body["times"],
356
387
  body["position_error"],
357
388
  body["orientation_error_deg"],
358
- ):
359
- writer.writerow([label, frame_idx, t, p, r])
389
+ ]
390
+ if per_axis:
391
+ columns += [body["err_x"], body["err_y"], body["err_z"]]
392
+ for row in zip(*columns):
393
+ writer.writerow([label, *row])
360
394
  return buf.getvalue()