jaxsim 0.4.3.dev362__tar.gz → 0.4.3.dev365__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 (131) hide show
  1. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/PKG-INFO +2 -1
  2. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/environment.yml +1 -0
  3. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/examples/jaxsim_for_robot_controllers.ipynb +16 -11
  4. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/pyproject.toml +2 -1
  5. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/_version.py +2 -2
  6. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/parsers/descriptions/__init__.py +7 -1
  7. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/parsers/descriptions/collision.py +19 -0
  8. jaxsim-0.4.3.dev365/src/jaxsim/parsers/rod/meshes.py +104 -0
  9. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/parsers/rod/parser.py +12 -0
  10. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/parsers/rod/utils.py +53 -0
  11. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim.egg-info/PKG-INFO +2 -1
  12. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim.egg-info/SOURCES.txt +2 -0
  13. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim.egg-info/requires.txt +1 -0
  14. jaxsim-0.4.3.dev365/tests/test_meshes.py +100 -0
  15. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/.devcontainer/Dockerfile +0 -0
  16. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/.devcontainer/devcontainer.json +0 -0
  17. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/.gitattributes +0 -0
  18. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/.github/CODEOWNERS +0 -0
  19. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/.github/dependabot.yml +0 -0
  20. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/.github/workflows/ci_cd.yml +0 -0
  21. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/.github/workflows/pixi.yml +0 -0
  22. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/.github/workflows/read_the_docs.yml +0 -0
  23. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/.gitignore +0 -0
  24. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/.pre-commit-config.yaml +0 -0
  25. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/.readthedocs.yaml +0 -0
  26. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/CONTRIBUTING.md +0 -0
  27. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/LICENSE +0 -0
  28. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/README.md +0 -0
  29. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/docs/Makefile +0 -0
  30. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/docs/conf.py +0 -0
  31. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/docs/examples.rst +0 -0
  32. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/docs/guide/install.rst +0 -0
  33. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/docs/index.rst +0 -0
  34. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/docs/make.bat +0 -0
  35. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/docs/modules/api.rst +0 -0
  36. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/docs/modules/integrators.rst +0 -0
  37. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/docs/modules/math.rst +0 -0
  38. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/docs/modules/mujoco.rst +0 -0
  39. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/docs/modules/parsers.rst +0 -0
  40. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/docs/modules/rbda.rst +0 -0
  41. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/docs/modules/typing.rst +0 -0
  42. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/docs/modules/utils.rst +0 -0
  43. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/examples/.gitattributes +0 -0
  44. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/examples/.gitignore +0 -0
  45. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/examples/README.md +0 -0
  46. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/examples/assets/build_cartpole_urdf.py +0 -0
  47. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/examples/assets/cartpole.urdf +0 -0
  48. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/examples/jaxsim_as_multibody_dynamics_library.ipynb +0 -0
  49. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/examples/jaxsim_as_physics_engine.ipynb +0 -0
  50. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/pixi.lock +0 -0
  51. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/setup.cfg +0 -0
  52. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/setup.py +0 -0
  53. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/__init__.py +0 -0
  54. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/api/__init__.py +0 -0
  55. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/api/com.py +0 -0
  56. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/api/common.py +0 -0
  57. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/api/contact.py +0 -0
  58. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/api/data.py +0 -0
  59. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/api/frame.py +0 -0
  60. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/api/joint.py +0 -0
  61. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/api/kin_dyn_parameters.py +0 -0
  62. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/api/link.py +0 -0
  63. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/api/model.py +0 -0
  64. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/api/ode.py +0 -0
  65. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/api/ode_data.py +0 -0
  66. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/api/references.py +0 -0
  67. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/exceptions.py +0 -0
  68. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/integrators/__init__.py +0 -0
  69. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/integrators/common.py +0 -0
  70. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/integrators/fixed_step.py +0 -0
  71. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/integrators/variable_step.py +0 -0
  72. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/logging.py +0 -0
  73. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/math/__init__.py +0 -0
  74. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/math/adjoint.py +0 -0
  75. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/math/cross.py +0 -0
  76. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/math/inertia.py +0 -0
  77. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/math/joint_model.py +0 -0
  78. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/math/quaternion.py +0 -0
  79. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/math/rotation.py +0 -0
  80. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/math/skew.py +0 -0
  81. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/math/transform.py +0 -0
  82. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/mujoco/__init__.py +0 -0
  83. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/mujoco/__main__.py +0 -0
  84. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/mujoco/loaders.py +0 -0
  85. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/mujoco/model.py +0 -0
  86. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/mujoco/utils.py +0 -0
  87. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/mujoco/visualizer.py +0 -0
  88. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/parsers/__init__.py +0 -0
  89. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/parsers/descriptions/joint.py +0 -0
  90. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/parsers/descriptions/link.py +0 -0
  91. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/parsers/descriptions/model.py +0 -0
  92. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/parsers/kinematic_graph.py +0 -0
  93. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/parsers/rod/__init__.py +0 -0
  94. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/rbda/__init__.py +0 -0
  95. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/rbda/aba.py +0 -0
  96. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/rbda/collidable_points.py +0 -0
  97. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/rbda/contacts/__init__.py +0 -0
  98. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/rbda/contacts/common.py +0 -0
  99. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/rbda/contacts/relaxed_rigid.py +0 -0
  100. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/rbda/contacts/rigid.py +0 -0
  101. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/rbda/contacts/soft.py +0 -0
  102. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/rbda/contacts/visco_elastic.py +0 -0
  103. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/rbda/crba.py +0 -0
  104. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/rbda/forward_kinematics.py +0 -0
  105. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/rbda/jacobian.py +0 -0
  106. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/rbda/rnea.py +0 -0
  107. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/rbda/utils.py +0 -0
  108. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/terrain/__init__.py +0 -0
  109. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/terrain/terrain.py +0 -0
  110. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/typing.py +0 -0
  111. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/utils/__init__.py +0 -0
  112. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/utils/jaxsim_dataclass.py +0 -0
  113. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/utils/tracing.py +0 -0
  114. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim/utils/wrappers.py +0 -0
  115. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim.egg-info/dependency_links.txt +0 -0
  116. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/src/jaxsim.egg-info/top_level.txt +0 -0
  117. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/tests/__init__.py +0 -0
  118. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/tests/conftest.py +0 -0
  119. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/tests/test_api_com.py +0 -0
  120. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/tests/test_api_contact.py +0 -0
  121. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/tests/test_api_data.py +0 -0
  122. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/tests/test_api_frame.py +0 -0
  123. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/tests/test_api_joint.py +0 -0
  124. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/tests/test_api_link.py +0 -0
  125. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/tests/test_api_model.py +0 -0
  126. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/tests/test_automatic_differentiation.py +0 -0
  127. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/tests/test_contact.py +0 -0
  128. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/tests/test_exceptions.py +0 -0
  129. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/tests/test_pytree.py +0 -0
  130. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/tests/test_simulations.py +0 -0
  131. {jaxsim-0.4.3.dev362 → jaxsim-0.4.3.dev365}/tests/utils_idyntree.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: jaxsim
