rod 0.2.dev12__tar.gz → 0.2.1.dev16__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 (52) hide show
  1. {rod-0.2.dev12 → rod-0.2.1.dev16}/.github/workflows/ci_cd.yml +2 -1
  2. {rod-0.2.dev12 → rod-0.2.1.dev16}/PKG-INFO +2 -1
  3. {rod-0.2.dev12 → rod-0.2.1.dev16}/setup.cfg +1 -0
  4. rod-0.2.1.dev16/src/rod/builder/primitives.py +110 -0
  5. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod.egg-info/PKG-INFO +2 -1
  6. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod.egg-info/SOURCES.txt +1 -0
  7. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod.egg-info/requires.txt +1 -0
  8. rod-0.2.1.dev16/tests/test_meshbuilder.py +61 -0
  9. rod-0.2.dev12/src/rod/builder/primitives.py +0 -56
  10. {rod-0.2.dev12 → rod-0.2.1.dev16}/.github/workflows/style.yml +0 -0
  11. {rod-0.2.dev12 → rod-0.2.1.dev16}/.gitignore +0 -0
  12. {rod-0.2.dev12 → rod-0.2.1.dev16}/LICENSE +0 -0
  13. {rod-0.2.dev12 → rod-0.2.1.dev16}/README.md +0 -0
  14. {rod-0.2.dev12 → rod-0.2.1.dev16}/pyproject.toml +0 -0
  15. {rod-0.2.dev12 → rod-0.2.1.dev16}/setup.py +0 -0
  16. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/__init__.py +0 -0
  17. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/builder/__init__.py +0 -0
  18. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/builder/primitive_builder.py +0 -0
  19. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/kinematics/__init__.py +0 -0
  20. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/kinematics/kinematic_tree.py +0 -0
  21. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/kinematics/tree_transforms.py +0 -0
  22. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/logging.py +0 -0
  23. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/pretty_printer.py +0 -0
  24. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/__init__.py +0 -0
  25. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/collision.py +0 -0
  26. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/common.py +0 -0
  27. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/element.py +0 -0
  28. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/geometry.py +0 -0
  29. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/joint.py +0 -0
  30. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/link.py +0 -0
  31. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/material.py +0 -0
  32. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/model.py +0 -0
  33. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/physics.py +0 -0
  34. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/scene.py +0 -0
  35. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/sdf.py +0 -0
  36. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/visual.py +0 -0
  37. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/sdf/world.py +0 -0
  38. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/tree/__init__.py +0 -0
  39. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/tree/directed_tree.py +0 -0
  40. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/tree/tree_elements.py +0 -0
  41. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/urdf/__init__.py +0 -0
  42. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/urdf/exporter.py +0 -0
  43. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/utils/__init__.py +0 -0
  44. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/utils/frame_convention.py +0 -0
  45. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/utils/gazebo.py +0 -0
  46. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/utils/resolve_frames.py +0 -0
  47. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod/utils/resolve_uris.py +0 -0
  48. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod.egg-info/dependency_links.txt +0 -0
  49. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod.egg-info/not-zip-safe +0 -0
  50. {rod-0.2.dev12 → rod-0.2.1.dev16}/src/rod.egg-info/top_level.txt +0 -0
  51. {rod-0.2.dev12 → rod-0.2.1.dev16}/tests/test_urdf_parsing.py +0 -0
  52. {rod-0.2.dev12 → rod-0.2.1.dev16}/tests/utils_models.py +0 -0
@@ -122,7 +122,8 @@ jobs:
122
122
  pptree \
123
123
  idyntree \
124
124
  pytest \
125
- robot_descriptions
125
+ robot_descriptions \
126
+ trimesh
126
127
  # pytest-icdiff \ # creates problems on macOS
127
128
  mamba install -y gz-sim7 idyntree
128
129
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: rod
3
- Version: 0.2.dev12
3
+ Version: 0.2.1.dev16
4
4
  Summary: The ultimate Python tool for RObot Descriptions processing.
