// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2009 Gael Guennebaud <g.gael@free.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// SPDX-License-Identifier: MPL-2.0

#ifndef EIGEN_ALIGNED_VECTOR3_MODULE_H
#define EIGEN_ALIGNED_VECTOR3_MODULE_H

#include "../../Eigen/Geometry"

#include "../../Eigen/src/Core/util/DisableStupidWarnings.h"

namespace Eigen {

/**
 * \defgroup AlignedVector3_Module Aligned vector3 module
 *
 * \code
 * #include <contrib/Eigen/AlignedVector3>
 * \endcode
 */
//@{

/** \class AlignedVector3
 *
 * \brief A vectorization friendly 3D vector
 *
 * This class represents a 3D vector internally using a 4D vector
 * such that vectorization can be seamlessly enabled. Of course,
 * the same result can be achieved by directly using a 4D vector.
 * This class makes this process simpler.
 *
 */
// TODO: Specialize Cwise.
template <typename Scalar_>
class AlignedVector3;

namespace internal {
template <typename Scalar_>
struct traits<AlignedVector3<Scalar_> > : traits<Matrix<Scalar_, 3, 1, 0, 4, 1> > {};
}  // namespace internal

template <typename Scalar_>
class AlignedVector3 : public MatrixBase<AlignedVector3<Scalar_> > {
  typedef Matrix<Scalar_, 4, 1> CoeffType;
  CoeffType m_coeffs;

 public:
  typedef MatrixBase<AlignedVector3<Scalar_> > Base;
  EIGEN_DENSE_PUBLIC_INTERFACE(AlignedVector3)
  using Base::operator*;

  inline Index rows() const { return 3; }
  inline Index cols() const { return 1; }

  Scalar* data() { return m_coeffs.data(); }
  const Scalar* data() const { return m_coeffs.data(); }
  Index innerStride() const { return 1; }
  Index outerStride() const { return 3; }

  inline const Scalar& coeff(Index row, Index col) const { return m_coeffs.coeff(row, col); }

  inline Scalar& coeffRef(Index row, Index col) { return m_coeffs.coeffRef(row, col); }

  inline const Scalar& coeff(Index index) const { return m_coeffs.coeff(index); }

  inline Scalar& coeffRef(Index index) { return m_coeffs.coeffRef(index); }

  inline AlignedVector3() {}

  inline AlignedVector3(const Scalar& x, const Scalar& y, const Scalar& z) : m_coeffs(x, y, z, Scalar(0)) {}

  inline AlignedVector3(const AlignedVector3& other) : Base(), m_coeffs(other.m_coeffs) {}

  template <typename XprType, int Size = XprType::SizeAtCompileTime>
  struct generic_assign_selector {};

  template <typename XprType>
  struct generic_assign_selector<XprType, 4> {
    inline static void run(AlignedVector3& dest, const XprType& src) { dest.m_coeffs = src; }
  };

  template <typename XprType>
  struct generic_assign_selector<XprType, 3> {
    inline static void run(AlignedVector3& dest, const XprType& src) {
      dest.m_coeffs.template head<3>() = src;
      dest.m_coeffs.w() = Scalar(0);
    }
  };

  template <typename Derived>
  inline AlignedVector3(const MatrixBase<Derived>& other) {
    generic_assign_selector<Derived>::run(*this, other.derived());
  }

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

  template <typename Derived>
  inline AlignedVector3& operator=(const MatrixBase<Derived>& other) {
    generic_assign_selector<Derived>::run(*this, other.derived());
    return *this;
  }

  inline AlignedVector3 operator+(const AlignedVector3& other) const {
    return AlignedVector3(m_coeffs + other.m_coeffs);
  }

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

  inline AlignedVector3 operator-(const AlignedVector3& other) const {
    return AlignedVector3(m_coeffs - other.m_coeffs);
  }

  inline AlignedVector3 operator-() const { return AlignedVector3(-m_coeffs); }

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

  inline AlignedVector3 operator*(const Scalar& s) const { return AlignedVector3(m_coeffs * s); }

  inline friend AlignedVector3 operator*(const Scalar& s, const AlignedVector3& vec) {
    return AlignedVector3(s * vec.m_coeffs);
  }

  inline AlignedVector3& operator*=(const Scalar& s) {
    m_coeffs *= s;
    return *this;
  }

  inline AlignedVector3 operator/(const Scalar& s) const { return AlignedVector3(m_coeffs / s); }

  inline AlignedVector3& operator/=(const Scalar& s) {
    m_coeffs /= s;
    return *this;
  }

  inline Scalar dot(const AlignedVector3& other) const {
    eigen_assert(m_coeffs.w() == Scalar(0));
    eigen_assert(other.m_coeffs.w() == Scalar(0));
    return m_coeffs.dot(other.m_coeffs);
  }

  inline void normalize() { m_coeffs /= norm(); }

  inline AlignedVector3 normalized() const { return AlignedVector3(m_coeffs / norm()); }

  inline Scalar sum() const {
    eigen_assert(m_coeffs.w() == Scalar(0));
    return m_coeffs.sum();
  }

  inline Scalar squaredNorm() const {
    eigen_assert(m_coeffs.w() == Scalar(0));
    return m_coeffs.squaredNorm();
  }

  inline Scalar norm() const {
    using std::sqrt;
    return sqrt(squaredNorm());
  }

  inline AlignedVector3 cross(const AlignedVector3& other) const {
    return AlignedVector3(m_coeffs.cross3(other.m_coeffs));
  }

  template <typename Derived>
  inline bool isApprox(const MatrixBase<Derived>& other,
                       const RealScalar& eps = NumTraits<Scalar>::dummy_precision()) const {
    return m_coeffs.template head<3>().isApprox(other, eps);
  }

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

namespace internal {

template <typename Scalar_>
struct eval<AlignedVector3<Scalar_>, Dense> {
  typedef const AlignedVector3<Scalar_>& type;
};

template <typename Scalar>
struct evaluator<AlignedVector3<Scalar> > : evaluator<Matrix<Scalar, 4, 1> > {
  typedef AlignedVector3<Scalar> XprType;
  typedef evaluator<Matrix<Scalar, 4, 1> > Base;

  evaluator(const XprType& m) : Base(m.coeffs()) {}
};

}  // namespace internal

//@}

}  // namespace Eigen

#include "../../Eigen/src/Core/util/ReenableStupidWarnings.h"

#endif  // EIGEN_ALIGNED_VECTOR3_MODULE_H