3
- Version: 0.4.3.dev362
3
+ Version: 0.4.3.dev365
4
4
  Summary: A differentiable physics engine and multibody dynamics library for control and robot learning.
5
5
  Author-email: Diego Ferigo <dgferigo@gmail.com>, Filippo Luca Ferretti <filippoluca.ferretti@outlook.com>
6
6
  Maintainer-email: Filippo Luca Ferretti <filippo.ferretti@iit.it>, Alessandro Croci <alessandro.croci@iit.it>
@@ -70,6 +70,7 @@ Requires-Dist: optax>=0.2.3
70
70
  Requires-Dist: qpax
71
71
  Requires-Dist: rod>=0.3.3
72
72
  Requires-Dist: typing_extensions; python_version < "3.12"
73
+ Requires-Dist: trimesh
73
74
  Provides-Extra: style
74
75
  Requires-Dist: black[jupyter]~=24.0; extra == "style"
75
76
  Requires-Dist: isort; extra == "style"
@@ -15,6 +15,7 @@ dependencies:
15
15
  - pptree
16
16
  - qpax
17
17
  - rod >= 0.3.3
18
+ - trimesh
18
19
  - typing_extensions # python<3.12
19
20
  # ====================================
20
21
  # Optional dependencies from setup.cfg
@@ -90,6 +90,17 @@
90
90
  "[sdformat_github]: https://github.com/gazebosim/sdformat"
91
91
  ]
92
92
  },
93
+ {
94
+ "cell_type": "code",
95
+ "execution_count": null,
96
+ "metadata": {},
97
+ "outputs": [],
98
+ "source": [
99
+ "import os\n",
100
+ "\n",
101
+ "os.path.abspath(\"\")"
102
+ ]
103
+ },
93
104
  {
94
105
  "cell_type": "code",
95
106
  "execution_count": null,
@@ -98,18 +109,12 @@
98
109
  },
