Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Comply to biorbd Reborn #18

Merged
merged 8 commits into from
Oct 7, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 25 additions & 37 deletions BiorbdViz/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,12 @@

class BiorbdViz:
def __init__(self, model_path=None, loaded_model=None,
show_global_ref_frame=True,
show_markers=True, show_global_center_of_mass=True, show_segments_center_of_mass=True,
show_rt=True, show_muscles=True, show_meshes=True,
show_options=True):
show_meshes=True,
show_global_center_of_mass=True, show_segments_center_of_mass=True,
show_global_ref_frame=True, show_local_ref_frame=True,
show_markers=True,
show_muscles=True,
show_analyses_panel=True):
"""
Class that easily shows a biorbd model
Args:
Expand Down Expand Up @@ -55,7 +57,7 @@ def __init__(self, model_path=None, loaded_model=None,
self.show_global_ref_frame = show_global_ref_frame
self.show_global_center_of_mass = show_global_center_of_mass
self.show_segments_center_of_mass = show_segments_center_of_mass
self.show_rt = show_rt
self.show_local_ref_frame = show_local_ref_frame
if self.model.nbMuscleTotal() > 0:
self.show_muscles = show_muscles
else:
Expand All @@ -68,7 +70,7 @@ def __init__(self, model_path=None, loaded_model=None,
# Create all the reference to the things to plot
self.nQ = self.model.nbQ()
self.Q = np.zeros(self.nQ)
self.markers = Markers3d(np.ndarray((3, self.model.nTags(), 1)))
self.markers = Markers3d(np.ndarray((3, self.model.nMarkers(), 1)))
self.global_center_of_mass = Markers3d(np.ndarray((3, 1, 1)))
self.segments_center_of_mass = Markers3d(np.ndarray((3, self.model.nbBone(), 1)))
self.mesh = MeshCollection()
Expand All @@ -77,31 +79,24 @@ def __init__(self, model_path=None, loaded_model=None,
for k, mesh in enumerate(meshes):
tp[:, k, 0] = mesh.get_array()
self.mesh.append(Mesh(vertex=tp))
self.model.updateMuscles(self.model, self.Q, True)
self.model.updateMuscles(self.Q, True)
self.muscles = MeshCollection()
for group_idx in range(self.model.nbMuscleGroups()):
for muscle_idx in range(self.model.muscleGroup(group_idx).nbMuscles()):
musc_tp = self.model.muscleGroup(group_idx).muscle(muscle_idx)
muscle_type = biorbd.Model.getMuscleType(musc_tp).getString()
if muscle_type == "Hill":
musc = biorbd.HillType(musc_tp)
elif muscle_type == "HillThelen":
musc = biorbd.HillTypeThelen(musc_tp)
elif muscle_type == "HillSimple":
musc = biorbd.HillTypeSimple(musc_tp)
musc = self.model.muscleGroup(group_idx).muscle(muscle_idx)
tp = np.ndarray((3, len(musc.position().musclesPointsInGlobal()), 1))
for k, pts in enumerate(musc.position().musclesPointsInGlobal()):
tp[:, k, 0] = pts.get_array()
self.muscles.append(Mesh(vertex=tp))
self.rt = RotoTransCollection()
for rt in self.model.globalJCS(self.Q):
for rt in self.model.allGlobalJCS(self.Q):
self.rt.append(RotoTrans(rt.get_array()))

if self.show_global_ref_frame:
self.vtk_model.create_global_ref_frame()

self.show_options = show_options
if self.show_options:
self.show_analyses_panel = show_analyses_panel
if self.show_analyses_panel:
self.muscle_analyses = []
self.palette_active = QPalette()
self.palette_inactive = QPalette()
Expand Down Expand Up @@ -148,10 +143,10 @@ def set_q(self, Q, refresh_window=True):
raise TypeError(f"Q should be a {self.nQ} column vector")
self.Q = Q

self.model.UpdateKinematicsCustom(self.model, biorbd.GeneralizedCoordinates(self.Q))
self.model.UpdateKinematicsCustom(biorbd.GeneralizedCoordinates(self.Q))
if self.show_muscles:
self.__set_muscles_from_q()
if self.show_rt:
if self.show_local_ref_frame:
self.__set_rt_from_q()
if self.show_meshes:
self.__set_meshes_from_q()
Expand All @@ -163,7 +158,7 @@ def set_q(self, Q, refresh_window=True):
self.__set_markers_from_q()

# Update the sliders
if self.show_options:
if self.show_analyses_panel:
for i, slide in enumerate(self.sliders):
slide[1].blockSignals(True)
slide[1].setValue(self.Q[i]*self.double_factor)
Expand All @@ -184,7 +179,7 @@ def refresh_window(self):
def exec(self):
self.is_executing = True
while self.vtk_window.is_active:
if self.show_options and self.is_animating:
if self.show_analyses_panel and self.is_animating:
self.movement_slider[0].setValue(
(self.movement_slider[0].value() + 1) % self.movement_slider[0].maximum()
)
Expand Down Expand Up @@ -365,7 +360,7 @@ def __select_analyses_panel(self, radio_button, panel_to_activate):
raise RuntimeError("Non-existing panel asked... This should never happen, please report this issue!")

# Activate the required panel
self.__show_analyses_panel()
self.__show_local_ref_frame()

# Enlarge the main window
self.vtk_window.resize(int(self.vtk_window.size().width() * enlargement_factor / reduction_factor),
Expand All @@ -379,7 +374,7 @@ def __hide_analyses_panel(self):
self.vtk_window.main_layout.removeWidget(self.active_analyses_widget)
self.vtk_window.main_layout.setColumnStretch(2, 0)

def __show_analyses_panel(self):
def __show_local_ref_frame(self):
# Give the parent as main window
if self.active_analyses_widget is not None:
self.vtk_window.main_layout.addWidget(self.active_analyses_widget, 0, 2)
Expand Down Expand Up @@ -471,7 +466,7 @@ def __load_movement(self):
self.muscle_analyses.add_movement_to_dof_choice()

def __set_markers_from_q(self):
markers = self.model.Tags(self.model, self.Q, True, False)
markers = self.model.markers(self.Q, True, False)
for k, mark in enumerate(markers):
self.markers[0:3, k, 0] = mark.get_array().reshape(-1, 1)
self.vtk_model.update_markers(self.markers.get_frame(0))
Expand All @@ -490,29 +485,22 @@ def __set_segments_center_of_mass_from_q(self):
def __set_meshes_from_q(self):
for l, meshes in enumerate(self.model.meshPoints(self.Q, False)):
for k, mesh in enumerate(meshes):
self.mesh.get_frame(0)[l][0:3, k] = mesh.get_array()
self.mesh.get_frame(0)[l][0:3, k] = mesh.get_array()[:, np.newaxis]
self.vtk_model.update_mesh(self.mesh)

def __set_muscles_from_q(self):
self.model.updateMuscles(self.model, self.Q, True)
self.model.updateMuscles(self.Q, True)

idx = 0
for group_idx in range(self.model.nbMuscleGroups()):
for muscle_idx in range(self.model.muscleGroup(group_idx).nbMuscles()):
musc_tp = self.model.muscleGroup(group_idx).muscle(muscle_idx)
muscle_type = biorbd.Model.getMuscleType(musc_tp).getString()
if muscle_type == "Hill":
musc = biorbd.HillType(musc_tp)
elif muscle_type == "HillThelen":
musc = biorbd.HillTypeThelen(musc_tp)
elif muscle_type == "HillSimple":
musc = biorbd.HillTypeSimple(musc_tp)
musc = self.model.muscleGroup(group_idx).muscle(muscle_idx)
for k, pts in enumerate(musc.position().musclesPointsInGlobal()):
self.muscles.get_frame(0)[idx][0:3, k] = pts.get_array()
self.muscles.get_frame(0)[idx][0:3, k, 0] = pts.get_array()[:, np.newaxis]
idx += 1
self.vtk_model.update_muscle(self.muscles)

def __set_rt_from_q(self):
for k, rt in enumerate(self.model.globalJCS(self.Q, False)):
for k, rt in enumerate(self.model.allGlobalJCS()):
self.rt[k] = RotoTrans(rt.get_array())
self.vtk_model.update_rt(self.rt)
89 changes: 42 additions & 47 deletions BiorbdViz/analyses.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ def __init__(self, parent, main_window, background_color=(.5, .5, .5)):
# Add plots
analyses_layout = QGridLayout()
analyses_muscle_layout.addLayout(analyses_layout)
self.n_point_for_q = 100
self.n_point_for_q = 50

# Add muscle length plot
self.canvas_muscle_length = FigureCanvasQTAgg(plt.figure(facecolor=background_color))
Expand Down Expand Up @@ -102,7 +102,7 @@ def __init__(self, parent, main_window, background_color=(.5, .5, .5)):
for group in range(self.model.nbMuscleGroups()):
for mus in range(self.model.muscleGroup(group).nbMuscles()):
# Map the name to the right numbers
name = biorbd.HillType.getRef(self.model.muscleGroup(group).muscle(mus)).name().getString()
name = self.model.muscleGroup(group).muscle(mus).name().getString()
self.muscle_mapping[name] = (group, mus, cmp_mus)

# Add the CheckBox
Expand Down Expand Up @@ -144,30 +144,59 @@ def __set_current_dof(self):

def update_all_graphs(self, skip_muscle_length, skip_moment_arm, skip_passive_forces,
skip_active_forces):
x_axis, length, moment_arm, passive_forces, active_forces = self.__compute_all_values()
self.__update_specific_plot(self.canvas_muscle_length, self.ax_muscle_length,
self.__get_muscle_lengths, skip_muscle_length)
x_axis, length, skip_muscle_length)

self.__update_specific_plot(self.canvas_moment_arm, self.ax_moment_arm,
self.__get_moment_arms, skip_moment_arm)
x_axis, moment_arm, skip_moment_arm)

self.__update_specific_plot(self.canvas_passive_forces, self.ax_passive_forces,
self.__get_passive_forces, skip_passive_forces)
x_axis, passive_forces, skip_passive_forces)

self.__update_specific_plot(self.canvas_active_forces, self.ax_active_forces,
self.__get_active_forces, skip_active_forces)
x_axis, active_forces, skip_active_forces)

def __update_specific_plot(self, canvas, ax, func, skip=False):
def __compute_all_values(self):
q_idx = self.dof_mapping[self.current_dof]
x_axis, all_q = self.__generate_x_axis(q_idx)
length = np.ndarray((self.n_point_for_q, self.model.nbMuscleTotal()))
moment_arm = np.ndarray((self.n_point_for_q, self.model.nbMuscleTotal()))
passive_forces = np.ndarray((self.n_point_for_q, self.model.nbMuscleTotal()))
active_forces = np.ndarray((self.n_point_for_q, self.model.nbMuscleTotal()))
emg = biorbd.StateDynamics(0, self.active_forces_slider.value() / 100)
for i, q_mod in enumerate(all_q):
self.model.UpdateKinematicsCustom(biorbd.GeneralizedCoordinates(q_mod))
muscles_length_jacobian = self.model.musclesLengthJacobian().get_array()
for m in range(self.model.nbMuscleTotal()):
if self.checkboxes_muscle[m].isChecked():
mus_group_idx, mus_idx, _ = self.muscle_mapping[self.checkboxes_muscle[m].text()]
mus = self.model.muscleGroup(mus_group_idx).muscle(mus_idx)
mus.updateOrientations(self.model, q_mod, 1)

length[i, m] = mus.length(self.model, q_mod, False)
moment_arm[i, m] = muscles_length_jacobian[mus_idx, q_idx]
if mus.type() != biorbd.IDEALIZED_ACTUATOR:
passive_forces[i, m] = biorbd.HillType(mus).FlPE()
else:
passive_forces[i, m] = 0
if mus.type() != biorbd.IDEALIZED_ACTUATOR:
active_forces[i, m] = biorbd.HillType(mus).FlCE(emg)
else:
active_forces[i, m] = 0

return x_axis, length, moment_arm, passive_forces, active_forces

def __update_specific_plot(self, canvas, ax, x, y, skip=False):
# Plot all active muscles
number_of_active = 0
for ax_idx, checkbox in enumerate(self.checkboxes_muscle):
if checkbox.isChecked():
for m in range(self.model.nbMuscleTotal()):
if self.checkboxes_muscle[m].isChecked():
if not skip:
x, y = func(q_idx, *self.muscle_mapping[checkbox.text()])
ax.get_lines()[ax_idx].set_data(x, y)
ax.get_lines()[m].set_data(x, y[:, m])
number_of_active += 1
else:
ax.get_lines()[ax_idx].set_data(np.nan, np.nan)
ax.get_lines()[m].set_data(np.nan, np.nan)

# Empty the vertical bar (otherwise relim takes it in account
ax.get_lines()[-1].set_data(np.nan, np.nan)
Expand All @@ -182,7 +211,7 @@ def __update_specific_plot(self, canvas, ax, func, skip=False):
if self.animation_checkbox.isChecked():
ax.set_xlabel("Time frame (index)")
else:
ax.set_xlabel(self.model.nameDof()[q_idx] + " (rad) along full range")
ax.set_xlabel(self.model.nameDof()[self.dof_mapping[self.current_dof]] + " (rad) along full range")

# Add vertical bar to show current dof (it must be done after relim so we know the new lims)
q_idx = self.combobox_dof.currentIndex()
Expand All @@ -207,37 +236,3 @@ def __generate_x_axis(self, q_idx):
q[:, q_idx] = np.linspace(-np.pi, np.pi, self.n_point_for_q)
x = q[:, q_idx]
return x, q

def __get_muscle_lengths(self, q_idx, mus_group_idx, mus_idx, _):
x_axis, all_q = self.__generate_x_axis(q_idx)
length = np.ndarray(x_axis.shape)
for i, q_mod in enumerate(all_q):
length[i] = biorbd.HillType.getRef(
self.model.muscleGroup(mus_group_idx).muscle(mus_idx)).length(self.model, q_mod)
return x_axis, length

def __get_moment_arms(self, q_idx, _, __, mus_idx):
x_axis, all_q = self.__generate_x_axis(q_idx)
moment_arm = np.ndarray(x_axis.shape)
for i, q_mod in enumerate(all_q):
moment_arm[i] = self.model.musclesLengthJacobian(self.model, q_mod).get_array()[mus_idx, q_idx]
return x_axis, moment_arm

def __get_passive_forces(self, q_idx, mus_group_idx, mus_idx, _):
mus = biorbd.HillType.getRef(self.model.muscleGroup(mus_group_idx).muscle(mus_idx))
x_axis, all_q = self.__generate_x_axis(q_idx)
passive_forces = np.ndarray(x_axis.shape)
for i, q_mod in enumerate(all_q):
mus.updateOrientations(self.model, q_mod)
passive_forces[i] = mus.FlPE()
return x_axis, passive_forces

def __get_active_forces(self, q_idx, mus_group_idx, mus_idx, _):
mus = biorbd.HillType.getRef(self.model.muscleGroup(mus_group_idx).muscle(mus_idx))
emg = biorbd.StateDynamics(0, self.active_forces_slider.value()/100)
x_axis, all_q = self.__generate_x_axis(q_idx)
active_forces = np.ndarray(x_axis.shape)
for i, q_mod in enumerate(all_q):
mus.updateOrientations(self.model, q_mod)
active_forces[i] = mus.FlCE(emg)
return x_axis, active_forces
Loading