Example #1
0
 def test_to_matrix(self):
     self.assertAlmostEqual(
         RotateAxisAngle(X, 90).to_matrix(), affine_matrix(X, Z, -Y))
     self.assertAlmostEqual(
         RotateAxisAngle(X + Y, 180).to_matrix(), affine_matrix(Y, X, -Z))
     self.assertAlmostEqual(
         RotateAxisAngle(X + Y + Z, 120).to_matrix(),
         affine_matrix(Y, Z, X))
Example #2
0
    def to_matrix(self):
        axis, angle = self._to_axis_angle()

        if axis is None:
            # No rotation
            return Matrix.identity(4)
        else:
            # Yes rotation
            return RotateAxisAngle(axis, angle).to_matrix()
Example #3
0
    def to_scad(self, target):
        axis, angle = self._to_axis_angle()

        if axis is None:
            # No rotation. Generate a zero XYZ transform instead of simply
            # returning the target. This improves code clarity and also ensures
            # that a valid ScadObject is returned even if target is None.
            return RotateXyz(0, 0, 0).to_scad(target).comment(str(self))
        else:
            # Yes rotation
            return RotateAxisAngle(axis.normalized(), angle).to_scad(target).comment(str(self))
    def test_rotate(self):
        # Canonical axis/angle
        self.assertEqual(rotate(axis = Vector(1, 2, 3), angle = 45), RotateAxisAngle(Vector(1, 2, 3), 45)) # Vector
        self.assertEqual(rotate(axis =       [1, 2, 3], angle = 45), RotateAxisAngle(Vector(1, 2, 3), 45)) # List

        # Canonical from/to
        self.assertEqual(rotate(frm = Vector(1, 2, 3), to = Vector(4, 5, 6)), RotateFromTo(Vector(1, 2, 3), Vector(4, 5, 6))) # Vectors
        self.assertEqual(rotate(frm =       [1, 2, 3], to =       [4, 5, 6]), RotateFromTo(Vector(1, 2, 3), Vector(4, 5, 6))) # Lists

        # Canonical XYZ
        self.assertEqual(rotate(xyz = [45, 0, 30]), RotateXyz(45, 0, 30))

        # Canonical yaw/pitch/roll
        self.assertEqual(rotate(ypr = [90, -20, 5]), RotateYpr(90, -20, 5))

        # Convenience axis/angle (implicit)
        self.assertEqual(rotate(Vector(1, 2, 3), 45), RotateAxisAngle(Vector(1, 2, 3), 45)) # Vector
        self.assertEqual(rotate(      [1, 2, 3], 45), RotateAxisAngle(Vector(1, 2, 3), 45)) # List

        # Convenience axis/angle (explicit)
        self.assertEqual(rotate(Vector(1, 2, 3), angle = 45), RotateAxisAngle(Vector(1, 2, 3), 45)) # Vector
        self.assertEqual(rotate(      [1, 2, 3], angle = 45), RotateAxisAngle(Vector(1, 2, 3), 45)) # List

        # Convenience from/to (implicit)
        self.assertEqual(rotate(X        , Y        ), RotateFromTo(X, Y)) # Vectors
        self.assertEqual(rotate([1, 0, 0], [0, 1, 0]), RotateFromTo(X, Y)) # Lists

        # Convenience from/to (explicit)
        self.assertEqual(rotate(X        , to = Y        ), RotateFromTo(X, Y)) # Vectors
        self.assertEqual(rotate([1, 0, 0], to = [0, 1, 0]), RotateFromTo(X, Y)) # Lists
Example #5
0
    def test_equality(self):
        # Same object
        self.assertEqualToItself(RotateAxisAngle(Vector(1, 2, 3), 45))

        # Equal objects
        self.assertEqual(RotateAxisAngle(Vector(1, 2, 3), 45),
                         RotateAxisAngle(Vector(1, 2, 3), 45))  # Equal

        # Different objects
        self.assertNotEqual(RotateAxisAngle(Vector(1, 2, 3), 45),
                            RotateAxisAngle(Vector(1, 2, 4),
                                            45))  # Different axis
        self.assertNotEqual(RotateAxisAngle(Vector(1, 2, 3), 45),
                            RotateAxisAngle(Vector(1, 2, 3),
                                            46))  # Different angle

        # Equal objects from different specifications
        self.assertEqual(RotateAxisAngle([1, 2, 3], 45),
                         RotateAxisAngle(Vector(1, 2, 3),
                                         45))  # list vs. Vector