5
5
  Home-page: https://github.com/ami-iit/rod
6
6
  Author: Diego Ferigo
@@ -38,6 +38,7 @@ Requires-Dist: numpy
38
38
  Requires-Dist: packaging
39
39
  Requires-Dist: resolve-robotics-uri-py
40
40
  Requires-Dist: scipy
41
+ Requires-Dist: trimesh
41
42
  Requires-Dist: xmltodict
42
43
  Provides-Extra: style
43
44
  Requires-Dist: black; extra == "style"
@@ -58,6 +58,7 @@ install_requires =
58
58
  packaging
59
59
  resolve-robotics-uri-py
60
60
  scipy
61
+ trimesh
61
62
  xmltodict
62
63
 
63
64
  [options.extras_require]
@@ -0,0 +1,110 @@
1
+ import dataclasses
2
+ import pathlib
3
+ from typing import Union
4
+
5
+ import trimesh
6
+ from numpy.typing import NDArray
7
+
8
+ import rod
9
+ from rod.builder.primitive_builder import PrimitiveBuilder
10
+
11
+
12
+ @dataclasses.dataclass
13
+ class SphereBuilder(PrimitiveBuilder):
14
+ radius: float
15
+
16
+ def _inertia(self) -> rod.Inertia:
17
+ return rod.Inertia(
18
+ ixx=2 / 5 * self.mass * (self.radius) ** 2,
19
+ iyy=2 / 5 * self.mass * (self.radius) ** 2,
20
+ izz=2 / 5 * self.mass * (self.radius) ** 2,
21
+ )
22
+
23
+ def _geometry(self) -> rod.Geometry:
24
+ return rod.Geometry(sphere=rod.Sphere(radius=self.radius))
25
+
26
+
27
+ @dataclasses.dataclass
28
+ class BoxBuilder(PrimitiveBuilder):
29
+ x: float
30
+ y: float
31
+ z: float
32
+
33
+ def _inertia(self) -> rod.Inertia:
34
+ return rod.Inertia(
35
+ ixx=self.mass / 12 * (self.y**2 + self.z**2),
36
+ iyy=self.mass / 12 * (self.x**2 + self.z**2),
37
+ izz=self.mass / 12 * (self.x**2 + self.y**2),
38
+ )
39
+
40
+ def _geometry(self) -> rod.Geometry:
41
+ return rod.Geometry(box=rod.Box(size=[self.x, self.y, self.z]))
42
+
43
+
44
+ @dataclasses.dataclass
45
+ class CylinderBuilder(PrimitiveBuilder):
46
+ radius: float
47
+ length: float
48
+
49
+ def _inertia(self) -> rod.Inertia:
50
+ ixx_iyy = self.mass * (3 * self.radius**2 + self.length**2) / 12
51
+
52
+ return rod.Inertia(
53
+ ixx=ixx_iyy,
54
+ iyy=ixx_iyy,
55
+ izz=0.5 * self.mass * self.radius**2,
56
+ )
57
+
58
+ def _geometry(self) -> rod.Geometry:
59
+ return rod.Geometry(
60
+ cylinder=rod.Cylinder(radius=self.radius, length=self.length)
61
+ )
62
+
63
+
64
+ @dataclasses.dataclass
65
+ class MeshBuilder(PrimitiveBuilder):
66
+ mesh_path: Union[str, pathlib.Path]
67
+ scale: NDArray
68
+
69
+ def __post_init__(self) -> None:
70
+ """
71
+ Post-initialization method for the class.
72
+ Loads the mesh from the specified file path and performs necessary checks.
73
+
74
+ Raises:
75
+ AssertionError: If the scale is not a 3D vector.
76
+ TypeError: If the mesh_path is not a str or pathlib.Path.
77
+ """
78
+
79
+ if isinstance(self.mesh_path, str):
80
+ extension = pathlib.Path(self.mesh_path).suffix
81
+ elif isinstance(self.mesh_path, pathlib.Path):
82
+ extension = self.mesh_path.suffix
83
+ else:
84
+ raise TypeError(
85
+ f"Expected str or pathlib.Path for mesh_path, got {type(self.mesh_path)}"
86
+ )
87
+
88
+ self.mesh: trimesh.base.Trimesh = trimesh.load(
89
+ str(self.mesh_path),
90
+ force="mesh",
91
+ file_type=extension,
92
+ )
93
+
94
+ assert self.scale.shape == (
95
+ 3,
96
+ ), f"Scale must be a 3D vector, got {self.scale.shape}"
97
+
98
+ def _inertia(self) -> rod.Inertia:
99
+ inertia = self.mesh.moment_inertia
100
+ return rod.Inertia(
101
+ ixx=inertia[0, 0],
102
+ ixy=inertia[0, 1],
103
+ ixz=inertia[0, 2],
104
+ iyy=inertia[1, 1],
105
+ iyz=inertia[1, 2],
106
+ izz=inertia[2, 2],
107
+ )
108
+
109
+ def _geometry(self) -> rod.Geometry:
110
+ return rod.Geometry(mesh=rod.Mesh(uri=str(self.mesh_path), scale=self.scale))
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: rod
3
- Version: 0.2.dev12
3
+ Version: 0.2.1.dev16
4
4
  Summary: The ultimate Python tool for RObot Descriptions processing.
