//
// 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_DUALQUATH_H
#define PXR_BASE_GF_DUALQUATH_H

/// \file gf/dualQuath.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/half.h"

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

#include <iosfwd>

PXR_NAMESPACE_OPEN_SCOPE

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

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


/// \class GfDualQuath
/// \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 GfDualQuath final
{
  public:
    typedef GfHalf ScalarType;

    /// GfDualQuath value-initializes to zero and performs no default
    /// initialization, like float or double.
    GfDualQuath() = default;

    /// 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 GfDualQuath( GfHalf realVal ) : _real( realVal ), _dual( 0 ) {}

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

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

    /// This constructor initializes from a rotation and a translation components.
    GfDualQuath( const GfQuath &rotation, const GfVec3h &translation )
        : _real( rotation ) {
        SetTranslation( translation );
    }

    /// Construct from GfDualQuatd.
    GF_API
    explicit GfDualQuath(const GfDualQuatd &other);
    /// Construct from GfDualQuatf.
    GF_API
    explicit GfDualQuath(const GfDualQuatf &other);

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

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

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

    /// Returns the dual part of the dual quaternion.
    const GfQuath &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 GfDualQuath GetZero() {
        return GfDualQuath(GfQuath::GetZero(), GfQuath::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 GfDualQuath GetIdentity() {
        return GfDualQuath(GfQuath::GetIdentity(), GfQuath::GetZero());
    }

    /// Returns geometric length of this dual quaternion.
    GF_API
    std::pair<GfHalf, GfHalf> 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
    GfDualQuath GetNormalized(GfHalf 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<GfHalf, GfHalf> Normalize(GfHalf eps = GF_MIN_VECTOR_LENGTH);

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

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

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

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

    /// Hash.
    friend inline size_t hash_value(const GfDualQuath &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 GfDualQuath &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 GfDualQuath &dq) const {
        return ! (*this == dq);
    }

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

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

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

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

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

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

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

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

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

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

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

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

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


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


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

PXR_NAMESPACE_CLOSE_SCOPE

#endif // PXR_BASE_GF_DUALQUATH_H
