// // Copyright 2016 Pixar // // Licensed under the Apache License, Version 2.0 (the "Apache License") // with the following modification; you may not use this file except in // compliance with the Apache License and the following modification to it: // Section 6. Trademarks. is deleted and replaced with: // // 6. Trademarks. This License does not grant permission to use the trade // names, trademarks, service marks, or product names of the Licensor // and its affiliates, except as required to comply with Section 4(c) of // the License and to reproduce the content of the NOTICE file. // // You may obtain a copy of the Apache License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the Apache License with the above modification is // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the Apache License for the specific // language governing permissions and limitations under the Apache License. // //////////////////////////////////////////////////////////////////////// // This file is generated by a script. Do not edit directly. Edit the // vec.template.h file to make changes. #ifndef PXR_BASE_GF_{{ UPPER(VEC)[2:] }}_H #define PXR_BASE_GF_{{ UPPER(VEC)[2:] }}_H /// \file gf/vec{{ SUFFIX }}.h /// \ingroup group_gf_LinearAlgebra #include "pxr/pxr.h" #include "pxr/base/tf/diagnostic.h" #include "pxr/base/gf/api.h" #include "pxr/base/gf/limits.h" #include "pxr/base/gf/traits.h" {% if IS_FLOATING_POINT(SCL) -%} #include "pxr/base/gf/math.h" {% if SCL == 'GfHalf' -%} #include "pxr/base/gf/half.h" {% endif %} {% endif %} #include #include {% if IS_FLOATING_POINT(SCL) -%} #include {% endif %} #include PXR_NAMESPACE_OPEN_SCOPE class {{ VEC }}; template <> struct GfIsGfVec { static const bool value = true; }; /// \class {{ VEC }} /// \ingroup group_gf_LinearAlgebra /// /// Basic type for a vector of {{ DIM }} {{ SCL }} components. /// /// Represents a vector of {{ DIM }} components of type \c {{ SCL }}. /// It is intended to be fast and simple. /// class {{ VEC }} { public: /// Scalar element type and dimension. typedef {{ SCL }} ScalarType; static const size_t dimension = {{ DIM }}; /// Default constructor does no initialization. {{ VEC }}() = default; /// Initialize all elements to a single value. constexpr explicit {{ VEC }}({{ SCL }} value) : _data{ {{ LIST("value") }} } { } /// Initialize all elements with explicit arguments. constexpr {{ VEC }}({{ LIST(SCL + " s%(i)s") }}) : _data{ {{ LIST("s%(i)s") }} } { } /// Construct with pointer to values. template constexpr explicit {{ VEC }}(Scl const *p) : _data{ {{ LIST("p[%(i)s]") }} } { } {% if IS_FLOATING_POINT(SCL) %} {% for S in SCALARS if S != SCL %} /// {{ "Implicitly convert" if ALLOW_IMPLICIT_CONVERSION(S, SCL) else "Construct" }} from {{ VECNAME(DIM, S) }}. {{ '' if ALLOW_IMPLICIT_CONVERSION(S, SCL) else 'explicit ' }}{{ VEC }}(class {{ VECNAME(DIM, S) }} const &other); {% endfor %} {% endif %} {% for X in 'XYZW'[:DIM] %} /// Create a unit vector along the {{ X }}-axis. static {{ VEC }} {{ X }}Axis() { {{ VEC }} result(0); result[{{ loop.index0 }}] = 1; return result; } {% endfor %} /// Create a unit vector along the i-th axis, zero-based. Return the zero /// vector if \p i is greater than or equal to {{ DIM }}. static {{ VEC }} Axis(size_t i) { {{ VEC }} result(0); if (i < {{ DIM }}) result[i] = 1; return result; } /// Set all elements with passed arguments. {{ VEC }} &Set({{ LIST(SCL + " s%(i)s") }}) { {{ LIST("_data[%(i)s] = s%(i)s;", sep='\n ') }} return *this; } /// Set all elements with a pointer to data. {{ VEC }} &Set({{ SCL }} const *a) { return Set({{ LIST("a[%(i)s]") }}); } /// Direct data access. {{ SCL }} const *data() const { return _data; } {{ SCL }} *data() { return _data; } {{ SCL }} const *GetArray() const { return data(); } /// Indexing. {{ SCL }} const &operator[](size_t i) const { return _data[i]; } {{ SCL }} &operator[](size_t i) { return _data[i]; } /// Hash. friend inline size_t hash_value({{ VEC }} const &vec) { size_t h = 0; {{ LIST("boost::hash_combine(h, vec[%(i)s]);", sep='\n ') }} return h; } /// Equality comparison. bool operator==({{ VEC }} const &other) const { return {{ LIST("_data[%(i)s] == other[%(i)s]", sep=' &&\n ') }}; } bool operator!=({{ VEC }} const &other) const { return !(*this == other); } // TODO Add inequality for other vec types... {% for S in SCALARS if S != SCL -%} /// Equality comparison. GF_API bool operator==(class {{ VECNAME(DIM, S) }} const &other) const; {% endfor %} /// Create a vec with negated elements. {{ VEC }} operator-() const { return {{ VEC }}({{ LIST("-_data[%(i)s]") }}); } /// Addition. {{ VEC }} &operator+=({{ VEC }} const &other) { {{ LIST("_data[%(i)s] += other[%(i)s];", sep='\n ') }} return *this; } friend {{ VEC }} operator+({{ VEC }} const &l, {{ VEC }} const &r) { return {{ VEC }}(l) += r; } /// Subtraction. {{ VEC }} &operator-=({{ VEC }} const &other) { {{ LIST("_data[%(i)s] -= other[%(i)s];", sep='\n ') }} return *this; } friend {{ VEC }} operator-({{ VEC }} const &l, {{ VEC }} const &r) { return {{ VEC }}(l) -= r; } /// Multiplication by scalar. {{ VEC }} &operator*=(double s) { {{ LIST("_data[%(i)s] *= s;", sep='\n ') }} return *this; } {{ VEC }} operator*(double s) const { return {{ VEC }}(*this) *= s; } friend {{ VEC }} operator*(double s, {{ VEC }} const &v) { return v * s; } {% if IS_FLOATING_POINT(SCL) %} /// Division by scalar. // TODO should divide by the scalar type. {{ VEC }} &operator/=(double s) { // TODO This should not multiply by 1/s, it should do the division. // Doing the division is more numerically stable when s is close to // zero. return *this *= (1.0 / s); } {{ VEC }} operator/(double s) const { return *this * (1.0 / s); } {% else %} /// Division by scalar. {{ VEC }} &operator/=({{ SCL }} s) { {{ LIST("_data[%(i)s] /= s;", sep='\n ') }} return *this; } {{ VEC }} operator/({{ SCL }} s) const { return {{ VEC }}(*this) /= s; } {% endif %} /// See GfDot(). {{ SCL }} operator*({{ VEC }} const &v) const { return {{ LIST("_data[%(i)s] * v[%(i)s]", sep=" + ") }}; } /// Returns the projection of \p this onto \p v. That is: /// \code /// v * (*this * v) /// \endcode {{ VEC }} GetProjection({{ VEC }} const &v) const { return v * (*this * v); } /// Returns the orthogonal complement of \p this->GetProjection(b). /// That is: /// \code /// *this - this->GetProjection(b) /// \endcode {{ VEC }} GetComplement({{ VEC }} const &b) const { return *this - this->GetProjection(b); } /// Squared length. {{ SCL }} GetLengthSq() const { return *this * *this; } {% if IS_FLOATING_POINT(SCL) %} /// Length {{ SCL }} GetLength() const { // TODO should use GfSqrt. return sqrt(GetLengthSq()); } /// Normalizes the vector in place to unit length, returning the /// length before normalization. If the length of the vector is /// smaller than \p eps, then the vector is set to vector/\c eps. /// The original length of the vector is returned. See also GfNormalize(). /// /// \todo This was fixed for bug 67777. This is a gcc64 optimizer bug. /// By tickling the code, it no longer tries to write into /// an illegal memory address (in the code section of memory). {{ SCL }} Normalize({{ SCL }} eps = {{ EPS }}) { // TODO this seems suspect... suggest dividing by length so long as // length is not zero. {{ SCL }} length = GetLength(); *this /= (length > eps) ? length : eps; return length; } {{ VEC }} GetNormalized({{ SCL }} eps = {{ EPS }}) const { {{ VEC }} normalized(*this); normalized.Normalize(eps); return normalized; } {% if DIM == 3 %} /// Orthogonalize and optionally normalize a set of basis vectors. This /// uses an iterative method that is very stable even when the vectors are /// far from orthogonal (close to colinear). The number of iterations and /// thus the computation time does increase as the vectors become close to /// colinear, however. Returns a bool specifying whether the solution /// converged after a number of iterations. If it did not converge, the /// returned vectors will be as close as possible to orthogonal within the /// iteration limit. Colinear vectors will be unaltered, and the method /// will return false. GF_API static bool OrthogonalizeBasis( {{ VEC }} *tx, {{ VEC }} *ty, {{ VEC }} *tz, const bool normalize, double eps = GF_MIN_ORTHO_TOLERANCE); /// Sets \c v1 and \c v2 to unit vectors such that v1, v2 and *this are /// mutually orthogonal. If the length L of *this is smaller than \c eps, /// then v1 and v2 will have magnitude L/eps. As a result, the function /// delivers a continuous result as *this shrinks in length. GF_API void BuildOrthonormalFrame({{ VEC }} *v1, {{ VEC }} *v2, {{ SCL }} eps = {{ EPS }}) const; {% endif %} {# DIM == 3 #} {% endif %} {# IS_FLOATING_POINT(SCL) #} private: {{ SCL }} _data[{{ DIM }}]; }; /// Output a {{ VEC }}. /// \ingroup group_gf_DebuggingOutput GF_API std::ostream& operator<<(std::ostream &, {{ VEC }} const &); {% if IS_FLOATING_POINT(SCL) %} PXR_NAMESPACE_CLOSE_SCOPE {% for S in SCALARS if S != SCL %} #include "pxr/base/gf/vec{{ DIM }}{{ SCALAR_SUFFIX(S) }}.h" {% endfor %} PXR_NAMESPACE_OPEN_SCOPE {% for S in SCALARS if S != SCL %} inline {{ VEC }}::{{ VEC }}(class {{ VECNAME(DIM, S) }} const &other) { {{ LIST("_data[%(i)s] = other[%(i)s];", sep='\n ') }} } {% endfor %} {% endif %} /// Returns component-wise multiplication of vectors \p v1 and \p v2. inline {{ VEC }} GfCompMult({{ VEC }} const &v1, {{ VEC }} const &v2) { return {{ VEC }}( {{ LIST("v1[%(i)s] * v2[%(i)s]", sep=",\n ") }} ); } /// Returns component-wise quotient of vectors \p v1 and \p v2. inline {{ VEC }} GfCompDiv({{ VEC }} const &v1, {{ VEC }} const &v2) { return {{ VEC }}( {{ LIST("v1[%(i)s] / v2[%(i)s]", sep=",\n ") }} ); } /// Returns the dot (inner) product of two vectors. inline {{ SCL }} GfDot({{ VEC }} const &v1, {{ VEC }} const &v2) { return v1 * v2; } {% if IS_FLOATING_POINT(SCL) %} /// Returns the geometric length of \c v. inline {{ SCL }} GfGetLength({{ VEC }} const &v) { return v.GetLength(); } /// Normalizes \c *v in place to unit length, returning the length before /// normalization. If the length of \c *v is smaller than \p eps then \c *v is /// set to \c *v/eps. The original length of \c *v is returned. inline {{ SCL }} GfNormalize({{ VEC }} *v, {{ SCL }} eps = {{ EPS }}) { return v->Normalize(eps); } /// Returns a normalized (unit-length) vector with the same direction as \p v. /// If the length of this vector is smaller than \p eps, the vector divided by /// \p eps is returned. inline {{ VEC }} GfGetNormalized({{ VEC }} const &v, {{ SCL }} eps = {{ EPS }}) { return v.GetNormalized(eps); } /// Returns the projection of \p a onto \p b. That is: /// \code /// b * (a * b) /// \endcode inline {{ VEC }} GfGetProjection({{ VEC }} const &a, {{ VEC }} const &b) { return a.GetProjection(b); } /// Returns the orthogonal complement of \p a.GetProjection(b). That is: /// \code /// a - a.GetProjection(b) /// \endcode inline {{ VEC }} GfGetComplement({{ VEC }} const &a, {{ VEC }} const &b) { return a.GetComplement(b); } /// Tests for equality within a given tolerance, returning \c true if the /// length of the difference vector is less than or equal to \p tolerance. inline bool GfIsClose({{ VEC }} const &v1, {{ VEC }} const &v2, double tolerance) { {{ VEC }} delta = v1 - v2; return delta.GetLengthSq() <= tolerance * tolerance; } {% if DIM == 3 %} GF_API bool GfOrthogonalizeBasis({{ VEC }} *tx, {{ VEC }} *ty, {{ VEC }} *tz, bool normalize, double eps = GF_MIN_ORTHO_TOLERANCE); GF_API void GfBuildOrthonormalFrame({{ VEC }} const &v0, {{ VEC }}* v1, {{ VEC }}* v2, {{ SCL }} eps = {{ EPS }}); /// Returns the cross product of \p v1 and \p v2. inline {{ VEC }} GfCross({{ VEC }} const &v1, {{ VEC }} const &v2) { return {{ VEC }}( v1[1] * v2[2] - v1[2] * v2[1], v1[2] * v2[0] - v1[0] * v2[2], v1[0] * v2[1] - v1[1] * v2[0]); } /// Returns the cross product of \p v1 and \p v2. /// \see GfCross() inline {{ VEC }} operator^({{ VEC }} const &v1, {{ VEC }} const &v2) { return GfCross(v1, v2); } /// Spherical linear interpolation in three dimensions. GF_API {{ VEC }} GfSlerp(double alpha, {{ VEC }} const &v0, {{ VEC }} const &v1); {% endif %} {# DIM == 3 #} {% endif %} {# IS_FLOATING_POINT(SCL) #} PXR_NAMESPACE_CLOSE_SCOPE #endif // PXR_BASE_GF_{{ UPPER(VEC)[2:] }}_H