5
5
  Home-page: https://github.com/ami-iit/rod
6
6
  Author: Diego Ferigo
@@ -38,6 +38,7 @@ Requires-Dist: numpy
38
38
  Requires-Dist: packaging
39
39
  Requires-Dist: resolve-robotics-uri-py
40
40
  Requires-Dist: scipy
41
+ Requires-Dist: trimesh
41
42
  Requires-Dist: xmltodict
42
43
  Provides-Extra: style
43
44
  Requires-Dist: black; extra == "style"
@@ -45,5 +45,6 @@ src/rod/utils/frame_convention.py
45
45
  src/rod/utils/gazebo.py
46
46
  src/rod/utils/resolve_frames.py
47
47
  src/rod/utils/resolve_uris.py
48
+ tests/test_meshbuilder.py
48
49
  tests/test_urdf_parsing.py
49
50
  tests/utils_models.py
@@ -4,6 +4,7 @@ numpy
4
4
  packaging
5
5
  resolve-robotics-uri-py
6
6
  scipy
7
+ trimesh
7
8
  xmltodict
8
9
 
9
10
  [all]
@@ -0,0 +1,61 @@
1
+ import os
2
+ import pathlib
3
+ import tempfile
4
+
5
+ import numpy as np
6
+ import trimesh
7
+
8
+ from rod.builder.primitives import MeshBuilder
9
+
10
+
11
+ def test_builder_creation():
12
+ mesh = trimesh.creation.box([1, 1, 1])
13
+
14
+ # Temporary write to file because rod Mesh works with uri
15
+ with tempfile.NamedTemporaryFile(suffix=".stl") as fp:
16
+ mesh.export(fp.name, file_type="stl")
17
+
18
+ builder = MeshBuilder(
19
+ name="test_mesh",
20
+ mesh_path=fp.name,
21
+ mass=1.0,
22
+ scale=np.array([1.0, 1.0, 1.0]),
23
+ )
24
+ assert (
25
+ builder.mesh.vertices.shape == mesh.vertices.shape
26
+ ), f"{builder.mesh.vertices.shape} != {mesh.vertices.shape}"
27
+ assert (
28
+ builder.mesh.faces.shape == mesh.faces.shape
29
+ ), f"{builder.mesh.faces.shape} != {mesh.faces.shape}"
30
+ assert (
31
+ builder.mesh.moment_inertia.all() == mesh.moment_inertia.all()
32
+ ), f"{builder.mesh.moment_inertia} != {mesh.moment_inertia}"
33
+ assert builder.mesh.volume == mesh.volume, f"{builder.mesh.volume} != {mesh.volume}"
34
+
35
+
36
+ def test_builder_creation_custom_mesh():
37
+ # Create a custom mesh
38
+ vertices = np.array([[0, 0, 0], [1, 0, 0], [0, 1, 0], [0, 0, 1]])
39
+ faces = np.array([[0, 1, 2], [0, 2, 3]])
40
+ mesh = trimesh.Trimesh(vertices=vertices, faces=faces)
41
+
42
+ # Temporary write to file because rod Mesh works with uri
43
+ with tempfile.NamedTemporaryFile(suffix=".stl") as fp:
44
+ mesh.export(fp.name, file_type="stl")
45
+
46
+ builder = MeshBuilder(
47
+ name="test_mesh",
48
+ mesh_path=fp.name,
49
+ mass=1.0,
50
+ scale=np.array([1.0, 1.0, 1.0]),
51
+ )
52
+ assert (
53
+ builder.mesh.vertices.shape == mesh.vertices.shape
54
+ ), f"{builder.mesh.vertices.shape} != {mesh.vertices.shape}"
55
+ assert (
56
+ builder.mesh.faces.shape == mesh.faces.shape
57
+ ), f"{builder.mesh.faces.shape} != {mesh.faces.shape}"
58
+ assert (
59
+ builder.mesh.moment_inertia.all() == mesh.moment_inertia.all()
60
+ ), f"{builder.mesh.moment_inertia} != {mesh.moment_inertia}"
61
+ assert builder.mesh.volume == mesh.volume, f"{builder.mesh.volume} != {mesh.volume}"
@@ -1,56 +0,0 @@
1
- import dataclasses
2
-
3
- import rod
4
- from rod.builder.primitive_builder import PrimitiveBuilder
5
-
6
-
7
- @dataclasses.dataclass
8
- class SphereBuilder(PrimitiveBuilder):
9
- radius: float
10
-
11
- def _inertia(self) -> rod.Inertia:
12
- return rod.Inertia(
13
- ixx=2 / 5 * self.mass * (self.radius) ** 2,
14
- iyy=2 / 5 * self.mass * (self.radius) ** 2,
15
- izz=2 / 5 * self.mass * (self.radius) ** 2,
16
- )
17
-
18
- def _geometry(self) -> rod.Geometry:
19
- return rod.Geometry(sphere=rod.Sphere(radius=self.radius))
20
-
21
-
22
- @dataclasses.dataclass
23
- class BoxBuilder(PrimitiveBuilder):
24
- x: float
25
- y: float
26
- z: float
27
-
28
- def _inertia(self) -> rod.Inertia:
29
- return rod.Inertia(
30
- ixx=self.mass / 12 * (self.y**2 + self.z**2),
31
- iyy=self.mass / 12 * (self.x**2 + self.z**2),
32
- izz=self.mass / 12 * (self.x**2 + self.y**2),
33
- )
34
-
35
- def _geometry(self) -> rod.Geometry:
36
- return rod.Geometry(box=rod.Box(size=[self.x, self.y, self.z]))
37
-
38
-
39
- @dataclasses.dataclass
40
- class CylinderBuilder(PrimitiveBuilder):
41
- radius: float
42
- length: float
43
-
44
- def _inertia(self) -> rod.Inertia:
45
- ixx_iyy = self.mass * (3 * self.radius**2 + self.length**2) / 12
46
-
47
- return rod.Inertia(
48
- ixx=ixx_iyy,
49
- iyy=ixx_iyy,
50
- izz=0.5 * self.mass * self.radius**2,
51
- )
52
-
53
- def _geometry(self) -> rod.Geometry:
54
- return rod.Geometry(
55
- cylinder=rod.Cylinder(radius=self.radius, length=self.length)
56
- )
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes