//
// Copyright 2021 Pixar
//
// Licensed under the terms set forth in the LICENSE.txt file available at
// https://openusd.org/license.
//
////////////////////////////////////////////////////////////////////////
// This file is generated by a script.  Do not edit directly.  Edit the
// dualQuat.template.h file to make changes.

#ifndef PXR_BASE_GF_DUALQUATD_H
#define PXR_BASE_GF_DUALQUATD_H

/// \file gf/dualQuatd.h
/// \ingroup group_gf_LinearAlgebra

#include "pxr/pxr.h"
#include "pxr/base/gf/api.h"
#include "pxr/base/gf/declare.h"
#include "pxr/base/gf/traits.h"

#include "pxr/base/gf/quatd.h"
#include "pxr/base/tf/hash.h"

#include <iosfwd>

PXR_NAMESPACE_OPEN_SCOPE

template <>
struct GfIsGfDualQuat<class GfDualQuatd> { static const bool value = true; };

/// Return the dot (inner) product of two dual quaternions.
double GfDot(const GfDualQuatd& dq1, const GfDualQuatd& dq2);


/// \class GfDualQuatd
/// \ingroup group_gf_LinearAlgebra
///
/// Basic type: a real part quaternion and a dual part quaternion.
///
/// This class represents a generalized dual quaternion that has a real part
/// and a dual part quaternions. Dual quaternions are used to represent a
/// combination of rotation and translation.
///
/// References:
///    https://www.cs.utah.edu/~ladislav/kavan06dual/kavan06dual.pdf
///    https://faculty.sites.iastate.edu/jia/files/inline-files/dual-quaternion.pdf
///
class GfDualQuatd final
{
  public:
    typedef double ScalarType;

    /// The default constructor leaves the dual quaternion undefined.
    GfDualQuatd() {}

    /// Initialize the real part to \p realVal and the imaginary part
    /// to zero quaternion.
    ///
    /// Since quaternions typically must be normalized, reasonable values for
    /// \p realVal are -1, 0, or 1.  Other values are legal but are likely to
    /// be meaningless.
    ///
    explicit GfDualQuatd( double realVal ) : _real( realVal ), _dual( 0 ) {}

    /// Initialize the real part to \p real quaternion and the imaginary part
    /// to zero quaternion.
    ///
    explicit GfDualQuatd( const GfQuatd &real )
        : _real( real ), _dual( 0 ) {
    }

    /// This constructor initializes the real and dual parts.
    GfDualQuatd( const GfQuatd &real, const GfQuatd &dual )
        : _real( real ), _dual( dual ) {
    }

    /// This constructor initializes from a rotation and a translation components.
    GfDualQuatd( const GfQuatd &rotation, const GfVec3d &translation )
        : _real( rotation ) {
        SetTranslation( translation );
    }

    /// Implicitly convert from GfDualQuatf.
    GF_API
    GfDualQuatd(const GfDualQuatf &other);
    /// Implicitly convert from GfDualQuath.
    GF_API
    GfDualQuatd(const GfDualQuath &other);

    /// Sets the real part of the dual quaternion.
    void SetReal(const GfQuatd &real) {
        _real  = real;
    }

    /// Sets the dual part of the dual quaternion.
    void SetDual(const GfQuatd &dual) {
        _dual  = dual;
    }

    /// Returns the real part of the dual quaternion.
    const GfQuatd &GetReal() const {
        return _real;
    }

    /// Returns the dual part of the dual quaternion.
    const GfQuatd &GetDual() const {
        return _dual;
    }

    /// Returns the zero dual quaternion, which has a real part of (0,0,0,0) and
    /// a dual part of (0,0,0,0).
    static GfDualQuatd GetZero() {
        return GfDualQuatd(GfQuatd::GetZero(), GfQuatd::GetZero());
    }

    /// Returns the identity dual quaternion, which has a real part of (1,0,0,0) and
    /// a dual part of (0,0,0,0).
    static GfDualQuatd GetIdentity() {
        return GfDualQuatd(GfQuatd::GetIdentity(), GfQuatd::GetZero());
    }

    /// Returns geometric length of this dual quaternion.
    GF_API
    std::pair<double, double> GetLength() const;

    /// Returns a normalized (unit-length) version of this dual quaternion.
    /// If the length of this dual quaternion is smaller than \p
    /// eps, this returns the identity dual quaternion.
    GF_API
    GfDualQuatd GetNormalized(double eps = GF_MIN_VECTOR_LENGTH) const;

