Exemple #1
0
    def from_factors(cls, factors, frame=None):
        """Construct a scale transformation from scale factors.

        Parameters
        ----------
        factors : list of float
            The scale factors along X, Y, Z.
        frame : :class:`compas.geometry.Frame`, optional
            The anchor frame for the scaling transformation.
            Defaults to ``None``.

        Returns
        -------
        Scale
            A scale transformation.

        Examples
        --------
        >>> point = Point(2, 5, 0)
        >>> frame = Frame(point, (1, 0, 0), (0, 1, 0))
        >>> points = [point, Point(2, 10, 0)]
        >>> S = Scale.from_factors([2.] * 3, frame)
        >>> [p.transformed(S) for p in points]
        [Point(2.000, 5.000, 0.000), Point(2.000, 15.000, 0.000)]
        """
        S = cls()
        if frame:
            Tw = matrix_from_frame(frame)
            Tl = matrix_inverse(Tw)
            Sc = matrix_from_scale_factors(factors)
            S.matrix = multiply_matrices(multiply_matrices(Tw, Sc), Tl)
        else:
            S.matrix = matrix_from_scale_factors(factors)
        return S
Exemple #2
0
def compose_matrix(scale=None,
                   shear=None,
                   angles=None,
                   translation=None,
                   perspective=None):
    """Calculates a matrix from the components of scale, shear, euler_angles, translation and perspective.

    Parameters
    ----------
    scale : [float, float, float]
        The 3 scale factors in x-, y-, and z-direction.
    shear : [float, float, float]
        The 3 shear factors for x-y, x-z, and y-z axes.
    angles : [float, float, float]
        The rotation specified through the 3 Euler angles about static x, y, z axes.
    translation : [float, float, float]
        The 3 values of translation.
    perspective : [float, float, float, float]
        The 4 perspective entries of the matrix.

    Returns
    -------
    list[list[float]]
        The 4x4 matrix that combines the provided transformation components.

    Examples
    --------
    >>> trans1 = [1, 2, 3]
    >>> angle1 = [-2.142, 1.141, -0.142]
    >>> scale1 = [0.123, 2, 0.5]
    >>> M = compose_matrix(scale1, None, angle1, trans1, None)
    >>> scale2, shear2, angle2, trans2, persp2 = decompose_matrix(M)
    >>> allclose(scale1, scale2)
    True
    >>> allclose(angle1, angle2)
    True
    >>> allclose(trans1, trans2)
    True

    """
    M = [[1. if i == j else 0. for i in range(4)] for j in range(4)]
    if perspective is not None:
        P = matrix_from_perspective_entries(perspective)
        M = multiply_matrices(M, P)
    if translation is not None:
        T = matrix_from_translation(translation)
        M = multiply_matrices(M, T)
    if angles is not None:
        R = matrix_from_euler_angles(angles, static=True, axes="xyz")
        M = multiply_matrices(M, R)
    if shear is not None:
        H = matrix_from_shear_entries(shear)
        M = multiply_matrices(M, H)
    if scale is not None:
        S = matrix_from_scale_factors(scale)
        M = multiply_matrices(M, S)
    for i in range(4):
        for j in range(4):
            M[i][j] /= M[3][3]
    return M
Exemple #3
0
 def get_matrix_from_trs(self, node):
     matrix = identity_matrix(4)
     if 'translation' in node:
         translation = matrix_from_translation(node['translation'])
         matrix = multiply_matrices(matrix, translation)
     if 'rotation' in node:
         rotation = matrix_from_quaternion(node['rotation'])
         matrix = multiply_matrices(matrix, rotation)
     if 'scale' in node:
         scale = matrix_from_scale_factors(node['scale'])
         matrix = multiply_matrices(matrix, scale)
     return matrix
