1 // 2 // Copyright 2016 Pixar 3 // 4 // Licensed under the Apache License, Version 2.0 (the "Apache License") 5 // with the following modification; you may not use this file except in 6 // compliance with the Apache License and the following modification to it: 7 // Section 6. Trademarks. is deleted and replaced with: 8 // 9 // 6. Trademarks. This License does not grant permission to use the trade 10 // names, trademarks, service marks, or product names of the Licensor 11 // and its affiliates, except as required to comply with Section 4(c) of 12 // the License and to reproduce the content of the NOTICE file. 13 // 14 // You may obtain a copy of the Apache License at 15 // 16 // http://www.apache.org/licenses/LICENSE-2.0 17 // 18 // Unless required by applicable law or agreed to in writing, software 19 // distributed under the Apache License with the above modification is 20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 21 // KIND, either express or implied. See the Apache License for the specific 22 // language governing permissions and limitations under the Apache License. 23 // 24 //////////////////////////////////////////////////////////////////////// 25 // This file is generated by a script. Do not edit directly. Edit the 26 // vec.template.h file to make changes. 27 28 #ifndef PXR_BASE_GF_{{ UPPER(VEC)[2:] }}_H 29 #define PXR_BASE_GF_{{ UPPER(VEC)[2:] }}_H 30 31 /// \file gf/vec{{ SUFFIX }}.h 32 /// \ingroup group_gf_LinearAlgebra 33 34 #include "pxr/pxr.h" 35 #include "pxr/base/tf/diagnostic.h" 36 #include "pxr/base/gf/api.h" 37 #include "pxr/base/gf/limits.h" 38 #include "pxr/base/gf/traits.h" 39 {% if IS_FLOATING_POINT(SCL) -%} 40 #include "pxr/base/gf/math.h" 41 {% if SCL == 'GfHalf' -%} 42 #include "pxr/base/gf/half.h" 43 {% endif %} 44 {% endif %} 45 46 #include <boost/functional/hash.hpp> 47 48 #include <cstddef> 49 {% if IS_FLOATING_POINT(SCL) -%} 50 #include <cmath> 51 {% endif %} 52 53 #include <iosfwd> 54 55 PXR_NAMESPACE_OPEN_SCOPE 56 57 class {{ VEC }}; 58 59 template <> 60 struct GfIsGfVec<class {{ VEC }}> { static const bool value = true; }; 61 62 /// \class {{ VEC }} 63 /// \ingroup group_gf_LinearAlgebra 64 /// 65 /// Basic type for a vector of {{ DIM }} {{ SCL }} components. 66 /// 67 /// Represents a vector of {{ DIM }} components of type \c {{ SCL }}. 68 /// It is intended to be fast and simple. 69 /// 70 class {{ VEC }} 71 { 72 public: 73 /// Scalar element type and dimension. 74 typedef {{ SCL }} ScalarType; 75 static const size_t dimension = {{ DIM }}; 76 77 /// Default constructor does no initialization. 78 {{ VEC }}() = default; 79 80 /// Initialize all elements to a single value. 81 constexpr explicit {{ VEC }}({{ SCL }} value) 82 : _data{ {{ LIST("value") }} } 83 { 84 } 85 86 /// Initialize all elements with explicit arguments. 87 constexpr {{ VEC }}({{ LIST(SCL + " s%(i)s") }}) 88 : _data{ {{ LIST("s%(i)s") }} } 89 { 90 } 91 92 /// Construct with pointer to values. 93 template <class Scl> 94 constexpr explicit {{ VEC }}(Scl const *p) 95 : _data{ {{ LIST("p[%(i)s]") }} } 96 { 97 } 98 {% if IS_FLOATING_POINT(SCL) %} 99 {% for S in SCALARS if S != SCL %} 100 101 /// {{ "Implicitly convert" if ALLOW_IMPLICIT_CONVERSION(S, SCL) else "Construct" }} from {{ VECNAME(DIM, S) }}. 102 {{ '' if ALLOW_IMPLICIT_CONVERSION(S, SCL) else 'explicit ' }}{{ VEC }}(class {{ VECNAME(DIM, S) }} const &other); 103 {% endfor %} 104 {% endif %} 105 106 {% for X in 'XYZW'[:DIM] %} 107 /// Create a unit vector along the {{ X }}-axis. 108 static {{ VEC }} {{ X }}Axis() { 109 {{ VEC }} result(0); 110 result[{{ loop.index0 }}] = 1; 111 return result; 112 } 113 {% endfor %} 114 115 /// Create a unit vector along the i-th axis, zero-based. Return the zero 116 /// vector if \p i is greater than or equal to {{ DIM }}. 117 static {{ VEC }} Axis(size_t i) { 118 {{ VEC }} result(0); 119 if (i < {{ DIM }}) 120 result[i] = 1; 121 return result; 122 } 123 124 /// Set all elements with passed arguments. 125 {{ VEC }} &Set({{ LIST(SCL + " s%(i)s") }}) { 126 {{ LIST("_data[%(i)s] = s%(i)s;", sep='\n ') }} 127 return *this; 128 } 129 130 /// Set all elements with a pointer to data. 131 {{ VEC }} &Set({{ SCL }} const *a) { 132 return Set({{ LIST("a[%(i)s]") }}); 133 } 134 135 /// Direct data access. 136 {{ SCL }} const *data() const { return _data; } 137 {{ SCL }} *data() { return _data; } 138 {{ SCL }} const *GetArray() const { return data(); } 139 140 /// Indexing. 141 {{ SCL }} const &operator[](size_t i) const { return _data[i]; } 142 {{ SCL }} &operator[](size_t i) { return _data[i]; } 143 144 /// Hash. 145 friend inline size_t hash_value({{ VEC }} const &vec) { 146 size_t h = 0; 147 {{ LIST("boost::hash_combine(h, vec[%(i)s]);", sep='\n ') }} 148 return h; 149 } 150 151 /// Equality comparison. 152 bool operator==({{ VEC }} const &other) const { 153 return {{ LIST("_data[%(i)s] == other[%(i)s]", 154 sep=' &&\n ') }}; 155 } 156 bool operator!=({{ VEC }} const &other) const { 157 return !(*this == other); 158 } 159 160 // TODO Add inequality for other vec types... 161 {% for S in SCALARS if S != SCL -%} 162 /// Equality comparison. 163 GF_API 164 bool operator==(class {{ VECNAME(DIM, S) }} const &other) const; 165 {% endfor %} 166 167 /// Create a vec with negated elements. 168 {{ VEC }} operator-() const { 169 return {{ VEC }}({{ LIST("-_data[%(i)s]") }}); 170 } 171 172 /// Addition. 173 {{ VEC }} &operator+=({{ VEC }} const &other) { 174 {{ LIST("_data[%(i)s] += other[%(i)s];", sep='\n ') }} 175 return *this; 176 } 177 friend {{ VEC }} operator+({{ VEC }} const &l, {{ VEC }} const &r) { 178 return {{ VEC }}(l) += r; 179 } 180 181 /// Subtraction. 182 {{ VEC }} &operator-=({{ VEC }} const &other) { 183 {{ LIST("_data[%(i)s] -= other[%(i)s];", sep='\n ') }} 184 return *this; 185 } 186 friend {{ VEC }} operator-({{ VEC }} const &l, {{ VEC }} const &r) { 187 return {{ VEC }}(l) -= r; 188 } 189 190 /// Multiplication by scalar. 191 {{ VEC }} &operator*=(double s) { 192 {{ LIST("_data[%(i)s] *= s;", sep='\n ') }} 193 return *this; 194 } 195 {{ VEC }} operator*(double s) const { 196 return {{ VEC }}(*this) *= s; 197 } 198 friend {{ VEC }} operator*(double s, {{ VEC }} const &v) { 199 return v * s; 200 } 201 202 {% if IS_FLOATING_POINT(SCL) %} 203 /// Division by scalar. 204 // TODO should divide by the scalar type. 205 {{ VEC }} &operator/=(double s) { 206 // TODO This should not multiply by 1/s, it should do the division. 207 // Doing the division is more numerically stable when s is close to 208 // zero. 209 return *this *= (1.0 / s); 210 } 211 {{ VEC }} operator/(double s) const { 212 return *this * (1.0 / s); 213 } 214 {% else %} 215 /// Division by scalar. 216 {{ VEC }} &operator/=({{ SCL }} s) { 217 {{ LIST("_data[%(i)s] /= s;", sep='\n ') }} 218 return *this; 219 } 220 {{ VEC }} operator/({{ SCL }} s) const { 221 return {{ VEC }}(*this) /= s; 222 } 223 {% endif %} 224 225 /// See GfDot(). 226 {{ SCL }} operator*({{ VEC }} const &v) const { 227 return {{ LIST("_data[%(i)s] * v[%(i)s]", sep=" + ") }}; 228 } 229 230 /// Returns the projection of \p this onto \p v. That is: 231 /// \code 232 /// v * (*this * v) 233 /// \endcode 234 {{ VEC }} GetProjection({{ VEC }} const &v) const { 235 return v * (*this * v); 236 } 237 238 /// Returns the orthogonal complement of \p this->GetProjection(b). 239 /// That is: 240 /// \code 241 /// *this - this->GetProjection(b) 242 /// \endcode 243 {{ VEC }} GetComplement({{ VEC }} const &b) const { 244 return *this - this->GetProjection(b); 245 } 246 247 /// Squared length. 248 {{ SCL }} GetLengthSq() const { 249 return *this * *this; 250 } 251 252 {% if IS_FLOATING_POINT(SCL) %} 253 /// Length 254 {{ SCL }} GetLength() const { 255 // TODO should use GfSqrt. 256 return sqrt(GetLengthSq()); 257 } 258 259 /// Normalizes the vector in place to unit length, returning the 260 /// length before normalization. If the length of the vector is 261 /// smaller than \p eps, then the vector is set to vector/\c eps. 262 /// The original length of the vector is returned. See also GfNormalize(). 263 /// 264 /// \todo This was fixed for bug 67777. This is a gcc64 optimizer bug. 265 /// By tickling the code, it no longer tries to write into 266 /// an illegal memory address (in the code section of memory). 267 {{ SCL }} Normalize({{ SCL }} eps = {{ EPS }}) { 268 // TODO this seems suspect... suggest dividing by length so long as 269 // length is not zero. 270 {{ SCL }} length = GetLength(); 271 *this /= (length > eps) ? length : eps; 272 return length; 273 } 274 275 {{ VEC }} GetNormalized({{ SCL }} eps = {{ EPS }}) const { 276 {{ VEC }} normalized(*this); 277 normalized.Normalize(eps); 278 return normalized; 279 } 280 281 {% if DIM == 3 %} 282 /// Orthogonalize and optionally normalize a set of basis vectors. This 283 /// uses an iterative method that is very stable even when the vectors are 284 /// far from orthogonal (close to colinear). The number of iterations and 285 /// thus the computation time does increase as the vectors become close to 286 /// colinear, however. Returns a bool specifying whether the solution 287 /// converged after a number of iterations. If it did not converge, the 288 /// returned vectors will be as close as possible to orthogonal within the 289 /// iteration limit. Colinear vectors will be unaltered, and the method 290 /// will return false. 291 GF_API 292 static bool OrthogonalizeBasis( 293 {{ VEC }} *tx, {{ VEC }} *ty, {{ VEC }} *tz, 294 const bool normalize, 295 double eps = GF_MIN_ORTHO_TOLERANCE); 296 297 /// Sets \c v1 and \c v2 to unit vectors such that v1, v2 and *this are 298 /// mutually orthogonal. If the length L of *this is smaller than \c eps, 299 /// then v1 and v2 will have magnitude L/eps. As a result, the function 300 /// delivers a continuous result as *this shrinks in length. 301 GF_API 302 void BuildOrthonormalFrame({{ VEC }} *v1, {{ VEC }} *v2, 303 {{ SCL }} eps = {{ EPS }}) const; 304 305 {% endif %} {# DIM == 3 #} 306 {% endif %} {# IS_FLOATING_POINT(SCL) #} 307 308 private: 309 {{ SCL }} _data[{{ DIM }}]; 310 }; 311 312 /// Output a {{ VEC }}. 313 /// \ingroup group_gf_DebuggingOutput 314 GF_API std::ostream& operator<<(std::ostream &, {{ VEC }} const &); 315 316 {% if IS_FLOATING_POINT(SCL) %} 317 318 PXR_NAMESPACE_CLOSE_SCOPE 319 320 {% for S in SCALARS if S != SCL %} 321 #include "pxr/base/gf/vec{{ DIM }}{{ SCALAR_SUFFIX(S) }}.h" 322 {% endfor %} 323 324 PXR_NAMESPACE_OPEN_SCOPE 325 326 {% for S in SCALARS if S != SCL %} 327 inline 328 {{ VEC }}::{{ VEC }}(class {{ VECNAME(DIM, S) }} const &other) 329 { 330 {{ LIST("_data[%(i)s] = other[%(i)s];", sep='\n ') }} 331 } 332 {% endfor %} 333 {% endif %} 334 335 /// Returns component-wise multiplication of vectors \p v1 and \p v2. 336 inline {{ VEC }} 337 GfCompMult({{ VEC }} const &v1, {{ VEC }} const &v2) { 338 return {{ VEC }}( 339 {{ LIST("v1[%(i)s] * v2[%(i)s]", sep=",\n ") }} 340 ); 341 } 342 343 /// Returns component-wise quotient of vectors \p v1 and \p v2. 344 inline {{ VEC }} 345 GfCompDiv({{ VEC }} const &v1, {{ VEC }} const &v2) { 346 return {{ VEC }}( 347 {{ LIST("v1[%(i)s] / v2[%(i)s]", sep=",\n ") }} 348 ); 349 } 350 351 /// Returns the dot (inner) product of two vectors. 352 inline {{ SCL }} 353 GfDot({{ VEC }} const &v1, {{ VEC }} const &v2) { 354 return v1 * v2; 355 } 356 357 {% if IS_FLOATING_POINT(SCL) %} 358 359 /// Returns the geometric length of \c v. 360 inline {{ SCL }} 361 GfGetLength({{ VEC }} const &v) 362 { 363 return v.GetLength(); 364 } 365 366 /// Normalizes \c *v in place to unit length, returning the length before 367 /// normalization. If the length of \c *v is smaller than \p eps then \c *v is 368 /// set to \c *v/eps. The original length of \c *v is returned. 369 inline {{ SCL }} 370 GfNormalize({{ VEC }} *v, {{ SCL }} eps = {{ EPS }}) 371 { 372 return v->Normalize(eps); 373 } 374 375 /// Returns a normalized (unit-length) vector with the same direction as \p v. 376 /// If the length of this vector is smaller than \p eps, the vector divided by 377 /// \p eps is returned. 378 inline {{ VEC }} 379 GfGetNormalized({{ VEC }} const &v, {{ SCL }} eps = {{ EPS }}) 380 { 381 return v.GetNormalized(eps); 382 } 383 384 /// Returns the projection of \p a onto \p b. That is: 385 /// \code 386 /// b * (a * b) 387 /// \endcode 388 inline {{ VEC }} 389 GfGetProjection({{ VEC }} const &a, {{ VEC }} const &b) 390 { 391 return a.GetProjection(b); 392 } 393 394 /// Returns the orthogonal complement of \p a.GetProjection(b). That is: 395 /// \code 396 /// a - a.GetProjection(b) 397 /// \endcode 398 inline {{ VEC }} 399 GfGetComplement({{ VEC }} const &a, {{ VEC }} const &b) 400 { 401 return a.GetComplement(b); 402 } 403 404 /// Tests for equality within a given tolerance, returning \c true if the 405 /// length of the difference vector is less than or equal to \p tolerance. 406 inline bool 407 GfIsClose({{ VEC }} const &v1, {{ VEC }} const &v2, double tolerance) 408 { 409 {{ VEC }} delta = v1 - v2; 410 return delta.GetLengthSq() <= tolerance * tolerance; 411 } 412 413 {% if DIM == 3 %} 414 415 GF_API bool 416 GfOrthogonalizeBasis({{ VEC }} *tx, {{ VEC }} *ty, {{ VEC }} *tz, 417 bool normalize, double eps = GF_MIN_ORTHO_TOLERANCE); 418 419 GF_API void 420 GfBuildOrthonormalFrame({{ VEC }} const &v0, 421 {{ VEC }}* v1, 422 {{ VEC }}* v2, 423 {{ SCL }} eps = {{ EPS }}); 424 425 /// Returns the cross product of \p v1 and \p v2. 426 inline {{ VEC }} 427 GfCross({{ VEC }} const &v1, {{ VEC }} const &v2) 428 { 429 return {{ VEC }}( 430 v1[1] * v2[2] - v1[2] * v2[1], 431 v1[2] * v2[0] - v1[0] * v2[2], 432 v1[0] * v2[1] - v1[1] * v2[0]); 433 } 434 435 /// Returns the cross product of \p v1 and \p v2. 436 /// \see GfCross() 437 inline {{ VEC }} 438 operator^({{ VEC }} const &v1, {{ VEC }} const &v2) 439 { 440 return GfCross(v1, v2); 441 } 442 443 /// Spherical linear interpolation in three dimensions. 444 GF_API {{ VEC }} 445 GfSlerp(double alpha, {{ VEC }} const &v0, {{ VEC }} const &v1); 446 447 {% endif %} {# DIM == 3 #} 448 449 {% endif %} {# IS_FLOATING_POINT(SCL) #} 450 451 PXR_NAMESPACE_CLOSE_SCOPE 452 453 #endif // PXR_BASE_GF_{{ UPPER(VEC)[2:] }}_H 454