    /// Normalizes this dual quaternion in place.
    /// Normalizes this dual quaternion in place to unit length, returning the
    /// length before normalization. If the length of this dual quaternion is
    /// smaller than \p eps, this sets the dual quaternion to identity.
    GF_API
    std::pair<double, double> Normalize(double eps = GF_MIN_VECTOR_LENGTH);

    /// Returns the conjugate of this dual quaternion.
    GF_API
    GfDualQuatd GetConjugate() const;

    /// Returns the inverse of this dual quaternion.
    GF_API
    GfDualQuatd GetInverse() const;

    /// Set the translation component of this dual quaternion.
    GF_API
    void SetTranslation( const GfVec3d &translation );

    /// Get the translation component of this dual quaternion.
    GF_API
    GfVec3d GetTranslation() const;

    /// Hash.
    friend inline size_t hash_value(const GfDualQuatd &dq) {
        return TfHash::Combine(dq.GetReal(), dq.GetDual());
    }

    /// Component-wise dual quaternion equality test. The real and dual parts
    /// must match exactly for dual quaternions to be considered equal.
    bool operator ==(const GfDualQuatd &dq) const {
        return (GetReal() == dq.GetReal() &&
                GetDual() == dq.GetDual());
    }

    /// Component-wise dual quaternion inequality test. The real and dual
    /// parts must match exactly for dual quaternions to be considered equal.
    bool operator !=(const GfDualQuatd &dq) const {
        return ! (*this == dq);
    }

    /// Component-wise unary sum operator.
    GfDualQuatd &operator +=(const GfDualQuatd &dq)  {
        _real += dq._real;
        _dual += dq._dual;
        return *this;
    }

    /// Component-wise unary difference operator.
    GfDualQuatd &operator -=(const GfDualQuatd &dq)  {
        _real -= dq._real;
        _dual -= dq._dual;
        return *this;
    }

    /// Post-multiplies dual quaternion \p dq into this dual quaternion.
    GF_API
    GfDualQuatd &operator *=(const GfDualQuatd &dq);

    /// Scales this dual quaternion by \p s.
    GfDualQuatd &operator *=(double s) {
        _real *= s;
        _dual *= s;
        return *this;
    }

    /// Scales this dual quaternion by 1 / \p s.
    GfDualQuatd &operator /=(double s) {
        return (*this) *= 1.0 / s;
    }

    /// Component-wise binary sum operator.
    friend GfDualQuatd operator +(const GfDualQuatd &dq1,
                                     const GfDualQuatd &dq2) {
        GfDualQuatd dqt = dq1;
        return dqt += dq2;
    }

    /// Component-wise binary difference operator.
    friend GfDualQuatd operator -(const GfDualQuatd &dq1,
                                     const GfDualQuatd &dq2) {
        GfDualQuatd dqt = dq1;
        return dqt -= dq2;
    }

    /// Returns the product of dual quaternions \p dq1 and \p dq2.
    friend GfDualQuatd operator *(const GfDualQuatd &dq1,
                                     const GfDualQuatd &dq2) {
        GfDualQuatd dqt  = dq1;
        return dqt *= dq2;
    }

    /// Returns the product of dual quaternion \p dq and scalar \p s.
    friend GfDualQuatd operator *(const GfDualQuatd &dq, double s) {
        GfDualQuatd dqt  = dq;
        return dqt *= s;
    }

    /// Returns the product of dual quaternion \p dq and scalar \p s.
    friend GfDualQuatd operator *(double s, const GfDualQuatd &dq) {
        GfDualQuatd dqt  = dq;
        return dqt *= s;
    }

    /// Returns the product of dual quaternion \p dq and scalar 1 / \p s.
    friend GfDualQuatd operator /(const GfDualQuatd &dq, double s) {
        GfDualQuatd dqt  = dq;
        return dqt /= s;
    }

    /// Transforms the row vector \e vec by the dual quaternion.
    GF_API
    GfVec3d Transform(const GfVec3d &vec) const;

  private:
    GfQuatd _real;   // for rotation
    GfQuatd _dual;   // for translation
};


/// Output a GfDualQuatd using the format ((rw, rx, ry, rz), (dw, dx, dy, dz)).
/// \ingroup group_gf_DebuggingOutput
GF_API std::ostream &operator<<(std::ostream &out, const GfDualQuatd &dq);


/// Returns the dot (inner) product of two dual quaternions.
inline double
GfDot(const GfDualQuatd& dq1, const GfDualQuatd& dq2) {
    return GfDot(dq1.GetReal(), dq2.GetReal()) + GfDot(dq1.GetDual(), dq2.GetDual());
}

PXR_NAMESPACE_CLOSE_SCOPE

#endif // PXR_BASE_GF_DUALQUATD_H