Exemple #4
0
def matrix_from_change_of_basis(frame_from, frame_to):
    """Computes a change of basis transformation between two frames.

    A basis change is essentially a remapping of geometry from one
    coordinate system to another.

    Parameters
    ----------
    frame_from : :class:`compas.geometry.Frame`
        A frame defining the original Cartesian coordinate system
    frame_to : :class:`compas.geometry.Frame`
        A frame defining the targeted Cartesian coordinate system

    Returns
    -------
    list[list[float]]
        A 4x4 transformation matrix representing a change of basis.

    Examples
    --------
    >>> from compas.geometry import Point, Frame
    >>> f1 = Frame([2, 2, 2], [0.12, 0.58, 0.81], [-0.80, 0.53, -0.26])
    >>> f2 = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15])
    >>> T = matrix_from_change_of_basis(f1, f2)

    """
    T1 = matrix_from_frame(frame_from)
    T2 = matrix_from_frame(frame_to)
    return multiply_matrices(matrix_inverse(T2), T1)
Exemple #5
0
def matrix_from_frame_to_frame(frame_from, frame_to):
    """Computes a transformation between two frames.

    This transformation allows to transform geometry from one Cartesian
    coordinate system defined by `frame_from` to another Cartesian
    coordinate system defined by `frame_to`.

    Parameters
    ----------
    frame_from : :class:`compas.geometry.Frame`
        A frame defining the original Cartesian coordinate system
    frame_to : :class:`compas.geometry.Frame`
        A frame defining the targeted Cartesian coordinate system

    Returns
    -------
    list[list[float]]
        A 4x4 transformation matrix representing the transformation
        from one frame to another.

    Examples
    --------
    >>> from compas.geometry import Frame
    >>> f1 = Frame([2, 2, 2], [0.12, 0.58, 0.81], [-0.80, 0.53, -0.26])
    >>> f2 = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15])
    >>> T = matrix_from_frame_to_frame(f1, f2)
    """
    T1 = matrix_from_frame(frame_from)
    T2 = matrix_from_frame(frame_to)
    return multiply_matrices(T2, matrix_inverse(T1))
Exemple #6
0
    def process_children(self, parent_key, scene_obj):
        child_keys = scene_obj.nodes[parent_key].children
        for key in child_keys:
            gltf_node = GLTFNode()

            node = self.reader.json['nodes'][key]

            gltf_node.name = node.get('name')
            gltf_node.children = node.get('children', [])
            gltf_node.matrix = self.get_matrix(node)
            gltf_node.weights = node.get('weights')
            gltf_node.mesh_index = node.get('mesh')

            gltf_node.transform = multiply_matrices(
                scene_obj.nodes[parent_key].transform, gltf_node.matrix)
            gltf_node.position = self.inhomogeneous_transformation(
                gltf_node.transform,
                scene_obj.nodes[DEFAULT_ROOT_NAME].position)
            gltf_node.node_key = key

            if gltf_node.mesh_index is not None:
                gltf_node.mesh_data = self.get_mesh_data(gltf_node)

            scene_obj.nodes[key] = gltf_node

            self.process_children(key, scene_obj)
    def update_scene_transforms_and_positions(self, scene):
        """Walks through the scene tree and updates transforms and positions.  To be used when
        nodes have been added or the nodes' matrices or TRS attributes have been set or updated.

        Parameters
        ----------
        scene : :class:`compas.files.GLTFScene`

        Returns
        -------

        """
        origin = [0, 0, 0]
        for node_key in scene.children:
            node = self.nodes[node_key]
            node.transform = node.matrix or node.get_matrix_from_trs()
            node.position = transform_points([origin], node.transform)[0]
            queue = [node_key]
            while queue:
                cur_key = queue.pop(0)
                cur = self.nodes[cur_key]
                for child_key in cur.children:
                    child = self.nodes[child_key]
                    child.transform = multiply_matrices(
                        cur.transform,
                        child.matrix or child.get_matrix_from_trs()
                    )
                    child.position = transform_points([origin], child.transform)[0]
                    queue.append(child_key)