Example #6
0
    def test_inequality(self):
        # Different-type transformations are not equal (even if the values are identical)
        transforms = [
            RotateAxisAngle(X, 0),
            RotateFromTo(X, X),
            RotateXyz(0, 0, 0),
            RotateYpr(0, 0, 0),
            ScaleAxisFactor(X, 1),
            ScaleUniform(1),
            ScaleAxes (1, 1, 1),
            Translate([0, 0, 0]),
        ]

        for t1 in transforms:
            for t2 in transforms:
                if t1 is not t2:
                    self.assertNotEqual(t1, t2)
Example #7
0
    def test_multiplication_with_vector(self):
        r = RotateAxisAngle(X, 90)
        s = ScaleAxes (1, 2, -1)
        t = Translate([1, 2, 3])

        self.assertAlmostEqual(r * Vector( 0,  0,  0), Vector( 0,   0,  0))
        self.assertAlmostEqual(r * Vector(10, 20, 30), Vector(10, -30, 20))

        self.assertAlmostEqual(s * Vector( 0,  0,  0), Vector( 0,  0,   0))
        self.assertAlmostEqual(s * Vector(10, 20, 30), Vector(10, 40, -30))

        self.assertAlmostEqual(t * Vector( 0,  0,  0), Vector( 1,  2,  3))
        self.assertAlmostEqual(t * Vector(10, 20, 30), Vector(11, 22, 33))

        self.assertAlmostEqual((t *  s) * Vector(10, 20, 30) , Vector(11, 42, -27))
        self.assertAlmostEqual( t * (s  * Vector(10, 20, 30)), Vector(11, 42, -27))

        with self.assertRaises(ValueError): r * Vector(0, 0)
Example #8
0
    def test_construction(self):
        # Valid
        RotateAxisAngle([1, 2, 3], 45)
        RotateAxisAngle(Vector(1, 2, 3), 45)

        # Invalid
        with self.assertRaises(ValueError):
            RotateAxisAngle([0, 0, 0], 45)
        with self.assertRaises(TypeError):
            RotateAxisAngle([1, 2, "3"], 4)
        with self.assertRaises(TypeError):
            RotateAxisAngle([1, 2, 3], "4")
        with self.assertRaises(TypeError):
            RotateAxisAngle(1, "4")
