Imported Upstream version 3.1.9
[platform/upstream/Imath.git] / src / Imath / ImathVec.h
1 //
2 // SPDX-License-Identifier: BSD-3-Clause
3 // Copyright Contributors to the OpenEXR Project.
4 // 
5
6 //
7 // 2D, 3D and 4D point/vector class templates
8 //
9
10 #ifndef INCLUDED_IMATHVEC_H
11 #define INCLUDED_IMATHVEC_H
12
13 #include "ImathExport.h"
14 #include "ImathNamespace.h"
15 #include "ImathTypeTraits.h"
16
17 #include "ImathMath.h"
18
19 #include <iostream>
20 #include <limits>
21 #include <cstdint>
22 #include <stdexcept>
23
24 #if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
25 // suppress exception specification warnings
26 #    pragma warning(push)
27 #    pragma warning(disable : 4290)
28 #endif
29
30 IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
31
32 template <class T> class Vec2;
33 template <class T> class Vec3;
34 template <class T> class Vec4;
35
36 /// Enum for the Vec4 to Vec3 conversion constructor
37 enum IMATH_EXPORT_ENUM InfException
38 {
39     INF_EXCEPTION
40 };
41
42 ///
43 /// 2-element vector
44 ///
45
46 template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Vec2
47 {
48   public:
49
50     /// @{
51     /// @name Direct access to elements
52     
53     T x, y;
54
55     /// @}
56     
57     /// Element access by index.  
58     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T& operator[] (int i) IMATH_NOEXCEPT;
59
60     /// Element access by index.  
61     IMATH_HOSTDEVICE constexpr const T& operator[] (int i) const IMATH_NOEXCEPT;
62
63     /// @{
64     /// @name Constructors and Assignment
65
66     /// Uninitialized by default
67     IMATH_HOSTDEVICE Vec2() IMATH_NOEXCEPT;
68
69     /// Initialize to a scalar `(a,a)`
70     IMATH_HOSTDEVICE constexpr explicit Vec2 (T a) IMATH_NOEXCEPT;
71
72     /// Initialize to given elements `(a,b)`
73     IMATH_HOSTDEVICE constexpr Vec2 (T a, T b) IMATH_NOEXCEPT;
74
75     /// Copy constructor
76     IMATH_HOSTDEVICE constexpr Vec2 (const Vec2& v) IMATH_NOEXCEPT;
77
78     /// Construct from Vec2 of another base type
79     template <class S> IMATH_HOSTDEVICE constexpr Vec2 (const Vec2<S>& v) IMATH_NOEXCEPT;
80
81
82     /// Assignment
83     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec2& operator= (const Vec2& v) IMATH_NOEXCEPT;
84
85     /// Destructor
86     ~Vec2() IMATH_NOEXCEPT = default;
87
88     /// @}
89
90 #if IMATH_FOREIGN_VECTOR_INTEROP
91     /// @{
92     /// @name Interoperability with other vector types
93     ///
94     /// Construction and assignment are allowed from other classes that
95     /// appear to be equivalent vector types, provided that they have either
96     /// a subscripting operator, or data members .x and .y, that are of the
97     /// same type as the elements of this vector, and their size appears to
98     /// be the right number of elements.
99     ///
100     /// This functionality is disabled for gcc 4.x, which seems to have a
101     /// compiler bug that results in spurious errors. It can also be
102     /// disabled by defining IMATH_FOREIGN_VECTOR_INTEROP to be 0 prior to
103     /// including any Imath header files.
104     ///
105
106     template<typename V, IMATH_ENABLE_IF(has_xy<V,T>::value)>
107     IMATH_HOSTDEVICE explicit constexpr Vec2 (const V& v) IMATH_NOEXCEPT
108         : Vec2(T(v.x), T(v.y)) { }
109
110     template<typename V, IMATH_ENABLE_IF(has_subscript<V,T,2>::value
111                                          && !has_xy<V,T>::value)>
112     IMATH_HOSTDEVICE explicit Vec2 (const V& v) : Vec2(T(v[0]), T(v[1])) { }
113
114     template<typename V, IMATH_ENABLE_IF(has_xy<V,T>::value)>
115     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec2& operator= (const V& v) IMATH_NOEXCEPT {
116         x = T(v.x);
117         y = T(v.y);
118         return *this;
119     }
120
121     template<typename V, IMATH_ENABLE_IF(has_subscript<V,T,2>::value
122                                          && !has_xy<V,T>::value)>
123     IMATH_HOSTDEVICE const Vec2& operator= (const V& v) {
124         x = T(v[0]);
125         y = T(v[1]);
126         return *this;
127     }
128 #endif
129
130     /// @{
131     /// @name Compatibility with Sb
132
133     /// Set the value
134     template <class S> IMATH_HOSTDEVICE void setValue (S a, S b) IMATH_NOEXCEPT;
135
136     /// Set the value
137     template <class S> IMATH_HOSTDEVICE void setValue (const Vec2<S>& v) IMATH_NOEXCEPT;
138
139     /// Return the value in `a` and `b`
140     template <class S> IMATH_HOSTDEVICE void getValue (S& a, S& b) const IMATH_NOEXCEPT;
141
142     /// Return the value in `v`
143     template <class S> IMATH_HOSTDEVICE void getValue (Vec2<S>& v) const IMATH_NOEXCEPT;
144
145     /// Return a raw pointer to the array of values
146     IMATH_HOSTDEVICE T* getValue() IMATH_NOEXCEPT;
147
148     /// Return a raw pointer to the array of values
149     IMATH_HOSTDEVICE const T* getValue() const IMATH_NOEXCEPT;
150
151     /// @}
152     
153     /// @{
154     /// @name Arithmetic and Comparison
155     
156     /// Equality
157     template <class S> IMATH_HOSTDEVICE constexpr bool operator== (const Vec2<S>& v) const IMATH_NOEXCEPT;
158
159
160     /// Inequality
161     template <class S> IMATH_HOSTDEVICE constexpr bool operator!= (const Vec2<S>& v) const IMATH_NOEXCEPT;
162
163     /// Compare two matrices and test if they are "approximately equal":
164     /// @return True if the coefficients of this and `m` are the same
165     /// with an absolute error of no more than e, i.e., for all i, j:
166     ///
167     ///     abs (this[i][j] - m[i][j]) <= e
168     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithAbsError (const Vec2<T>& v, T e) const IMATH_NOEXCEPT;
169
170     /// Compare two matrices and test if they are "approximately equal":
171     /// @return True if the coefficients of this and m are the same with
172     /// a relative error of no more than e, i.e., for all i, j:
173     ///
174     ///     abs (this[i] - v[i][j]) <= e * abs (this[i][j])
175     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithRelError (const Vec2<T>& v, T e) const IMATH_NOEXCEPT;
176
177     /// Dot product
178     IMATH_HOSTDEVICE constexpr T dot (const Vec2& v) const IMATH_NOEXCEPT;
179
180     /// Dot product
181     IMATH_HOSTDEVICE constexpr T operator^ (const Vec2& v) const IMATH_NOEXCEPT;
182
183     /// Right-handed cross product, i.e. z component of
184     /// Vec3 (this->x, this->y, 0) % Vec3 (v.x, v.y, 0)
185     IMATH_HOSTDEVICE constexpr T cross (const Vec2& v) const IMATH_NOEXCEPT;
186
187     /// Right-handed cross product, i.e. z component of
188     /// Vec3 (this->x, this->y, 0) % Vec3 (v.x, v.y, 0)
189     IMATH_HOSTDEVICE constexpr T operator% (const Vec2& v) const IMATH_NOEXCEPT;
190
191     /// Component-wise addition
192     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec2& operator+= (const Vec2& v) IMATH_NOEXCEPT;
193
194     /// Component-wise addition
195     IMATH_HOSTDEVICE constexpr Vec2 operator+ (const Vec2& v) const IMATH_NOEXCEPT;
196
197     /// Component-wise subtraction
198     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec2& operator-= (const Vec2& v) IMATH_NOEXCEPT;
199
200     /// Component-wise subtraction
201     IMATH_HOSTDEVICE constexpr Vec2 operator- (const Vec2& v) const IMATH_NOEXCEPT;
202
203     /// Component-wise multiplication by -1
204     IMATH_HOSTDEVICE constexpr Vec2 operator-() const IMATH_NOEXCEPT;
205
206     /// Component-wise multiplication by -1
207     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec2& negate() IMATH_NOEXCEPT;
208
209     /// Component-wise multiplication
210     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec2& operator*= (const Vec2& v) IMATH_NOEXCEPT;
211
212     /// Component-wise multiplication
213     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec2& operator*= (T a) IMATH_NOEXCEPT;
214
215     /// Component-wise multiplication
216     IMATH_HOSTDEVICE constexpr Vec2 operator* (const Vec2& v) const IMATH_NOEXCEPT;
217
218     /// Component-wise multiplication
219     IMATH_HOSTDEVICE constexpr Vec2 operator* (T a) const IMATH_NOEXCEPT;
220
221     /// Component-wise division
222     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec2& operator/= (const Vec2& v) IMATH_NOEXCEPT;
223
224     /// Component-wise division
225     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec2& operator/= (T a) IMATH_NOEXCEPT;
226
227     /// Component-wise division
228     IMATH_HOSTDEVICE constexpr Vec2 operator/ (const Vec2& v) const IMATH_NOEXCEPT;
229
230     /// Component-wise division
231     IMATH_HOSTDEVICE constexpr Vec2 operator/ (T a) const IMATH_NOEXCEPT;
232
233     /// @}
234
235     /// @{
236     /// @name Query and Manipulation
237
238     /// Return the Euclidean norm
239     IMATH_HOSTDEVICE T length() const IMATH_NOEXCEPT;
240
241     /// Return the square of the Euclidean norm, i.e. the dot product
242     /// with itself.
243     IMATH_HOSTDEVICE constexpr T length2() const IMATH_NOEXCEPT;
244
245     /// Normalize in place. If length()==0, return a null vector.
246     IMATH_HOSTDEVICE const Vec2& normalize() IMATH_NOEXCEPT;
247
248     /// Normalize in place. If length()==0, throw an exception.
249     const Vec2& normalizeExc();
250     
251     /// Normalize without any checks for length()==0. Slightly faster
252     /// than the other normalization routines, but if v.length() is
253     /// 0.0, the result is undefined.
254     IMATH_HOSTDEVICE const Vec2& normalizeNonNull() IMATH_NOEXCEPT;
255
256     /// Return a normalized vector. Does not modify *this.
257     IMATH_HOSTDEVICE Vec2<T> normalized() const IMATH_NOEXCEPT; 
258
259     /// Return a normalized vector. Does not modify *this. Throw an
260     /// exception if length()==0.
261     Vec2<T> normalizedExc() const;
262
263     /// Return a normalized vector. Does not modify *this, and does
264     /// not check for length()==0. Slightly faster than the other
265     /// normalization routines, but if v.length() is 0.0, the result
266     /// is undefined.
267     IMATH_HOSTDEVICE Vec2<T> normalizedNonNull() const IMATH_NOEXCEPT;
268
269     /// @}
270
271     /// @{
272     /// @name Numeric Limits
273     
274     /// Largest possible negative value
275     IMATH_HOSTDEVICE constexpr static T baseTypeLowest() IMATH_NOEXCEPT { return std::numeric_limits<T>::lowest(); }
276
277     /// Largest possible positive value
278     IMATH_HOSTDEVICE constexpr static T baseTypeMax() IMATH_NOEXCEPT { return std::numeric_limits<T>::max(); }
279
280     /// Smallest possible positive value
281     IMATH_HOSTDEVICE constexpr static T baseTypeSmallest() IMATH_NOEXCEPT { return std::numeric_limits<T>::min(); }
282
283     /// Smallest possible e for which 1+e != 1
284     IMATH_HOSTDEVICE constexpr static T baseTypeEpsilon() IMATH_NOEXCEPT { return std::numeric_limits<T>::epsilon(); }
285
286     /// @}
287     
288     /// Return the number of dimensions, i.e. 2
289     IMATH_HOSTDEVICE constexpr static unsigned int dimensions() IMATH_NOEXCEPT { return 2; }
290
291     /// The base type: In templates that accept a parameter `V`, you
292     /// can refer to `T` as `V::BaseType`
293     typedef T BaseType;
294
295   private:
296
297     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T lengthTiny() const IMATH_NOEXCEPT;
298 };
299
300 ///
301 /// 3-element vector
302 ///
303
304 template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Vec3
305 {
306   public:
307
308     /// @{
309     /// @name Direct access to elements
310
311     T x, y, z;
312
313     /// @}
314     
315     /// Element access by index.  
316     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T& operator[] (int i) IMATH_NOEXCEPT;
317
318     /// Element access by index.  
319     IMATH_HOSTDEVICE constexpr const T& operator[] (int i) const IMATH_NOEXCEPT;
320
321     /// @{
322     /// @name Constructors and Assignment
323
324     /// Uninitialized by default
325     IMATH_HOSTDEVICE Vec3() IMATH_NOEXCEPT;
326     
327     /// Initialize to a scalar `(a,a,a)`
328     IMATH_HOSTDEVICE constexpr explicit Vec3 (T a) IMATH_NOEXCEPT;
329
330     /// Initialize to given elements `(a,b,c)`
331     IMATH_HOSTDEVICE constexpr Vec3 (T a, T b, T c) IMATH_NOEXCEPT;
332
333     /// Copy constructor
334     IMATH_HOSTDEVICE constexpr Vec3 (const Vec3& v) IMATH_NOEXCEPT;
335
336     /// Construct from Vec3 of another base type
337     template <class S> IMATH_HOSTDEVICE constexpr Vec3 (const Vec3<S>& v) IMATH_NOEXCEPT;
338
339     /// Vec4 to Vec3 conversion: divide x, y and z by w, even if w is
340     /// 0.  The result depends on how the environment handles
341     /// floating-point exceptions.
342     template <class S> IMATH_HOSTDEVICE explicit constexpr Vec3 (const Vec4<S>& v) IMATH_NOEXCEPT;
343
344     /// Vec4 to Vec3 conversion: divide x, y and z by w.  Throws an
345     /// exception if w is zero or if division by w would overflow.
346     template <class S>
347     explicit IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Vec3 (const Vec4<S>& v, InfException);
348
349     /// Assignment
350     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec3& operator= (const Vec3& v) IMATH_NOEXCEPT;
351
352     /// Destructor
353     ~Vec3() IMATH_NOEXCEPT = default;
354
355     /// @}
356
357 #if IMATH_FOREIGN_VECTOR_INTEROP
358     /// @{
359     /// @name Interoperability with other vector types
360     ///
361     /// Construction and assignment are allowed from other classes that
362     /// appear to be equivalent vector types, provided that they have either
363     /// a subscripting operator, or data members .x, .y, .z, that are of the
364     /// same type as the elements of this vector, and their size appears to
365     /// be the right number of elements.
366     ///
367     /// This functionality is disabled for gcc 4.x, which seems to have a
368     /// compiler bug that results in spurious errors. It can also be
369     /// disabled by defining IMATH_FOREIGN_VECTOR_INTEROP to be 0 prior to
370     /// including any Imath header files.
371     ///
372
373     template<typename V, IMATH_ENABLE_IF(has_xyz<V,T>::value)>
374     IMATH_HOSTDEVICE explicit constexpr Vec3 (const V& v) IMATH_NOEXCEPT
375         : Vec3(T(v.x), T(v.y), T(v.z)) { }
376
377     template<typename V, IMATH_ENABLE_IF(has_subscript<V,T,3>::value
378                                          && !has_xyz<V,T>::value)>
379     IMATH_HOSTDEVICE explicit Vec3 (const V& v) : Vec3(T(v[0]), T(v[1]), T(v[2])) { }
380
381     /// Interoperability assignment from another type that behaves as if it
382     /// were an equivalent vector.
383     template<typename V, IMATH_ENABLE_IF(has_xyz<V,T>::value)>
384     IMATH_HOSTDEVICE const Vec3& operator= (const V& v) IMATH_NOEXCEPT {
385         x = T(v.x);
386         y = T(v.y);
387         z = T(v.z);
388         return *this;
389     }
390
391     template<typename V, IMATH_ENABLE_IF(has_subscript<V,T,3>::value
392                                          && !has_xyz<V,T>::value)>
393     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec3& operator= (const V& v) {
394         x = T(v[0]);
395         y = T(v[1]);
396         z = T(v[2]);
397         return *this;
398     }
399     /// @}
400 #endif
401
402     /// @{
403     /// @name Compatibility with Sb
404
405     /// Set the value
406     template <class S> IMATH_HOSTDEVICE void setValue (S a, S b, S c) IMATH_NOEXCEPT;
407
408     /// Set the value
409     template <class S> IMATH_HOSTDEVICE void setValue (const Vec3<S>& v) IMATH_NOEXCEPT;
410
411     /// Return the value in `a`, `b`, and `c`
412     template <class S> IMATH_HOSTDEVICE void getValue (S& a, S& b, S& c) const IMATH_NOEXCEPT;
413
414     /// Return the value in `v`
415     template <class S> IMATH_HOSTDEVICE void getValue (Vec3<S>& v) const IMATH_NOEXCEPT;
416
417     /// Return a raw pointer to the array of values
418     IMATH_HOSTDEVICE T* getValue() IMATH_NOEXCEPT;
419
420     /// Return a raw pointer to the array of values
421     IMATH_HOSTDEVICE const T* getValue() const IMATH_NOEXCEPT;
422
423     /// @}
424
425     /// @{
426     /// @name Arithmetic and Comparison
427     
428     /// Equality
429     template <class S> IMATH_HOSTDEVICE constexpr bool operator== (const Vec3<S>& v) const IMATH_NOEXCEPT;
430
431     /// Inequality
432     template <class S> IMATH_HOSTDEVICE constexpr bool operator!= (const Vec3<S>& v) const IMATH_NOEXCEPT;
433
434     /// Compare two matrices and test if they are "approximately equal":
435     /// @return True if the coefficients of this and `m` are the same
436     /// with an absolute error of no more than e, i.e., for all i, j:
437     ///
438     ///     abs (this[i][j] - m[i][j]) <= e
439     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithAbsError (const Vec3<T>& v, T e) const IMATH_NOEXCEPT;
440
441     /// Compare two matrices and test if they are "approximately equal":
442     /// @return True if the coefficients of this and m are the same with
443     /// a relative error of no more than e, i.e., for all i, j:
444     ///
445     ///     abs (this[i] - v[i][j]) <= e * abs (this[i][j])
446     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithRelError (const Vec3<T>& v, T e) const IMATH_NOEXCEPT;
447
448     /// Dot product
449     IMATH_HOSTDEVICE constexpr T dot (const Vec3& v) const IMATH_NOEXCEPT;
450
451     /// Dot product
452     IMATH_HOSTDEVICE constexpr T operator^ (const Vec3& v) const IMATH_NOEXCEPT;
453
454     /// Right-handed cross product
455     IMATH_HOSTDEVICE constexpr Vec3 cross (const Vec3& v) const IMATH_NOEXCEPT;
456
457     /// Right-handed cross product
458     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec3& operator%= (const Vec3& v) IMATH_NOEXCEPT;
459
460     /// Right-handed cross product
461     IMATH_HOSTDEVICE constexpr Vec3 operator% (const Vec3& v) const IMATH_NOEXCEPT;
462
463     /// Component-wise addition
464     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec3& operator+= (const Vec3& v) IMATH_NOEXCEPT;
465
466     /// Component-wise addition
467     IMATH_HOSTDEVICE constexpr Vec3 operator+ (const Vec3& v) const IMATH_NOEXCEPT;
468
469     /// Component-wise subtraction
470     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec3& operator-= (const Vec3& v) IMATH_NOEXCEPT;
471
472     /// Component-wise subtraction
473     IMATH_HOSTDEVICE constexpr Vec3 operator- (const Vec3& v) const IMATH_NOEXCEPT;
474
475     /// Component-wise multiplication by -1
476     IMATH_HOSTDEVICE constexpr Vec3 operator-() const IMATH_NOEXCEPT;
477
478     /// Component-wise multiplication by -1
479     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec3& negate() IMATH_NOEXCEPT;
480
481     /// Component-wise multiplication
482     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec3& operator*= (const Vec3& v) IMATH_NOEXCEPT;
483
484     /// Component-wise multiplication
485     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec3& operator*= (T a) IMATH_NOEXCEPT;
486
487     /// Component-wise multiplication
488     IMATH_HOSTDEVICE constexpr Vec3 operator* (const Vec3& v) const IMATH_NOEXCEPT;
489
490     /// Component-wise multiplication
491     IMATH_HOSTDEVICE constexpr Vec3 operator* (T a) const IMATH_NOEXCEPT;
492
493     /// Component-wise division
494     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec3& operator/= (const Vec3& v) IMATH_NOEXCEPT;
495
496     /// Component-wise division
497     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec3& operator/= (T a) IMATH_NOEXCEPT;
498
499     /// Component-wise division
500     IMATH_HOSTDEVICE constexpr Vec3 operator/ (const Vec3& v) const IMATH_NOEXCEPT;
501
502     /// Component-wise division
503     IMATH_HOSTDEVICE constexpr Vec3 operator/ (T a) const IMATH_NOEXCEPT;
504
505     /// @}
506
507     /// @{
508     /// @name Query and Manipulation
509
510     /// Return the Euclidean norm
511     IMATH_HOSTDEVICE T length() const IMATH_NOEXCEPT;
512
513     /// Return the square of the Euclidean norm, i.e. the dot product
514     /// with itself.
515     IMATH_HOSTDEVICE constexpr T length2() const IMATH_NOEXCEPT;
516
517     /// Normalize in place. If length()==0, return a null vector.
518     IMATH_HOSTDEVICE const Vec3& normalize() IMATH_NOEXCEPT;
519
520     /// Normalize in place. If length()==0, throw an exception.
521     const Vec3& normalizeExc();
522
523     /// Normalize without any checks for length()==0. Slightly faster
524     /// than the other normalization routines, but if v.length() is
525     /// 0.0, the result is undefined.
526     IMATH_HOSTDEVICE const Vec3& normalizeNonNull() IMATH_NOEXCEPT;
527
528     /// Return a normalized vector. Does not modify *this.
529     IMATH_HOSTDEVICE Vec3<T> normalized() const IMATH_NOEXCEPT; // does not modify *this
530
531     /// Return a normalized vector. Does not modify *this. Throw an
532     /// exception if length()==0.
533     Vec3<T> normalizedExc() const;
534
535     /// Return a normalized vector. Does not modify *this, and does
536     /// not check for length()==0. Slightly faster than the other
537     /// normalization routines, but if v.length() is 0.0, the result
538     /// is undefined.
539     IMATH_HOSTDEVICE Vec3<T> normalizedNonNull() const IMATH_NOEXCEPT;
540
541     /// @}
542
543     /// @{
544     /// @name Numeric Limits
545
546     /// Largest possible negative value
547     IMATH_HOSTDEVICE constexpr static T baseTypeLowest() IMATH_NOEXCEPT { return std::numeric_limits<T>::lowest(); }
548
549     /// Largest possible positive value
550     IMATH_HOSTDEVICE constexpr static T baseTypeMax() IMATH_NOEXCEPT { return std::numeric_limits<T>::max(); }
551
552     /// Smallest possible positive value
553     IMATH_HOSTDEVICE constexpr static T baseTypeSmallest() IMATH_NOEXCEPT { return std::numeric_limits<T>::min(); }
554
555     /// Smallest possible e for which 1+e != 1
556     IMATH_HOSTDEVICE constexpr static T baseTypeEpsilon() IMATH_NOEXCEPT { return std::numeric_limits<T>::epsilon(); }
557
558     /// @}
559     
560     /// Return the number of dimensions, i.e. 3
561     IMATH_HOSTDEVICE constexpr static unsigned int dimensions() IMATH_NOEXCEPT { return 3; }
562
563     /// The base type: In templates that accept a parameter `V`, you
564     /// can refer to `T` as `V::BaseType`
565     typedef T BaseType;
566
567   private:
568     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T lengthTiny() const IMATH_NOEXCEPT;
569 };
570
571 ///
572 /// 4-element vector
573 ///
574
575 template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Vec4
576 {
577   public:
578
579     /// @{
580     /// @name Direct access to elements
581
582     T x, y, z, w;
583
584     /// @}
585     
586     /// Element access by index.  
587     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T& operator[] (int i) IMATH_NOEXCEPT;
588
589     /// Element access by index.  
590     IMATH_HOSTDEVICE constexpr const T& operator[] (int i) const IMATH_NOEXCEPT;
591
592     /// @{
593     /// @name Constructors and Assignment
594
595     /// Uninitialized by default
596     IMATH_HOSTDEVICE Vec4() IMATH_NOEXCEPT;                            // no initialization
597
598     /// Initialize to a scalar `(a,a,a,a)`
599     IMATH_HOSTDEVICE constexpr explicit Vec4 (T a) IMATH_NOEXCEPT;
600
601     /// Initialize to given elements `(a,b,c,d)`
602     IMATH_HOSTDEVICE constexpr Vec4 (T a, T b, T c, T d) IMATH_NOEXCEPT;
603
604     /// Copy constructor
605     IMATH_HOSTDEVICE constexpr Vec4 (const Vec4& v) IMATH_NOEXCEPT;
606
607     /// Construct from Vec4 of another base type
608     template <class S> IMATH_HOSTDEVICE constexpr Vec4 (const Vec4<S>& v) IMATH_NOEXCEPT;
609
610     /// Vec3 to Vec4 conversion, sets w to 1.
611     template <class S> IMATH_HOSTDEVICE explicit constexpr Vec4 (const Vec3<S>& v) IMATH_NOEXCEPT;
612
613     /// Assignment
614     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec4& operator= (const Vec4& v) IMATH_NOEXCEPT;
615
616     /// Destructor
617     ~Vec4() IMATH_NOEXCEPT = default;
618
619     /// @}
620
621 #if IMATH_FOREIGN_VECTOR_INTEROP
622     /// @{
623     /// @name Interoperability with other vector types
624     ///
625     /// Construction and assignment are allowed from other classes that
626     /// appear to be equivalent vector types, provided that they have either
627     /// a subscripting operator, or data members .x, .y, .z, .w that are of
628     /// the same type as the elements of this vector, and their size appears
629     /// to be the right number of elements.
630     ///
631     /// This functionality is disabled for gcc 4.x, which seems to have a
632     /// compiler bug that results in spurious errors. It can also be
633     /// disabled by defining IMATH_FOREIGN_VECTOR_INTEROP to be 0 prior to
634     /// including any Imath header files.
635     ///
636
637     template<typename V, IMATH_ENABLE_IF(has_xyzw<V,T>::value)>
638     IMATH_HOSTDEVICE explicit constexpr Vec4 (const V& v) IMATH_NOEXCEPT
639         : Vec4(T(v.x), T(v.y), T(v.z), T(v.w)) { }
640
641     template<typename V, IMATH_ENABLE_IF(has_subscript<V,T,4>::value
642                                          && !has_xyzw<V,T>::value)>
643     IMATH_HOSTDEVICE explicit Vec4 (const V& v) : Vec4(T(v[0]), T(v[1]), T(v[2]), T(v[3])) { }
644
645     template<typename V, IMATH_ENABLE_IF(has_xyzw<V,T>::value)>
646     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec4& operator= (const V& v) IMATH_NOEXCEPT {
647         x = T(v.x);
648         y = T(v.y);
649         z = T(v.z);
650         w = T(v.w);
651         return *this;
652     }
653
654     template<typename V, IMATH_ENABLE_IF(has_subscript<V,T,4>::value
655                                          && !has_xyzw<V,T>::value)>
656     IMATH_HOSTDEVICE const Vec4& operator= (const V& v) {
657         x = T(v[0]);
658         y = T(v[1]);
659         z = T(v[2]);
660         w = T(v[3]);
661         return *this;
662     }
663     /// @}
664 #endif
665
666     /// @{
667     /// @name Arithmetic and Comparison
668     
669     /// Equality
670     template <class S> IMATH_HOSTDEVICE constexpr bool operator== (const Vec4<S>& v) const IMATH_NOEXCEPT;
671
672     /// Inequality
673     template <class S> IMATH_HOSTDEVICE constexpr bool operator!= (const Vec4<S>& v) const IMATH_NOEXCEPT;
674
675     /// Compare two matrices and test if they are "approximately equal":
676     /// @return True if the coefficients of this and `m` are the same
677     /// with an absolute error of no more than e, i.e., for all i, j:
678     ///
679     ///     abs (this[i][j] - m[i][j]) <= e
680     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithAbsError (const Vec4<T>& v, T e) const IMATH_NOEXCEPT;
681
682     /// Compare two matrices and test if they are "approximately equal":
683     /// @return True if the coefficients of this and m are the same with
684     /// a relative error of no more than e, i.e., for all i, j:
685     ///
686     ///     abs (this[i] - v[i][j]) <= e * abs (this[i][j])
687     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithRelError (const Vec4<T>& v, T e) const IMATH_NOEXCEPT;
688
689     /// Dot product
690     IMATH_HOSTDEVICE constexpr T dot (const Vec4& v) const IMATH_NOEXCEPT;
691
692     /// Dot product
693     IMATH_HOSTDEVICE constexpr T operator^ (const Vec4& v) const IMATH_NOEXCEPT;
694
695     /// Component-wise addition
696     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec4& operator+= (const Vec4& v) IMATH_NOEXCEPT;
697
698     /// Component-wise addition
699     IMATH_HOSTDEVICE constexpr Vec4 operator+ (const Vec4& v) const IMATH_NOEXCEPT;
700
701     /// Component-wise subtraction
702     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec4& operator-= (const Vec4& v) IMATH_NOEXCEPT;
703
704     /// Component-wise subtraction
705     IMATH_HOSTDEVICE constexpr Vec4 operator- (const Vec4& v) const IMATH_NOEXCEPT;
706
707     /// Component-wise multiplication by -1
708     IMATH_HOSTDEVICE constexpr Vec4 operator-() const IMATH_NOEXCEPT;
709
710     /// Component-wise multiplication by -1
711     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec4& negate() IMATH_NOEXCEPT;
712
713     /// Component-wise multiplication
714     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec4& operator*= (const Vec4& v) IMATH_NOEXCEPT;
715
716     /// Component-wise multiplication
717     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec4& operator*= (T a) IMATH_NOEXCEPT;
718
719     /// Component-wise multiplication
720     IMATH_HOSTDEVICE constexpr Vec4 operator* (const Vec4& v) const IMATH_NOEXCEPT;
721
722     /// Component-wise multiplication
723     IMATH_HOSTDEVICE constexpr Vec4 operator* (T a) const IMATH_NOEXCEPT;
724
725     /// Component-wise division
726     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec4& operator/= (const Vec4& v) IMATH_NOEXCEPT;
727
728     /// Component-wise division
729     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Vec4& operator/= (T a) IMATH_NOEXCEPT;
730
731     /// Component-wise division
732     IMATH_HOSTDEVICE constexpr Vec4 operator/ (const Vec4& v) const IMATH_NOEXCEPT;
733
734     /// Component-wise division
735     IMATH_HOSTDEVICE constexpr Vec4 operator/ (T a) const IMATH_NOEXCEPT;
736
737     /// @}
738
739     /// @{
740     /// @name Query and Manipulation
741
742     /// Return the Euclidean norm
743     IMATH_HOSTDEVICE T length() const IMATH_NOEXCEPT;
744
745     /// Return the square of the Euclidean norm, i.e. the dot product
746     /// with itself.
747     IMATH_HOSTDEVICE constexpr T length2() const IMATH_NOEXCEPT;
748
749     /// Normalize in place. If length()==0, return a null vector.
750     IMATH_HOSTDEVICE const Vec4& normalize() IMATH_NOEXCEPT; // modifies *this
751
752     /// Normalize in place. If length()==0, throw an exception.
753     const Vec4& normalizeExc();
754
755     /// Normalize without any checks for length()==0. Slightly faster
756     /// than the other normalization routines, but if v.length() is
757     /// 0.0, the result is undefined.
758     IMATH_HOSTDEVICE const Vec4& normalizeNonNull() IMATH_NOEXCEPT;
759
760     /// Return a normalized vector. Does not modify *this.
761     IMATH_HOSTDEVICE Vec4<T> normalized() const IMATH_NOEXCEPT; // does not modify *this
762
763     /// Return a normalized vector. Does not modify *this. Throw an
764     /// exception if length()==0.
765     Vec4<T> normalizedExc() const;
766
767     /// Return a normalized vector. Does not modify *this, and does
768     /// not check for length()==0. Slightly faster than the other
769     /// normalization routines, but if v.length() is 0.0, the result
770     /// is undefined.
771     IMATH_HOSTDEVICE Vec4<T> normalizedNonNull() const IMATH_NOEXCEPT;
772
773     /// @}
774     
775     /// @{
776     /// @name Numeric Limits
777     
778     /// Largest possible negative value
779     IMATH_HOSTDEVICE constexpr static T baseTypeLowest() IMATH_NOEXCEPT { return std::numeric_limits<T>::lowest(); }
780
781     /// Largest possible positive value
782     IMATH_HOSTDEVICE constexpr static T baseTypeMax() IMATH_NOEXCEPT { return std::numeric_limits<T>::max(); }
783
784     /// Smallest possible positive value
785     IMATH_HOSTDEVICE constexpr static T baseTypeSmallest() IMATH_NOEXCEPT { return std::numeric_limits<T>::min(); }
786
787     /// Smallest possible e for which 1+e != 1
788     IMATH_HOSTDEVICE constexpr static T baseTypeEpsilon() IMATH_NOEXCEPT { return std::numeric_limits<T>::epsilon(); }
789
790     /// @}
791     
792     /// Return the number of dimensions, i.e. 4
793     IMATH_HOSTDEVICE constexpr static unsigned int dimensions() IMATH_NOEXCEPT { return 4; }
794
795     /// The base type: In templates that accept a parameter `V`, you
796     /// can refer to `T` as `V::BaseType`
797     typedef T BaseType;
798
799   private:
800     IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T lengthTiny() const IMATH_NOEXCEPT;
801 };
802
803 /// Stream output, as "(x y)"
804 template <class T> std::ostream& operator<< (std::ostream& s, const Vec2<T>& v);
805
806 /// Stream output, as "(x y z)"
807 template <class T> std::ostream& operator<< (std::ostream& s, const Vec3<T>& v);
808
809 /// Stream output, as "(x y z w)"
810 template <class T> std::ostream& operator<< (std::ostream& s, const Vec4<T>& v);
811
812 /// Reverse multiplication: S * Vec2<T>
813 template <class T> IMATH_HOSTDEVICE constexpr Vec2<T> operator* (T a, const Vec2<T>& v) IMATH_NOEXCEPT;
814
815 /// Reverse multiplication: S * Vec3<T>
816 template <class T> IMATH_HOSTDEVICE constexpr Vec3<T> operator* (T a, const Vec3<T>& v) IMATH_NOEXCEPT;
817
818 /// Reverse multiplication: S * Vec4<T>
819 template <class T> IMATH_HOSTDEVICE constexpr Vec4<T> operator* (T a, const Vec4<T>& v) IMATH_NOEXCEPT;
820
821 //-------------------------
822 // Typedefs for convenience
823 //-------------------------
824
825 /// Vec2 of short
826 typedef Vec2<short> V2s;
827
828 /// Vec2 of integer
829 typedef Vec2<int> V2i;
830
831 /// Vec2 of int64_t
832 typedef Vec2<int64_t> V2i64;
833
834 /// Vec2 of float
835 typedef Vec2<float> V2f;
836
837 /// Vec2 of double
838 typedef Vec2<double> V2d;
839
840 /// Vec3 of short
841 typedef Vec3<short> V3s;
842
843 /// Vec3 of integer
844 typedef Vec3<int> V3i;
845
846 /// Vec3 of int64_t
847 typedef Vec3<int64_t> V3i64;
848
849 /// Vec3 of float
850 typedef Vec3<float> V3f;
851
852 /// Vec3 of double
853 typedef Vec3<double> V3d;
854
855 /// Vec4 of short
856 typedef Vec4<short> V4s;
857
858 /// Vec4 of integer
859 typedef Vec4<int> V4i;
860
861 /// Vec4 of int64_t
862 typedef Vec4<int64_t> V4i64;
863
864 /// Vec4 of float
865 typedef Vec4<float> V4f;
866
867 /// Vec4 of double
868 typedef Vec4<double> V4d;
869
870 //----------------------------------------------------------------------------
871 // Specializations for VecN<short>, VecN<int>
872 //
873 // Normalize and length don't make sense for integer vectors, so disable them.
874 //----------------------------------------------------------------------------
875
876 /// @cond Doxygen_Suppress
877
878 // Vec2<short>
879 template <> IMATH_HOSTDEVICE short Vec2<short>::length() const IMATH_NOEXCEPT = delete;
880 template <> IMATH_HOSTDEVICE const Vec2<short>& Vec2<short>::normalize() IMATH_NOEXCEPT = delete;
881 template <> const Vec2<short>& Vec2<short>::normalizeExc() = delete;
882 template <> IMATH_HOSTDEVICE const Vec2<short>& Vec2<short>::normalizeNonNull() IMATH_NOEXCEPT = delete;
883 template <> IMATH_HOSTDEVICE Vec2<short> Vec2<short>::normalized() const IMATH_NOEXCEPT = delete;
884 template <> Vec2<short> Vec2<short>::normalizedExc() const = delete;
885 template <> IMATH_HOSTDEVICE Vec2<short> Vec2<short>::normalizedNonNull() const IMATH_NOEXCEPT = delete;
886
887 // Vec2<int>
888 template <> IMATH_HOSTDEVICE int Vec2<int>::length() const IMATH_NOEXCEPT = delete;
889 template <> IMATH_HOSTDEVICE const Vec2<int>& Vec2<int>::normalize() IMATH_NOEXCEPT = delete;
890 template <> const Vec2<int>& Vec2<int>::normalizeExc() = delete;
891 template <> IMATH_HOSTDEVICE const Vec2<int>& Vec2<int>::normalizeNonNull() IMATH_NOEXCEPT = delete;
892 template <> IMATH_HOSTDEVICE Vec2<int> Vec2<int>::normalized() const IMATH_NOEXCEPT = delete;
893 template <> Vec2<int> Vec2<int>::normalizedExc() const = delete;
894 template <> IMATH_HOSTDEVICE Vec2<int> Vec2<int>::normalizedNonNull() const IMATH_NOEXCEPT = delete;
895
896 // Vec2<int64_t>
897 template <> IMATH_HOSTDEVICE int64_t Vec2<int64_t>::length() const IMATH_NOEXCEPT = delete;
898 template <> IMATH_HOSTDEVICE const Vec2<int64_t>& Vec2<int64_t>::normalize() IMATH_NOEXCEPT = delete;
899 template <> const Vec2<int64_t>& Vec2<int64_t>::normalizeExc() = delete;
900 template <> IMATH_HOSTDEVICE const Vec2<int64_t>& Vec2<int64_t>::normalizeNonNull() IMATH_NOEXCEPT = delete;
901 template <> IMATH_HOSTDEVICE Vec2<int64_t> Vec2<int64_t>::normalized() const IMATH_NOEXCEPT = delete;
902 template <> Vec2<int64_t> Vec2<int64_t>::normalizedExc() const = delete;
903 template <> IMATH_HOSTDEVICE Vec2<int64_t> Vec2<int64_t>::normalizedNonNull() const IMATH_NOEXCEPT = delete;
904
905 // Vec3<short>
906 template <> IMATH_HOSTDEVICE short Vec3<short>::length() const IMATH_NOEXCEPT = delete;
907 template <> IMATH_HOSTDEVICE const Vec3<short>& Vec3<short>::normalize() IMATH_NOEXCEPT = delete;
908 template <> const Vec3<short>& Vec3<short>::normalizeExc() = delete;
909 template <> IMATH_HOSTDEVICE const Vec3<short>& Vec3<short>::normalizeNonNull() IMATH_NOEXCEPT = delete;
910 template <> IMATH_HOSTDEVICE Vec3<short> Vec3<short>::normalized() const IMATH_NOEXCEPT = delete;
911 template <> Vec3<short> Vec3<short>::normalizedExc() const = delete;
912 template <> IMATH_HOSTDEVICE Vec3<short> Vec3<short>::normalizedNonNull() const IMATH_NOEXCEPT = delete;
913
914 // Vec3<int>
915 template <> IMATH_HOSTDEVICE int Vec3<int>::length() const IMATH_NOEXCEPT = delete;
916 template <> IMATH_HOSTDEVICE const Vec3<int>& Vec3<int>::normalize() IMATH_NOEXCEPT = delete;
917 template <> const Vec3<int>& Vec3<int>::normalizeExc() = delete;
918 template <> IMATH_HOSTDEVICE const Vec3<int>& Vec3<int>::normalizeNonNull() IMATH_NOEXCEPT = delete;
919 template <> IMATH_HOSTDEVICE Vec3<int> Vec3<int>::normalized() const IMATH_NOEXCEPT = delete;
920 template <> Vec3<int> Vec3<int>::normalizedExc() const = delete;
921 template <> IMATH_HOSTDEVICE Vec3<int> Vec3<int>::normalizedNonNull() const IMATH_NOEXCEPT = delete;
922
923 // Vec3<int64_t>
924 template <> IMATH_HOSTDEVICE int64_t Vec3<int64_t>::length() const IMATH_NOEXCEPT = delete;
925 template <> IMATH_HOSTDEVICE const Vec3<int64_t>& Vec3<int64_t>::normalize() IMATH_NOEXCEPT = delete;
926 template <> const Vec3<int64_t>& Vec3<int64_t>::normalizeExc() = delete;
927 template <> IMATH_HOSTDEVICE const Vec3<int64_t>& Vec3<int64_t>::normalizeNonNull() IMATH_NOEXCEPT = delete;
928 template <> IMATH_HOSTDEVICE Vec3<int64_t> Vec3<int64_t>::normalized() const IMATH_NOEXCEPT = delete;
929 template <> Vec3<int64_t> Vec3<int64_t>::normalizedExc() const = delete;
930 template <> IMATH_HOSTDEVICE Vec3<int64_t> Vec3<int64_t>::normalizedNonNull() const IMATH_NOEXCEPT = delete;
931
932 // Vec4<short>
933 template <> IMATH_HOSTDEVICE short Vec4<short>::length() const IMATH_NOEXCEPT = delete;
934 template <> IMATH_HOSTDEVICE const Vec4<short>& Vec4<short>::normalize() IMATH_NOEXCEPT = delete;
935 template <> const Vec4<short>& Vec4<short>::normalizeExc() = delete;
936 template <> IMATH_HOSTDEVICE const Vec4<short>& Vec4<short>::normalizeNonNull() IMATH_NOEXCEPT = delete;
937 template <> IMATH_HOSTDEVICE Vec4<short> Vec4<short>::normalized() const IMATH_NOEXCEPT = delete;
938 template <> Vec4<short> Vec4<short>::normalizedExc() const = delete;
939 template <> IMATH_HOSTDEVICE Vec4<short> Vec4<short>::normalizedNonNull() const IMATH_NOEXCEPT = delete;
940
941 // Vec4<int>
942 template <> IMATH_HOSTDEVICE int Vec4<int>::length() const IMATH_NOEXCEPT = delete;
943 template <> IMATH_HOSTDEVICE const Vec4<int>& Vec4<int>::normalize() IMATH_NOEXCEPT = delete;
944 template <> const Vec4<int>& Vec4<int>::normalizeExc() = delete;
945 template <> IMATH_HOSTDEVICE const Vec4<int>& Vec4<int>::normalizeNonNull() IMATH_NOEXCEPT = delete;
946 template <> IMATH_HOSTDEVICE Vec4<int> Vec4<int>::normalized() const IMATH_NOEXCEPT = delete;
947 template <> Vec4<int> Vec4<int>::normalizedExc() const = delete;
948 template <> IMATH_HOSTDEVICE Vec4<int> Vec4<int>::normalizedNonNull() const IMATH_NOEXCEPT = delete;
949
950 // Vec4<int64_t>
951 template <> IMATH_HOSTDEVICE int64_t Vec4<int64_t>::length() const IMATH_NOEXCEPT = delete;
952 template <> IMATH_HOSTDEVICE const Vec4<int64_t>& Vec4<int64_t>::normalize() IMATH_NOEXCEPT = delete;
953 template <> const Vec4<int64_t>& Vec4<int64_t>::normalizeExc() = delete;
954 template <> IMATH_HOSTDEVICE const Vec4<int64_t>& Vec4<int64_t>::normalizeNonNull() IMATH_NOEXCEPT = delete;
955 template <> IMATH_HOSTDEVICE Vec4<int64_t> Vec4<int64_t>::normalized() const IMATH_NOEXCEPT = delete;
956 template <> Vec4<int64_t> Vec4<int64_t>::normalizedExc() const = delete;
957 template <> IMATH_HOSTDEVICE Vec4<int64_t> Vec4<int64_t>::normalizedNonNull() const IMATH_NOEXCEPT = delete;
958
959 /// @endcond Doxygen_Suppress
960
961 //------------------------
962 // Implementation of Vec2:
963 //------------------------
964
965 template <class T>
966 IMATH_CONSTEXPR14 IMATH_HOSTDEVICE inline T&
967 Vec2<T>::operator[] (int i) IMATH_NOEXCEPT
968 {
969     return (&x)[i]; // NOSONAR - suppress SonarCloud bug report.
970 }
971
972 template <class T>
973 constexpr IMATH_HOSTDEVICE inline const T&
974 Vec2<T>::operator[] (int i) const IMATH_NOEXCEPT
975 {
976     return (&x)[i]; // NOSONAR - suppress SonarCloud bug report.
977 }
978
979 template <class T> IMATH_HOSTDEVICE inline Vec2<T>::Vec2() IMATH_NOEXCEPT
980 {
981     // empty, and not constexpr because data is uninitialized.
982 }
983
984 template <class T> IMATH_HOSTDEVICE constexpr inline Vec2<T>::Vec2 (T a) IMATH_NOEXCEPT
985     : x(a), y(a)
986 {
987 }
988
989 template <class T> IMATH_HOSTDEVICE constexpr inline Vec2<T>::Vec2 (T a, T b) IMATH_NOEXCEPT
990     : x(a), y(b)
991 {
992 }
993
994 template <class T> IMATH_HOSTDEVICE constexpr inline Vec2<T>::Vec2 (const Vec2& v) IMATH_NOEXCEPT
995     : x(v.x), y(v.y)
996 {
997 }
998
999 template <class T> template <class S> IMATH_HOSTDEVICE constexpr inline Vec2<T>::Vec2 (const Vec2<S>& v) IMATH_NOEXCEPT
1000     : x(T(v.x)), y(T(v.y))
1001 {
1002 }
1003
1004 template <class T>
1005 IMATH_CONSTEXPR14 IMATH_HOSTDEVICE inline const Vec2<T>&
1006 Vec2<T>::operator= (const Vec2& v) IMATH_NOEXCEPT
1007 {
1008     x = v.x;
1009     y = v.y;
1010     return *this;
1011 }
1012
1013 template <class T>
1014 template <class S>
1015 IMATH_HOSTDEVICE inline void
1016 Vec2<T>::setValue (S a, S b) IMATH_NOEXCEPT
1017 {
1018     x = T (a);
1019     y = T (b);
1020 }
1021
1022 template <class T>
1023 template <class S>
1024 IMATH_HOSTDEVICE inline void
1025 Vec2<T>::setValue (const Vec2<S>& v) IMATH_NOEXCEPT
1026 {
1027     x = T (v.x);
1028     y = T (v.y);
1029 }
1030
1031 template <class T>
1032 template <class S>
1033 IMATH_HOSTDEVICE inline void
1034 Vec2<T>::getValue (S& a, S& b) const IMATH_NOEXCEPT
1035 {
1036     a = S (x);
1037     b = S (y);
1038 }
1039
1040 template <class T>
1041 template <class S>
1042 IMATH_HOSTDEVICE inline void
1043 Vec2<T>::getValue (Vec2<S>& v) const IMATH_NOEXCEPT
1044 {
1045     v.x = S (x);
1046     v.y = S (y);
1047 }
1048
1049 template <class T>
1050 IMATH_HOSTDEVICE inline T*
1051 Vec2<T>::getValue() IMATH_NOEXCEPT
1052 {
1053     return (T*) &x;
1054 }
1055
1056 template <class T>
1057 IMATH_HOSTDEVICE inline const T*
1058 Vec2<T>::getValue() const IMATH_NOEXCEPT
1059 {
1060     return (const T*) &x;
1061 }
1062
1063 template <class T>
1064 template <class S>
1065 IMATH_HOSTDEVICE constexpr inline bool
1066 Vec2<T>::operator== (const Vec2<S>& v) const IMATH_NOEXCEPT
1067 {
1068     return x == v.x && y == v.y;
1069 }
1070
1071 template <class T>
1072 template <class S>
1073 IMATH_HOSTDEVICE constexpr inline bool
1074 Vec2<T>::operator!= (const Vec2<S>& v) const IMATH_NOEXCEPT
1075 {
1076     return x != v.x || y != v.y;
1077 }
1078
1079 template <class T>
1080 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
1081 Vec2<T>::equalWithAbsError (const Vec2<T>& v, T e) const IMATH_NOEXCEPT
1082 {
1083     for (int i = 0; i < 2; i++)
1084         if (!IMATH_INTERNAL_NAMESPACE::equalWithAbsError ((*this)[i], v[i], e))
1085             return false;
1086
1087     return true;
1088 }
1089
1090 template <class T>
1091 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
1092 Vec2<T>::equalWithRelError (const Vec2<T>& v, T e) const IMATH_NOEXCEPT
1093 {
1094     for (int i = 0; i < 2; i++)
1095         if (!IMATH_INTERNAL_NAMESPACE::equalWithRelError ((*this)[i], v[i], e))
1096             return false;
1097
1098     return true;
1099 }
1100
1101 template <class T>
1102 IMATH_HOSTDEVICE constexpr inline T
1103 Vec2<T>::dot (const Vec2& v) const IMATH_NOEXCEPT
1104 {
1105     return x * v.x + y * v.y;
1106 }
1107
1108 template <class T>
1109 IMATH_HOSTDEVICE constexpr inline T
1110 Vec2<T>::operator^ (const Vec2& v) const IMATH_NOEXCEPT
1111 {
1112     return dot (v);
1113 }
1114
1115 template <class T>
1116 IMATH_HOSTDEVICE constexpr inline T
1117 Vec2<T>::cross (const Vec2& v) const IMATH_NOEXCEPT
1118 {
1119     return x * v.y - y * v.x;
1120 }
1121
1122 template <class T>
1123 IMATH_HOSTDEVICE constexpr inline T
1124 Vec2<T>::operator% (const Vec2& v) const IMATH_NOEXCEPT
1125 {
1126     return x * v.y - y * v.x;
1127 }
1128
1129 template <class T>
1130 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec2<T>&
1131 Vec2<T>::operator+= (const Vec2& v) IMATH_NOEXCEPT
1132 {
1133     x += v.x;
1134     y += v.y;
1135     return *this;
1136 }
1137
1138 template <class T>
1139 IMATH_HOSTDEVICE constexpr inline Vec2<T>
1140 Vec2<T>::operator+ (const Vec2& v) const IMATH_NOEXCEPT
1141 {
1142     return Vec2 (x + v.x, y + v.y);
1143 }
1144
1145 template <class T>
1146 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec2<T>&
1147 Vec2<T>::operator-= (const Vec2& v) IMATH_NOEXCEPT
1148 {
1149     x -= v.x;
1150     y -= v.y;
1151     return *this;
1152 }
1153
1154 template <class T>
1155 IMATH_HOSTDEVICE constexpr inline Vec2<T>
1156 Vec2<T>::operator- (const Vec2& v) const IMATH_NOEXCEPT
1157 {
1158     return Vec2 (x - v.x, y - v.y);
1159 }
1160
1161 template <class T>
1162 IMATH_HOSTDEVICE constexpr inline Vec2<T>
1163 Vec2<T>::operator-() const IMATH_NOEXCEPT
1164 {
1165     return Vec2 (-x, -y);
1166 }
1167
1168 template <class T>
1169 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec2<T>&
1170 Vec2<T>::negate() IMATH_NOEXCEPT
1171 {
1172     x = -x;
1173     y = -y;
1174     return *this;
1175 }
1176
1177 template <class T>
1178 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec2<T>&
1179 Vec2<T>::operator*= (const Vec2& v) IMATH_NOEXCEPT
1180 {
1181     x *= v.x;
1182     y *= v.y;
1183     return *this;
1184 }
1185
1186 template <class T>
1187 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec2<T>&
1188 Vec2<T>::operator*= (T a) IMATH_NOEXCEPT
1189 {
1190     x *= a;
1191     y *= a;
1192     return *this;
1193 }
1194
1195 template <class T>
1196 IMATH_HOSTDEVICE constexpr inline Vec2<T>
1197 Vec2<T>::operator* (const Vec2& v) const IMATH_NOEXCEPT
1198 {
1199     return Vec2 (x * v.x, y * v.y);
1200 }
1201
1202 template <class T>
1203 IMATH_HOSTDEVICE constexpr inline Vec2<T>
1204 Vec2<T>::operator* (T a) const IMATH_NOEXCEPT
1205 {
1206     return Vec2 (x * a, y * a);
1207 }
1208
1209 template <class T>
1210 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec2<T>&
1211 Vec2<T>::operator/= (const Vec2& v) IMATH_NOEXCEPT
1212 {
1213     x /= v.x;
1214     y /= v.y;
1215     return *this;
1216 }
1217
1218 template <class T>
1219 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec2<T>&
1220 Vec2<T>::operator/= (T a) IMATH_NOEXCEPT
1221 {
1222     x /= a;
1223     y /= a;
1224     return *this;
1225 }
1226
1227 template <class T>
1228 IMATH_HOSTDEVICE constexpr inline Vec2<T>
1229 Vec2<T>::operator/ (const Vec2& v) const IMATH_NOEXCEPT
1230 {
1231     return Vec2 (x / v.x, y / v.y);
1232 }
1233
1234 template <class T>
1235 IMATH_HOSTDEVICE constexpr inline Vec2<T>
1236 Vec2<T>::operator/ (T a) const IMATH_NOEXCEPT
1237 {
1238     return Vec2 (x / a, y / a);
1239 }
1240
1241 template <class T>
1242 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T
1243 Vec2<T>::lengthTiny() const IMATH_NOEXCEPT
1244 {
1245     T absX = std::abs(x);
1246     T absY = std::abs(y);
1247
1248     T max = absX;
1249
1250     if (max < absY)
1251         max = absY;
1252
1253     if (IMATH_UNLIKELY(max == T (0)))
1254         return T (0);
1255
1256     //
1257     // Do not replace the divisions by max with multiplications by 1/max.
1258     // Computing 1/max can overflow but the divisions below will always
1259     // produce results less than or equal to 1.
1260     //
1261
1262     absX /= max;
1263     absY /= max;
1264
1265     return max * std::sqrt (absX * absX + absY * absY);
1266 }
1267
1268 template <class T>
1269 IMATH_HOSTDEVICE inline T
1270 Vec2<T>::length() const IMATH_NOEXCEPT
1271 {
1272     T length2 = dot (*this);
1273
1274     if (IMATH_UNLIKELY(length2 < T (2) * std::numeric_limits<T>::min()))
1275         return lengthTiny();
1276
1277     return std::sqrt (length2);
1278 }
1279
1280 template <class T>
1281 IMATH_HOSTDEVICE constexpr inline T
1282 Vec2<T>::length2() const IMATH_NOEXCEPT
1283 {
1284     return dot (*this);
1285 }
1286
1287 template <class T>
1288 IMATH_HOSTDEVICE inline const Vec2<T>&
1289 Vec2<T>::normalize() IMATH_NOEXCEPT
1290 {
1291     T l = length();
1292
1293     if (IMATH_LIKELY(l != T (0)))
1294     {
1295         //
1296         // Do not replace the divisions by l with multiplications by 1/l.
1297         // Computing 1/l can overflow but the divisions below will always
1298         // produce results less than or equal to 1.
1299         //
1300
1301         x /= l;
1302         y /= l;
1303     }
1304
1305     return *this;
1306 }
1307
1308 template <class T>
1309 inline const Vec2<T>&
1310 Vec2<T>::normalizeExc()
1311 {
1312     T l = length();
1313
1314     if (IMATH_UNLIKELY(l == T (0)))
1315         throw std::domain_error ("Cannot normalize null vector.");
1316
1317     x /= l;
1318     y /= l;
1319     return *this;
1320 }
1321
1322 template <class T>
1323 IMATH_HOSTDEVICE inline const Vec2<T>&
1324 Vec2<T>::normalizeNonNull() IMATH_NOEXCEPT
1325 {
1326     T l = length();
1327     x /= l;
1328     y /= l;
1329     return *this;
1330 }
1331
1332 template <class T>
1333 IMATH_HOSTDEVICE inline Vec2<T>
1334 Vec2<T>::normalized() const IMATH_NOEXCEPT
1335 {
1336     T l = length();
1337
1338     if (IMATH_UNLIKELY(l == T (0)))
1339         return Vec2 (T (0));
1340
1341     return Vec2 (x / l, y / l);
1342 }
1343
1344 template <class T>
1345 inline Vec2<T>
1346 Vec2<T>::normalizedExc() const
1347 {
1348     T l = length();
1349
1350     if (IMATH_UNLIKELY(l == T (0)))
1351         throw std::domain_error ("Cannot normalize null vector.");
1352
1353     return Vec2 (x / l, y / l);
1354 }
1355
1356 template <class T>
1357 IMATH_HOSTDEVICE inline Vec2<T>
1358 Vec2<T>::normalizedNonNull() const IMATH_NOEXCEPT
1359 {
1360     T l = length();
1361     return Vec2 (x / l, y / l);
1362 }
1363
1364 //-----------------------
1365 // Implementation of Vec3
1366 //-----------------------
1367
1368 template <class T>
1369 IMATH_HOSTDEVICE
1370 IMATH_CONSTEXPR14 inline T&
1371 Vec3<T>::operator[] (int i) IMATH_NOEXCEPT
1372 {
1373     return (&x)[i]; // NOSONAR - suppress SonarCloud bug report.
1374 }
1375
1376 template <class T>
1377 IMATH_HOSTDEVICE constexpr inline const T&
1378 Vec3<T>::operator[] (int i) const IMATH_NOEXCEPT
1379 {
1380     return (&x)[i]; // NOSONAR - suppress SonarCloud bug report.
1381 }
1382
1383 template <class T> IMATH_HOSTDEVICE inline Vec3<T>::Vec3() IMATH_NOEXCEPT
1384 {
1385     // empty, and not constexpr because data is uninitialized.
1386 }
1387
1388 template <class T> IMATH_HOSTDEVICE constexpr inline Vec3<T>::Vec3 (T a) IMATH_NOEXCEPT
1389     : x(a), y(a), z(a)
1390 {
1391 }
1392
1393 template <class T> IMATH_HOSTDEVICE constexpr inline Vec3<T>::Vec3 (T a, T b, T c) IMATH_NOEXCEPT
1394     : x(a), y(b), z(c)
1395 {
1396 }
1397
1398 template <class T> IMATH_HOSTDEVICE constexpr inline Vec3<T>::Vec3 (const Vec3& v) IMATH_NOEXCEPT
1399     : x(v.x), y(v.y), z(v.z)
1400 {
1401 }
1402
1403 template <class T> template <class S>
1404 IMATH_HOSTDEVICE constexpr inline Vec3<T>::Vec3 (const Vec3<S>& v) IMATH_NOEXCEPT
1405     : x(T(v.x)), y(T(v.y)), z(T(v.z))
1406 {
1407 }
1408
1409 template <class T>
1410 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec3<T>&
1411 Vec3<T>::operator= (const Vec3& v) IMATH_NOEXCEPT
1412 {
1413     x = v.x;
1414     y = v.y;
1415     z = v.z;
1416     return *this;
1417 }
1418
1419 template <class T> template <class S>
1420 IMATH_HOSTDEVICE constexpr inline Vec3<T>::Vec3 (const Vec4<S>& v) IMATH_NOEXCEPT
1421     : x(T(v.x/v.w)), y(T(v.y/v.w)), z(T(v.z/v.w))
1422 {
1423 }
1424
1425 template <class T>
1426 template <class S>
1427 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Vec3<T>::Vec3 (const Vec4<S>& v, InfException)
1428 {
1429     T vx = T (v.x);
1430     T vy = T (v.y);
1431     T vz = T (v.z);
1432     T vw = T (v.w);
1433
1434     T absW = (vw >= T (0)) ? vw : -vw;
1435
1436     if (absW < 1)
1437     {
1438         T m = baseTypeMax() * absW;
1439
1440         if (vx <= -m || vx >= m || vy <= -m || vy >= m || vz <= -m || vz >= m)
1441             throw std::domain_error ("Cannot normalize point at infinity.");
1442     }
1443
1444     x = vx / vw;
1445     y = vy / vw;
1446     z = vz / vw;
1447 }
1448
1449 template <class T>
1450 template <class S>
1451 IMATH_HOSTDEVICE inline void
1452 Vec3<T>::setValue (S a, S b, S c) IMATH_NOEXCEPT
1453 {
1454     x = T (a);
1455     y = T (b);
1456     z = T (c);
1457 }
1458
1459 template <class T>
1460 template <class S>
1461 IMATH_HOSTDEVICE inline void
1462 Vec3<T>::setValue (const Vec3<S>& v) IMATH_NOEXCEPT
1463 {
1464     x = T (v.x);
1465     y = T (v.y);
1466     z = T (v.z);
1467 }
1468
1469 template <class T>
1470 template <class S>
1471 IMATH_HOSTDEVICE inline void
1472 Vec3<T>::getValue (S& a, S& b, S& c) const IMATH_NOEXCEPT
1473 {
1474     a = S (x);
1475     b = S (y);
1476     c = S (z);
1477 }
1478
1479 template <class T>
1480 template <class S>
1481 IMATH_HOSTDEVICE inline void
1482 Vec3<T>::getValue (Vec3<S>& v) const IMATH_NOEXCEPT
1483 {
1484     v.x = S (x);
1485     v.y = S (y);
1486     v.z = S (z);
1487 }
1488
1489 template <class T>
1490 IMATH_HOSTDEVICE inline T*
1491 Vec3<T>::getValue() IMATH_NOEXCEPT
1492 {
1493     return (T*) &x;
1494 }
1495
1496 template <class T>
1497 IMATH_HOSTDEVICE inline const T*
1498 Vec3<T>::getValue() const IMATH_NOEXCEPT
1499 {
1500     return (const T*) &x;
1501 }
1502
1503 template <class T>
1504 template <class S>
1505 IMATH_HOSTDEVICE constexpr inline bool
1506 Vec3<T>::operator== (const Vec3<S>& v) const IMATH_NOEXCEPT
1507 {
1508     return x == v.x && y == v.y && z == v.z;
1509 }
1510
1511 template <class T>
1512 template <class S>
1513 IMATH_HOSTDEVICE constexpr inline bool
1514 Vec3<T>::operator!= (const Vec3<S>& v) const IMATH_NOEXCEPT
1515 {
1516     return x != v.x || y != v.y || z != v.z;
1517 }
1518
1519 template <class T>
1520 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
1521 Vec3<T>::equalWithAbsError (const Vec3<T>& v, T e) const IMATH_NOEXCEPT
1522 {
1523     for (int i = 0; i < 3; i++)
1524         if (!IMATH_INTERNAL_NAMESPACE::equalWithAbsError ((*this)[i], v[i], e))
1525             return false;
1526
1527     return true;
1528 }
1529
1530 template <class T>
1531 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
1532 Vec3<T>::equalWithRelError (const Vec3<T>& v, T e) const IMATH_NOEXCEPT
1533 {
1534     for (int i = 0; i < 3; i++)
1535         if (!IMATH_INTERNAL_NAMESPACE::equalWithRelError ((*this)[i], v[i], e))
1536             return false;
1537
1538     return true;
1539 }
1540
1541 template <class T>
1542 IMATH_HOSTDEVICE constexpr inline T
1543 Vec3<T>::dot (const Vec3& v) const IMATH_NOEXCEPT
1544 {
1545     return x * v.x + y * v.y + z * v.z;
1546 }
1547
1548 template <class T>
1549 IMATH_HOSTDEVICE constexpr inline T
1550 Vec3<T>::operator^ (const Vec3& v) const IMATH_NOEXCEPT
1551 {
1552     return dot (v);
1553 }
1554
1555 template <class T>
1556 IMATH_HOSTDEVICE constexpr inline Vec3<T>
1557 Vec3<T>::cross (const Vec3& v) const IMATH_NOEXCEPT
1558 {
1559     return Vec3 (y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x);
1560 }
1561
1562 template <class T>
1563 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec3<T>&
1564 Vec3<T>::operator%= (const Vec3& v) IMATH_NOEXCEPT
1565 {
1566     T a = y * v.z - z * v.y;
1567     T b = z * v.x - x * v.z;
1568     T c = x * v.y - y * v.x;
1569     x   = a;
1570     y   = b;
1571     z   = c;
1572     return *this;
1573 }
1574
1575 template <class T>
1576 IMATH_HOSTDEVICE constexpr inline Vec3<T>
1577 Vec3<T>::operator% (const Vec3& v) const IMATH_NOEXCEPT
1578 {
1579     return Vec3 (y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x);
1580 }
1581
1582 template <class T>
1583 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec3<T>&
1584 Vec3<T>::operator+= (const Vec3& v) IMATH_NOEXCEPT
1585 {
1586     x += v.x;
1587     y += v.y;
1588     z += v.z;
1589     return *this;
1590 }
1591
1592 template <class T>
1593 IMATH_HOSTDEVICE constexpr inline Vec3<T>
1594 Vec3<T>::operator+ (const Vec3& v) const IMATH_NOEXCEPT
1595 {
1596     return Vec3 (x + v.x, y + v.y, z + v.z);
1597 }
1598
1599 template <class T>
1600 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec3<T>&
1601 Vec3<T>::operator-= (const Vec3& v) IMATH_NOEXCEPT
1602 {
1603     x -= v.x;
1604     y -= v.y;
1605     z -= v.z;
1606     return *this;
1607 }
1608
1609 template <class T>
1610 IMATH_HOSTDEVICE constexpr inline Vec3<T>
1611 Vec3<T>::operator- (const Vec3& v) const IMATH_NOEXCEPT
1612 {
1613     return Vec3 (x - v.x, y - v.y, z - v.z);
1614 }
1615
1616 template <class T>
1617 IMATH_HOSTDEVICE constexpr inline Vec3<T>
1618 Vec3<T>::operator-() const IMATH_NOEXCEPT
1619 {
1620     return Vec3 (-x, -y, -z);
1621 }
1622
1623 template <class T>
1624 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec3<T>&
1625 Vec3<T>::negate() IMATH_NOEXCEPT
1626 {
1627     x = -x;
1628     y = -y;
1629     z = -z;
1630     return *this;
1631 }
1632
1633 template <class T>
1634 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec3<T>&
1635 Vec3<T>::operator*= (const Vec3& v) IMATH_NOEXCEPT
1636 {
1637     x *= v.x;
1638     y *= v.y;
1639     z *= v.z;
1640     return *this;
1641 }
1642
1643 template <class T>
1644 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec3<T>&
1645 Vec3<T>::operator*= (T a) IMATH_NOEXCEPT
1646 {
1647     x *= a;
1648     y *= a;
1649     z *= a;
1650     return *this;
1651 }
1652
1653 template <class T>
1654 IMATH_HOSTDEVICE constexpr inline Vec3<T>
1655 Vec3<T>::operator* (const Vec3& v) const IMATH_NOEXCEPT
1656 {
1657     return Vec3 (x * v.x, y * v.y, z * v.z);
1658 }
1659
1660 template <class T>
1661 IMATH_HOSTDEVICE constexpr inline Vec3<T>
1662 Vec3<T>::operator* (T a) const IMATH_NOEXCEPT
1663 {
1664     return Vec3 (x * a, y * a, z * a);
1665 }
1666
1667 template <class T>
1668 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec3<T>&
1669 Vec3<T>::operator/= (const Vec3& v) IMATH_NOEXCEPT
1670 {
1671     x /= v.x;
1672     y /= v.y;
1673     z /= v.z;
1674     return *this;
1675 }
1676
1677 template <class T>
1678 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec3<T>&
1679 Vec3<T>::operator/= (T a) IMATH_NOEXCEPT
1680 {
1681     x /= a;
1682     y /= a;
1683     z /= a;
1684     return *this;
1685 }
1686
1687 template <class T>
1688 IMATH_HOSTDEVICE constexpr inline Vec3<T>
1689 Vec3<T>::operator/ (const Vec3& v) const IMATH_NOEXCEPT
1690 {
1691     return Vec3 (x / v.x, y / v.y, z / v.z);
1692 }
1693
1694 template <class T>
1695 IMATH_HOSTDEVICE constexpr inline Vec3<T>
1696 Vec3<T>::operator/ (T a) const IMATH_NOEXCEPT
1697 {
1698     return Vec3 (x / a, y / a, z / a);
1699 }
1700
1701 template <class T>
1702 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T
1703 Vec3<T>::lengthTiny() const IMATH_NOEXCEPT
1704 {
1705     T absX = (x >= T (0)) ? x : -x;
1706     T absY = (y >= T (0)) ? y : -y;
1707     T absZ = (z >= T (0)) ? z : -z;
1708
1709     T max = absX;
1710
1711     if (max < absY)
1712         max = absY;
1713
1714     if (max < absZ)
1715         max = absZ;
1716
1717     if (IMATH_UNLIKELY(max == T (0)))
1718         return T (0);
1719
1720     //
1721     // Do not replace the divisions by max with multiplications by 1/max.
1722     // Computing 1/max can overflow but the divisions below will always
1723     // produce results less than or equal to 1.
1724     //
1725
1726     absX /= max;
1727     absY /= max;
1728     absZ /= max;
1729
1730     return max * std::sqrt (absX * absX + absY * absY + absZ * absZ);
1731 }
1732
1733 template <class T>
1734 IMATH_HOSTDEVICE inline T
1735 Vec3<T>::length() const IMATH_NOEXCEPT
1736 {
1737     T length2 = dot (*this);
1738
1739     if (IMATH_UNLIKELY(length2 < T (2) * std::numeric_limits<T>::min()))
1740         return lengthTiny();
1741
1742     return std::sqrt (length2);
1743 }
1744
1745 template <class T>
1746 IMATH_HOSTDEVICE constexpr inline T
1747 Vec3<T>::length2() const IMATH_NOEXCEPT
1748 {
1749     return dot (*this);
1750 }
1751
1752 template <class T>
1753 IMATH_HOSTDEVICE inline const Vec3<T>&
1754 Vec3<T>::normalize() IMATH_NOEXCEPT
1755 {
1756     T l = length();
1757
1758     if (IMATH_LIKELY(l != T (0)))
1759     {
1760         //
1761         // Do not replace the divisions by l with multiplications by 1/l.
1762         // Computing 1/l can overflow but the divisions below will always
1763         // produce results less than or equal to 1.
1764         //
1765
1766         x /= l;
1767         y /= l;
1768         z /= l;
1769     }
1770
1771     return *this;
1772 }
1773
1774 template <class T>
1775 inline const Vec3<T>&
1776 Vec3<T>::normalizeExc()
1777 {
1778     T l = length();
1779
1780     if (IMATH_UNLIKELY(l == T (0)))
1781         throw std::domain_error ("Cannot normalize null vector.");
1782
1783     x /= l;
1784     y /= l;
1785     z /= l;
1786     return *this;
1787 }
1788
1789 template <class T>
1790 IMATH_HOSTDEVICE inline const Vec3<T>&
1791 Vec3<T>::normalizeNonNull() IMATH_NOEXCEPT
1792 {
1793     T l = length();
1794     x /= l;
1795     y /= l;
1796     z /= l;
1797     return *this;
1798 }
1799
1800 template <class T>
1801 IMATH_HOSTDEVICE inline Vec3<T>
1802 Vec3<T>::normalized() const IMATH_NOEXCEPT
1803 {
1804     T l = length();
1805
1806     if (IMATH_UNLIKELY((l == T (0))))
1807         return Vec3 (T (0));
1808
1809     return Vec3 (x / l, y / l, z / l);
1810 }
1811
1812 template <class T>
1813 inline Vec3<T>
1814 Vec3<T>::normalizedExc() const
1815 {
1816     T l = length();
1817
1818     if (IMATH_UNLIKELY(l == T (0)))
1819         throw std::domain_error ("Cannot normalize null vector.");
1820
1821     return Vec3 (x / l, y / l, z / l);
1822 }
1823
1824 template <class T>
1825 IMATH_HOSTDEVICE inline Vec3<T>
1826 Vec3<T>::normalizedNonNull() const IMATH_NOEXCEPT
1827 {
1828     T l = length();
1829     return Vec3 (x / l, y / l, z / l);
1830 }
1831
1832 //-----------------------
1833 // Implementation of Vec4
1834 //-----------------------
1835
1836 template <class T>
1837 IMATH_HOSTDEVICE
1838 IMATH_CONSTEXPR14 inline T&
1839 Vec4<T>::operator[] (int i) IMATH_NOEXCEPT
1840 {
1841     return (&x)[i]; // NOSONAR - suppress SonarCloud bug report.
1842 }
1843
1844 template <class T>
1845 IMATH_HOSTDEVICE constexpr inline const T&
1846 Vec4<T>::operator[] (int i) const IMATH_NOEXCEPT
1847 {
1848     return (&x)[i]; // NOSONAR - suppress SonarCloud bug report.
1849 }
1850
1851 template <class T> IMATH_HOSTDEVICE inline Vec4<T>::Vec4() IMATH_NOEXCEPT
1852 {
1853     // empty, and not constexpr because data is uninitialized.
1854 }
1855
1856 template <class T> IMATH_HOSTDEVICE constexpr inline Vec4<T>::Vec4 (T a) IMATH_NOEXCEPT
1857     : x(a), y(a), z(a), w(a)
1858 {
1859 }
1860
1861 template <class T> IMATH_HOSTDEVICE constexpr inline Vec4<T>::Vec4 (T a, T b, T c, T d) IMATH_NOEXCEPT
1862     : x(a), y(b), z(c), w(d)
1863 {
1864 }
1865
1866 template <class T> IMATH_HOSTDEVICE constexpr inline Vec4<T>::Vec4 (const Vec4& v) IMATH_NOEXCEPT
1867     : x(v.x), y(v.y), z(v.z), w(v.w)
1868 {
1869 }
1870
1871 template <class T> template <class S>
1872 IMATH_HOSTDEVICE constexpr inline Vec4<T>::Vec4 (const Vec4<S>& v) IMATH_NOEXCEPT
1873     : x(T(v.x)), y(T(v.y)), z(T(v.z)), w(T(v.w))
1874 {
1875 }
1876
1877 template <class T>
1878 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec4<T>&
1879 Vec4<T>::operator= (const Vec4& v) IMATH_NOEXCEPT
1880 {
1881     x = v.x;
1882     y = v.y;
1883     z = v.z;
1884     w = v.w;
1885     return *this;
1886 }
1887
1888 template <class T> template <class S>
1889 IMATH_HOSTDEVICE constexpr inline Vec4<T>::Vec4 (const Vec3<S>& v) IMATH_NOEXCEPT
1890     : x(T(v.x)), y(T(v.y)), z(T(v.z)), w(T(1))
1891 {
1892 }
1893
1894 template <class T>
1895 template <class S>
1896 IMATH_HOSTDEVICE constexpr inline bool
1897 Vec4<T>::operator== (const Vec4<S>& v) const IMATH_NOEXCEPT
1898 {
1899     return x == v.x && y == v.y && z == v.z && w == v.w;
1900 }
1901
1902 template <class T>
1903 template <class S>
1904 IMATH_HOSTDEVICE constexpr inline bool
1905 Vec4<T>::operator!= (const Vec4<S>& v) const IMATH_NOEXCEPT
1906 {
1907     return x != v.x || y != v.y || z != v.z || w != v.w;
1908 }
1909
1910 template <class T>
1911 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
1912 Vec4<T>::equalWithAbsError (const Vec4<T>& v, T e) const IMATH_NOEXCEPT
1913 {
1914     for (int i = 0; i < 4; i++)
1915         if (!IMATH_INTERNAL_NAMESPACE::equalWithAbsError ((*this)[i], v[i], e))
1916             return false;
1917
1918     return true;
1919 }
1920
1921 template <class T>
1922 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
1923 Vec4<T>::equalWithRelError (const Vec4<T>& v, T e) const IMATH_NOEXCEPT
1924 {
1925     for (int i = 0; i < 4; i++)
1926         if (!IMATH_INTERNAL_NAMESPACE::equalWithRelError ((*this)[i], v[i], e))
1927             return false;
1928
1929     return true;
1930 }
1931
1932 template <class T>
1933 IMATH_HOSTDEVICE constexpr inline T
1934 Vec4<T>::dot (const Vec4& v) const IMATH_NOEXCEPT
1935 {
1936     return x * v.x + y * v.y + z * v.z + w * v.w;
1937 }
1938
1939 template <class T>
1940 IMATH_HOSTDEVICE constexpr inline T
1941 Vec4<T>::operator^ (const Vec4& v) const IMATH_NOEXCEPT
1942 {
1943     return dot (v);
1944 }
1945
1946 template <class T>
1947 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec4<T>&
1948 Vec4<T>::operator+= (const Vec4& v) IMATH_NOEXCEPT
1949 {
1950     x += v.x;
1951     y += v.y;
1952     z += v.z;
1953     w += v.w;
1954     return *this;
1955 }
1956
1957 template <class T>
1958 IMATH_HOSTDEVICE constexpr inline Vec4<T>
1959 Vec4<T>::operator+ (const Vec4& v) const IMATH_NOEXCEPT
1960 {
1961     return Vec4 (x + v.x, y + v.y, z + v.z, w + v.w);
1962 }
1963
1964 template <class T>
1965 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec4<T>&
1966 Vec4<T>::operator-= (const Vec4& v) IMATH_NOEXCEPT
1967 {
1968     x -= v.x;
1969     y -= v.y;
1970     z -= v.z;
1971     w -= v.w;
1972     return *this;
1973 }
1974
1975 template <class T>
1976 IMATH_HOSTDEVICE constexpr inline Vec4<T>
1977 Vec4<T>::operator- (const Vec4& v) const IMATH_NOEXCEPT
1978 {
1979     return Vec4 (x - v.x, y - v.y, z - v.z, w - v.w);
1980 }
1981
1982 template <class T>
1983 IMATH_HOSTDEVICE constexpr inline Vec4<T>
1984 Vec4<T>::operator-() const IMATH_NOEXCEPT
1985 {
1986     return Vec4 (-x, -y, -z, -w);
1987 }
1988
1989 template <class T>
1990 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec4<T>&
1991 Vec4<T>::negate() IMATH_NOEXCEPT
1992 {
1993     x = -x;
1994     y = -y;
1995     z = -z;
1996     w = -w;
1997     return *this;
1998 }
1999
2000 template <class T>
2001 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec4<T>&
2002 Vec4<T>::operator*= (const Vec4& v) IMATH_NOEXCEPT
2003 {
2004     x *= v.x;
2005     y *= v.y;
2006     z *= v.z;
2007     w *= v.w;
2008     return *this;
2009 }
2010
2011 template <class T>
2012 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec4<T>&
2013 Vec4<T>::operator*= (T a) IMATH_NOEXCEPT
2014 {
2015     x *= a;
2016     y *= a;
2017     z *= a;
2018     w *= a;
2019     return *this;
2020 }
2021
2022 template <class T>
2023 IMATH_HOSTDEVICE constexpr inline Vec4<T>
2024 Vec4<T>::operator* (const Vec4& v) const IMATH_NOEXCEPT
2025 {
2026     return Vec4 (x * v.x, y * v.y, z * v.z, w * v.w);
2027 }
2028
2029 template <class T>
2030 IMATH_HOSTDEVICE constexpr inline Vec4<T>
2031 Vec4<T>::operator* (T a) const IMATH_NOEXCEPT
2032 {
2033     return Vec4 (x * a, y * a, z * a, w * a);
2034 }
2035
2036 template <class T>
2037 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec4<T>&
2038 Vec4<T>::operator/= (const Vec4& v) IMATH_NOEXCEPT
2039 {
2040     x /= v.x;
2041     y /= v.y;
2042     z /= v.z;
2043     w /= v.w;
2044     return *this;
2045 }
2046
2047 template <class T>
2048 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Vec4<T>&
2049 Vec4<T>::operator/= (T a) IMATH_NOEXCEPT
2050 {
2051     x /= a;
2052     y /= a;
2053     z /= a;
2054     w /= a;
2055     return *this;
2056 }
2057
2058 template <class T>
2059 IMATH_HOSTDEVICE constexpr inline Vec4<T>
2060 Vec4<T>::operator/ (const Vec4& v) const IMATH_NOEXCEPT
2061 {
2062     return Vec4 (x / v.x, y / v.y, z / v.z, w / v.w);
2063 }
2064
2065 template <class T>
2066 IMATH_HOSTDEVICE constexpr inline Vec4<T>
2067 Vec4<T>::operator/ (T a) const IMATH_NOEXCEPT
2068 {
2069     return Vec4 (x / a, y / a, z / a, w / a);
2070 }
2071
2072 template <class T>
2073 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T
2074 Vec4<T>::lengthTiny() const IMATH_NOEXCEPT
2075 {
2076     T absX = (x >= T (0)) ? x : -x;
2077     T absY = (y >= T (0)) ? y : -y;
2078     T absZ = (z >= T (0)) ? z : -z;
2079     T absW = (w >= T (0)) ? w : -w;
2080
2081     T max = absX;
2082
2083     if (max < absY)
2084         max = absY;
2085
2086     if (max < absZ)
2087         max = absZ;
2088
2089     if (max < absW)
2090         max = absW;
2091
2092     if (IMATH_UNLIKELY(max == T (0)))
2093         return T (0);
2094
2095     //
2096     // Do not replace the divisions by max with multiplications by 1/max.
2097     // Computing 1/max can overflow but the divisions below will always
2098     // produce results less than or equal to 1.
2099     //
2100
2101     absX /= max;
2102     absY /= max;
2103     absZ /= max;
2104     absW /= max;
2105
2106     return max * std::sqrt (absX * absX + absY * absY + absZ * absZ + absW * absW);
2107 }
2108
2109 template <class T>
2110 IMATH_HOSTDEVICE inline T
2111 Vec4<T>::length() const IMATH_NOEXCEPT
2112 {
2113     T length2 = dot (*this);
2114
2115     if (IMATH_UNLIKELY(length2 < T (2) * std::numeric_limits<T>::min()))
2116         return lengthTiny();
2117
2118     return std::sqrt (length2);
2119 }
2120
2121 template <class T>
2122 IMATH_HOSTDEVICE constexpr inline T
2123 Vec4<T>::length2() const IMATH_NOEXCEPT
2124 {
2125     return dot (*this);
2126 }
2127
2128 template <class T>
2129 IMATH_HOSTDEVICE const inline Vec4<T>&
2130 Vec4<T>::normalize() IMATH_NOEXCEPT
2131 {
2132     T l = length();
2133
2134     if (IMATH_LIKELY(l != T (0)))
2135     {
2136         //
2137         // Do not replace the divisions by l with multiplications by 1/l.
2138         // Computing 1/l can overflow but the divisions below will always
2139         // produce results less than or equal to 1.
2140         //
2141
2142         x /= l;
2143         y /= l;
2144         z /= l;
2145         w /= l;
2146     }
2147
2148     return *this;
2149 }
2150
2151 template <class T>
2152 const inline Vec4<T>&
2153 Vec4<T>::normalizeExc()
2154 {
2155     T l = length();
2156
2157     if (IMATH_UNLIKELY(l == T (0)))
2158         throw std::domain_error ("Cannot normalize null vector.");
2159
2160     x /= l;
2161     y /= l;
2162     z /= l;
2163     w /= l;
2164     return *this;
2165 }
2166
2167 template <class T>
2168 IMATH_HOSTDEVICE inline const Vec4<T>&
2169 Vec4<T>::normalizeNonNull() IMATH_NOEXCEPT
2170 {
2171     T l = length();
2172     x /= l;
2173     y /= l;
2174     z /= l;
2175     w /= l;
2176     return *this;
2177 }
2178
2179 template <class T>
2180 IMATH_HOSTDEVICE inline Vec4<T>
2181 Vec4<T>::normalized() const IMATH_NOEXCEPT
2182 {
2183     T l = length();
2184
2185     if (IMATH_UNLIKELY(l == T (0)))
2186         return Vec4 (T (0));
2187
2188     return Vec4 (x / l, y / l, z / l, w / l);
2189 }
2190
2191 template <class T>
2192 inline Vec4<T>
2193 Vec4<T>::normalizedExc() const
2194 {
2195     T l = length();
2196
2197     if (IMATH_UNLIKELY(l == T (0)))
2198         throw std::domain_error ("Cannot normalize null vector.");
2199
2200     return Vec4 (x / l, y / l, z / l, w / l);
2201 }
2202
2203 template <class T>
2204 IMATH_HOSTDEVICE inline Vec4<T>
2205 Vec4<T>::normalizedNonNull() const IMATH_NOEXCEPT
2206 {
2207     T l = length();
2208     return Vec4 (x / l, y / l, z / l, w / l);
2209 }
2210
2211 //-----------------------------
2212 // Stream output implementation
2213 //-----------------------------
2214
2215 template <class T>
2216 std::ostream&
2217 operator<< (std::ostream& s, const Vec2<T>& v)
2218 {
2219     return s << '(' << v.x << ' ' << v.y << ')';
2220 }
2221
2222 template <class T>
2223 std::ostream&
2224 operator<< (std::ostream& s, const Vec3<T>& v)
2225 {
2226     return s << '(' << v.x << ' ' << v.y << ' ' << v.z << ')';
2227 }
2228
2229 template <class T>
2230 std::ostream&
2231 operator<< (std::ostream& s, const Vec4<T>& v)
2232 {
2233     return s << '(' << v.x << ' ' << v.y << ' ' << v.z << ' ' << v.w << ')';
2234 }
2235
2236 //-----------------------------------------
2237 // Implementation of reverse multiplication
2238 //-----------------------------------------
2239
2240 template <class T>
2241 IMATH_HOSTDEVICE constexpr inline Vec2<T>
2242 operator* (T a, const Vec2<T>& v) IMATH_NOEXCEPT
2243 {
2244     return Vec2<T> (a * v.x, a * v.y);
2245 }
2246
2247 template <class T>
2248 IMATH_HOSTDEVICE constexpr inline Vec3<T>
2249 operator* (T a, const Vec3<T>& v) IMATH_NOEXCEPT
2250 {
2251     return Vec3<T> (a * v.x, a * v.y, a * v.z);
2252 }
2253
2254 template <class T>
2255 IMATH_HOSTDEVICE constexpr inline Vec4<T>
2256 operator* (T a, const Vec4<T>& v) IMATH_NOEXCEPT
2257 {
2258     return Vec4<T> (a * v.x, a * v.y, a * v.z, a * v.w);
2259 }
2260
2261 #if (defined _WIN32 || defined _WIN64) && defined _MSC_VER
2262 #    pragma warning(pop)
2263 #endif
2264
2265 IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
2266
2267 #endif // INCLUDED_IMATHVEC_H