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