Example #1
0
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,
    )
Example #2
0
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)
Example #4
0
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)
Example #5
0
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)
Example #7
0
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],
    )
Example #8
0
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)
Example #9
0
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)
Example #10
0
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])
Example #12
0
    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
    },
Example #14
0
    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)
Example #15
0
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)
Example #16
0
# 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(
Example #17
0
    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)
Example #18
0
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")
Example #21
0
    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)