Skip to content

Commit 7bc55f2

Browse files
authored
Merge pull request #56 from Ipuch/chunks
2 parents a7a40cf + f3a3e39 commit 7bc55f2

File tree

6 files changed

+80
-39
lines changed

6 files changed

+80
-39
lines changed

environment.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ channels:
44
- default
55
dependencies:
66
- ezc3d
7-
- rerun-sdk>=0.20.1
8-
- numpy
7+
- rerun-sdk=0.21.0
8+
- numpy=1.26.4
99
- biorbd>=1.10.5
1010
- trimesh
1111
- pyomeca

pyorerun/biorbd_components/model_display_options.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,9 @@ class DisplayModelOptions:
1010
markers_color: tuple[int, int, int] = (0, 0, 255)
1111
markers_radius: float = 0.01
1212

13+
centers_of_mass_color: tuple[int, int, int] = (0, 0, 0)
14+
centers_of_mass_radius: float = 0.01
15+
1316
ligaments_color: tuple[int, int, int] = (255, 255, 0)
1417
ligaments_radius: float = 0.01
1518

pyorerun/biorbd_components/model_interface.py

Lines changed: 51 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
1+
from functools import cached_property
2+
13
import biorbd
24
import numpy as np
3-
from biorbd import GeneralizedCoordinates, segment_index
5+
from biorbd import GeneralizedCoordinates
46

57
from .model_display_options import DisplayModelOptions
68

9+
MINIMAL_SEGMENT_MASS = 1e-08
10+
711

812
class BiorbdSegment:
913
"""
@@ -14,32 +18,36 @@ def __init__(self, segment, index):
1418
self.segment = segment
1519
self._index: int = index
1620

17-
@property
21+
@cached_property
1822
def name(self) -> str:
1923
return self.segment.name().to_string()
2024

21-
@property
25+
@cached_property
2226
def id(self) -> int:
2327
return self._index
2428

25-
@property
29+
@cached_property
2630
def has_mesh(self) -> bool:
2731
has_mesh = self.segment.characteristics().mesh().hasMesh()
2832
if has_mesh:
2933
return not self.mesh_path.endswith("/") # Avoid empty mesh path
3034
return has_mesh
3135

32-
@property
36+
@cached_property
3337
def has_meshlines(self) -> bool:
3438
has_mesh = self.segment.characteristics().mesh().hasMesh()
3539
if has_mesh:
3640
return self.mesh_path.endswith("/") # Avoid empty mesh path
3741
return has_mesh
3842

39-
@property
43+
@cached_property
4044
def mesh_path(self) -> str:
4145
return self.segment.characteristics().mesh().path().absolutePath().to_string()
4246

47+
@cached_property
48+
def mass(self) -> float:
49+
return self.segment.characteristics().mass()
50+
4351

4452
class BiorbdModelNoMesh:
4553
"""
@@ -55,30 +63,38 @@ def __init__(self, path: str, options=None):
5563
def from_biorbd_object(cls, model: biorbd.Model, options=None):
5664
return cls(model.path().absolutePath().to_string(), options)
5765

58-
@property
66+
@cached_property
5967
def name(self):
6068
return self.path.split("/")[-1].split(".")[0]
6169

62-
@property
70+
@cached_property
6371
def marker_names(self) -> tuple[str, ...]:
6472
return tuple([s.to_string() for s in self.model.markerNames()])
6573

66-
@property
74+
@cached_property
6775
def nb_markers(self) -> int:
6876
return self.model.nbMarkers()
6977

70-
@property
78+
@cached_property
7179
def segment_names(self) -> tuple[str, ...]:
7280
return tuple([s.name().to_string() for s in self.model.segments()])
7381

74-
@property
82+
@cached_property
7583
def nb_segments(self) -> int:
7684
return self.model.nbSegment()
7785

78-
@property
86+
@cached_property
7987
def segments(self) -> tuple[BiorbdSegment, ...]:
8088
return tuple(BiorbdSegment(s, i) for i, s in enumerate(self.model.segments()))
8189

