// 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 <unsupported/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
