1+ from functools import cached_property
2+
13import biorbd
24import numpy as np
3- from biorbd import GeneralizedCoordinates , segment_index
5+ from biorbd import GeneralizedCoordinates
46
57from .model_display_options import DisplayModelOptions
68
9+ MINIMAL_SEGMENT_MASS = 1e-08
10+
711
812class 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
4452class 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 = []
0 commit comments