99
110
  "outputs": [],
100
111
  "source": [
101
- "# @title Download the URDF model\n",
102
- "\n",
103
- "import requests\n",
104
- "\n",
105
- "url = \"https://raw.githubusercontent.com/ami-iit/jaxsim/main/examples/assets/cartpole.urdf\"\n",
106
- "\n",
107
- "response = requests.get(url)\n",
112
+ "# @title Load the URDF model\n",
113
+ "import pathlib\n",
108
114
  "\n",
109
- "if response.status_code == 200:\n",
110
- " model_urdf_string = response.text\n",
111
- "else:\n",
112
- " raise RuntimeError(\"Failed to fetch data.\")"
115
+ "model_urdf_string = pathlib.Path(\n",
116
+ " os.path.abspath(\"\") + \"/assets/cartpole.urdf\"\n",
117
+ ").read_text()"
113
118
  ]
114
119
  },
115
120
  {
@@ -55,6 +55,7 @@ dependencies = [
55
55
  "qpax",
56
56
  "rod >= 0.3.3",
57
57
  "typing_extensions ; python_version < '3.12'",
58
+ "trimesh",
58
59
  ]
59
60
 
60
61
  [project.optional-dependencies]
@@ -67,7 +68,7 @@ testing = [
67
68
  "idyntree >= 12.2.1",
68
69
  "pytest >=6.0",
69
70
  "pytest-icdiff",
70
- "robot-descriptions",
71
+ "robot-descriptions"
71
72
  ]
72
73
  viz = [
73
74
  "lxml",
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '0.4.3.dev362'
16
- __version_tuple__ = version_tuple = (0, 4, 3, 'dev362')
15
+ __version__ = version = '0.4.3.dev365'
16
+ __version_tuple__ = version_tuple = (0, 4, 3, 'dev365')
@@ -1,4 +1,10 @@
1
- from .collision import BoxCollision, CollidablePoint, CollisionShape, SphereCollision
1
+ from .collision import (
2
+ BoxCollision,
3
+ CollidablePoint,
4
+ CollisionShape,
5
+ MeshCollision,
6
+ SphereCollision,
7
+ )
2
8
  from .joint import JointDescription, JointGenericAxis, JointType
3
9
  from .link import LinkDescription
4
10
  from .model import ModelDescription
@@ -154,3 +154,22 @@ class SphereCollision(CollisionShape):
154
154
  return False
155
155
 
156
156
  return hash(self) == hash(other)
157
+
158
+
159
+ @dataclasses.dataclass
160
+ class MeshCollision(CollisionShape):
161
+ center: jtp.VectorLike
162
+
163
+ def __hash__(self) -> int:
164
+ return hash(
165
+ (
166
+ hash(tuple(self.center.tolist())),
167
+ hash(self.collidable_points),
168
+ )
169
+ )
170
+
171
+ def __eq__(self, other: MeshCollision) -> bool:
172
+ if not isinstance(other, MeshCollision):
173
+ return False
174
+
175
+ return hash(self) == hash(other)
@@ -0,0 +1,104 @@
1
+ import numpy as np
2
+ import trimesh
3
+
4
+ VALID_AXIS = {"x": 0, "y": 1, "z": 2}
5
+
6
+
7
+ def extract_points_vertices(mesh: trimesh.Trimesh) -> np.ndarray:
8
+ """
9
+ Extracts the vertices of a mesh as points.
10
+ """
11
+ return mesh.vertices
12
+
13
+
14
+ def extract_points_random_surface_sampling(mesh: trimesh.Trimesh, n) -> np.ndarray:
15
+ """
16
+ Extracts N random points from the surface of a mesh.
17
+
18
+ Args:
19
+ mesh: The mesh from which to extract points.
20
+ n: The number of points to extract.
21
+
22
+ Returns:
23
+ The extracted points (N x 3 array).
24
+ """
25
+
26
+ return mesh.sample(n)
27
+
28
+
29
+ def extract_points_uniform_surface_sampling(
30
+ mesh: trimesh.Trimesh, n: int
31
+ ) -> np.ndarray:
32
+ """
33
+ Extracts N uniformly sampled points from the surface of a mesh.
34
+
35
+ Args:
36
+ mesh: The mesh from which to extract points.
37
+ n: The number of points to extract.
38
+
39
+ Returns:
40
+ The extracted points (N x 3 array).
41
+ """
42
+
43
+ return trimesh.sample.sample_surface_even(mesh=mesh, count=n)[0]
44
+
45
+
46
+ def extract_points_select_points_over_axis(
47
+ mesh: trimesh.Trimesh, axis: str, direction: str, n: int
48
+ ) -> np.ndarray:
49
+ """
50
+ Extracts N points from a mesh along a specified axis. The points are selected based on their position along the axis.
51
+
52
+ Args:
53
+ mesh: The mesh from which to extract points.
54
+ axis: The axis along which to extract points.
55
+ direction: The direction along the axis from which to extract points. Valid values are "higher" and "lower".
56
+ n: The number of points to extract.
57
+
58
+ Returns:
59
+ The extracted points (N x 3 array).
60
+ """
61
+
62
+ dirs = {"higher": np.s_[-n:], "lower": np.s_[:n]}
63
+ arr = mesh.vertices
64
+
65
+ # Sort rows lexicographically first, then columnar.
66
+ arr.sort(axis=0)
67
+ sorted_arr = arr[dirs[direction]]
68
+ return sorted_arr
69
+
70
+
71
+ def extract_points_aap(
72
+ mesh: trimesh.Trimesh,
73
+ axis: str,
74
+ upper: float | None = None,
75
+ lower: float | None = None,
76
+ ) -> np.ndarray:
77
+ """
78
+ Extracts points from a mesh along a specified axis within a specified range. The points are selected based on their position along the axis.
79
+
80
+ Args:
81
+ mesh: The mesh from which to extract points.
82
+ axis: The axis along which to extract points.
83
+ upper: The upper bound of the range.
84
+ lower: The lower bound of the range.
85
+
86
+ Returns:
87
+ The extracted points (N x 3 array).
88
+
89
+ Raises:
90
+ AssertionError: If the lower bound is greater than the upper bound.
91
+ """
92
+
93
+ # Check bounds.
94
+ upper = upper if upper is not None else np.inf
95
+ lower = lower if lower is not None else -np.inf
96
+ assert lower < upper, "Invalid bounds for axis-aligned plane"
97
+
98
+ # Logic.
99
+ points = mesh.vertices[
100
+ (mesh.vertices[:, VALID_AXIS[axis]] >= lower)
101
+ & (mesh.vertices[:, VALID_AXIS[axis]] <= upper)
102
+ ]
103
+
104
+ return points
@@ -334,6 +334,18 @@ def extract_model_data(
334
334
 
335
335
  collisions.append(sphere_collision)
336
336
 
337
+ if collision.geometry.mesh is not None and int(
338
+ os.environ.get("JAXSIM_COLLISION_MESH_ENABLED", "0")
339
+ ):
340
+ logging.warning("Mesh collision support is still experimental.")
341
+ mesh_collision = utils.create_mesh_collision(
342
+ collision=collision,
343
+ link_description=links_dict[link.name],
344
+ method=utils.meshes.extract_points_vertices,
345
+ )
346
+
347
+ collisions.append(mesh_collision)
348
+
337
349
  return SDFData(
338
350
  model_name=sdf_model.name,
339
351
  link_descriptions=links,
@@ -1,12 +1,21 @@
1
1
  import os
2
+ import pathlib
3
+ from collections.abc import Callable
4
+ from typing import TypeVar
2
5
 
3
6
  import numpy as np
4
7
  import numpy.typing as npt
5
8
  import rod
9
+ import trimesh
10
+ from rod.utils.resolve_uris import resolve_local_uri
6
11
 
7
12
  import jaxsim.typing as jtp
13
+ from jaxsim import logging
8
14
  from jaxsim.math import Adjoint, Inertia
9
15
  from jaxsim.parsers import descriptions
16
+ from jaxsim.parsers.rod import meshes
17
+
18
+ MeshMappingMethod = TypeVar("MeshMappingMethod", bound=Callable[..., npt.NDArray])
10
19
 
11
20
 
12
21
  def from_sdf_inertial(inertial: rod.Inertial) -> jtp.Matrix:
@@ -202,3 +211,47 @@ def create_sphere_collision(
202
211
  return descriptions.SphereCollision(
203
212
  collidable_points=collidable_points, center=center_wrt_link
204
213
  )
214
+
215
+
216
+ def create_mesh_collision(
217
+ collision: rod.Collision,
218
+ link_description: descriptions.LinkDescription,
219
+ method: MeshMappingMethod = None,
220
+ ) -> descriptions.MeshCollision:
221
+
222
+ file = pathlib.Path(resolve_local_uri(uri=collision.geometry.mesh.uri))
223
+ _file_type = file.suffix.replace(".", "")
224
+ mesh = trimesh.load_mesh(file, file_type=_file_type)
225
+
226
+ if mesh.is_empty:
227
+ raise RuntimeError(f"Failed to process '{file}' with trimesh")
228
+
229
+ mesh.apply_scale(collision.geometry.mesh.scale)
230
+ logging.info(
231
+ msg=f"Loading mesh {collision.geometry.mesh.uri} with scale {collision.geometry.mesh.scale}, file type '{_file_type}'"
232
+ )
233
+
234
+ if method is None:
235
+ method = meshes.VertexExtraction()
236
+ logging.debug("Using default Vertex Extraction method for mesh wrapping")
237
+ else:
238
+ logging.debug(f"Using method {method} for mesh wrapping")
239
+
240
+ points = method(mesh=mesh)
241
+ logging.debug(f"Extracted {len(points)} points from mesh")
242
+
243
+ W_H_L = collision.pose.transform() if collision.pose is not None else np.eye(4)
244
+
245
+ # Extract translation from transformation matrix
246
+ W_p_L = W_H_L[:3, 3]
247
+ mesh_points_wrt_link = points @ W_H_L[:3, :3].T + W_p_L
248
+ collidable_points = [
249
+ descriptions.CollidablePoint(
250
+ parent_link=link_description,
251
+ position=point,
252
+ enabled=True,
253
+ )
254
+ for point in mesh_points_wrt_link
255
+ ]
256
+
257
+ return descriptions.MeshCollision(collidable_points=collidable_points, center=W_p_L)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: jaxsim
3
- Version: 0.4.3.dev362
3
+ Version: 0.4.3.dev365
4
4
  Summary: A differentiable physics engine and multibody dynamics library for control and robot learning.
5
5
  Author-email: Diego Ferigo <dgferigo@gmail.com>, Filippo Luca Ferretti <filippoluca.ferretti@outlook.com>
6
6
  Maintainer-email: Filippo Luca Ferretti <filippo.ferretti@iit.it>, Alessandro Croci <alessandro.croci@iit.it>
@@ -70,6 +70,7 @@ Requires-Dist: optax>=0.2.3
70
70
  Requires-Dist: qpax
71
71
  Requires-Dist: rod>=0.3.3
72
72
  Requires-Dist: typing_extensions; python_version < "3.12"
73
+ Requires-Dist: trimesh
73
74
  Provides-Extra: style
74
75
  Requires-Dist: black[jupyter]~=24.0; extra == "style"
75
76
  Requires-Dist: isort; extra == "style"
@@ -88,6 +88,7 @@ src/jaxsim/parsers/descriptions/joint.py
88
88
  src/jaxsim/parsers/descriptions/link.py
89
89
  src/jaxsim/parsers/descriptions/model.py
90
90
  src/jaxsim/parsers/rod/__init__.py
91
+ src/jaxsim/parsers/rod/meshes.py
91
92
  src/jaxsim/parsers/rod/parser.py
92
93
  src/jaxsim/parsers/rod/utils.py
93
94
  src/jaxsim/rbda/__init__.py
@@ -122,6 +123,7 @@ tests/test_api_model.py
122
123
  tests/test_automatic_differentiation.py
123
124
  tests/test_contact.py
124
125
  tests/test_exceptions.py
126
+ tests/test_meshes.py
125
127
  tests/test_pytree.py
126
128
  tests/test_simulations.py
127
129
  tests/utils_idyntree.py
@@ -7,6 +7,7 @@ pptree
7
7
  optax>=0.2.3
8
8
  qpax
9
9
  rod>=0.3.3
10
+ trimesh
10
11
 
11
12
  [:python_version < "3.12"]
12
13
  typing_extensions
@@ -0,0 +1,100 @@
1
+ import trimesh
2
+
3
+ from jaxsim.parsers.rod import meshes
4
+
5
+
6
+ def test_mesh_wrapping_vertex_extraction():
7
+ """
8
+ Test the vertex extraction method on different meshes.
9
+ 1. A simple box
10
+ 2. A sphere
11
+ """
12
+
13
+ # Test 1: A simple box.
14
+ # First, create a box with origin at (0,0,0) and extents (3,3,3),
15
+ # i.e. points span from -1.5 to 1.5 on the axis.
16
+ mesh = trimesh.creation.box(
17
+ extents=[3.0, 3.0, 3.0],
18
+ )
19
+ points = meshes.extract_points_vertices(mesh=mesh)
20
+ assert len(points) == len(mesh.vertices)
21
+
22
+ # Test 2: A sphere.
23
+ # The sphere is centered at the origin and has a radius of 1.0.
24
+ mesh = trimesh.creation.icosphere(subdivisions=4, radius=1.0)
25
+ points = meshes.extract_points_vertices(mesh=mesh)
26
+ assert len(points) == len(mesh.vertices)
27
+
28
+
29
+ def test_mesh_wrapping_aap():
30
+ """
31
+ Test the AAP wrapping method on different meshes.
32
+ 1. A simple box
33
+ 1.1: Remove all points above x=0.0
34
+ 1.2: Remove all points below y=0.0
35
+ 2. A sphere
36
+ """
37
+
38
+ # Test 1.1: Remove all points above x=0.0.
39
+ # The expected result is that the number of points is halved.
40
+ # First, create a box with origin at (0,0,0) and extents (3,3,3),
41
+ # i.e. points span from -1.5 to 1.5 on the axis.
42
+ mesh = trimesh.creation.box(extents=[3.0, 3.0, 3.0])
43
+ points = meshes.extract_points_aap(mesh=mesh, axis="x", lower=0.0)
44
+ assert len(points) == len(mesh.vertices) // 2
45
+ assert all(points[:, 0] > 0.0)
46
+
47
+ # Test 1.2: Remove all points below y=0.0.
48
+ # The expected result is that the number of points is halved.
49
+ points = meshes.extract_points_aap(mesh=mesh, axis="y", upper=0.0)
50
+ assert len(points) == len(mesh.vertices) // 2
51
+ assert all(points[:, 1] < 0.0)
52
+
53
+ # Test 2: A sphere.
54
+ # The sphere is centered at the origin and has a radius of 1.0.
55
+ # Points are expected to be halved.
56
+ mesh = trimesh.creation.icosphere(subdivisions=4, radius=1.0)
57
+
58
+ # Remove all points above y=0.0.
59
+ points = meshes.extract_points_aap(mesh=mesh, axis="y", lower=0.0)
60
+ assert all(points[:, 1] >= 0.0)
61
+ assert len(points) < len(mesh.vertices)
62
+
63
+
64
+ def test_mesh_wrapping_points_over_axis():
65
+ """
66
+ Test the points over axis method on different meshes.
67
+ 1. A simple box
68
+ 1.1: Select 10 points from the lower end of the x-axis
69
+ 1.2: Select 10 points from the higher end of the y-axis
70
+ 2. A sphere
71
+ """
72
+
73
+ # Test 1.1: Remove 10 points from the lower end of the x-axis.
74
+ # First, create a box with origin at (0,0,0) and extents (3,3,3),
75
+ # i.e. points span from -1.5 to 1.5 on the axis.
76
+ mesh = trimesh.creation.box(extents=[3.0, 3.0, 3.0])
77
+ points = meshes.extract_points_select_points_over_axis(
78
+ mesh=mesh, axis="x", direction="lower", n=4
79
+ )
80
+ assert len(points) == 4
81
+ assert all(points[:, 0] < 0.0)
82
+
83
+ # Test 1.2: Select 10 points from the higher end of the y-axis.
84
+ points = meshes.extract_points_select_points_over_axis(
85
+ mesh=mesh, axis="y", direction="higher", n=4
86
+ )
87
+ assert len(points) == 4
88
+ assert all(points[:, 1] > 0.0)
89
+
90
+ # Test 2: A sphere.
91
+ # The sphere is centered at the origin and has a radius of 1.0.
92
+ mesh = trimesh.creation.icosphere(subdivisions=4, radius=1.0)
93
+ sphere_n_vertices = len(mesh.vertices)
94
+
95
+ # Select 10 points from the higher end of the z-axis.
96
+ points = meshes.extract_points_select_points_over_axis(
97
+ mesh=mesh, axis="z", direction="higher", n=sphere_n_vertices // 2
98
+ )
99
+ assert len(points) == sphere_n_vertices // 2
100
+ assert all(points[:, 2] >= 0.0)
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes