// This file is part of Eigen, a lightweight C++ template library
// for linear algebra. Eigen itself is part of the KDE project.
//
// Copyright (C) 2008 Gael Guennebaud <g.gael@free.fr>
//
// Eigen is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 3 of the License, or (at your option) any later version.
//
// Alternatively, you can redistribute it and/or
// modify it under the terms of the GNU General Public License as
// published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Eigen is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
// FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License or the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License and a copy of the GNU General Public License along with
// Eigen. If not, see <http://www.gnu.org/licenses/>.

#ifndef EIGEN_SCALING_H
#define EIGEN_SCALING_H

/** \geometry_module \ingroup GeometryModule
  *
  * \class Scaling
  *
  * \brief Represents a possibly non uniform scaling transformation
  *
  * \param _Scalar the scalar type, i.e., the type of the coefficients.
  * \param _Dim the  dimension of the space, can be a compile time value or Dynamic
  *
  * \note This class is not aimed to be used to store a scaling transformation,
  * but rather to make easier the constructions and updates of Transform objects.
  *
  * \sa class Translation, class Transform
  */
template<typename _Scalar, int _Dim>
class Scaling
{
public:
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW_IF_VECTORIZABLE(_Scalar,_Dim)
  /** dimension of the space */
  enum { Dim = _Dim };
  /** the scalar type of the coefficients */
  typedef _Scalar Scalar;
  /** corresponding vector type */
  typedef Matrix<Scalar,Dim,1> VectorType;
  /** corresponding linear transformation matrix type */
  typedef Matrix<Scalar,Dim,Dim> LinearMatrixType;
  /** corresponding translation type */
  typedef Translation<Scalar,Dim> TranslationType;
  /** corresponding affine transformation type */
  typedef Transform<Scalar,Dim> TransformType;

protected:

  VectorType m_coeffs;

public:

  /** Default constructor without initialization. */
  Scaling() {}
  /** Constructs and initialize a uniform scaling transformation */
  explicit inline Scaling(const Scalar& s) { m_coeffs.setConstant(s); }
  /** 2D only */
  inline Scaling(const Scalar& sx, const Scalar& sy)
  {
    ei_assert(Dim==2);
    m_coeffs.x() = sx;
    m_coeffs.y() = sy;
  }
  /** 3D only */
  inline Scaling(const Scalar& sx, const Scalar& sy, const Scalar& sz)
  {
    ei_assert(Dim==3);
    m_coeffs.x() = sx;
    m_coeffs.y() = sy;
    m_coeffs.z() = sz;
  }
  /** Constructs and initialize the scaling transformation from a vector of scaling coefficients */
  explicit inline Scaling(const VectorType& coeffs) : m_coeffs(coeffs) {}

  const VectorType& coeffs() const { return m_coeffs; }
  VectorType& coeffs() { return m_coeffs; }

  /** Concatenates two scaling */
  inline Scaling operator* (const Scaling& other) const
  { return Scaling(coeffs().cwise() * other.coeffs()); }

  /** Concatenates a scaling and a translation */
  inline TransformType operator* (const TranslationType& t) const;

  /** Concatenates a scaling and an affine transformation */
  inline TransformType operator* (const TransformType& t) const;

  /** Concatenates a scaling and a linear transformation matrix */
  // TODO returns an expression
  inline LinearMatrixType operator* (const LinearMatrixType& other) const
  { return coeffs().asDiagonal() * other; }

  /** Concatenates a linear transformation matrix and a scaling */
  // TODO returns an expression
  friend inline LinearMatrixType operator* (const LinearMatrixType& other, const Scaling& s)
  { return other * s.coeffs().asDiagonal(); }

  template<typename Derived>
  inline LinearMatrixType operator*(const RotationBase<Derived,Dim>& r) const
  { return *this * r.toRotationMatrix(); }

  /** Applies scaling to vector */
  inline VectorType operator* (const VectorType& other) const
  { return coeffs().asDiagonal() * other; }

  /** \returns the inverse scaling */
  inline Scaling inverse() const
  { return Scaling(coeffs.cwise().inverse()); }

  inline Scaling& operator=(const Scaling& other)
  {
    m_coeffs = other.m_coeffs;
    return *this;
  }

  /** \returns \c *this with scalar type casted to \a NewScalarType
    *
    * Note that if \a NewScalarType is equal to the current scalar type of \c *this
    * then this function smartly returns a const reference to \c *this.
    */
  template<typename NewScalarType>
  inline typename ei_cast_return_type<Scaling,Scaling<NewScalarType,Dim> >::type cast() const
  { return typename ei_cast_return_type<Scaling,Scaling<NewScalarType,Dim> >::type(*this); }

  /** Copy constructor with scalar type conversion */
  template<typename OtherScalarType>
  inline explicit Scaling(const Scaling<OtherScalarType,Dim>& other)
  { m_coeffs = other.coeffs().template cast<Scalar>(); }

  /** \returns \c true if \c *this is approximately equal to \a other, within the precision
    * determined by \a prec.
    *
    * \sa MatrixBase::isApprox() */
  bool isApprox(const Scaling& other, typename NumTraits<Scalar>::Real prec = precision<Scalar>()) const
  { return m_coeffs.isApprox(other.m_coeffs, prec); }

};

/** \addtogroup GeometryModule */
//@{
typedef Scaling<float, 2> Scaling2f;
typedef Scaling<double,2> Scaling2d;
typedef Scaling<float, 3> Scaling3f;
typedef Scaling<double,3> Scaling3d;
//@}

template<typename Scalar, int Dim>
inline typename Scaling<Scalar,Dim>::TransformType
Scaling<Scalar,Dim>::operator* (const TranslationType& t) const
{
  TransformType res;
  res.matrix().setZero();
  res.linear().diagonal() = coeffs();
  res.translation() = m_coeffs.cwise() * t.vector();
  res(Dim,Dim) = Scalar(1);
  return res;
}

template<typename Scalar, int Dim>
inline typename Scaling<Scalar,Dim>::TransformType
Scaling<Scalar,Dim>::operator* (const TransformType& t) const
{
  TransformType res = t;
  res.prescale(m_coeffs);
  return res;
}

#endif // EIGEN_SCALING_H