Exemple #8
0
    def from_euler_angles(cls,
                          euler_angles,
                          static=True,
                          axes='xyz',
                          point=[0, 0, 0]):
        """Construct a transformation from a rotation represented by Euler angles.

        Parameters
        ----------
        euler_angles : list of float
            Three numbers that represent the angles of rotations about the defined axes.
        static : bool, optional
            If true the rotations are applied to a static frame.
            If not, to a rotational.
            Defaults to ``True``.
        axes : str, optional
            A 3 character string specifying the order of the axes.
            Defaults to ``'xyz'``.
        point : list of float, optional
            The point of the frame.
            Defaults to ``[0, 0, 0]``.

        Returns
        -------
        :class:`compas.geometry.Transformation`
            The constructed transformation.
        """
        R = matrix_from_euler_angles(euler_angles, static, axes)
        T = matrix_from_translation(point)
        M = multiply_matrices(T, R)
        return cls.from_matrix(M)
    def from_frame_to_frame(cls, frame_from, frame_to):
        """Computes a transformation between two frames.

        This transformation allows to transform geometry from one Cartesian
        coordinate system defined by "frame_from" to another Cartesian
        coordinate system defined by "frame_to".

        Parameters
        ----------
        frame_from : :class:`Frame`
            A frame defining the original Cartesian coordinate system.
        frame_to : :class:`Frame`
            A frame defining the targeted Cartesian coordinate system.

        Returns
        -------
        Transformation
            The ``Transformation`` object representing a change of basis.

        Examples
        --------
        >>> from compas.geometry import Frame
        >>> f1 = Frame([2, 2, 2], [0.12, 0.58, 0.81], [-0.80, 0.53, -0.26])
        >>> f2 = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15])
        >>> T = Transformation.from_frame_to_frame(f1, f2)
        >>> f1.transform(T)
        >>> f1 == f2
        True
        """
        T1 = cls.from_frame(frame_from)
        T2 = cls.from_frame(frame_to)
        return cls(multiply_matrices(T2.matrix, matrix_inverse(T1.matrix)))
Exemple #10
0
    def from_change_of_basis(cls, frame_from, frame_to):
        """Computes a change of basis transformation between two frames.

        A basis change is essentially a remapping of geometry from one
        coordinate system to another.

        Parameters
        ----------
        frame_from : :class:`Frame`
            A frame defining the original Cartesian coordinate system.
        frame_to : :class:`Frame`
            A frame defining the targeted Cartesian coordinate system.

        Examples
        --------
        >>> from compas.geometry import Point, Frame
        >>> f1 = Frame([2, 2, 2], [0.12, 0.58, 0.81], [-0.80, 0.53, -0.26])
        >>> f2 = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15])
        >>> T = Transformation.from_change_of_basis(f1, f2)
        >>> p_f1 = Point(1, 1, 1)  # point in f1
        >>> p_f1.transformed(T)  # point represented in f2
        Point(1.395, 0.955, 1.934)
        >>> Frame.local_to_local_coordinates(f1, f2, p_f1)
        Point(1.395, 0.955, 1.934)
        """
        T1 = cls.from_frame(frame_from)
        T2 = cls.from_frame(frame_to)
        return cls(multiply_matrices(matrix_inverse(T2.matrix), T1.matrix))
Exemple #11
0
def transform_frames(frames, T):
    """Transform multiple frames with one transformation matrix.

    Parameters
    ----------
    frames : sequence[[point, vector, vector] | :class:`compas.geometry.Frame`]
        A list of frames to be transformed.
    T : list[list[float]] | :class:`compas.geometry.Transformation`
        The transformation to apply on the frames.

    Returns
    -------
    list[[point, vector, vector]]
        Transformed frames.

    Examples
    --------
    >>> from compas.geometry import Frame, matrix_from_axis_and_angle
    >>> frames = [Frame([1, 0, 0], [1, 2, 4], [4, 7, 1]), Frame([0, 2, 0], [5, 2, 1], [0, 2, 1])]
    >>> T = matrix_from_axis_and_angle([0, 2, 0], math.radians(45), point=[4, 5, 6])
    >>> transformed_frames = transform_frames(frames, T)

    """
    points_and_vectors = homogenize_and_flatten_frames(frames)
    return dehomogenize_and_unflatten_frames(
        multiply_matrices(points_and_vectors, transpose_matrix(T)))
