mujoco-mojo 2.2.0__tar.gz → 2.2.2__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.
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/PKG-INFO +1 -1
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/pyproject.toml +8 -8
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/mesh.py +186 -2
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/geom.py +27 -4
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/filters/filters.py +42 -46
- mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/routers/mosaic.py +488 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/base.html +201 -10
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/monitor.html +8 -8
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/mosaic.html +3 -3
- mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/partials/trial_viewer/_chart.html +1085 -0
- mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/partials/trial_viewer/_header.html +322 -0
- mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/partials/trial_viewer/_json_editor.html +60 -0
- mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/partials/trial_viewer/_overlays.html +83 -0
- mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/partials/trial_viewer/_series_panel.html +1009 -0
- mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/js/__init__.py +0 -0
- mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/js/main.js +277 -0
- mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/js/monitor.js +212 -0
- mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/js/mosaic.js +42 -0
- mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/js/toast.js +4 -0
- mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/js/trial-viewer.js +1388 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/main.css +22 -0
- mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored/__init__.py +0 -0
- mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/trial_viewer.html +55 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/proximity_mixin.py +12 -22
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo.egg-info/PKG-INFO +1 -1
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo.egg-info/SOURCES.txt +18 -6
- mujoco_mojo-2.2.0/src/mujoco_mojo/utils/layers/dojo/routers/mosaic.py +0 -208
- mujoco_mojo-2.2.0/src/mujoco_mojo/utils/layers/dojo/templates/trial_viewer.html +0 -2241
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/LICENSE +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/README.md +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/setup.cfg +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/__about__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/base.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/meta.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/defaults.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/dependency_path.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/extension.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/meta/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/meta/frame.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/meta/include.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/meta/replicate.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/adhesion.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/base.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/cylinder.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/damper.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/dcmotor.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/general.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/intvelocity.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/motor.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/muscle.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/plugin.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/position.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/actuator_attr/velocity.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/hfield.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/material.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/material_attr/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/material_attr/layer.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/model.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/asset_attr/texture.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/attach.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/camera.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/composite.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/composite_attr/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/composite_attr/geom.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/composite_attr/joint.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/composite_attr/site.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/composite_attr/skin.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/flexcomp.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/flexcomp_attr/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/flexcomp_attr/contact.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/flexcomp_attr/edge.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/flexcomp_attr/elasticity.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/flexcomp_attr/pin.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/free_joint.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/inertial.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/joint.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/light.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/plugin.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/body_attr/site.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/compiler.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/compiler_attr/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/compiler_attr/lengthrange.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/contact.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/contact_attr/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/contact_attr/exclude.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/contact_attr/pair.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/flex.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/flex_attr/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/flex_attr/contact.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/flex_attr/edge.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/flex_attr/elasticity.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/skin.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/skin_attr/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/deformable_attr/skin_attr/bone.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/connect.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/equality_base.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/flex.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/flexstrain.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/flexvert.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/joint.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/tendon.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/equality_attr/weld.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/keyframe.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/keyframe_attr/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/keyframe_attr/key.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/option.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/option_attr/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/option_attr/flag.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/accelerometer.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/actuatorfrc.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/actuatorpos.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/actuatorvel.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/ballangvel.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/ballquat.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/base.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/base_collision.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/camprojection.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/clock.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/contact.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/distance.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/e_kinetic.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/e_potential.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/force.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/frameangacc.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/frameangvel.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/framelinacc.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/framelinvel.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/framepos.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/framequat.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/framexaxis.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/frameyaxis.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/framezaxis.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/fromto.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/gyro.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/insidesite.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/jointactuatorfrc.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/jointlimitfrc.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/jointlimitpos.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/jointlimitvel.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/jointpos.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/jointvel.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/magnetometer.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/normal.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/plugin.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/rangefinder.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/subtreeangmom.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/subtreecom.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/subtreelinvel.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/tactile.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/tendonactuatorfrc.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/tendonlimitfrc.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/tendonlimitpos.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/tendonlimitvel.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/tendonpos.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/tendonvel.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/torque.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/touch.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/user.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/sensor_attr/velocimeter.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/size.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/statistic.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/fixed.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/fixed_attr/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/fixed_attr/joint.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/spatial.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/spatial_attr/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/spatial_attr/geom.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/spatial_attr/pulley.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/spatial_attr/site.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/tendon_attr/tendon_base.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual_attr/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual_attr/global_.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual_attr/headlight.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual_attr/map.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual_attr/quality.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual_attr/rgba.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/mujoco_attr/visual_attr/scale.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/orientation.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/plugin.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/pose.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/position.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mjcf/xml_model.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/mojo_model.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/runtime/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/runtime/load.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/runtime/runtime_manager.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/runtime/signal_manager.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/runtime/video_recorder.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/stochas/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/typing.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/color.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/dataframe.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/defaults.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/filters/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/interp.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/cli.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/main.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/routers/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/routers/monitor.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/routers/morph.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/shared.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/error.html +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/morph.html +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/__init__.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/chime.mp3 +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/dark-logo.svg +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/light-logo.svg +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/main.js +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/monitor.js +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/mosaic.js +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/dojo/templates/static/trial-viewer.js +0 -0
- {mujoco_mojo-2.2.0/src/mujoco_mojo/utils/layers/dojo/templates/static → mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored}/alpine.min.js +0 -0
- {mujoco_mojo-2.2.0/src/mujoco_mojo/utils/layers/dojo/templates/static → mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored}/confetti.browser.min.js +0 -0
- {mujoco_mojo-2.2.0/src/mujoco_mojo/utils/layers/dojo/templates/static → mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored}/iro.min.js +0 -0
- {mujoco_mojo-2.2.0/src/mujoco_mojo/utils/layers/dojo/templates/static → mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored}/lz-string.min.js +0 -0
- {mujoco_mojo-2.2.0/src/mujoco_mojo/utils/layers/dojo/templates/static → mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored}/plotly-3.4.0.min.js +0 -0
- {mujoco_mojo-2.2.0/src/mujoco_mojo/utils/layers/dojo/templates/static → mujoco_mojo-2.2.2/src/mujoco_mojo/utils/layers/dojo/templates/static/vendored}/tailwind.min.js +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/layers/reloaded.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/log.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/proximity.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/runner.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/statusing.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/utils/utils.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo/visualization.py +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo.egg-info/dependency_links.txt +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo.egg-info/entry_points.txt +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo.egg-info/requires.txt +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/src/mujoco_mojo.egg-info/top_level.txt +0 -0
- {mujoco_mojo-2.2.0 → mujoco_mojo-2.2.2}/tests/test_writer.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: mujoco-mojo
|
|
3
|
-
Version: 2.2.
|
|
3
|
+
Version: 2.2.2
|
|
4
4
|
Summary: A complete MJCF lifecycle and trial orchestration suite for MuJoCo, powered by Pydantic v2.
|
|
5
5
|
Author-email: David Gable <dave.a.gable@gmail.com>
|
|
6
6
|
Maintainer-email: David Gable <dave.a.gable@gmail.com>
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "mujoco-mojo"
|
|
7
|
-
version = "2.2.
|
|
7
|
+
version = "2.2.2"
|
|
8
8
|
description = "A complete MJCF lifecycle and trial orchestration suite for MuJoCo, powered by Pydantic v2."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.12"
|
|
@@ -68,11 +68,8 @@ keywords = [
|
|
|
68
68
|
"mjcf",
|
|
69
69
|
]
|
|
70
70
|
|
|
71
|
-
[project.
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
[tool.setuptools.package-data]
|
|
75
|
-
"*" = ["*.html", "*.js", "*.mp3", "*.svg", "*.css"]
|
|
71
|
+
[project.optional-dependencies]
|
|
72
|
+
reloaded = ["mjviser>=0.0.11", "viser>=1.0.26"]
|
|
76
73
|
|
|
77
74
|
[dependency-groups]
|
|
78
75
|
dev = [
|
|
@@ -94,8 +91,11 @@ dev = [
|
|
|
94
91
|
"zensical>=0.0.31",
|
|
95
92
|
]
|
|
96
93
|
|
|
97
|
-
[project.
|
|
98
|
-
|
|
94
|
+
[project.scripts]
|
|
95
|
+
mujoco-mojo = "mujoco_mojo.utils.layers.cli:cli_app"
|
|
96
|
+
|
|
97
|
+
[tool.setuptools.package-data]
|
|
98
|
+
"*" = ["*.html", "*.js", "*.mp3", "*.svg", "*.css"]
|
|
99
99
|
|
|
100
100
|
[tool.ruff]
|
|
101
101
|
exclude = ["typings", "scripts/templating/sensor_template.py"]
|
|
@@ -1,10 +1,23 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from pathlib import Path
|
|
4
|
-
from typing import
|
|
4
|
+
from typing import (
|
|
5
|
+
TYPE_CHECKING,
|
|
6
|
+
Annotated,
|
|
7
|
+
Any,
|
|
8
|
+
ClassVar,
|
|
9
|
+
Literal,
|
|
10
|
+
NotRequired,
|
|
11
|
+
Self,
|
|
12
|
+
TypedDict,
|
|
13
|
+
Unpack,
|
|
14
|
+
overload,
|
|
15
|
+
)
|
|
5
16
|
|
|
6
17
|
import mujoco
|
|
7
18
|
import numpy as np
|
|
19
|
+
import trimesh
|
|
20
|
+
import trimesh.visual
|
|
8
21
|
from pydantic import Field, field_validator, model_validator
|
|
9
22
|
|
|
10
23
|
from mujoco_mojo.mjcf.dependency_path import DepPath
|
|
@@ -12,6 +25,8 @@ from mujoco_mojo.mjcf.xml_model import XMLModel
|
|
|
12
25
|
from mujoco_mojo.typing import Inertia, MaterialName, MeshName, Vec3, Vec4
|
|
13
26
|
from mujoco_mojo.utils.log import get_logger
|
|
14
27
|
|
|
28
|
+
if TYPE_CHECKING:
|
|
29
|
+
from trimesh.typed import BooleanEngineType
|
|
15
30
|
logger = get_logger(__name__)
|
|
16
31
|
|
|
17
32
|
__all__ = [
|
|
@@ -29,6 +44,7 @@ _mesh_attr = (
|
|
|
29
44
|
"name",
|
|
30
45
|
"class_",
|
|
31
46
|
"content_type",
|
|
47
|
+
"scale",
|
|
32
48
|
"file",
|
|
33
49
|
"vertex",
|
|
34
50
|
"normal",
|
|
@@ -36,7 +52,6 @@ _mesh_attr = (
|
|
|
36
52
|
"face",
|
|
37
53
|
"refpos",
|
|
38
54
|
"refquat",
|
|
39
|
-
"scale",
|
|
40
55
|
"smoothnormal",
|
|
41
56
|
"maxhullvert",
|
|
42
57
|
"inertia",
|
|
@@ -44,6 +59,24 @@ _mesh_attr = (
|
|
|
44
59
|
)
|
|
45
60
|
|
|
46
61
|
|
|
62
|
+
class MeshAttributes(TypedDict):
|
|
63
|
+
name: NotRequired[MeshName | None]
|
|
64
|
+
class_: NotRequired[str | None]
|
|
65
|
+
content_type: NotRequired[str | None]
|
|
66
|
+
file: NotRequired[DepPath | None]
|
|
67
|
+
scale: NotRequired[Vec3]
|
|
68
|
+
inertia: NotRequired[Inertia]
|
|
69
|
+
smoothnormal: NotRequired[bool]
|
|
70
|
+
maxhullvert: NotRequired[int]
|
|
71
|
+
vertex: NotRequired[tuple[tuple[float, float, float], ...] | None]
|
|
72
|
+
normal: NotRequired[tuple[tuple[float, float, float], ...] | None]
|
|
73
|
+
texcoord: NotRequired[tuple[tuple[float, float], ...] | None]
|
|
74
|
+
face: NotRequired[tuple[tuple[int, int, int], ...] | None]
|
|
75
|
+
refpos: NotRequired[Vec3]
|
|
76
|
+
refquat: NotRequired[Vec4]
|
|
77
|
+
material: NotRequired[MaterialName | None]
|
|
78
|
+
|
|
79
|
+
|
|
47
80
|
class MeshBase(XMLModel):
|
|
48
81
|
"""Base class from which other mesh classes are built from."""
|
|
49
82
|
|
|
@@ -314,6 +347,157 @@ class Mesh(MeshBase):
|
|
|
314
347
|
|
|
315
348
|
builtin: Literal["none"] = "none"
|
|
316
349
|
|
|
350
|
+
@classmethod
|
|
351
|
+
def new_from_trimesh(
|
|
352
|
+
cls,
|
|
353
|
+
mesh: trimesh.Trimesh | trimesh.Scene,
|
|
354
|
+
**kwargs: Unpack[MeshAttributes],
|
|
355
|
+
) -> Self:
|
|
356
|
+
"""
|
|
357
|
+
Creates a Mesh instance from a trimesh object.
|
|
358
|
+
|
|
359
|
+
Automatically extracts vertices, faces, and (if present) normals/texcoords.
|
|
360
|
+
"""
|
|
361
|
+
if isinstance(mesh, trimesh.Scene):
|
|
362
|
+
mesh = mesh.to_mesh()
|
|
363
|
+
|
|
364
|
+
assert isinstance(mesh, trimesh.Trimesh)
|
|
365
|
+
mesh.process(validate=True)
|
|
366
|
+
mesh.fill_holes()
|
|
367
|
+
|
|
368
|
+
# mandatory geometry data
|
|
369
|
+
extracted_data: dict[str, Any] = {
|
|
370
|
+
"vertex": tuple(map(tuple, mesh.vertices.tolist())),
|
|
371
|
+
"face": tuple(map(tuple, mesh.faces.tolist())),
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
# extract normals (if they exist and weren't provided)
|
|
375
|
+
if "normal" not in kwargs:
|
|
376
|
+
# only pull if the count matches
|
|
377
|
+
v_normals = getattr(mesh, "vertex_normals", None)
|
|
378
|
+
if v_normals is not None and len(v_normals) == len(mesh.vertices):
|
|
379
|
+
extracted_data["normal"] = tuple(map(tuple, v_normals.tolist()))
|
|
380
|
+
|
|
381
|
+
# extract texture coordinates (if they exist and weren't provided)
|
|
382
|
+
if "texcoord" not in kwargs:
|
|
383
|
+
if isinstance(mesh.visual, trimesh.visual.TextureVisuals):
|
|
384
|
+
uvs = mesh.visual.uv
|
|
385
|
+
if uvs is not None and len(uvs) == len(mesh.vertices):
|
|
386
|
+
extracted_data["texcoord"] = tuple(map(tuple, uvs.tolist()))
|
|
387
|
+
|
|
388
|
+
# merge kwargs
|
|
389
|
+
final_attrs = {**extracted_data, **kwargs}
|
|
390
|
+
|
|
391
|
+
return cls(**final_attrs)
|
|
392
|
+
|
|
393
|
+
@classmethod
|
|
394
|
+
def new_frustum(
|
|
395
|
+
cls,
|
|
396
|
+
radius_bottom: float,
|
|
397
|
+
radius_top: float,
|
|
398
|
+
height: float,
|
|
399
|
+
sections: int = 32,
|
|
400
|
+
wall_thickness: float = 0.0,
|
|
401
|
+
engine: BooleanEngineType = None,
|
|
402
|
+
base_at_zero: bool = True,
|
|
403
|
+
**kwargs: Unpack[MeshAttributes],
|
|
404
|
+
) -> Self:
|
|
405
|
+
"""
|
|
406
|
+
Generates a conical frustum (tapered cylinder).
|
|
407
|
+
|
|
408
|
+
Args:
|
|
409
|
+
radius_bottom (float): Radius at z = -height/2.
|
|
410
|
+
radius_top (float): Radius at z = +height/2.
|
|
411
|
+
height (float): Total height of the frustum.
|
|
412
|
+
sections (int): Number of radial segments.
|
|
413
|
+
wall_thickness (float): Thickness of the walls (makes a hollow frustum if not equal to zero).
|
|
414
|
+
engine (BooleanEngineType): Which engine to use for boolean subtraction (only used for hollow volumes, reccomended to use "manifold" but requires `manifold3d`).
|
|
415
|
+
base_at_zero (bool): Whether or not to shift the volume so it sits on z=0 instead of underground.
|
|
416
|
+
**kwargs (MeshAttributes): Standard MuJoCo mesh attributes (name, inertia, etc.)
|
|
417
|
+
|
|
418
|
+
Example:
|
|
419
|
+
<img src="https://raw.githubusercontent.com/Hydrowelder/mujoco-mojo/refs/heads/master/docs/assets/mesh/frustums.jpg" width="300" />
|
|
420
|
+
|
|
421
|
+
Two frustums generated using this method. The red frustum has its wall thickness set to 0 and its bottom radius is greater than the top. The cyan frustum has a non-zero wall thickness and a larger top radius than the bottom resulting in a hollow volume. The cyan frustum has more sections than the red.
|
|
422
|
+
|
|
423
|
+
"""
|
|
424
|
+
# create the outer mesh
|
|
425
|
+
mesh = trimesh.creation.cylinder(radius=1.0, height=height, sections=sections)
|
|
426
|
+
|
|
427
|
+
def taper_mesh(m: trimesh.Trimesh, r_b: float, r_t: float) -> None:
|
|
428
|
+
verts = m.vertices.copy()
|
|
429
|
+
# Dynamically find the midpoint of the specific mesh's height extent
|
|
430
|
+
z_ext = m.bounds[:, 2]
|
|
431
|
+
z_mid = (z_ext[1] - z_ext[0]) / 4
|
|
432
|
+
|
|
433
|
+
mask_top = verts[:, 2] > z_mid
|
|
434
|
+
mask_bottom = verts[:, 2] < -z_mid
|
|
435
|
+
|
|
436
|
+
verts[mask_top, :2] *= r_t
|
|
437
|
+
verts[mask_bottom, :2] *= r_b
|
|
438
|
+
m.vertices = verts
|
|
439
|
+
|
|
440
|
+
taper_mesh(mesh, radius_bottom, radius_top)
|
|
441
|
+
|
|
442
|
+
if wall_thickness != 0:
|
|
443
|
+
inner = trimesh.creation.cylinder(
|
|
444
|
+
radius=1.0, height=height + 0.02, sections=sections
|
|
445
|
+
)
|
|
446
|
+
taper_mesh(
|
|
447
|
+
inner, radius_bottom - wall_thickness, radius_top - wall_thickness
|
|
448
|
+
)
|
|
449
|
+
|
|
450
|
+
# perform boolean subtraction to make it hollow
|
|
451
|
+
# Note: This requires the 'manifold' or 'blender' engine installed for trimesh,
|
|
452
|
+
# otherwise it falls back to a simpler but less robust internal boolean.
|
|
453
|
+
mesh = mesh.difference(inner, engine=engine)
|
|
454
|
+
|
|
455
|
+
if base_at_zero:
|
|
456
|
+
mesh.apply_translation([0, 0, height / 2])
|
|
457
|
+
return cls.new_from_trimesh(mesh, **kwargs)
|
|
458
|
+
|
|
459
|
+
@classmethod
|
|
460
|
+
def new_hollow_box(
|
|
461
|
+
cls,
|
|
462
|
+
width: float,
|
|
463
|
+
depth: float,
|
|
464
|
+
height: float,
|
|
465
|
+
wall_thickness: float = 0.02,
|
|
466
|
+
engine: BooleanEngineType = None,
|
|
467
|
+
base_at_zero: bool = True,
|
|
468
|
+
**kwargs: Unpack[MeshAttributes],
|
|
469
|
+
) -> Self:
|
|
470
|
+
"""
|
|
471
|
+
Generates an open-top box with physical wall thickness (concave bin).
|
|
472
|
+
|
|
473
|
+
Args:
|
|
474
|
+
width (float): Total outer dimension along X.
|
|
475
|
+
depth (float): Total outer dimension along Y.
|
|
476
|
+
height (float): Total outer dimension along Z.
|
|
477
|
+
wall_thickness (float): Thickness of the walls and bottom floor.
|
|
478
|
+
engine (BooleanEngineType): Engine to use for boolean subtraction.
|
|
479
|
+
base_at_zero (bool): Shift volume so it sits on z=0 instead of underground.
|
|
480
|
+
**kwargs (MeshAttributes): Standard MuJoCo mesh attributes (name, inertia, etc.)
|
|
481
|
+
|
|
482
|
+
"""
|
|
483
|
+
# outer box centered at (0, 0, 0)
|
|
484
|
+
outer = trimesh.creation.box(extents=(width, depth, height))
|
|
485
|
+
|
|
486
|
+
# inner cutout box
|
|
487
|
+
inner = trimesh.creation.box(
|
|
488
|
+
extents=(width - (2 * wall_thickness), depth - (2 * wall_thickness), height)
|
|
489
|
+
)
|
|
490
|
+
|
|
491
|
+
# shift the inner tool up by the floor thickness
|
|
492
|
+
inner.apply_translation([0, 0, wall_thickness])
|
|
493
|
+
|
|
494
|
+
mesh = outer.difference(inner, engine=engine)
|
|
495
|
+
|
|
496
|
+
if base_at_zero:
|
|
497
|
+
mesh.apply_translation([0, 0, height / 2])
|
|
498
|
+
|
|
499
|
+
return cls.new_from_trimesh(mesh, **kwargs)
|
|
500
|
+
|
|
317
501
|
|
|
318
502
|
class MeshSphere(MeshBase):
|
|
319
503
|
"""
|
|
@@ -4,6 +4,7 @@ from typing import TYPE_CHECKING, Annotated, ClassVar, Literal
|
|
|
4
4
|
|
|
5
5
|
import mujoco
|
|
6
6
|
import numpy as np
|
|
7
|
+
import trimesh
|
|
7
8
|
from pydantic import ConfigDict, Field
|
|
8
9
|
|
|
9
10
|
from mujoco_mojo.mjcf.defaults import SOLIMP_DEFAULT, SOLREF_DEFAULT
|
|
@@ -262,10 +263,7 @@ class GeomBase(XMLModel):
|
|
|
262
263
|
signal_manager: SignalManager,
|
|
263
264
|
attrs: list[
|
|
264
265
|
Literal["xpos", "xmat", "xvelp", "xvelr", "xaccp", "xaccr", "quat"]
|
|
265
|
-
] = [
|
|
266
|
-
"xpos",
|
|
267
|
-
"quat",
|
|
268
|
-
],
|
|
266
|
+
] = ["xpos", "quat"],
|
|
269
267
|
):
|
|
270
268
|
"""
|
|
271
269
|
Registers specific geom attributes for logging.
|
|
@@ -476,6 +474,31 @@ class GeomMesh(GeomBase, ProximityMixin):
|
|
|
476
474
|
mesh: MeshName
|
|
477
475
|
"""If the geom type is "mesh", this attribute is required. It references the mesh asset to be instantiated. This attribute can also be specified if the geom type corresponds to a geometric primitive, namely one of "sphere", "capsule", "cylinder", "ellipsoid", "box". In that case the primitive is automatically fitted to the mesh asset referenced here. The fitting procedure uses either the equivalent inertia box or the axis-aligned bounding box of the mesh, as determined by the attribute fitaabb of compiler. The resulting size of the fitted geom is usually what one would expect, but if not, it can be further adjusted with the fitscale attribute below. In the compiled mjModel the geom is represented as a regular geom of the specified primitive type, and there is no reference to the mesh used for fitting."""
|
|
478
476
|
|
|
477
|
+
def trimesh(self, mj_model: mujoco.MjModel) -> trimesh.Trimesh:
|
|
478
|
+
# get mesh id and data from mujoco
|
|
479
|
+
mesh_id = mj_model.geom_dataid[self.get_id(mj_model)]
|
|
480
|
+
|
|
481
|
+
if mesh_id == -1:
|
|
482
|
+
msg = "Exact proximity mesh tool is not currently supported for geoms of this type. Please use the `SPHERE_TO_SPHERE`/`CONVEX_HULL` algorithm, or convert the Geom to a GeomMesh."
|
|
483
|
+
logger.error(msg)
|
|
484
|
+
raise TypeError(msg)
|
|
485
|
+
|
|
486
|
+
# extract vertices and faces
|
|
487
|
+
if self._local_verts is None:
|
|
488
|
+
adr = mj_model.mesh_vertadr[mesh_id]
|
|
489
|
+
num = mj_model.mesh_vertnum[mesh_id]
|
|
490
|
+
self._local_verts = mj_model.mesh_vert[adr : adr + num].copy()
|
|
491
|
+
|
|
492
|
+
f_adr = mj_model.mesh_faceadr[mesh_id]
|
|
493
|
+
f_num = mj_model.mesh_facenum[mesh_id]
|
|
494
|
+
self._local_faces = mj_model.mesh_face[f_adr : f_adr + f_num].copy()
|
|
495
|
+
|
|
496
|
+
# create a trimesh and its proximity query
|
|
497
|
+
self._baked_mesh = trimesh.Trimesh(
|
|
498
|
+
vertices=self._local_verts, faces=self._local_faces
|
|
499
|
+
)
|
|
500
|
+
return self._baked_mesh
|
|
501
|
+
|
|
479
502
|
|
|
480
503
|
class GeomSDF(GeomBase):
|
|
481
504
|
attributes = (*_geom_attr, "type")
|
|
@@ -11,6 +11,7 @@ from pydantic import BaseModel, ConfigDict, Field, TypeAdapter, model_validator
|
|
|
11
11
|
from scipy.signal import savgol_filter
|
|
12
12
|
|
|
13
13
|
__all__ = [
|
|
14
|
+
"UNIT_GROUPS",
|
|
14
15
|
"AbsoluteValueFilter",
|
|
15
16
|
"AnyFilter",
|
|
16
17
|
"ClipFilter",
|
|
@@ -302,56 +303,50 @@ class SavitzkyGolayFilter(BaseFilter):
|
|
|
302
303
|
|
|
303
304
|
|
|
304
305
|
ureg = pint.UnitRegistry()
|
|
305
|
-
# --- Kinematics ---
|
|
306
|
-
AngleUnit = Literal["rad", "deg", "rad/s", "deg/s", "rad/s^2", "deg/s^2", "rev", "rpm"]
|
|
307
|
-
LenUnit = Literal["m", "mm", "cm", "km", "in", "ft", "thou"]
|
|
308
|
-
VelUnit = Literal["m/s", "ft/s", "in/s", "km/h", "mph"]
|
|
309
|
-
AccUnit = Literal["m/s^2", "g", "ft/s^2", "in/s^2"]
|
|
310
|
-
|
|
311
|
-
# --- Dynamics & Statics ---
|
|
312
|
-
MassUnit = Literal["kg", "lbm", "slug", "g", "mg"]
|
|
313
|
-
ForceUnit = Literal["N", "lbf", "kN", "mN"]
|
|
314
|
-
TorqueUnit = Literal["N*m", "N*mm", "mN*m", "lbf*ft", "lbf*in", "ozf*in"]
|
|
315
|
-
InertiaUnit = Literal["kg*m^2", "lbm*in^2", "lbm*ft^2", "slug*ft^2"]
|
|
316
|
-
|
|
317
|
-
# --- Work & Thermodynamics ---
|
|
318
|
-
EnergyUnit = Literal["J", "kJ", "mJ", "W*s", "ft*lbf", "BTU"]
|
|
319
|
-
PowerUnit = Literal["W", "kW", "hp", "ft*lbf/s"]
|
|
320
|
-
PressureUnit = Literal["Pa", "kPa", "psi", "bar", "atm", "torr"]
|
|
321
|
-
|
|
322
|
-
# --- Temporal & Electronics ---
|
|
323
|
-
TimeUnit = Literal["s", "ms", "us", "ns", "min", "hr"]
|
|
324
|
-
FreqUnit = Literal["Hz", "kHz", "MHz", "rad/s"]
|
|
325
|
-
|
|
326
|
-
# --- Dimensionless & Ratios ---
|
|
327
|
-
MiscUnit = Literal["dimensionless", "pct", "count", "bit", "V", "A"]
|
|
328
|
-
|
|
329
|
-
SignalUnit = (
|
|
330
|
-
AngleUnit
|
|
331
|
-
| LenUnit
|
|
332
|
-
| VelUnit
|
|
333
|
-
| AccUnit
|
|
334
|
-
| MassUnit
|
|
335
|
-
| ForceUnit
|
|
336
|
-
| TorqueUnit
|
|
337
|
-
| InertiaUnit
|
|
338
|
-
| EnergyUnit
|
|
339
|
-
| PowerUnit
|
|
340
|
-
| PressureUnit
|
|
341
|
-
| TimeUnit
|
|
342
|
-
| FreqUnit
|
|
343
|
-
| MiscUnit
|
|
344
|
-
| str
|
|
345
|
-
)
|
|
346
|
-
|
|
347
306
|
try:
|
|
348
|
-
# explicitly map lbm and lbf to avoid ambiguity
|
|
349
307
|
ureg.define("lbm = pound")
|
|
350
308
|
ureg.define("lbf = force_pound")
|
|
309
|
+
ureg.define("ozf = force_ounce")
|
|
351
310
|
except pint.errors.RedefinitionError:
|
|
352
|
-
# already defined in some Pint versions
|
|
353
311
|
pass
|
|
354
312
|
|
|
313
|
+
# ---------------------------------------------------------------------------
|
|
314
|
+
# Unit groups — single source of truth for both the frontend smart dropdown
|
|
315
|
+
# and the SignalUnit type annotation on UnitFilter. To add a new unit,
|
|
316
|
+
# add it here; SignalUnit is derived automatically. Verify that pint can
|
|
317
|
+
# parse any new string via `ureg.parse_units(...)` before committing.
|
|
318
|
+
# ---------------------------------------------------------------------------
|
|
319
|
+
UNIT_GROUPS: list[tuple[str, list[str]]] = [
|
|
320
|
+
# --- Kinematics ---
|
|
321
|
+
("Angle", ["rad", "deg", "mrad", "rev", "rpm"]),
|
|
322
|
+
("Angular Velocity", ["rad/s", "deg/s"]),
|
|
323
|
+
("Angular Accel.", ["rad/s^2", "deg/s^2"]),
|
|
324
|
+
("Length", ["m", "mm", "cm", "um", "km", "in", "ft", "thou"]),
|
|
325
|
+
("Velocity", ["m/s", "mm/s", "cm/s", "ft/s", "in/s", "km/h", "mph"]),
|
|
326
|
+
("Acceleration", ["m/s^2", "mm/s^2", "ft/s^2", "in/s^2"]),
|
|
327
|
+
# --- Dynamics & Statics ---
|
|
328
|
+
("Mass", ["kg", "g", "mg", "lbm", "slug"]),
|
|
329
|
+
("Force", ["N", "mN", "uN", "kN", "lbf"]),
|
|
330
|
+
("Torque", ["N*m", "N*mm", "mN*m", "kN*m", "lbf*ft", "lbf*in", "ozf*in"]),
|
|
331
|
+
("Inertia", ["kg*m^2", "kg*mm^2", "lbm*in^2", "lbm*ft^2", "slug*ft^2"]),
|
|
332
|
+
# --- Work & Thermodynamics ---
|
|
333
|
+
("Energy", ["J", "mJ", "kJ", "W*s", "W*h", "kW*h", "ft*lbf", "BTU"]),
|
|
334
|
+
("Power", ["W", "mW", "kW", "MW", "hp", "ft*lbf/s"]),
|
|
335
|
+
("Pressure", ["Pa", "kPa", "MPa", "psi", "bar", "atm", "torr"]),
|
|
336
|
+
# --- Temporal & Electronics ---
|
|
337
|
+
("Time", ["s", "ms", "us", "ns", "min", "hr"]),
|
|
338
|
+
("Frequency", ["Hz", "kHz", "MHz"]),
|
|
339
|
+
("Voltage", ["V", "mV", "kV"]),
|
|
340
|
+
("Current", ["A", "mA"]),
|
|
341
|
+
# --- Dimensionless & Ratios ---
|
|
342
|
+
("Misc.", ["dimensionless", "pct", "count", "bit"]),
|
|
343
|
+
]
|
|
344
|
+
|
|
345
|
+
# Derived automatically — Literal[tuple_of_strings] is equivalent to Literal["a", "b", ...]
|
|
346
|
+
# in Python 3.9+ because x[a, b] and x[(a, b)] make the same __getitem__ call.
|
|
347
|
+
_ALL_UNITS: tuple[str, ...] = tuple(u for _, us in UNIT_GROUPS for u in us)
|
|
348
|
+
SignalUnit = Literal[_ALL_UNITS] | str
|
|
349
|
+
|
|
355
350
|
|
|
356
351
|
class UnitFilter(BaseFilter):
|
|
357
352
|
"""
|
|
@@ -362,9 +357,10 @@ class UnitFilter(BaseFilter):
|
|
|
362
357
|
type: Literal[FilterType.UNIT] = FilterType.UNIT
|
|
363
358
|
"""The discriminator type for Pydantic."""
|
|
364
359
|
|
|
365
|
-
from_unit: SignalUnit
|
|
360
|
+
from_unit: SignalUnit # pyright: ignore[reportInvalidTypeForm]
|
|
366
361
|
"""The original unit of the telemetry data (e.g., 'rad')."""
|
|
367
|
-
|
|
362
|
+
|
|
363
|
+
to_unit: SignalUnit # pyright: ignore[reportInvalidTypeForm]
|
|
368
364
|
"""The target unit for analysis/display (e.g., 'deg')."""
|
|
369
365
|
|
|
370
366
|
@model_validator(mode="after")
|