90+
@cached_property
91+
def segments_with_mass(self) -> tuple[BiorbdSegment, ...]:
92+
return tuple([s for s in self.segments if s.mass > MINIMAL_SEGMENT_MASS])
93+
94+
@cached_property
95+
def segment_names_with_mass(self) -> tuple[str, ...]:
96+
return tuple([s.name for s in self.segments_with_mass])
97+
8298
def segment_homogeneous_matrices_in_global(self, q: np.ndarray, segment_index: int) -> np.ndarray:
8399
"""
84100
Returns a biorbd object containing the roto-translation matrix of the segment in the global reference frame.
@@ -91,24 +107,27 @@ def markers(self, q: np.ndarray) -> np.ndarray:
91107
"""
92108
Returns a [N_markers x 3] array containing the position of each marker in the global reference frame
93109
"""
94-
return np.array(
95-
[self.model.markers(GeneralizedCoordinates(q))[i].to_array() for i in range(self.model.nbMarkers())]
96-
)
110+
return np.array([self.model.markers(GeneralizedCoordinates(q))[i].to_array() for i in range(self.nb_markers)])
97111

98-
def center_of_mass(self, q: np.ndarray) -> np.ndarray:
112+
def centers_of_mass(self, q: np.ndarray) -> np.ndarray:
99113
"""
100-
Returns the position of the center of mass in the global reference frame
114+
Returns the position of the centers of mass in the global reference frame
101115
"""
102-
return self.model.CoM(GeneralizedCoordinates(q)).to_array()
116+
all_com = np.array([com.to_array() for com in self.model.CoMbySegment(GeneralizedCoordinates(q))])
117+
all_com_with_mass = np.zeros((len(self.segments_with_mass), 3))
118+
for i, segment in enumerate(self.segments_with_mass):
119+
all_com_with_mass[i, :] = all_com[segment.id, :]
103120

104-
@property
121+
return all_com_with_mass
122+
123+
@cached_property
105124
def nb_ligaments(self) -> int:
106125
"""
107126
Returns the number of ligaments
108127
"""
109128
return self.model.nbLigaments()
110129

111-
@property
130+
@cached_property
112131
def ligament_names(self) -> tuple[str, ...]:
113132
"""
114133
Returns the names of the ligaments
@@ -129,14 +148,14 @@ def ligament_strips(self, q: np.ndarray) -> list[list[np.ndarray]]:
129148
ligaments.append(ligament_strip)
130149
return ligaments
131150

132-
@property
151+
@cached_property
133152
def nb_muscles(self) -> int:
134153
"""
135154
Returns the number of ligaments
136155
"""
137156
return self.model.nbMuscles()
138157

139-
@property
158+
@cached_property
140159
def muscle_names(self) -> tuple[str, ...]:
141160
"""
142161
Returns the names of the ligaments
@@ -157,32 +176,32 @@ def muscle_strips(self, q: np.ndarray) -> list[list[np.ndarray]]:
157176
muscles.append(muscle_strip)
158177
return muscles
159178

160-
@property
179+
@cached_property
161180
def nb_q(self) -> int:
162181
return self.model.nbQ()
163182

164-
@property
183+
@cached_property
165184
def dof_names(self) -> tuple[str, ...]:
166185
return tuple(s.to_string() for s in self.model.nameDof())
167186

168-
@property
187+
@cached_property
169188
def q_ranges(self) -> tuple[tuple[float, float], ...]:
170189
q_ranges = [q_range for segment in self.model.segments() for q_range in segment.QRanges()]
171190
return tuple((q_range.min(), q_range.max()) for q_range in q_ranges)
172191

173-
@property
192+
@cached_property
174193
def gravity(self) -> np.ndarray:
175194
return self.model.getGravity().to_array()
176195

177-
@property
196+
@cached_property
178197
def has_mesh(self) -> bool:
179198
return any([s.has_mesh for s in self.segments])
180199

181-
@property
200+
@cached_property
182201
def has_meshlines(self) -> bool:
183202
return any([s.has_meshlines for s in self.segments])
184203

185-
@property
204+
@cached_property
186205
def has_soft_contacts(self) -> bool:
187206
return self.model.nbSoftContacts() > 0
188207

@@ -193,14 +212,14 @@ def soft_contacts(self, q: np.ndarray) -> np.ndarray:
193212
soft_contacts = self.model.softContacts(q, True)
194213
return np.array([soft_contacts[i].to_array() for i in range(self.model.nbSoftContacts())])
195214

196-
@property
215+
@cached_property
197216
def soft_contacts_names(self) -> tuple[str, ...]:
198217
"""
199218
Returns the names of the soft contacts
200219
"""
201220
return tuple([s.to_string() for s in self.model.softContactNames()])
202221

203-
@property
222+
@cached_property
204223
def soft_contact_radii(self) -> tuple[float, ...]:
205224
"""
206225
Returns the radii of the soft contacts
@@ -227,7 +246,7 @@ def __init__(self, path, options=None):
227246
def segments(self) -> tuple[BiorbdSegment, ...]:
228247
return tuple([s for s in super().segments if s.has_mesh or s.has_meshlines])
229248