Exemple #12
0
def rotation_matrix(angle, direction, point=None):
    """Creates a rotation matrix for rotating vectors around an axis.

    Parameters:
        angle (float): Angle in radians to rotate by.
        direction (list): The x, y and z components of the rotation axis.

    Returns:
        list: The (3 x 3) rotation matrix.

    Rotates a vector around a given axis (the axis will be unitised), the
    rotation is based on the right hand rule, i.e. anti-clockwise when the axis
    of rotation points towards the observer.

    Examples:
        >>> R = rotation_matrix(angle=pi/2, direction=[0, 0, 1])
        [[  6.12-17  -1.00+00   0.00+00]
         [  1.00+00   6.12-17   0.00+00]
         [  0.00+00   0.00+00   1.00+00]]
    """
    # To perform a rotation around an arbitrary line (i.e. an axis not through
    # the origin) an origin other than (0, 0, 0) may be provided for the
    # direction vector. Note that the returned 'rotation matrix' is then
    # composed of three translations and a rotation: Tp-1 Txy-1 Tz-1 R Tz Txy Tp
    # l = sum(direction[i] ** 2 for i in range(3)) ** 0.5
    # u = [direction[i] / l for i in range(3)]
    x, y, z = normalize_vector(direction)
    c = cos(angle)
    t = 1 - c
    s = sin(angle)
    R = [[t * x * x + c, t * x * y - s * z, t * x * z + s * y, 0.0],
         [t * x * y + s * z, t * y * y + c, t * y * z - s * x, 0.0],
         [t * x * z - s * y, t * y * z + s * x, t * z * z + c, 0.0],
         [0.0, 0.0, 0.0, 1.0]]

    if point is None:
        return R

    T1 = translation_matrix([-p for p in point])
    T2 = translation_matrix(point)

    return multiply_matrices(T2, multiply_matrices(R, T1))
Exemple #13
0
    def get_matrix_from_trs(self):
        """If the node's displacement from the origin is given by its translation, rotation and
        scale attributes, this method returns the matrix given by the composition of these
        attributes.

        Returns
        -------

        """
        matrix = identity_matrix(4)
        if self.translation:
            translation = matrix_from_translation(self.translation)
            matrix = multiply_matrices(matrix, translation)
        if self.rotation:
            rotation = matrix_from_quaternion(self.rotation)
            matrix = multiply_matrices(matrix, rotation)
        if self.scale:
            scale = matrix_from_scale_factors(self.scale)
            matrix = multiply_matrices(matrix, scale)
        return matrix
Exemple #14
0
    def concatenated(self, other):
        """Concatenate two transformations into one ``Transformation``.

        Parameters
        ----------
        other : :class:`compas.geometry.Transformation`
            The transformation object to concatenate.

        Returns
        -------
        T : :class:`compas.geometry.Transformation`
            The new transformation that is the concatenation of this one and the other.

        Notes
        -----
        Rz * Ry * Rx means that Rx is first transformation, Ry second, and Rz third.
        """
        cls = type(self)
        if isinstance(other, cls):
            return cls(multiply_matrices(self.matrix, other.matrix))
        return Transformation(multiply_matrices(self.matrix, other.matrix))
Exemple #15
0
def transform_vectors(vectors, T):
    """Transform multiple vectors with one transformation matrix.

    Parameters
    ----------
    vectors : list of :class:`Vector` or list of list of float
        A list of vectors to be transformed.
    T : :class:`Transformation` list of list of float
        The transformation to apply.

    Examples
    --------
    >>> vectors = [[1, 0, 0], [1, 2, 4], [4, 7, 1]]
    >>> T = matrix_from_axis_and_angle([0, 2, 0], math.radians(45), point=[4, 5, 6])
    >>> vectors_transformed = transform_vectors(vectors, T)
    """
    return dehomogenize(multiply_matrices(homogenize(vectors, w=0.0), transpose_matrix(T)))
