def test_read_markers( usecols, shape_val, first_last_val, mean_val, median_val, sum_val, nans_val, extension, ): if extension == "csv": data = Markers.from_csv(**markers_csv_kwargs, usecols=usecols) decimal = 0 elif extension == "c3d": data = Markers.from_c3d(MARKERS_ANALOGS_C3D, prefix_delimiter=":", usecols=usecols) decimal = 4 else: raise ValueError("wrong extension provided") if usecols and isinstance(usecols[0], str): np.testing.assert_array_equal(x=data.channel, y=usecols) is_expected_array( data, shape_val, first_last_val, mean_val, median_val, sum_val, nans_val, decimal=decimal, )
def test_proc_matmul(): restart_seed() random_markers_1 = Markers.from_random_data() random_markers_2 = Markers.from_random_data() markers_matmul = random_markers_1.meca.matmul(random_markers_2) ref_markers_matmul = random_markers_1 @ random_markers_2 np.testing.assert_almost_equal(markers_matmul, -33729.52497131, decimal=6) np.testing.assert_almost_equal(markers_matmul, ref_markers_matmul, decimal=6)
def test_markers_creation(): dims = ("axis", "channel", "time") array = Markers() np.testing.assert_array_equal(x=array, y=xr.DataArray()) assert array.dims == dims array = Markers(MARKERS_DATA.values) is_expected_array(array, **EXPECTED_VALUES[57]) size = 3, 10, 100 array = Markers.from_random_data(size=size) assert array.shape == (4, size[1], size[2]) assert array.dims == dims with pytest.raises(ValueError): Markers(ANALOGS_DATA)
def test_read_catch_error( usecols, extension, ): with pytest.raises(IndexError): Markers.from_csv(MARKERS_CSV) if extension == "csv": with pytest.raises(ValueError): Analogs.from_csv(**analogs_csv_kwargs, usecols=usecols) with pytest.raises(ValueError): Markers.from_csv(**markers_csv_kwargs, usecols=usecols) elif extension == "c3d": with pytest.raises(ValueError): Analogs.from_c3d(MARKERS_ANALOGS_C3D, usecols=usecols) reader = getattr(Markers, f"from_{extension}") with pytest.raises(ValueError): reader(MARKERS_ANALOGS_C3D, usecols=usecols)
def test_csv_without_header(): is_expected_array( Analogs.from_csv(ANALOGS_CSV, first_row=5, first_column=2), **EXPECTED_VALUES[59], ) is_expected_array( Markers.from_csv(MARKERS_CSV_WITHOUT_HEADER, first_column=2), **EXPECTED_VALUES[58], )
def test_rototrans_creation(): dims = ("row", "col", "time") array = Rototrans() np.testing.assert_array_equal(x=array, y=xr.DataArray(np.eye(4)[..., np.newaxis])) assert array.dims == dims data = Markers(MARKERS_DATA.values) array = Rototrans.from_markers( origin=data.isel(channel=[0]), axis_1=data.isel(channel=[0, 1]), axis_2=data.isel(channel=[0, 2]), axes_name="xy", axis_to_recalculate="y", ) is_expected_array(array, **EXPECTED_VALUES[67]) size = 4, 4, 100 array = Rototrans.from_random_data(size=size) assert array.shape == size assert array.dims == dims with pytest.raises(ValueError): Angles(ANALOGS_DATA)
def test_read_xlsx(): is_expected_array( Markers.from_excel(**{ **markers_csv_kwargs, **dict(filename=MARKERS_XLSX) }), **EXPECTED_VALUES[60], ) is_expected_array( Analogs.from_excel(**{ **analogs_csv_kwargs, **dict(filename=ANALOGS_XLSX) }), **EXPECTED_VALUES[61], )
def test_proc_norm_marker(): n_frames = 100 n_markers = 10 random_marker = Markers.from_random_data(size=(3, n_markers, n_frames)) norm = random_marker.meca.norm(dim="axis") norm_without_ones = random_marker.drop_sel(axis="ones").meca.norm( dim="axis") np.testing.assert_array_equal(norm, norm_without_ones) expected_norm = np.ndarray((n_markers, n_frames)) for marker in range(n_markers): for frame in range(n_frames): expected_norm[marker, frame] = np.sqrt( random_marker[0:3, marker, frame].dot(random_marker[0:3, marker, frame])) np.testing.assert_array_equal(norm, expected_norm)
def test_rotate(): n_frames = 100 n_markers = 10 angles = Angles.from_random_data(size=(3, 1, n_frames)) rt = Rototrans.from_euler_angles(angles, "xyz") markers = Markers.from_random_data(size=(3, n_markers, n_frames)) rotated_markers = Markers.from_rototrans(markers, rt) expected_rotated_marker = np.ndarray((4, n_markers, n_frames)) for marker in range(n_markers): for frame in range(n_frames): expected_rotated_marker[:, marker, frame] = np.dot( rt.isel(time=frame), markers.isel(channel=marker, time=frame), ) np.testing.assert_array_almost_equal(rotated_markers, expected_rotated_marker, decimal=10) rotated_markers = Markers.from_rototrans(markers.isel(time=0), rt.isel(time=0)) expected_rotated_marker = np.ndarray(rotated_markers.shape) for marker in range(n_markers): expected_rotated_marker[:, marker] = np.dot( rt.isel(time=0), markers.isel(channel=marker, time=0)) np.testing.assert_array_almost_equal(rotated_markers, expected_rotated_marker, decimal=10) rotated_markers = Markers.from_rototrans(markers, rt.isel(time=0)) expected_rotated_marker = np.ndarray(rotated_markers.shape) for marker in range(n_markers): expected_rotated_marker[:, marker] = np.dot(rt.isel(time=0), markers.isel(channel=marker)) np.testing.assert_array_almost_equal(rotated_markers, expected_rotated_marker, decimal=10) with pytest.raises(ValueError): Markers.from_rototrans(markers.isel(time=0), rt)
def test_proc_norm(): n_frames = 100 n_markers = 10 m = Markers(np.random.rand(3, n_markers, n_frames)) # norm by hand expected_norm = np.linalg.norm(m[:3, ...], axis=0) # norm with pyomeca computed_norm = m.meca.norm(dim="axis") np.testing.assert_almost_equal(computed_norm, expected_norm, decimal=10) is_expected_array(MARKERS_DATA.meca.norm(dim="axis"), **EXPECTED_VALUES[44]) is_expected_array(MARKERS_DATA.meca.norm(dim="channel"), **EXPECTED_VALUES[45]) is_expected_array(MARKERS_DATA.meca.norm(dim="time"), **EXPECTED_VALUES[46]) is_expected_array(ANALOGS_DATA.meca.norm(dim="channel"), **EXPECTED_VALUES[47]) is_expected_array(ANALOGS_DATA.meca.norm(dim="time"), **EXPECTED_VALUES[48])
def test_read_trc(): is_expected_array(Markers.from_trc(MARKERS_TRC), **EXPECTED_VALUES[64])
def __init__( self, parent, markers_size=0.010, markers_color=(1, 1, 1), markers_opacity=1.0, global_ref_frame_length=0.15, global_ref_frame_width=5, global_center_of_mass_size=0.0075, global_center_of_mass_color=(0, 0, 0), global_center_of_mass_opacity=1.0, segments_center_of_mass_size=0.005, segments_center_of_mass_color=(0, 0, 0), segments_center_of_mass_opacity=1.0, mesh_color=(0, 0, 0), mesh_opacity=1.0, muscle_color=(150 / 255, 15 / 255, 15 / 255), muscle_opacity=1.0, rt_length=0.1, rt_width=2, ): """ Creates a model that will holds things to plot Parameters ---------- parent Parent of the Model window markers_size : float Size the markers should be drawn markers_color : Tuple(int) Color the markers should be drawn (1 is max brightness) markers_opacity : float Opacity of the markers (0.0 is completely transparent, 1.0 completely opaque) rt_length : int Length of the axes of the system of axes """ QtWidgets.QWidget.__init__(self, parent) self.parent_window = parent palette = QPalette() palette.setColor(self.backgroundRole(), QColor(255, 255, 255)) self.setAutoFillBackground(True) self.setPalette(palette) self.markers = Markers() self.markers_size = markers_size self.markers_color = markers_color self.markers_opacity = markers_opacity self.markers_actors = list() self.has_global_ref_frame = False self.global_ref_frame_length = global_ref_frame_length self.global_ref_frame_width = global_ref_frame_width self.global_center_of_mass = Markers() self.global_center_of_mass_size = global_center_of_mass_size self.global_center_of_mass_color = global_center_of_mass_color self.global_center_of_mass_opacity = global_center_of_mass_opacity self.global_center_of_mass_actors = list() self.segments_center_of_mass = Markers() self.segments_center_of_mass_size = segments_center_of_mass_size self.segments_center_of_mass_color = segments_center_of_mass_color self.segments_center_of_mass_opacity = segments_center_of_mass_opacity self.segments_center_of_mass_actors = list() self.all_rt = [] self.n_rt = 0 self.rt_length = rt_length self.rt_width = rt_width self.rt_actors = list() self.parent_window.should_reset_camera = True self.all_meshes = [] self.mesh_color = mesh_color self.mesh_opacity = mesh_opacity self.mesh_actors = list() self.all_muscles = [] self.muscle_color = muscle_color self.muscle_opacity = muscle_opacity self.muscle_actors = list()
DATA_FOLDER = Path("tests") / "data" MARKERS_CSV = DATA_FOLDER / "markers.csv" MARKERS_ANALOGS_C3D = DATA_FOLDER / "markers_analogs.c3d" ANALOGS_CSV = DATA_FOLDER / "analogs.csv" MARKERS_CSV_WITHOUT_HEADER = DATA_FOLDER / "markers_without_header.csv" MARKERS_XLSX = DATA_FOLDER / "markers.xlsx" MARKERS_TRC = DATA_FOLDER / "markers.trc" ANALOGS_XLSX = DATA_FOLDER / "analogs.xlsx" ANALOGS_STO = DATA_FOLDER / "inverse_dyn.sto" ANALOGS_MOT = DATA_FOLDER / "inverse_kin.mot" EXPECTED_VALUES_CSV = DATA_FOLDER / "is_expected_array_val.csv" MARKERS_DATA = Markers.from_c3d( MARKERS_ANALOGS_C3D, usecols=["CLAV_post", "PSISl", "STERr", "CLAV_post"], prefix_delimiter=":", ) ANALOGS_DATA = Analogs.from_c3d( MARKERS_ANALOGS_C3D, usecols=["EMG1", "EMG10", "EMG11", "EMG12"], prefix_delimiter=".", ) EXPECTED_VALUES = pd.read_csv( EXPECTED_VALUES_CSV, index_col=[0], converters={ "shape_val": eval, "first_last_val": eval },
def __init__( self, model_path=None, loaded_model=None, show_meshes=True, show_global_center_of_mass=True, show_segments_center_of_mass=True, segments_center_of_mass_size=0.005, show_global_ref_frame=True, show_local_ref_frame=True, show_markers=True, markers_size=0.010, show_contacts=True, contacts_size=0.010, show_muscles=True, show_wrappings=True, show_analyses_panel=True, background_color=(0.5, 0.5, 0.5), **kwargs, ): """ Class that easily shows a biorbd model Args: loaded_model: reference to a biorbd loaded model (if both loaded_model and model_path, load_model is selected model_path: path of the model to load """ # Load and store the model if loaded_model is not None: if not isinstance(loaded_model, biorbd.Model): raise TypeError( "loaded_model should be of a biorbd.Model type") self.model = loaded_model elif model_path is not None: self.model = biorbd.Model(model_path) else: raise ValueError("loaded_model or model_path must be provided") # Create the plot self.vtk_window = VtkWindow(background_color=background_color) self.vtk_model = VtkModel( self.vtk_window, markers_color=(0, 0, 1), markers_size=markers_size, contacts_size=contacts_size, segments_center_of_mass_size=segments_center_of_mass_size) self.is_executing = False self.animation_warning_already_shown = False # Set Z vertical cam = self.vtk_window.ren.GetActiveCamera() cam.SetFocalPoint(0, 0, 0) cam.SetPosition(5, 0, 0) cam.SetRoll(-90) # Get the options self.show_markers = show_markers self.show_contacts = show_contacts 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_local_ref_frame = show_local_ref_frame if self.model.nbMuscles() > 0: self.show_muscles = show_muscles else: self.show_muscles = False show_wrappings = False self.show_wrappings = show_wrappings if sum([ len(i) for i in self.model.meshPoints(np.zeros(self.model.nbQ())) ]) > 0: self.show_meshes = show_meshes else: self.show_meshes = 0 # Create all the reference to the things to plot self.nQ = self.model.nbQ() self.Q = np.zeros(self.nQ) if self.show_markers: self.Markers = InterfacesCollections.Markers(self.model) self.markers = Markers(np.ndarray((3, self.model.nbMarkers(), 1))) if self.show_contacts: self.Contacts = InterfacesCollections.Contact(self.model) self.contacts = Markers(np.ndarray( (3, self.model.nbContacts(), 1))) if self.show_global_center_of_mass: self.CoM = InterfacesCollections.CoM(self.model) self.global_center_of_mass = Markers(np.ndarray((3, 1, 1))) if self.show_segments_center_of_mass: self.CoMbySegment = InterfacesCollections.CoMbySegment(self.model) self.segments_center_of_mass = Markers( np.ndarray((3, self.model.nbSegment(), 1))) if self.show_meshes: self.mesh = [] self.meshPointsInMatrix = InterfacesCollections.MeshPointsInMatrix( self.model) for i, vertices in enumerate( self.meshPointsInMatrix.get_data(Q=self.Q, compute_kin=False)): triangles = np.array([p.face() for p in self.model.meshFaces()[i]], dtype="int32") \ if len(self.model.meshFaces()[i]) else np.ndarray((0, 3), dtype="int32") self.mesh.append(Mesh(vertex=vertices, triangles=triangles.T)) if self.show_muscles: self.model.updateMuscles(self.Q, True) self.muscles = [] for group_idx in range(self.model.nbMuscleGroups()): for muscle_idx in range( self.model.muscleGroup(group_idx).nbMuscles()): musc = self.model.muscleGroup(group_idx).muscle(muscle_idx) tp = np.zeros( (3, len(musc.position().musclesPointsInGlobal()), 1)) self.muscles.append(Mesh(vertex=tp)) self.musclesPointsInGlobal = InterfacesCollections.MusclesPointsInGlobal( self.model) if self.show_local_ref_frame or self.show_global_ref_frame: self.rt = [] self.allGlobalJCS = InterfacesCollections.AllGlobalJCS(self.model) for rt in self.allGlobalJCS.get_data(Q=self.Q, compute_kin=False): self.rt.append(Rototrans(rt)) if self.show_global_ref_frame: self.vtk_model.create_global_ref_frame() if self.show_wrappings: self.wraps_base = [] self.wraps_current = [] for m in range(self.model.nbMuscles()): path_modifier = self.model.muscle(m).pathModifier() wraps = [] wraps_current = [] for w in range(path_modifier.nbWraps()): wrap = path_modifier.object(w) if wrap.typeOfNode() == biorbd.VIA_POINT: continue # Do not show via points elif wrap.typeOfNode() == biorbd.WRAPPING_HALF_CYLINDER: wrap_cylinder = biorbd.WrappingHalfCylinder(wrap) res = 11 # resolution x = np.sin(np.linspace(0, np.pi, res)) * wrap_cylinder.radius() y = np.cos(np.linspace(0, np.pi, res)) * wrap_cylinder.radius() z = np.ones((res, )) * wrap_cylinder.length() vertices = np.concatenate([ np.array([0, 0, z[0]])[:, np.newaxis], [x, y, z], np.array([0, 0, -z[0]])[:, np.newaxis], [x, y, -z] ], axis=1) tri_0_0 = np.zeros((res - 1, 1)) tri_1_0 = np.arange(1, res)[:, np.newaxis] tri_2_0 = np.arange(2, res + 1)[:, np.newaxis] tri_0 = np.concatenate([tri_0_0, tri_1_0, tri_2_0], axis=1) tri_1 = tri_0 + res + 1 tri_2 = np.concatenate( [tri_1_0, tri_2_0, tri_1_0 + res + 1], axis=1) tri_3 = np.concatenate( [tri_1_0 + res + 1, tri_1_0 + res + 2, tri_2_0], axis=1) tri_4 = np.array([[1, res, res + 2], [res, res + 2, res + res + 1]]) triangles = np.array(np.concatenate( (tri_0, tri_1, tri_2, tri_3, tri_4)), dtype="int32").T else: raise NotImplementedError( "The wrapping object is not implemented in bioviz") wraps.append( Mesh(vertex=vertices[:, :, np.newaxis], triangles=triangles)) wraps_current.append( Mesh(vertex=vertices[:, :, np.newaxis], triangles=triangles)) self.wraps_base.append(wraps) self.wraps_current.append(wraps_current) self.show_analyses_panel = show_analyses_panel if self.show_analyses_panel: self.muscle_analyses = [] self.palette_active = QPalette() self.palette_inactive = QPalette() self.set_viz_palette() self.animated_Q = [] self.play_stop_push_button = [] self.is_animating = False self.is_recording = False self.start_icon = QIcon( QPixmap(f"{os.path.dirname(__file__)}/ressources/start.png")) self.pause_icon = QIcon( QPixmap(f"{os.path.dirname(__file__)}/ressources/pause.png")) self.record_icon = QIcon( QPixmap(f"{os.path.dirname(__file__)}/ressources/record.png")) self.add_icon = QIcon( QPixmap(f"{os.path.dirname(__file__)}/ressources/add.png")) self.stop_icon = QIcon( QPixmap(f"{os.path.dirname(__file__)}/ressources/stop.png")) self.double_factor = 10000 self.sliders = list() self.movement_slider = [] self.active_analyses_widget = None self.analyses_layout = QHBoxLayout() self.analyses_muscle_widget = QWidget() self.add_options_panel() # Update everything at the position Q=0 self.set_q(self.Q)
class Viz: def __init__( self, model_path=None, loaded_model=None, show_meshes=True, show_global_center_of_mass=True, show_segments_center_of_mass=True, segments_center_of_mass_size=0.005, show_global_ref_frame=True, show_local_ref_frame=True, show_markers=True, markers_size=0.010, show_contacts=True, contacts_size=0.010, show_muscles=True, show_wrappings=True, show_analyses_panel=True, background_color=(0.5, 0.5, 0.5), **kwargs, ): """ Class that easily shows a biorbd model Args: loaded_model: reference to a biorbd loaded model (if both loaded_model and model_path, load_model is selected model_path: path of the model to load """ # Load and store the model if loaded_model is not None: if not isinstance(loaded_model, biorbd.Model): raise TypeError( "loaded_model should be of a biorbd.Model type") self.model = loaded_model elif model_path is not None: self.model = biorbd.Model(model_path) else: raise ValueError("loaded_model or model_path must be provided") # Create the plot self.vtk_window = VtkWindow(background_color=background_color) self.vtk_model = VtkModel( self.vtk_window, markers_color=(0, 0, 1), markers_size=markers_size, contacts_size=contacts_size, segments_center_of_mass_size=segments_center_of_mass_size) self.is_executing = False self.animation_warning_already_shown = False # Set Z vertical cam = self.vtk_window.ren.GetActiveCamera() cam.SetFocalPoint(0, 0, 0) cam.SetPosition(5, 0, 0) cam.SetRoll(-90) # Get the options self.show_markers = show_markers self.show_contacts = show_contacts 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_local_ref_frame = show_local_ref_frame if self.model.nbMuscles() > 0: self.show_muscles = show_muscles else: self.show_muscles = False show_wrappings = False self.show_wrappings = show_wrappings if sum([ len(i) for i in self.model.meshPoints(np.zeros(self.model.nbQ())) ]) > 0: self.show_meshes = show_meshes else: self.show_meshes = 0 # Create all the reference to the things to plot self.nQ = self.model.nbQ() self.Q = np.zeros(self.nQ) if self.show_markers: self.Markers = InterfacesCollections.Markers(self.model) self.markers = Markers(np.ndarray((3, self.model.nbMarkers(), 1))) if self.show_contacts: self.Contacts = InterfacesCollections.Contact(self.model) self.contacts = Markers(np.ndarray( (3, self.model.nbContacts(), 1))) if self.show_global_center_of_mass: self.CoM = InterfacesCollections.CoM(self.model) self.global_center_of_mass = Markers(np.ndarray((3, 1, 1))) if self.show_segments_center_of_mass: self.CoMbySegment = InterfacesCollections.CoMbySegment(self.model) self.segments_center_of_mass = Markers( np.ndarray((3, self.model.nbSegment(), 1))) if self.show_meshes: self.mesh = [] self.meshPointsInMatrix = InterfacesCollections.MeshPointsInMatrix( self.model) for i, vertices in enumerate( self.meshPointsInMatrix.get_data(Q=self.Q, compute_kin=False)): triangles = np.array([p.face() for p in self.model.meshFaces()[i]], dtype="int32") \ if len(self.model.meshFaces()[i]) else np.ndarray((0, 3), dtype="int32") self.mesh.append(Mesh(vertex=vertices, triangles=triangles.T)) if self.show_muscles: self.model.updateMuscles(self.Q, True) self.muscles = [] for group_idx in range(self.model.nbMuscleGroups()): for muscle_idx in range( self.model.muscleGroup(group_idx).nbMuscles()): musc = self.model.muscleGroup(group_idx).muscle(muscle_idx) tp = np.zeros( (3, len(musc.position().musclesPointsInGlobal()), 1)) self.muscles.append(Mesh(vertex=tp)) self.musclesPointsInGlobal = InterfacesCollections.MusclesPointsInGlobal( self.model) if self.show_local_ref_frame or self.show_global_ref_frame: self.rt = [] self.allGlobalJCS = InterfacesCollections.AllGlobalJCS(self.model) for rt in self.allGlobalJCS.get_data(Q=self.Q, compute_kin=False): self.rt.append(Rototrans(rt)) if self.show_global_ref_frame: self.vtk_model.create_global_ref_frame() if self.show_wrappings: self.wraps_base = [] self.wraps_current = [] for m in range(self.model.nbMuscles()): path_modifier = self.model.muscle(m).pathModifier() wraps = [] wraps_current = [] for w in range(path_modifier.nbWraps()): wrap = path_modifier.object(w) if wrap.typeOfNode() == biorbd.VIA_POINT: continue # Do not show via points elif wrap.typeOfNode() == biorbd.WRAPPING_HALF_CYLINDER: wrap_cylinder = biorbd.WrappingHalfCylinder(wrap) res = 11 # resolution x = np.sin(np.linspace(0, np.pi, res)) * wrap_cylinder.radius() y = np.cos(np.linspace(0, np.pi, res)) * wrap_cylinder.radius() z = np.ones((res, )) * wrap_cylinder.length() vertices = np.concatenate([ np.array([0, 0, z[0]])[:, np.newaxis], [x, y, z], np.array([0, 0, -z[0]])[:, np.newaxis], [x, y, -z] ], axis=1) tri_0_0 = np.zeros((res - 1, 1)) tri_1_0 = np.arange(1, res)[:, np.newaxis] tri_2_0 = np.arange(2, res + 1)[:, np.newaxis] tri_0 = np.concatenate([tri_0_0, tri_1_0, tri_2_0], axis=1) tri_1 = tri_0 + res + 1 tri_2 = np.concatenate( [tri_1_0, tri_2_0, tri_1_0 + res + 1], axis=1) tri_3 = np.concatenate( [tri_1_0 + res + 1, tri_1_0 + res + 2, tri_2_0], axis=1) tri_4 = np.array([[1, res, res + 2], [res, res + 2, res + res + 1]]) triangles = np.array(np.concatenate( (tri_0, tri_1, tri_2, tri_3, tri_4)), dtype="int32").T else: raise NotImplementedError( "The wrapping object is not implemented in bioviz") wraps.append( Mesh(vertex=vertices[:, :, np.newaxis], triangles=triangles)) wraps_current.append( Mesh(vertex=vertices[:, :, np.newaxis], triangles=triangles)) self.wraps_base.append(wraps) self.wraps_current.append(wraps_current) self.show_analyses_panel = show_analyses_panel if self.show_analyses_panel: self.muscle_analyses = [] self.palette_active = QPalette() self.palette_inactive = QPalette() self.set_viz_palette() self.animated_Q = [] self.play_stop_push_button = [] self.is_animating = False self.is_recording = False self.start_icon = QIcon( QPixmap(f"{os.path.dirname(__file__)}/ressources/start.png")) self.pause_icon = QIcon( QPixmap(f"{os.path.dirname(__file__)}/ressources/pause.png")) self.record_icon = QIcon( QPixmap(f"{os.path.dirname(__file__)}/ressources/record.png")) self.add_icon = QIcon( QPixmap(f"{os.path.dirname(__file__)}/ressources/add.png")) self.stop_icon = QIcon( QPixmap(f"{os.path.dirname(__file__)}/ressources/stop.png")) self.double_factor = 10000 self.sliders = list() self.movement_slider = [] self.active_analyses_widget = None self.analyses_layout = QHBoxLayout() self.analyses_muscle_widget = QWidget() self.add_options_panel() # Update everything at the position Q=0 self.set_q(self.Q) def reset_q(self): self.Q = np.zeros(self.Q.shape) for slider in self.sliders: slider[1].setValue(0) slider[2].setText(f"{0:.2f}") self.set_q(self.Q) # Reset also muscle analyses graphs self.__update_muscle_analyses_graphs(False, False, False, False) def copy_q_to_clipboard(self): pandas.DataFrame(self.Q[np.newaxis, :]).to_clipboard(sep=',', index=False, header=False) def set_q(self, Q, refresh_window=True): """ Manually update Args: Q: np.array Generalized coordinate refresh_window: bool If the window should be refreshed now or not """ if isinstance(Q, (tuple, list)): Q = np.array(Q) if not isinstance( Q, np.ndarray) and len(Q.shape) > 1 and Q.shape[0] != self.nQ: raise TypeError(f"Q should be a {self.nQ} column vector") self.Q = Q self.model.UpdateKinematicsCustom(self.Q) if self.show_muscles: self.__set_muscles_from_q() if self.show_local_ref_frame: self.__set_rt_from_q() if self.show_meshes: self.__set_meshes_from_q() if self.show_global_center_of_mass: self.__set_global_center_of_mass_from_q() if self.show_segments_center_of_mass: self.__set_segments_center_of_mass_from_q() if self.show_markers: self.__set_markers_from_q() if self.show_contacts: self.__set_contacts_from_q() if self.show_wrappings: self.__set_wrapping_from_q() # Update the sliders if self.show_analyses_panel: for i, slide in enumerate(self.sliders): slide[1].blockSignals(True) slide[1].setValue(int(self.Q[i] * self.double_factor)) slide[1].blockSignals(False) slide[2].setText(f"{self.Q[i]:.2f}") if refresh_window: self.refresh_window() def refresh_window(self): """ Manually refresh the window. One should be aware when manually managing the window, that the plot won't even rotate if not refreshed """ self.vtk_window.update_frame() def update(self): 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() + 1)) if self.is_recording: self.__record() if self.movement_slider[0].value() + 1 == ( self.movement_slider[0].maximum() + 1): self.__start_stop_animation() self.refresh_window() def exec(self): self.is_executing = True while self.vtk_window.is_active: self.update() self.is_executing = False def set_viz_palette(self): self.palette_active.setColor(QPalette.WindowText, QColor(Qt.black)) self.palette_active.setColor(QPalette.ButtonText, QColor(Qt.black)) self.palette_inactive.setColor(QPalette.WindowText, QColor(Qt.gray)) def add_options_panel(self): # Prepare the sliders options_layout = QVBoxLayout() options_layout.addStretch() # Centralize the sliders sliders_layout = QVBoxLayout() max_label_width = -1 # Get min and max for all dof ranges = [] for i in range(self.model.nbSegment()): seg = self.model.segment(i) for r in seg.QRanges(): ranges.append([r.min(), r.max()]) for i in range(self.model.nbQ()): slider_layout = QHBoxLayout() sliders_layout.addLayout(slider_layout) # Add a name name_label = QLabel() name = f"{self.model.nameDof()[i].to_string()}" name_label.setText(name) name_label.setPalette(self.palette_active) label_width = name_label.fontMetrics().boundingRect( name_label.text()).width() if label_width > max_label_width: max_label_width = label_width slider_layout.addWidget(name_label) # Add the slider slider = QSlider(Qt.Horizontal) slider.setMinimumSize(100, 0) slider.setMinimum(int(ranges[i][0] * self.double_factor)) slider.setMaximum(int(ranges[i][1] * self.double_factor)) slider.setPageStep(self.double_factor) slider.setValue(0) slider.valueChanged.connect(self.__move_avatar_from_sliders) slider.sliderReleased.connect( partial(self.__update_muscle_analyses_graphs, False, False, False, False)) slider_layout.addWidget(slider) # Add the value value_label = QLabel() value_label.setText(f"{0:.2f}") value_label.setPalette(self.palette_active) slider_layout.addWidget(value_label) # Add to the main sliders self.sliders.append((name_label, slider, value_label)) # Adjust the size of the names for name_label, _, _ in self.sliders: name_label.setFixedWidth(max_label_width + 1) # Put the sliders in a scrollable area sliders_widget = QWidget() sliders_widget.setLayout(sliders_layout) sliders_scroll = QScrollArea() sliders_scroll.setFrameShape(0) sliders_scroll.setWidgetResizable(True) sliders_scroll.setWidget(sliders_widget) options_layout.addWidget(sliders_scroll) # Add reset button button_layout = QHBoxLayout() options_layout.addLayout(button_layout) reset_push_button = QPushButton("Reset") reset_push_button.setPalette(self.palette_active) reset_push_button.released.connect(self.reset_q) button_layout.addWidget(reset_push_button) copyq_push_button = QPushButton("Copy Q to clipboard") copyq_push_button.setPalette(self.palette_active) copyq_push_button.released.connect(self.copy_q_to_clipboard) button_layout.addWidget(copyq_push_button) # Add the radio button for analyses option_analyses_group = QGroupBox() option_analyses_layout = QVBoxLayout() # Add text analyse_text = QLabel() analyse_text.setPalette(self.palette_active) analyse_text.setText("Analyses") option_analyses_layout.addWidget(analyse_text) # Add the no analyses radio_none = QRadioButton() radio_none.setPalette(self.palette_active) radio_none.setChecked(True) radio_none.toggled.connect( lambda: self.__select_analyses_panel(radio_none, 0)) radio_none.setText("None") option_analyses_layout.addWidget(radio_none) # Add the muscles analyses radio_muscle = QRadioButton() radio_muscle.setPalette(self.palette_active) radio_muscle.toggled.connect( lambda: self.__select_analyses_panel(radio_muscle, 1)) radio_muscle.setText("Muscles") option_analyses_layout.addWidget(radio_muscle) # Add the layout to the interface option_analyses_group.setLayout(option_analyses_layout) options_layout.addWidget(option_analyses_group) # Finalize the options panel options_layout.addStretch() # Centralize the sliders # Animation panel animation_layout = QVBoxLayout() animation_layout.addWidget(self.vtk_window.avatar_widget) # Add the animation slider animation_slider_layout = QHBoxLayout() animation_layout.addLayout(animation_slider_layout) load_push_button = QPushButton("Load movement") load_push_button.setPalette(self.palette_active) load_push_button.released.connect(self.__load_movement_from_button) animation_slider_layout.addWidget(load_push_button) # Controllers self.play_stop_push_button = QPushButton() self.play_stop_push_button.setIcon(self.start_icon) self.play_stop_push_button.setPalette(self.palette_active) self.play_stop_push_button.setEnabled(False) self.play_stop_push_button.released.connect( self.__start_stop_animation) animation_slider_layout.addWidget(self.play_stop_push_button) slider = QSlider(Qt.Horizontal) slider.setMinimum(0) slider.setMaximum(100) slider.setValue(0) slider.setEnabled(False) slider.valueChanged.connect(self.__animate_from_slider) animation_slider_layout.addWidget(slider) self.record_push_button = QPushButton() self.record_push_button.setIcon(self.record_icon) self.record_push_button.setPalette(self.palette_active) self.record_push_button.setEnabled(True) self.record_push_button.released.connect(self.__record) animation_slider_layout.addWidget(self.record_push_button) self.stop_record_push_button = QPushButton() self.stop_record_push_button.setIcon(self.stop_icon) self.stop_record_push_button.setPalette(self.palette_active) self.stop_record_push_button.setEnabled(False) self.stop_record_push_button.released.connect(self.__stop_record, True) animation_slider_layout.addWidget(self.stop_record_push_button) # Add the frame count frame_label = QLabel() frame_label.setText(f"{0}") frame_label.setPalette(self.palette_inactive) animation_slider_layout.addWidget(frame_label) self.movement_slider = (slider, frame_label) # Global placement of the window self.vtk_window.main_layout.addLayout(options_layout, 0, 0) self.vtk_window.main_layout.addLayout(animation_layout, 0, 1) self.vtk_window.main_layout.setColumnStretch(0, 1) self.vtk_window.main_layout.setColumnStretch(1, 2) # Change the size of the window to account for the new sliders self.vtk_window.resize(self.vtk_window.size().width() * 2, self.vtk_window.size().height()) # Prepare all the analyses panel self.muscle_analyses = MuscleAnalyses(self.analyses_muscle_widget, self) if biorbd.currentLinearAlgebraBackend() == 1: radio_muscle.setEnabled(False) else: if self.model.nbMuscles() == 0: radio_muscle.setEnabled(False) self.__select_analyses_panel(radio_muscle, 1) def __select_analyses_panel(self, radio_button, panel_to_activate): if not radio_button.isChecked(): return # Hide previous analyses panel if necessary self.__hide_analyses_panel() size_factor_none = 1 size_factor_muscle = 1.40 # Find the size factor to get back to normal size if self.active_analyses_widget is None: reduction_factor = size_factor_none elif self.active_analyses_widget == self.analyses_muscle_widget: reduction_factor = size_factor_muscle else: raise RuntimeError( "Non-existing panel asked... This should never happen, please report this issue!" ) # Prepare the analyses panel and new size of window if panel_to_activate == 0: self.active_analyses_widget = None enlargement_factor = size_factor_none elif panel_to_activate == 1: self.active_analyses_widget = self.analyses_muscle_widget enlargement_factor = size_factor_muscle else: raise RuntimeError( "Non-existing panel asked... This should never happen, please report this issue!" ) # Activate the required panel self.__show_local_ref_frame() # Enlarge the main window self.vtk_window.resize( int(self.vtk_window.size().width() * enlargement_factor / reduction_factor), self.vtk_window.size().height()) def __hide_analyses_panel(self): if self.active_analyses_widget is None: return # Remove from main window self.active_analyses_widget.setVisible(False) self.vtk_window.main_layout.removeWidget(self.active_analyses_widget) self.vtk_window.main_layout.setColumnStretch(2, 0) 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) self.vtk_window.main_layout.setColumnStretch(2, 4) self.active_analyses_widget.setVisible(True) # Update graphs if needed self.__update_muscle_analyses_graphs(False, False, False, False) def __move_avatar_from_sliders(self): for i, slide in enumerate(self.sliders): self.Q[i] = slide[1].value() / self.double_factor slide[2].setText(f" {self.Q[i]:.2f}") self.set_q(self.Q) def __update_muscle_analyses_graphs(self, skip_muscle_length, skip_moment_arm, skip_passive_forces, skip_active_forces): # Adjust muscle analyses if needed if self.active_analyses_widget == self.analyses_muscle_widget: self.muscle_analyses.update_all_graphs(skip_muscle_length, skip_moment_arm, skip_passive_forces, skip_active_forces) def __animate_from_slider(self): # Move the avatar self.movement_slider[1].setText(f"{self.movement_slider[0].value()}") self.Q = copy.copy(self.animated_Q[self.movement_slider[0].value() - 1]) # 1-based self.set_q(self.Q) # Update graph of muscle analyses self.__update_muscle_analyses_graphs(True, True, True, True) def __start_stop_animation(self): if not self.is_executing and not self.animation_warning_already_shown: QMessageBox.warning( self.vtk_window, "Not executing", "bioviz has detected that it is not actually executing.\n\n" "Unless you know what you are doing, the automatic play of the animation will " "therefore not work. Please call the bioviz.exec() method to be able to play " "the animation.\n\nPlease note that the animation slider will work in any case.", ) self.animation_warning_already_shown = True if self.is_animating: self.is_animating = False self.play_stop_push_button.setIcon(self.start_icon) self.record_push_button.setEnabled(True) self.stop_record_push_button.setEnabled(self.is_recording) else: self.is_animating = True self.play_stop_push_button.setIcon(self.pause_icon) self.record_push_button.setEnabled(False) self.stop_record_push_button.setEnabled(False) def __stop_record(self): self.__record(finish=True) def __record(self, finish=False): file_name = None if not self.is_recording: options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog file_name = QFileDialog.getSaveFileName(self.vtk_window, "Save the video", "", "OGV files (*.ogv)", options=options) file_name, file_extension = os.path.splitext(file_name[0]) if file_name == "": return file_name += ".ogv" self.record_push_button.setIcon(self.add_icon) self.stop_record_push_button.setEnabled(True) self.is_recording = True self.vtk_window.record(button_to_block=[ self.record_push_button, self.stop_record_push_button ], finish=finish, file_name=file_name) if finish: self.is_recording = False self.record_push_button.setIcon(self.record_icon) self.stop_record_push_button.setEnabled(False) def __load_movement_from_button(self): # Load the actual movement options = QFileDialog.Options() options |= QFileDialog.DontUseNativeDialog file_name = QFileDialog.getOpenFileName(self.vtk_window, "Movement to load", "", "All Files (*)", options=options) if not file_name[0]: return if os.path.splitext( file_name[0] )[1] == ".Q1": # If it is from a Matlab reconstruction QLD self.animated_Q = scipy.io.loadmat(file_name[0])["Q1"].transpose() elif os.path.splitext( file_name[0] )[1] == ".Q2": # If it is from a Matlab reconstruction Kalman self.animated_Q = scipy.io.loadmat(file_name[0])["Q2"].transpose() else: # Otherwise assume this is a numpy array self.animated_Q = np.load(file_name[0]).T self.__load_movement() def load_movement(self, all_q, auto_start=True, ignore_animation_warning=True): self.animated_Q = all_q.T self.__load_movement() if ignore_animation_warning: self.animation_warning_already_shown = True if auto_start: self.__start_stop_animation() def __load_movement(self): # Activate the start button self.is_animating = False self.play_stop_push_button.setEnabled(True) self.play_stop_push_button.setIcon(self.start_icon) # Update the slider bar and frame count self.movement_slider[0].setEnabled(True) self.movement_slider[0].setMinimum(1) self.movement_slider[0].setMaximum(self.animated_Q.shape[0]) pal = QPalette() pal.setColor(QPalette.WindowText, QColor(Qt.black)) self.movement_slider[1].setPalette(pal) # Put back to first frame self.movement_slider[0].setValue(1) # Add the combobox in muscle analyses self.muscle_analyses.add_movement_to_dof_choice() def __set_markers_from_q(self): self.markers[0:3, :, :] = self.Markers.get_data(Q=self.Q, compute_kin=False) self.vtk_model.update_markers(self.markers.isel(time=[0])) def __set_contacts_from_q(self): self.contacts[0:3, :, :] = self.Contacts.get_data(Q=self.Q, compute_kin=False) self.vtk_model.update_contacts(self.contacts.isel(time=[0])) def __set_global_center_of_mass_from_q(self): com = self.CoM.get_data(Q=self.Q, compute_kin=False) self.global_center_of_mass.loc[{ "channel": 0, "time": 0 }] = com.squeeze() self.vtk_model.update_global_center_of_mass( self.global_center_of_mass.isel(time=[0])) def __set_segments_center_of_mass_from_q(self): coms = self.CoMbySegment.get_data(Q=self.Q, compute_kin=False) for k, com in enumerate(coms): self.segments_center_of_mass.loc[{ "channel": k, "time": 0 }] = com.squeeze() self.vtk_model.update_segments_center_of_mass( self.segments_center_of_mass.isel(time=[0])) def __set_meshes_from_q(self): for m, meshes in enumerate( self.meshPointsInMatrix.get_data(Q=self.Q, compute_kin=False)): self.mesh[m][0:3, :, :] = meshes self.vtk_model.update_mesh(self.mesh) def __set_muscles_from_q(self): muscles = self.musclesPointsInGlobal.get_data(Q=self.Q) idx = 0 cmp = 0 for group_idx in range(self.model.nbMuscleGroups()): for muscle_idx in range( self.model.muscleGroup(group_idx).nbMuscles()): musc = self.model.muscleGroup(group_idx).muscle(muscle_idx) for k, pts in enumerate( musc.position().musclesPointsInGlobal()): self.muscles[idx].loc[{ "channel": k, "time": 0 }] = np.append(muscles[cmp], 1) cmp += 1 idx += 1 self.vtk_model.update_muscle(self.muscles) def __set_wrapping_from_q(self): for i, wraps in enumerate(self.wraps_base): for j, wrap in enumerate(wraps): if self.model.muscle(i).pathModifier().object( j).typeOfNode() == biorbd.WRAPPING_HALF_CYLINDER: rt = biorbd.WrappingHalfCylinder( self.model.muscle(i).pathModifier().object(j)).RT( self.model, self.Q).to_array() self.wraps_current[i][j][0:3, :, 0] = np.dot(rt, wrap[:, :, 0])[0:3, :] else: raise NotImplementedError( "__set_wrapping_from_q is not ready for these wrapping object" ) self.vtk_model.update_wrapping(self.wraps_current) def __set_rt_from_q(self): for k, rt in enumerate( self.allGlobalJCS.get_data(Q=self.Q, compute_kin=False)): self.rt[k] = Rototrans(rt) self.vtk_model.update_rt(self.rt)
# Rototrans_sym = RT(transX, transY, transZ, angleX, angleY, angleZ) parent_dir_path = os.path.split(os.path.dirname(__file__))[0] # biorbd_model = biorbd.Model(parent_dir_path +'/model_scaling/new_scal/Belaise_scaled_updated.bioMod') biorbd_model = biorbd.Model(parent_dir_path + '/models/arm_Belaise_real_v2.bioMod') data = "flex" data_path = f'./Sujet_5/{data}.c3d' markers_names = [ "CLAV_SC", "CLAV_AC", "SCAP_CP", "SCAP_AA", "SCAP_TS", "SCAP_IA", "DELT", "ARMl", "EPICl", "EPICm", "LARM_ant", "LARM_post", "LARM_elb", "LARM_dist" ] # markers_names = ["XIPH", "STER", "CLAV_SC","CLAV_AC","SCAP_CP","SCAP_AA","SCAP_TS","SCAP_IA","DELT","ARMl","EPICl", # "EPICm","LARM_ant","LARM_post","LARM_elb","LARM_dist","STYLrad", "STYLulna"] markers = Markers.from_c3d(data_path, usecols=markers_names) mat_contents = sio.loadmat(f"{data}.mat") mat_contents = mat_contents["mov_reel"] val = mat_contents[0, 0] integ = val['integ'] q = integ['Q_reel'][0, 0] marker_exp = markers[:, :, :q.shape[1]].data * 1e-3 n_mark = len(markers_names) n_q = q.shape[0] t = integ['temps'][0, 0] # 0.24s n_frames = q.shape[1] marker_model = np.ndarray((4, n_mark, n_frames)) symbolic_states = MX.sym("q", n_q, 1) # markers_func = Function(
ubw.append(np.pi) Rototrans_sym = RT(transX, transY, transZ, angleX, angleY, angleZ) biorbd_model = biorbd.Model( os.path.split(os.path.dirname(__file__))[0] + '/models/arm_Belaise_real_v2.bioMod') data_path = './Sujet_5/flex.c3d' # data_path = './Sujet_5/horizon_co.c3d' markers_names = [ "CLAV_SC", "CLAV_AC", "SCAP_CP", "SCAP_AA", "SCAP_TS", "SCAP_IA", "DELT", "ARMl", "EPICl", "EPICm", "LARM_ant", "LARM_post", "LARM_elb", "LARM_dist" ] markers = Markers.from_c3d(data_path, usecols=markers_names) mat_contents = sio.loadmat("flex.mat") # mat_contents = sio.loadmat("horizon_co.mat") mat_contents = mat_contents["mov_reel"] val = mat_contents[0, 0] integ = val['integ'] q = integ['Q_reel'][0, 0] marker_exp = markers[:, :, :q.shape[1]].data * 1e-3 n_mark = marker_exp.shape[1] n_q = q.shape[0] t = integ['temps'][0, 0] # 0.24s n_frames = q.shape[1] marker_model = np.ndarray((4, n_mark, q.shape[1])) symbolic_states = MX.sym("q", n_q, 1)
from pathlib import Path import numpy as np from pyomeca import Markers, Rototrans, Angles from bioviz.biorbd_vtk import VtkModel, VtkWindow, Mesh # Path to data DATA_FOLDER = Path( "/home/pariterre/Programmation/biorbd-viz") / "tests" / "data" MARKERS_CSV = DATA_FOLDER / "markers.csv" MARKERS_ANALOGS_C3D = DATA_FOLDER / "markers_analogs.c3d" # Load data d = Markers.from_c3d(MARKERS_ANALOGS_C3D, usecols=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10], prefix_delimiter=":") d2 = Markers.from_c3d(MARKERS_ANALOGS_C3D, usecols=["CLAV_post", "PSISl", "STERr", "CLAV_post"], prefix_delimiter=":") # mean of first 3 markers d3 = Markers.from_c3d(MARKERS_ANALOGS_C3D, usecols=[0, 1, 2], prefix_delimiter=":").mean("channel", keepdims=True) # Create a windows with a nice gray background vtkWindow = VtkWindow(background_color=(0.5, 0.5, 0.5)) # Add marker holders to the window vtkModelReal = VtkModel(vtkWindow, markers_color=(1, 0, 0),
def test_rt_from_markers(): all_m = Markers.from_random_data() rt_xy = Rototrans.from_markers( origin=all_m.isel(channel=[0]), axis_1=all_m.isel(channel=[0, 1]), axis_2=all_m.isel(channel=[0, 2]), axes_name="xy", axis_to_recalculate="y", ) rt_yx = Rototrans.from_markers( origin=all_m.isel(channel=[0]), axis_1=all_m.isel(channel=[0, 2]), axis_2=all_m.isel(channel=[0, 1]), axes_name="yx", axis_to_recalculate="y", ) rt_xy_x_recalc = Rototrans.from_markers( origin=all_m.isel(channel=[0]), axis_1=all_m.isel(channel=[0, 1]), axis_2=all_m.isel(channel=[0, 2]), axes_name="yx", axis_to_recalculate="x", ) rt_xy_x_recalc = rt_xy_x_recalc.isel(col=[1, 0, 2, 3]) rt_xy_x_recalc[:, 2, :] = -rt_xy_x_recalc[:, 2, :] rt_yz = Rototrans.from_markers( origin=all_m.isel(channel=[0]), axis_1=all_m.isel(channel=[0, 1]), axis_2=all_m.isel(channel=[0, 2]), axes_name="yz", axis_to_recalculate="z", ) rt_zy = Rototrans.from_markers( origin=all_m.isel(channel=[0]), axis_1=all_m.isel(channel=[0, 2]), axis_2=all_m.isel(channel=[0, 1]), axes_name="zy", axis_to_recalculate="z", ) rt_xy_from_yz = rt_yz.isel(col=[1, 2, 0, 3]) rt_xz = Rototrans.from_markers( origin=all_m.isel(channel=[0]), axis_1=all_m.isel(channel=[0, 1]), axis_2=all_m.isel(channel=[0, 2]), axes_name="xz", axis_to_recalculate="z", ) rt_zx = Rototrans.from_markers( origin=all_m.isel(channel=[0]), axis_1=all_m.isel(channel=[0, 2]), axis_2=all_m.isel(channel=[0, 1]), axes_name="zx", axis_to_recalculate="z", ) rt_xy_from_zx = rt_xz.isel(col=[0, 2, 1, 3]) rt_xy_from_zx[:, 2, :] = -rt_xy_from_zx[:, 2, :] np.testing.assert_array_equal(rt_xy, rt_xy_x_recalc) np.testing.assert_array_equal(rt_xy, rt_yx) np.testing.assert_array_equal(rt_yz, rt_zy) np.testing.assert_array_equal(rt_xz, rt_zx) np.testing.assert_array_equal(rt_xy, rt_xy_from_yz) np.testing.assert_array_equal(rt_xy, rt_xy_from_zx) # Produce one that we know the solution ref_m = Markers( np.array(((1, 2, 3), (4, 5, 6), (6, 5, 4))).T[:, :, np.newaxis]) rt_xy_from_known_m = Rototrans.from_markers( origin=ref_m.isel(channel=[0]), axis_1=ref_m.isel(channel=[0, 1]), axis_2=ref_m.isel(channel=[0, 2]), axes_name="xy", axis_to_recalculate="y", ) rt_xy_expected = Rototrans( np.array([ [0.5773502691896257, 0.7071067811865475, -0.408248290463863, 1.0], [0.5773502691896257, 0.0, 0.816496580927726, 2.0], [0.5773502691896257, -0.7071067811865475, -0.408248290463863, 3.0], [0, 0, 0, 1.0], ])) np.testing.assert_array_equal(rt_xy_from_known_m, rt_xy_expected) exception_default_params = dict( origin=all_m.isel(channel=[0]), axis_1=all_m.isel(channel=[0, 1]), axis_2=all_m.isel(channel=[0, 2]), axes_name="xy", axis_to_recalculate="y", ) with pytest.raises(ValueError): Rototrans.from_markers(**{ **exception_default_params, **dict(origin=all_m.isel(channel=[0, 1])) }) with pytest.raises(ValueError): Rototrans.from_markers(**{ **exception_default_params, **dict(axis_1=all_m.isel(channel=[0])) }) with pytest.raises(ValueError): Rototrans.from_markers(**{ **exception_default_params, **dict(axis_2=all_m.isel(channel=[0])) }) with pytest.raises(ValueError): Rototrans.from_markers( **{ **exception_default_params, **dict(axis_1=all_m.isel(channel=[0, 1], time=slice(None, 50))), }) with pytest.raises(ValueError): Rototrans.from_markers(**{ **exception_default_params, **dict(axes_name="yyz") }) with pytest.raises(ValueError): Rototrans.from_markers(**{ **exception_default_params, **dict(axes_name="xxz") }) with pytest.raises(ValueError): Rototrans.from_markers(**{ **exception_default_params, **dict(axes_name="zzz") }) with pytest.raises(ValueError): Rototrans.from_markers(**{ **exception_default_params, **dict(axis_to_recalculate="h") })
# --- Markers --- # markers_full_names = [ "XIPH", "STER", "STERback", "CLAV_SC", "CLAV_AC", "SCAP_CP", "SCAP_AA", "SCAP_TS", "SCAP_IA", "DELT", "ARMl", "EPICl", "EPICm", "LARM_ant", "LARM_post", "LARM_elb", "LARM_dist" ] # markers_full_names = ["ASISr","PSISr", "PSISl","ASISl","XIPH","STER","STERlat","STERback","XIPHback","ThL", # "CLAV_SC","CLAV_AC","SCAP_CP","SCAP_AA","SCAPspine","SCAP_TS","SCAP_IA","DELT","ARMl", # "EPICl","EPICm","LARM_ant","LARM_post","LARM_elb","LARM_dist","STYLrad","STYLrad_up","STYLulna_up", # "STYLulna","META2dist","META2prox","META5prox","META5dist","MAIN_opp"] # markers_full_names = ["CLAV_SC","CLAV_AC","SCAP_CP","SCAP_AA","SCAP_TS","SCAP_IA","DELT","ARMl","EPICl", # "EPICm","LARM_ant","LARM_post","LARM_elb","LARM_dist"] markers_full = Markers.from_c3d(data_path, usecols=markers_full_names) marker_rate = int(markers_full.rate) marker_exp = markers_full[:, :, :].data * 1e-3 n_mark = marker_exp.shape[1] # t = 0.24 n_frames = marker_exp.shape[2] t = markers_full.time.data marker_treat = np.ndarray( (marker_exp.shape[0], marker_exp.shape[1], marker_exp.shape[2])) for k in range(n_mark): a = pd.DataFrame(marker_exp[:, k, :]) a = np.array(a.interpolate(method='polynomial', order=3, axis=1)) marker_treat[:, k, :] = a marker_treat[3, :, :] = [1] plt.figure("Markers")
def __init__( self, model_path=None, loaded_model=None, 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, markers_size=0.010, show_muscles=True, show_analyses_panel=True, background_color=(0.5, 0.5, 0.5), **kwargs, ): """ Class that easily shows a biorbd model Args: loaded_model: reference to a biorbd loaded model (if both loaded_model and model_path, load_model is selected model_path: path of the model to load """ # Load and store the model if loaded_model is not None: if not isinstance(loaded_model, biorbd.Model): raise TypeError( "loaded_model should be of a biorbd.Model type") self.model = loaded_model elif model_path is not None: self.model = biorbd.Model(model_path) else: raise ValueError("loaded_model or model_path must be provided") # Create the plot self.vtk_window = VtkWindow(background_color=background_color) self.vtk_model = VtkModel(self.vtk_window, markers_color=(0, 0, 1), markers_size=markers_size) self.is_executing = False self.animation_warning_already_shown = False # Set Z vertical cam = self.vtk_window.ren.GetActiveCamera() cam.SetFocalPoint(0, 0, 0) cam.SetPosition(5, 0, 0) cam.SetRoll(-90) # Get the options self.show_markers = show_markers 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_local_ref_frame = show_local_ref_frame if self.model.nbMuscles() > 0: self.show_muscles = show_muscles else: self.show_muscles = False if sum([ len(i) for i in self.model.meshPoints(np.zeros(self.model.nbQ())) ]) > 0: self.show_meshes = show_meshes else: self.show_meshes = 0 # Create all the reference to the things to plot self.nQ = self.model.nbQ() self.Q = np.zeros(self.nQ) self.markers = Markers(np.ndarray((3, self.model.nbMarkers(), 1))) if self.show_markers: self.Markers = InterfacesCollections.Markers(self.model) self.global_center_of_mass = Markers(np.ndarray((3, 1, 1))) if self.show_global_center_of_mass: self.CoM = InterfacesCollections.CoM(self.model) self.segments_center_of_mass = Markers( np.ndarray((3, self.model.nbSegment(), 1))) if self.show_segments_center_of_mass: self.CoMbySegment = InterfacesCollections.CoMbySegment(self.model) if self.show_meshes: self.mesh = [] self.meshPointsInMatrix = InterfacesCollections.MeshPointsInMatrix( self.model) for i, vertices in enumerate( self.meshPointsInMatrix.get_data(Q=self.Q, compute_kin=False)): triangles = np.ndarray((len(self.model.meshFaces()[i]), 3), dtype="int32") for k, patch in enumerate(self.model.meshFaces()[i]): triangles[k, :] = patch.face() self.mesh.append(Mesh(vertex=vertices, triangles=triangles.T)) self.model.updateMuscles(self.Q, True) self.muscles = [] for group_idx in range(self.model.nbMuscleGroups()): for muscle_idx in range( self.model.muscleGroup(group_idx).nbMuscles()): musc = self.model.muscleGroup(group_idx).muscle(muscle_idx) tp = np.zeros( (3, len(musc.position().musclesPointsInGlobal()), 1)) self.muscles.append(Mesh(vertex=tp)) self.musclesPointsInGlobal = InterfacesCollections.MusclesPointsInGlobal( self.model) self.rt = [] self.allGlobalJCS = InterfacesCollections.AllGlobalJCS(self.model) for rt in self.allGlobalJCS.get_data(Q=self.Q, compute_kin=False): self.rt.append(Rototrans(rt)) if self.show_global_ref_frame: self.vtk_model.create_global_ref_frame() self.show_analyses_panel = show_analyses_panel if self.show_analyses_panel: self.muscle_analyses = [] self.palette_active = QPalette() self.palette_inactive = QPalette() self.set_viz_palette() self.animated_Q = [] self.play_stop_push_button = [] self.is_animating = False self.is_recording = False self.start_icon = QIcon( QPixmap(f"{os.path.dirname(__file__)}/ressources/start.png")) self.pause_icon = QIcon( QPixmap(f"{os.path.dirname(__file__)}/ressources/pause.png")) self.record_icon = QIcon( QPixmap(f"{os.path.dirname(__file__)}/ressources/record.png")) self.add_icon = QIcon( QPixmap(f"{os.path.dirname(__file__)}/ressources/add.png")) self.stop_icon = QIcon( QPixmap(f"{os.path.dirname(__file__)}/ressources/stop.png")) self.double_factor = 10000 self.sliders = list() self.movement_slider = [] self.active_analyses_widget = None self.analyses_layout = QHBoxLayout() self.analyses_muscle_widget = QWidget() self.add_options_panel() # Update everything at the position Q=0 self.set_q(self.Q)