@@ -16,8 +16,10 @@ class LiveModelAnimation:
1616 ----------
1717 counter : int
1818 A counter to keep track of the number of updates.
19- model : BiorbdModel
20- The biorbd model to animate.
19+ model_updater : ModelUpdater
20+ An instance of ModelUpdater to handle model updates.
21+ model : AbstractModel
22+ The model to animate.
2123 q : np.ndarray
2224 The current joint angles.
2325 dof_sliders : list
@@ -41,6 +43,10 @@ def __init__(self, model_updater: ModelUpdater, with_q_charts: bool = False):
4143 """
4244
4345 self .counter = 0
46+ self .use_degrees = False
47+ self .root = None
48+ self ._btn_toggle_units = None
49+
4450 self .model_updater = model_updater
4551 self .model = self .model_updater .model
4652
@@ -109,19 +115,81 @@ def rerun(self, name: str = None):
109115 self .create_window_with_sliders ()
110116
111117 def create_window_with_sliders (self ):
112- root = tk .Tk ()
118+ self .root = tk .Tk ()
119+ root = self .root
113120 root .title ("Degree of Freedom q Sliders" )
114121
115122 for i in range (self .model .nb_q ):
116123 self .update_functions .append (lambda event , idx = i : self .update_viewer (event , idx ))
124+
117125 dof_slider_label = ttk .Label (root , text = f"q{ i } - { self .model .dof_names [i ]} : " , anchor = "w" )
118126 dof_slider_label .grid (row = i , column = 0 , padx = 10 , pady = 5 , sticky = "w" )
119127
120128 self .dof_sliders .append (
121129 ttk .Scale (root , from_ = - 5 , to = 5 , orient = "horizontal" , command = self .update_functions [i ], length = 200 )
122130 )
123131 self .dof_sliders [i ].grid (row = i , column = 1 , padx = 30 , pady = 5 )
124- self .dof_slider_values .append (ttk .Label (root , text = "0" ))
132+
133+ self .dof_slider_values .append (ttk .Label (root , text = self ._format_value_for_ui (0.0 )))
125134 self .dof_slider_values [i ].grid (row = i , column = 2 , padx = 10 , pady = 5 )
126135
136+ base_row = self .model .nb_q
137+ btn_copy = ttk .Button (root , text = "Copy q" , command = self ._copy_q_values ())
138+ btn_copy .grid (row = base_row , column = 0 , padx = 10 , pady = 10 , sticky = "ew" )
139+
140+ self ._btn_toggle_units = ttk .Button (root , text = "Switch rad/deg" , command = self ._toggle_units )
141+ self ._btn_toggle_units .grid (row = base_row , column = 1 , padx = 10 , pady = 10 , sticky = "ew" )
142+
143+ btn_reset = ttk .Button (root , text = "Reset all" , command = self ._reset_all )
144+ btn_reset .grid (row = base_row , column = 2 , padx = 10 , pady = 10 , sticky = "ew" )
145+
127146 root .mainloop ()
147+
148+ def _format_value_for_ui (self , value_rad : float ) -> str :
149+ if self .use_degrees :
150+ return f"{ np .degrees (value_rad ):.2f} °"
151+ return f"{ value_rad :.2f} rad"
152+
153+ def _update_value_label (self , idx : int ):
154+ val_rad = float (self .dof_sliders [idx ].get ())
155+ self .dof_slider_values [idx ].config (text = self ._format_value_for_ui (val_rad ))
156+
157+ def _toggle_units (self ):
158+ self .use_degrees = not self .use_degrees
159+ # rafraîchir toutes les étiquettes de valeurs
160+ for i in range (self .model .nb_q ):
161+ self ._update_value_label (i )
162+
163+ def _copy_q_values (self ):
164+ if self .root is None :
165+ return
166+ if self .use_degrees :
167+ values = [float (np .degrees (self .dof_sliders [i ].get ())) for i in range (self .model .nb_q )]
168+ unit = "deg"
169+ else :
170+ values = [float (self .dof_sliders [i ].get ()) for i in range (self .model .nb_q )]
171+ unit = "rad"
172+
173+ text = ", " .join (f"{ v :.6f} " for v in values ) + f" [{ unit } ]"
174+ self .root .clipboard_clear ()
175+ self .root .clipboard_append (text )
176+
177+ def _reset_all (self ):
178+ self .q [:] = 0.0
179+ for i , s in enumerate (self .dof_sliders ):
180+ s .configure (command = None )
181+ s .set (0.0 )
182+ self ._update_value_label (i )
183+ s .configure (command = self .update_functions [i ])
184+
185+ self .counter += 1
186+ rr .set_time (timeline = "step" , sequence = self .counter )
187+ self .update_model (self .q )
188+ if self .with_q_charts :
189+ self .update_trajectories (self .q )
190+
191+ def fetch_and_update_slider_value (self , event , dof_index : int ) -> tuple [int , float ]:
192+ the_dof_idx = dof_index
193+ val_rad = float (self .dof_sliders [the_dof_idx ].get ())
194+ self .dof_slider_values [the_dof_idx ].config (text = self ._format_value_for_ui (val_rad ))
195+ return the_dof_idx , val_rad
0 commit comments