230-
@property
249+
@cached_property
231250
def meshlines(self) -> list[np.ndarray]:
232251

233252
meshes = []

pyorerun/biorbd_components/model_updapter.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ def __init__(self, name, model: BiorbdModelNoMesh | BiorbdModel):
1919
self.name = name
2020
self.model = model
2121
self.markers = self.create_markers_updater()
22+
self.centers_of_mass = self.create_centers_of_mass_updater()
2223
self.soft_contacts = self.create_soft_contacts_updater()
2324
self.ligaments = self.create_ligaments_updater()
2425
self.segments = self.create_segments_updater()
@@ -73,6 +74,17 @@ def create_markers_updater(self):
7374
callable_markers=self.model.markers,
7475
)
7576

77+
def create_centers_of_mass_updater(self):
78+
return MarkersUpdater(
79+
self.name + "/centers_of_mass",
80+
marker_properties=MarkerProperties(
81+
markers_names=self.model.segment_names_with_mass,
82+
color=np.array(self.model.options.centers_of_mass_color),
83+
radius=self.model.options.centers_of_mass_radius,
84+
),
85+
callable_markers=self.model.centers_of_mass,
86+
)
87+
7688
def create_soft_contacts_updater(self):
7789
if not self.model.has_soft_contacts:
7890
return EmptyUpdater(self.name + "/soft_contacts")
@@ -160,7 +172,14 @@ def components(self) -> list[Any]:
160172
all_segment_components = []
161173
for segment in self.segments:
162174
all_segment_components.extend(segment.components)
163-
return [self.markers, self.soft_contacts, *all_segment_components, self.ligaments, self.muscles]
175+
return [
176+
self.markers,
177+
self.centers_of_mass,
178+
self.soft_contacts,
179+
*all_segment_components,
180+
self.ligaments,
181+
self.muscles,
182+
]
164183

165184
@property
166185
def component_names(self) -> list[str]:

pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,8 @@ classifiers = [
2121
]
2222
dependencies = [
2323
# "ezc3d", # Not yet available on pypi, use `conda install -c conda-forge ezc3d`
24-
"numpy",
25-
"rerun-sdk==0.20.1",
24+
"numpy==1.26.4",
25+
"rerun-sdk==0.21.0",
2626
"trimesh",
2727
"pyomeca",
2828
"tk",

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@
55
version="1.2.5",
66
install_requires=[
77
"ezc3d", # Not yet available on pypi, use `conda install -c conda-forge ezc3d`
8-
"numpy",
9-
"rerun-sdk>=0.20.1",
8+
"numpy=1.26.4",
9+
"rerun-sdk=0.21.0",
1010
"trimesh",
1111
"pyomeca",
1212
"tk",

0 commit comments

Comments
 (0)