Example #9
0
def rotate(axis_or_frm = None, angle_or_to = None, axis = None, angle = None, frm = None, to = None, xyz = None, ypr = None, ignore_ambiguity = False):
    """Generate a rotation around an axis through the origin.

    Signatures (canonical forms):
      * rotate(axis = x, angle = 45)
      * rotate(frm = x, to = y)
      * rotate(xyz = [45, 0, 30])
      * rotate(ypr = [45, -30, 10])
    Signatures (convenience forms):
      * rotate(x, 45)
      * rotate(x, angle = 45)
      * rotate(x, y)
      * rotate(x, to = y)
    """

    # Canonical forms:
    #     axis_or_axmag_or_frm  angle_or_to  axis  angle  frm   to   xyz   ypr
    #                        -            -   vec    num    -    -     -     -  # Axis/angle
    #                        -            -     -      -  vec  vec     -     -  # From/to
    #                        -            -     -      -    -    -  list     -  # XYZ
    #                        -            -     -      -    -    -     -  list  # Yaw/pitch/roll
    # Convenience forms (-: must be None, *: overwritten)
    #                      vec          num     *      *    -    -     -     -  # Axis/angle (implicit)
    #                      vec            -     *    num    -    -     -     -  # Axis/angle (explicit)
    #                      vec          vec     -      -    *    *     -     -  # From/to (implicit)
    #                      vec            -     -      -    *  vec     -     -  # From/to (explicit)
    #
    # "Vector type" is Vector, list, or tuple

    # Make sure that there are no conflicts between convenience parameters and canonical parameters
    if both(axis_or_frm, axis ): raise TypeError("axis"  " cannot be specified together with axis_or_frm")
    if both(axis_or_frm, frm  ): raise TypeError("frm"   " cannot be specified together with axis_or_frm")
    if both(angle_or_to, angle): raise TypeError("angle" " cannot be specified together with angle_or_to")
    if both(angle_or_to, to   ): raise TypeError("to"    " cannot be specified together with angle_or_to")

    # Transform the convenience forms to canonical form
    if axis_or_frm is not None:
        if not Vector.valid_type(axis_or_frm):
            raise TypeError("axis must be a vector type")

        if angle_or_to is not None:
            if number.valid(angle_or_to):
                # Axis/angle (implicit)
                axis = axis_or_frm
                angle = angle_or_to
            elif Vector.valid_type(angle_or_to):
                # From/to (implicit)
                frm = axis_or_frm
                to = angle_or_to
            else:
                raise TypeError("angle_or_to must be a number or a vector type")
        elif angle is not None:
            # Axis/angle (explicit)
            axis = axis_or_frm
        elif to is not None:
            # From/to (explicit)
            frm = axis_or_frm

    # Check the parameters that must appear in pairs
    if axis  is not None and angle is None: raise TypeError("angle" " is required when " "axis"  " is given")
    if angle is not None and axis  is None: raise TypeError("axis"  " is required when " "angle" " is given")
    if frm   is not None and to    is None: raise TypeError("to"    " is required when " "frm"   " is given")
    if to    is not None and frm   is None: raise TypeError("frm"   " is required when " "to"    " is given")

    # Handle the different cases
    if axis is not None:
        # Check that no other specification is given
        if frm is not None: raise TypeError("frm" " cannot be specified together with axis")
        if xyz is not None: raise TypeError("xyz" " cannot be specified together with axis")
        if ypr is not None: raise TypeError("ypr" " cannot be specified together with axis")

        return RotateAxisAngle(axis, angle)

    elif frm is not None:
        # Check that no other specification is given
        if axis is not None: raise TypeError("axis" " cannot be specified together with frm")
        if xyz  is not None: raise TypeError("xyz"  " cannot be specified together with frm")
        if ypr  is not None: raise TypeError("ypr"  " cannot be specified together with frm")

        return RotateFromTo(frm, to, ignore_ambiguity)

    elif xyz is not None:
        # Check that no other specification is given
        if axis is not None: raise TypeError("axis" " cannot be specified together with frm")
        if frm  is not None: raise TypeError("frm"  " cannot be specified together with axis")
        if ypr  is not None: raise TypeError("ypr"  " cannot be specified together with axis")

        return RotateXyz(*xyz)

    elif ypr is not None:
        # Check that no other specification is given
        if axis is not None: raise TypeError("axis" " cannot be specified together with frm")
        if frm  is not None: raise TypeError("frm"  " cannot be specified together with axis")
        if xyz  is not None: raise TypeError("xyz"  " cannot be specified together with axis")

        return RotateYpr(*ypr)

    else:
        raise TypeError("Invalid call signature")
Example #10
0
 def test_str(self):
     self.assertStr(RotateAxisAngle([1, 0, 0], 45),
                    "Rotate by 45° around <1, 0, 0>")
Example #11
0
 def test_repr(self):
     self.assertRepr(RotateAxisAngle([1, 0, 0], 45),
                     "RotateAxisAngle(Vector(1, 0, 0), 45)")
Example #12
0
 def test_to_scad(self):
     r = RotateAxisAngle([1, 2, 3], 45)
     self.assertScadObjectTarget(r, None, "rotate", None,
                                 [('a', 45), ('v', [1, 2, 3])], None)
Example #13
0
 def test_inverse(self):
     self.assertInverse(RotateAxisAngle(X, 45), RotateAxisAngle(-X, 45))