# Source code for pyrr.objects.matrix33

    # -*- coding: utf-8 -*-
    """Represents a 3x3 Matrix.

    The Matrix33 class provides a number of convenient functions and
    conversions.
    ::

        import numpy as np
        from pyrr import Quaternion, Matrix33, Matrix44, Vector3

        m = Matrix33()
        m = Matrix33([[1.,0.,0.],[0.,1.,0.],[0.,0.,1.]])

        # copy constructor
        m = Matrix44(Matrix44())

        # explicit creation
        m = Matrix33.identity()
        m = Matrix33.from_matrix44(Matrix44())

        # inferred conversions
        m = Matrix33(Quaternion())
        m = Matrix33(Matrix44())

        # multiply matricies together
        m = Matrix33() * Matrix33()
        m = Matrix33() * Matrix44()

        # extract a quaternion from a matrix
        q = m.quaternion

        # convert from quaternion back to matrix
        m = q.matrix33
        m = Matrix33(q)

        # rotate a matrix by a quaternion
        m = Matrix33.identity() * Quaternion()

        # rotate a vector 3 by a matrix
        v = Matrix33.from_x_rotation(np.pi) * Vector3([1.,2.,3.])

        # undo a rotation
        m = Matrix33.from_x_rotation(np.pi)
        v = m * Vector3([1.,1.,1.])
        # ~m is the same as m.inverse
        v = ~m * v

        # access specific parts of the matrix
        # first row
        m1 = m.m1
        # first element, first row
        m11 = m.m11
        # third element, third row
        m33 = m.m33
        # first row, same as m1
        r1 = m.r1
        # first column
        c1 = m.c1
    """
    from __future__ import absolute_import
    from numbers import Number
    import numpy as np
    from multipledispatch import dispatch
    from .base import BaseObject, BaseMatrix, BaseMatrix33, BaseQuaternion, BaseVector, NpProxy
    from .. import matrix33

    class Matrix33(BaseMatrix33):
        _module = matrix33
        _shape = (3,3,)

        # m<c> style access
        #: The first row of this Matrix as a numpy.ndarray.
        m1 = NpProxy(0)
        #: The second row of this Matrix as a numpy.ndarray.
        m2 = NpProxy(1)
        #: The third row of this Matrix as a numpy.ndarray.
        m3 = NpProxy(2)

        # m<r><c> access
        #: The [0,0] value of this Matrix.
        m11 = NpProxy((0,0))
        #: The [0,1] value of this Matrix.
        m12 = NpProxy((0,1))
        #: The [0,2] value of this Matrix.
        m13 = NpProxy((0,2))
        #: The [1,0] value of this Matrix.
        m21 = NpProxy((1,0))
        #: The [1,1] value of this Matrix.
        m22 = NpProxy((1,1))
        #: The [1,2] value of this Matrix.
        m23 = NpProxy((1,2))
        #: The [2,0] value of this Matrix.
        m31 = NpProxy((2,0))
        #: The [2,1] value of this Matrix.
        m32 = NpProxy((2,1))
        #: The [2,2] value of this Matrix.
        m33 = NpProxy((2,2))

        # rows
        #: The first row of this Matrix as a numpy.ndarray. This is the same as m1.
        r1 = NpProxy(0)
        #: The second row of this Matrix as a numpy.ndarray. This is the same as m2.
        r2 = NpProxy(1)
        #: The third row of this Matrix as a numpy.ndarray. This is the same as m3.
        r3 = NpProxy(2)

        # columns
        #: The first column of this Matrix as a numpy.ndarray.
        c1 = NpProxy((slice(0,3),0))
        #: The second column of this Matrix as a numpy.ndarray.
        c2 = NpProxy((slice(0,3),1))
        #: The third column of this Matrix as a numpy.ndarray.
        c3 = NpProxy((slice(0,3),2))

        ########################
        # Creation
        @classmethod
        def from_matrix44(cls, matrix, dtype=None):
            """Creates a Matrix33 from a Matrix44.

            The Matrix44 translation will be lost.
            """
            return cls(matrix33.create_from_matrix44(matrix, dtype))

        def __new__(cls, value=None, dtype=None):
            if value is not None:
                obj = value
                if not isinstance(value, np.ndarray):
                    obj = np.array(value, dtype=dtype)

                # matrix44
                if obj.shape == (4,4) or isinstance(obj, Matrix44):
                    obj = matrix33.create_from_matrix44(obj, dtype=dtype)
                # quaternion
                elif obj.shape == (4,) or isinstance(obj, Quaternion):
                    obj = matrix33.create_from_quaternion(obj, dtype=dtype)
            else:
                obj = np.zeros(cls._shape, dtype=dtype)
            obj = obj.view(cls)
            return super(Matrix33, cls).__new__(cls, obj)

        ########################
        # Basic Operators

        @dispatch(BaseObject)
        def __add__(self, other):
            self._unsupported_type('add', other)

        @dispatch(BaseObject)
        def __sub__(self, other):
            self._unsupported_type('subtract', other)

        @dispatch(BaseObject)
        def __mul__(self, other):
            self._unsupported_type('multiply', other)

        @dispatch(BaseObject)
        def __truediv__(self, other):
            self._unsupported_type('divide', other)

        @dispatch(BaseObject)
        def __div__(self, other):
            self._unsupported_type('divide', other)

        def __invert__(self):
            return self.inverse

        ########################
        # Matrices
        @dispatch((BaseMatrix, np.ndarray, list))
        def __add__(self, other):
            return Matrix33(super(Matrix33, self).__add__(Matrix33(other)))

        @dispatch((BaseMatrix, np.ndarray, list))
        def __sub__(self, other):
            return Matrix33(super(Matrix33, self).__sub__(Matrix33(other)))

        @dispatch((BaseMatrix, np.ndarray, list))
        def __mul__(self, other):
            return Matrix33(matrix33.multiply(Matrix33(other), self))

        @dispatch((BaseMatrix, np.ndarray, list))
        def __ne__(self, other):
            return bool(np.any(super(Matrix33, self).__ne__(other)))

        @dispatch((BaseMatrix, np.ndarray, list))
        def __eq__(self, other):
            return bool(np.all(super(Matrix33, self).__eq__(other)))

        ########################
        # Quaternions
        @dispatch(BaseQuaternion)
        def __mul__(self, other):
            m = other.matrix33
            return self * m

        ########################
        # Vectors
        @dispatch(BaseVector)
        def __mul__(self, other):
            return type(other)(matrix33.apply_to_vector(self, other))

        ########################
        # Number
        @dispatch((Number, np.number))
        def __add__(self, other):
            return Matrix33(super(Matrix33, self).__add__(other))

        @dispatch((Number, np.number))
        def __sub__(self, other):
            return Matrix33(super(Matrix33, self).__sub__(other))

        @dispatch((Number, np.number))
        def __mul__(self, other):
            return Matrix33(super(Matrix33, self).__mul__(other))

        @dispatch((Number, np.number))
        def __truediv__(self, other):
            return Matrix33(super(Matrix33, self).__truediv__(other))

        @dispatch((Number, np.number))
        def __div__(self, other):
            return Matrix33(super(Matrix33, self).__div__(other))

        ########################
        # Methods and Properties
        @property
        def matrix33(self):
            """Returns the Matrix33.

            This can be handy if you're not sure what type of Matrix class you have
            but require a Matrix33.
            """
            return self

        @property
        def matrix44(self):
            """Returns a Matrix44 representing this matrix.
            """
            return Matrix44(self)

        @property
        def quaternion(self):
            """Returns a Quaternion representing this matrix.
            """
            return Quaternion(self)

    from .matrix44 import Matrix44
    from .quaternion import Quaternion