Coverage Report

Created: 2026-10-14 06:45

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