Exemple #16
0
    def concatenate(self, other):
        """Concatenate another transformation to this transformation.

        Parameters
        ----------
        other: :class:`compas.geometry.Transformation`
            The transformation object to concatenate.

        Returns
        -------
        None
            This transformation object is changed in-place.

        Notes
        -----
        Rz * Ry * Rx means that Rx is first transformation, Ry second, and Rz third.
        """
        self.matrix = multiply_matrices(self.matrix, other.matrix)
Exemple #17
0
def transform_frames(frames, T):
    """Transform multiple frames with one transformation matrix.

    Parameters
    ----------
    frames : list of :class:`Frame`
        A list of frames to be transformed.
    T : :class:`Transformation`
        The transformation to apply on the frames.

    Examples
    --------
    >>> frames = [Frame([1, 0, 0], [1, 2, 4], [4, 7, 1]), Frame([0, 2, 0], [5, 2, 1], [0, 2, 1])]
    >>> T = matrix_from_axis_and_angle([0, 2, 0], math.radians(45), point=[4, 5, 6])
    >>> transformed_frames = transform_frames(frames, T)
    """
    points_and_vectors = homogenize_and_flatten_frames(frames)
    return dehomogenize_and_unflatten_frames(multiply_matrices(points_and_vectors, transpose_matrix(T)))
Exemple #18
0
def matrix_from_frame_to_frame(frame_from, frame_to):
    """Computes a transformation between two frames.

    This transformation allows to transform geometry from one Cartesian
    coordinate system defined by "frame_from" to another Cartesian
    coordinate system defined by "frame_to".

    Parameters
    ----------
    frame_from : :class:`Frame`
        A frame defining the original Cartesian coordinate system
    frame_to : :class:`Frame`
        A frame defining the targeted Cartesian coordinate system

    Examples
    --------
    >>> f1 = Frame([2, 2, 2], [0.12, 0.58, 0.81], [-0.80, 0.53, -0.26])
    >>> f2 = Frame([1, 1, 1], [0.68, 0.68, 0.27], [-0.67, 0.73, -0.15])
    >>> T = matrix_from_frame_to_frame(f1, f2)
    """
    T1 = matrix_from_frame(frame_from)
    T2 = matrix_from_frame(frame_to)
    return multiply_matrices(T2, matrix_inverse(T1))
Exemple #19
0
def transform_vectors(vectors, T):
    """Transform multiple vectors with one transformation matrix.

    Parameters
    ----------
    vectors : sequence[[float, float, float] | :class:`compas.geometry.Vector`]
        A list of vectors to be transformed.
    T : list[list[float]] | :class:`compas.geometry.Transformation`
        The transformation to apply.

    Returns
    -------
    list[[float, float, float]]
        Transformed vectors.

    Examples
    --------
    >>> vectors = [[1, 0, 0], [1, 2, 4], [4, 7, 1]]
    >>> T = matrix_from_axis_and_angle([0, 2, 0], math.radians(45), point=[4, 5, 6])
    >>> vectors_transformed = transform_vectors(vectors, T)

    """
    return dehomogenize(
        multiply_matrices(homogenize(vectors, w=0.0), transpose_matrix(T)))
Exemple #20
0
def transform(points, T):
    points = _homogenize(points)
    points = transpose_matrix(multiply_matrices(T, transpose_matrix(points)))
    return _dehomogenize(points)
Exemple #21
0
 def inhomogeneous_transformation(self, matrix, vector):
     return self.project_vector(
         multiply_matrices([self.embed_vector(vector)],
                           transpose_matrix(matrix))[0])