From e837b83822259878ea22a52974ca3bb0d52fc9c0 Mon Sep 17 00:00:00 2001 From: Ipuch Date: Thu, 9 May 2024 11:17:21 -0400 Subject: [PATCH 1/2] feat: model_updater as a lonely feature for custom rerun @aceglia --- pyorerun/biorbd_components/local_frame.py | 2 +- pyorerun/biorbd_components/model_updapter.py | 32 ++++++++++++++++++++ pyorerun/live_animation.py | 25 +++++++-------- 3 files changed, 46 insertions(+), 13 deletions(-) diff --git a/pyorerun/biorbd_components/local_frame.py b/pyorerun/biorbd_components/local_frame.py index e0a43d5..006a9d3 100644 --- a/pyorerun/biorbd_components/local_frame.py +++ b/pyorerun/biorbd_components/local_frame.py @@ -28,6 +28,6 @@ def to_rerun(self, q: np.ndarray) -> None: rr.Transform3D( # scale=self.scale, translation=homogenous_matrices[:3, 3], - mat3x3=homogenous_matrices[:3, :3], + mat3x3=homogenous_matrices[:3, :3] * 0.25, ), ) diff --git a/pyorerun/biorbd_components/model_updapter.py b/pyorerun/biorbd_components/model_updapter.py index 1d1c110..159f4b4 100644 --- a/pyorerun/biorbd_components/model_updapter.py +++ b/pyorerun/biorbd_components/model_updapter.py @@ -23,6 +23,38 @@ def __init__(self, name, model: BiorbdModel): self.segments = self.create_segments_updater() self.muscles = self.create_muscles_updater() + @classmethod + def from_file(cls, model_path: str): + """ + This factory method is meant to be used with rerun easily. For example, to display a model in rerun, + and add its custom experimental data. + + Parameters + ---------- + model_path: str + The path to the bioMod file, such as "path/to/model.bioMod". + + Returns + ------- + ModelUpdater + + Examples + -------- + >>> import rerun as rr + >>> import numpy as np + + >>> q = np.zeros(10) + >>> model = ModelUpdater.from_file("path/to/model.bioMod") + + >>> rr.init("my_thing", spawn=True) + >>> rr.set_time_sequence(timeline="step", sequence=0) + >>> model.to_rerun(q) + >>> rr.log("anything", rr.Anything()) + + """ + model = BiorbdModel(model_path) + return cls(model.name, model) + def create_markers_updater(self): if self.model.nb_markers == 0: return EmptyUpdater(self.name + "/markers") diff --git a/pyorerun/live_animation.py b/pyorerun/live_animation.py index e16d1ef..0f0d9e8 100644 --- a/pyorerun/live_animation.py +++ b/pyorerun/live_animation.py @@ -5,7 +5,7 @@ import rerun as rr from .biorbd_components.model_interface import BiorbdModel -from .phase_rerun import PhaseRerun +from .biorbd_components.model_updapter import ModelUpdater class LiveModelAnimation: @@ -43,8 +43,10 @@ def __init__(self, model_path: str, with_q_charts: bool = False): """ self.counter = 0 - self.model = BiorbdModel(model_path) + self.model_updater = ModelUpdater.from_file(model_path) + self.model = self.model_updater.model self.biorbd_model = self.model.model + self.q = np.zeros(self.biorbd_model.nbQ()) self.dof_sliders = [] self.dof_slider_values = [] @@ -52,11 +54,17 @@ def __init__(self, model_path: str, with_q_charts: bool = False): self.with_q_charts = with_q_charts def update_viewer(self, event, dof_index: int): + the_dof_idx, the_value = self.fetch_and_update_slider_value(event, dof_index) + self.update_rerun_components(the_dof_idx, the_value) + + def fetch_and_update_slider_value(self, event, dof_index: int) -> tuple[int, float]: the_dof_idx = dof_index the_value = self.dof_sliders[the_dof_idx].get() # update the slider value q self.dof_slider_values[the_dof_idx].config(text=f"{the_value:.2f}") - # update joint angles q + return the_dof_idx, the_value + + def update_rerun_components(self, the_dof_idx: int, the_value: float): self.q[the_dof_idx] = the_value # update counter self.counter += 1 @@ -68,7 +76,7 @@ def update_viewer(self, event, dof_index: int): self.update_trajectories(self.q) def update_model(self, q: np.ndarray): - self.viz.biorbd_models.rerun_models[0].to_rerun(q) + self.model_updater.to_rerun(q) def update_trajectories(self, q: np.ndarray): q_ranges = [q_range for segment in self.biorbd_model.segments() for q_range in segment.QRanges()] @@ -88,16 +96,9 @@ def to_serie_line(self, name: str, min: float, max: float, val: float): rr.log(f"{name}/value", rr.Scalar(val)) def rerun(self, name: str = None): - # Building a fake pyorerun animation - nb_frames = 1 - nb_seconds = 0 - t_span = np.linspace(0, nb_seconds, nb_frames) - q = np.zeros((self.model.model.nbQ(), nb_frames)) - self.viz = PhaseRerun(t_span) - self.viz.add_animated_model(self.model, q) - # update manually here rr.init(application_id=f"{self.model.name}" if name is None else name, spawn=True) + self.update_rerun_components(the_dof_idx=0, the_value=0.0) self.create_window_with_sliders() def create_window_with_sliders(self): From 34aa0d4a11a51b16a6cce43667a426f410bc5e2f Mon Sep 17 00:00:00 2001 From: Ipuch Date: Thu, 9 May 2024 11:21:41 -0400 Subject: [PATCH 2/2] docs: fix doc --- pyorerun/__init__.py | 1 + pyorerun/biorbd_components/model_updapter.py | 1 + 2 files changed, 2 insertions(+) diff --git a/pyorerun/__init__.py b/pyorerun/__init__.py index 6adaa1d..06ae53c 100644 --- a/pyorerun/__init__.py +++ b/pyorerun/__init__.py @@ -1,5 +1,6 @@ from .biorbd_components.model_display_options import DisplayModelOptions from .biorbd_components.model_interface import BiorbdModel, BiorbdModelNoMesh +from .biorbd_components.model_updapter import ModelUpdater from .live_animation import LiveModelAnimation from .multi_phase_rerun import MultiPhaseRerun diff --git a/pyorerun/biorbd_components/model_updapter.py b/pyorerun/biorbd_components/model_updapter.py index 159f4b4..8d11765 100644 --- a/pyorerun/biorbd_components/model_updapter.py +++ b/pyorerun/biorbd_components/model_updapter.py @@ -42,6 +42,7 @@ def from_file(cls, model_path: str): -------- >>> import rerun as rr >>> import numpy as np + >>> from pyorerun import ModelUpdater >>> q = np.zeros(10) >>> model = ModelUpdater.from_file("path/to/model.bioMod")