HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_FixedArrayMath.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_FixedArrayMath.h (UT Library, C++)
7  *
8  * COMMENTS: Define common math operations on fixed array-like types,
9  * which can be used to implement classes such as
10  * UT_Vector2.h, UT_Vector3.h, UT_Vector4.h, UT_FixedVector.h and more.
11  *
12  */
13 
14 #pragma once
15 
16 #ifndef __UT_FixedArrayMath__
17 #define __UT_FixedArrayMath__
18 
19 #include "UT_FixedArray.h"
20 #include <SYS/SYS_StaticAssert.h>
21 #include <SYS/SYS_TypeTraits.h>
22 #include <SYS/SYS_Math.h>
23 #include <SYS/SYS_Inline.h>
24 #include <utility>
25 
26 // namespace UT::FA
27 namespace UT { namespace FA {
28 
29 //
30 // Each function object below implements a math operation that involves
31 // one or more fixed array-like types.
32 // Having each operation as a function object instead of
33 // a free-standing function facilitates (partial) specialization and avoids
34 // the overloading issues that free-standing functions have.
35 // Each function object is parametrized by the element type and tuple size
36 // of the fixed array-like type it works with.
37 // The element type is not are not restricted to a scalar type,
38 // but may itself be a vector-like type.
39 //
40 // None of the below function objects use any type traits to
41 // decide which numeric types and numeric thresholds to use.
42 // Instead, it's up to client code to provide such types and thresholds.
43 //
44 
45 // Assign each element of as to the corresponding element of ts:
46 // For each i in [ 0, SIZE ) do ts[ i ] = as[ i ];
47 template< typename T, exint SIZE >
48 struct Set
49 {
50  template< typename TS >
51  constexpr SYS_FORCE_INLINE void operator()( TS& ts, const TS& as ) const noexcept
52  {
53  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
54 
55  for ( exint i = 0; i != SIZE; ++i )
56  {
57  ts[ i ] = as[ i ];
58  }
59  }
60 };
61 
62 // Convert each element of as to the corresponding element of ts:
63 // For each i in [ 0, SIZE ) do ts[ i ] = as[ i ];
64 template< typename T, exint SIZE, typename A >
65 struct Convert
66 {
67  template< typename TS, typename AS >
68  constexpr SYS_FORCE_INLINE void operator()( TS& ts, const AS& as ) const noexcept
69  {
70  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
71  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< AS, A, SIZE > );
72 
73  for ( exint i = 0; i != SIZE; ++i )
74  {
75  ts[ i ] = as[ i ];
76  }
77  }
78 };
79 
80 // Add each element of as to the corresponding element of ts:
81 // For each i in [ 0, SIZE ) do ts[ i ] += as[ i ];
82 template< typename T, exint SIZE >
83 struct Add
84 {
85  template< typename TS >
86  constexpr SYS_FORCE_INLINE void operator()( TS& ts, const TS& as ) const noexcept
87  {
88  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
89 
90  for ( exint i = 0; i != SIZE; ++i )
91  {
92  ts[ i ] += as[ i ];
93  }
94  }
95 };
96 
97 // Subtract each element of as from the corresponding element of ts:
98 // For each i in [ 0, SIZE ) do ts[ i ] -= as[ i ];
99 template< typename T, exint SIZE >
100 struct Subtract
101 {
102  template< typename TS >
103  constexpr SYS_FORCE_INLINE void operator()( TS& ts, const TS& as ) const noexcept
104  {
105  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
106 
107  for ( exint i = 0; i != SIZE; ++i )
108  {
109  ts[ i ] -= as[ i ];
110  }
111  }
112 };
113 
114 // Multiply each element of 'ts' by 'a':
115 // For each i in [ 0, SIZE ) do ts[ i ] *= a;
116 template< typename T, exint SIZE, typename S = T >
117 struct Scale
118 {
119  template< typename TS >
120  constexpr SYS_FORCE_INLINE void operator()( TS& ts, const S& a ) const noexcept
121  {
122  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
123 
124  for ( exint i = 0; i != SIZE; ++i )
125  {
126  ts[ i ] *= a;
127  }
128  }
129 };
130 
131 // Divide each element of 'ts' by 'a':
132 // For each i in [ 0, SIZE ) do ts[ i ] /= a;
133 template< typename T, exint SIZE, typename S = T >
134 struct Divide
135 {
136  template< typename TS >
137  constexpr SYS_FORCE_INLINE void operator()( TS& ts, const S& a ) const noexcept
138  {
139  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
140 
141  for ( exint i = 0; i != SIZE; ++i )
142  {
143  ts[ i ] /= a;
144  }
145  }
146 };
147 
148 // Negate each element of ts:
149 // For each i in [ 0, SIZE ) do ts[ i ] = -ts[ i ];
150 template< typename T, exint SIZE >
151 struct Negate
152 {
153  template< typename TS >
154  constexpr SYS_FORCE_INLINE void operator()( TS& ts ) const noexcept
155  {
156  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
157 
158  for ( exint i = 0; i != SIZE; ++i )
159  {
160  ts[ i ] = -ts[ i ];
161  }
162  }
163 };
164 
165 // Assign 'a' to each element of ts:
166 // For each i in [ 0, SIZE ) do ts[ i ] = a
167 template< typename T, exint SIZE >
169 {
170  template< typename TS >
171  constexpr SYS_FORCE_INLINE void operator()( TS& ts, const T& a ) const noexcept
172  {
173  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
174 
175  for ( exint i = 0; i != SIZE; ++i )
176  {
177  ts[ i ] = a;
178  }
179  }
180 };
181 
182 // Add 'a' to each element of ts:
183 // For each i in [ 0, SIZE ) do ts[ i ] += a
184 template< typename T, exint SIZE >
186 {
187  template< typename TS >
188  constexpr SYS_FORCE_INLINE void operator()( TS& ts, const T& a ) const noexcept
189  {
190  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
191 
192  for ( exint i = 0; i != SIZE; ++i )
193  {
194  ts[ i ] += a;
195  }
196  }
197 };
198 
199 // Subtract 'a' from each element of ts:
200 // For each i in [ 0, SIZE ) do ts[ i ] -= a
201 template< typename T, exint SIZE >
203 {
204  template< typename TS >
205  constexpr SYS_FORCE_INLINE void operator()( TS& ts, const T& a ) const noexcept
206  {
207  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
208 
209  for ( exint i = 0; i != SIZE; ++i )
210  {
211  ts[ i ] -= a;
212  }
213  }
214 };
215 
216 // Multiply each element of ts with the corresponding element of as:
217 // For each i in [ 0, SIZE ) do ts[ i ] *= as[ i ];
218 template< typename T, exint SIZE >
220 {
221  template< typename TS >
222  constexpr SYS_FORCE_INLINE void operator()( TS& ts, const TS& as ) const noexcept
223  {
224  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
225 
226  for( exint i = 0; i != SIZE; ++i )
227  {
228  ts[ i ] *= as[ i ];
229  }
230  }
231 };
232 
233 // Divide each element of ts by the corresponding element of as:
234 // For each i in [ 0, SIZE ) do ts[ i ] /= as[ i ];
235 template< typename T, exint SIZE >
237 {
238  template< typename TS >
239  constexpr SYS_FORCE_INLINE void operator()( TS& ts, const TS& as ) const noexcept
240  {
241  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
242 
243  for( exint i = 0; i != SIZE; ++i )
244  {
245  ts[ i ] /= as[ i ];
246  }
247  }
248 };
249 
250 template< typename T, typename = void >
252 
253 template< typename T >
254 struct HasDotFunction< T, SYS_Void_t< decltype( dot( std::declval< T >(), std::declval< T >() ) ) > > : SYS_TrueType {};
255 
256 template< typename T >
258 
259 //
260 // Dot returns the dot products of elements of as and bs:
261 // the sum over i in [ 0, SIZE ) of the dot product of as[ i ] and bs[ i ].
262 // If there exists a dot function that takes a pair of T values,
263 // then the dot product is computed using that dot function,
264 // otherwise, as[ i ] * bs[ i ] is used.
265 // To make Dot work correctly over a complex number type T,
266 // provide a function dot that computes the product of as[ i ]
267 // and the complex conjugate of bs[ i ].
268 //
269 
270 namespace Impl
271 {
272 
273 // Case where the element type does not have a 'dot' function defined in it
274 template< typename T, exint SIZE >
275 struct DotAtomic
276 {
277  using R = SYS_RemoveCVRef_t< decltype( std::declval< T >() * std::declval< T >() ) >;
278 
279  template< typename TS >
280  constexpr SYS_FORCE_INLINE R operator()( const TS& as, const TS& bs ) const noexcept
281  {
282  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
283 
284  const auto a_0{ as[ 0 ] };
285  const auto b_0{ bs[ 0 ] };
286  R r{ a_0 * b_0 };
287 
288  for ( exint i = 1; i != SIZE; ++i )
289  {
290  const auto a_i{ as[ i ] };
291  const auto b_i{ bs[ i ] };
292  r += a_i * b_i;
293  }
294 
295  return r;
296  }
297 };
298 
299 // Case where the element type has a 'dot' function defined on it
300 template< typename T, exint SIZE >
302 {
303  using R = SYS_RemoveCVRef_t< decltype( dot( std::declval< T >(), std::declval< T >() ) ) >;
304 
305  template< typename TS >
306  constexpr SYS_FORCE_INLINE R operator()( const TS& as, const TS& bs ) const noexcept
307  {
308  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
309 
310  R r{ dot( as[ 0 ], bs[ 0 ] ) };
311 
312  for ( exint i = 1; i != SIZE; ++i )
313  {
314  r += dot( as[ i ], bs[ i ] );
315  }
316 
317  return r;
318  }
319 };
320 
321 }
322 // namespace Impl
323 
324 template< typename T, exint SIZE >
326  HasDotFunction_v< T >,
327  Impl::DotComposite< T, SIZE >,
328  Impl::DotAtomic< T, SIZE >
329 >
330 {};
331 
332 // Alias template for use in places where auto return types cannot be used
333 template< typename T, exint SIZE >
335 
336 template< typename T, exint SIZE >
337 struct Length2
338 {
339  using R = SYS_RemoveCVRef_t< decltype( Dot< T, SIZE >{}( std::declval< T >(), std::declval< T >() ) ) >;
340 
341  template< typename TS >
342  constexpr SYS_FORCE_INLINE R operator()( const TS& as ) const noexcept
343  {
344  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
345 
346  return Dot< T, SIZE >{}( as, as );
347  }
348 };
349 
350 // Alias template for use in places where auto return types cannot be used
351 template< typename T, exint SIZE >
353 
354 template< typename T, exint SIZE >
355 struct Distance2
356 {
357  template< typename TS >
358  constexpr SYS_FORCE_INLINE T operator()( const TS& as, const TS& bs ) const noexcept
359  {
360  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
361 
362  TS ds{};
363  for ( exint i = 0; i != SIZE; ++i )
364  {
365  ds[ i ] = bs[ i ];
366  ds[ i ] -= as[ i ];
367  }
368 
369  return Length2< T, SIZE >{}( ds );
370  }
371 };
372 
373 //TODO: This uses three floating-point types: T, U, and MF. Can this be simplified?
374 template< typename T, exint SIZE, typename MF = T, typename U = T >
375 struct Normalize
376 {
377  template< typename TS >
378  SYS_FORCE_INLINE MF operator()( TS& ts, const MF l2_min ) const noexcept
379  {
380  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
381 
382  const U l2{ Length2< T, SIZE >{}( ts ) };
383 
384  if ( l2 <= l2_min )
385  {
386  return MF{ 0 };
387  }
388 
389  if ( l2 == U{ 1 } )
390  {
391  return MF{ 1 };
392  }
393 
394  const MF l{ SYSsqrt( MF( l2 ) ) };
395 
396  // Check if the square root is equal 1. sqrt(1+dx) ~ 1+dx/2,
397  // so it may get rounded to 1 when it wasn't 1 before.
398  if ( l != MF{ 1 } )
399  {
400  //TODO: Is this reciprocal pre-compute still worth it?
401  const MF il{ MF{ 1 } / l };
402 
403  for ( exint i = 0; i != SIZE; ++i )
404  {
405  ts[ i ] *= il;
406  }
407  }
408 
409  return l;
410  }
411 };
412 
413 // Return whether p is true for all the elements (each one)
414 template< typename T, exint SIZE >
415 struct AllOf
416 {
417  template< typename TS, typename UNARY_PREDICATE >
418  constexpr SYS_FORCE_INLINE bool operator()( const TS& as, const UNARY_PREDICATE p ) const noexcept
419  {
420  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
421 
422  for ( exint i = 0; i != SIZE; ++i )
423  {
424  if( ! p( as[ i ] ) )
425  {
426  return false;
427  }
428  }
429 
430  return true;
431  }
432 };
433 
434 // Return whether p is true for any elements (at least one)
435 template< typename T, exint SIZE >
436 struct AnyOf
437 {
438  template< typename TS, typename UNARY_PREDICATE >
439  constexpr SYS_FORCE_INLINE bool operator()( const TS& as, const UNARY_PREDICATE p ) const noexcept
440  {
441  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
442 
443  for ( exint i = 0; i != SIZE; ++i )
444  {
445  if( p( as[ i ] ) )
446  {
447  return true;
448  }
449  }
450 
451  return false;
452  }
453 };
454 
455 // Return whether as[ i ] == 0, for each component i in [ 0, SIZE )
456 // This relies only on operator== for the underlying type T.
457 template< typename T, exint SIZE >
459 {
460  template< typename TS >
461  constexpr SYS_FORCE_INLINE bool operator()( const TS& as ) const noexcept
462  {
463  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
464 
465  for ( exint i = 0; i != SIZE; ++i )
466  {
467  if( ! ( as[ i ] == T{ 0 } ) )
468  {
469  return false;
470  }
471  }
472 
473  return true;
474  }
475 };
476 
477 // Return whether as[ i ] == bs[ i ], for each component i in [ 0, SIZE )
478 // This relies only on operator== for the underlying type T.
479 template< typename T, exint SIZE >
480 struct AreEqual
481 {
482  template< typename TS >
483  constexpr SYS_FORCE_INLINE bool operator()( const TS& as, const TS& bs ) const noexcept
484  {
485  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
486 
487  for ( exint i = 0; i != SIZE; ++i )
488  {
489  if( ! ( as[ i ] == bs[ i ] ) )
490  {
491  return false;
492  }
493  }
494 
495  return true;
496  }
497 };
498 
499 // Return whether the maximum norm of 'as' is less than or equal to 'e'.
500 // This returns true if and only if each element of 'as' has absolute value
501 // less than or equal to 'e'
502 // This relies only on operator< for the underlying type T.
503 template< typename T, exint SIZE >
505 {
506  template< typename TS >
507  constexpr SYS_FORCE_INLINE bool operator()( const TS& as, const T e ) const noexcept
508  {
509  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
510 
511  for ( exint i = 0; i != SIZE; ++i )
512  {
513  if ( ( as[ i ] < -e ) || ( e < as[ i ] ) )
514  {
515  return false;
516  }
517  }
518 
519  return true;
520  }
521 };
522 
523 // Return whether the maximum metric of 'as' and 'bs' is less than or equal to 'e'.
524 // This returns true if and only if each componentwise difference has absolute value
525 // less than or equal to 'e'
526 // This relies only on operator< for the underlying type T.
527 template< typename T, exint SIZE >
529 {
530  template< typename TS >
531  constexpr SYS_FORCE_INLINE bool operator()( const TS& as, const TS& bs, const T e ) const noexcept
532  {
533  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
534 
535  for ( exint i = 0; i != SIZE; ++i )
536  {
537  if ( ( as[ i ] < bs[ i ] - e ) || ( bs[ i ] + e < as[ i ] ) )
538  {
539  return false;
540  }
541  }
542 
543  return true;
544  }
545 };
546 
547 // Return the maximum component
548 // This relies only on operator< for the underlying type T.
549 template< typename T, exint SIZE >
550 struct Max
551 {
552  template< typename TS >
553  constexpr SYS_FORCE_INLINE T operator()( const TS& as ) const noexcept
554  {
555  T t{ as[ 0 ] };
556 
557  for ( exint i = 1; i != SIZE; ++i )
558  {
559  t = ( t < as[ i ] ) ? as[ i ] : t;
560  }
561 
562  return t;
563  }
564 };
565 
566 // Return the minimum component
567 // This relies only on operator< for the underlying type T.
568 template< typename T, exint SIZE >
569 struct Min
570 {
571  template< typename TS >
572  constexpr SYS_FORCE_INLINE T operator()( const TS& as ) const noexcept
573  {
574  T t{ as[ 0 ] };
575 
576  for ( exint i = 1; i != SIZE; ++i )
577  {
578  t = ( as[ i ] < t ) ? as[ i ] : t;
579  }
580 
581  return t;
582  }
583 };
584 
585 // Return the sum of the components
586 // This relies only on operator+= for the underlying type T.
587 template< typename T, exint SIZE >
588 struct Sum
589 {
590  template< typename TS >
591  constexpr SYS_FORCE_INLINE T operator()( const TS& as ) const noexcept
592  {
593  T t{ as[ 0 ] };
594 
595  for ( exint i = 1; i != SIZE; ++i )
596  {
597  t += as[ i ];
598  }
599 
600  return t;
601  }
602 };
603 
604 // Based on lexicographical order, return
605 // -1, if as < bs
606 // 1, if bs < as
607 // 0, otherwise.
608 // This relies only on operator< for the underlying type T.
609 template< typename T, exint SIZE >
611 {
612  template< typename TS >
613  constexpr SYS_FORCE_INLINE int operator()( const TS& as, const TS& bs ) const noexcept
614  {
615  SYS_STATIC_ASSERT( SYS_IsFixedArrayOf_v< TS, T, SIZE > );
616 
617  for ( exint i = 0; i != SIZE; ++i )
618  {
619  if( as[ i ] < bs[ i ] )
620  {
621  return -1;
622  }
623 
624  if( bs[ i ] < as[ i ] )
625  {
626  return 1;
627  }
628  }
629 
630  return 0;
631  }
632 };
633 
634 } }
635 // end of namespace UT::FA
636 
637 #endif
638 
SYS_FORCE_INLINE MF operator()(TS &ts, const MF l2_min) const noexcept
constexpr SYS_FORCE_INLINE void operator()(TS &ts, const T &a) const noexcept
constexpr SYS_FORCE_INLINE void operator()(TS &ts, const AS &as) const noexcept
#define SYS_STATIC_ASSERT(expr)
typename std::conditional< B, T, F >::type conditional_t
Definition: core.h:322
void SYS_Void_t
Alternative for C++17's std::void that can be used in C++14:
constexpr SYS_FORCE_INLINE void operator()(TS &ts, const S &a) const noexcept
constexpr SYS_FORCE_INLINE void operator()(TS &ts, const S &a) const noexcept
constexpr SYS_FORCE_INLINE void operator()(TS &ts, const TS &as) const noexcept
int64 exint
Definition: SYS_Types.h:125
constexpr SYS_FORCE_INLINE T operator()(const TS &as, const TS &bs) const noexcept
constexpr SYS_FORCE_INLINE R operator()(const TS &as, const TS &bs) const noexcept
SYS_RemoveCVRef_t< decltype(Dot< T, SIZE >{}(std::declval< T >(), std::declval< T >())) > R
typename SYS_RemoveCVRef< T >::type SYS_RemoveCVRef_t
constexpr SYS_FORCE_INLINE void operator()(TS &ts, const TS &as) const noexcept
GLdouble GLdouble t
Definition: glew.h:1403
constexpr SYS_FORCE_INLINE R operator()(const TS &as) const noexcept
GLdouble l
Definition: glew.h:9164
constexpr SYS_FORCE_INLINE bool operator()(const TS &as, const T e) const noexcept
constexpr SYS_FORCE_INLINE void operator()(TS &ts, const TS &as) const noexcept
constexpr SYS_FORCE_INLINE bool operator()(const TS &as, const UNARY_PREDICATE p) const noexcept
constexpr SYS_FORCE_INLINE T operator()(const TS &as) const noexcept
fpreal64 dot(const CE_VectorT< T > &a, const CE_VectorT< T > &b)
Definition: CE_Vector.h:130
GLboolean GLboolean GLboolean GLboolean a
Definition: glcorearb.h:1222
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
constexpr SYS_FORCE_INLINE bool operator()(const TS &as) const noexcept
constexpr SYS_FORCE_INLINE bool operator()(const TS &as, const TS &bs) const noexcept
typename Dot< T, SIZE >::R DotReturn_t
constexpr SYS_FORCE_INLINE T operator()(const TS &as) const noexcept
GLfloat GLfloat p
Definition: glew.h:16656
constexpr SYS_FORCE_INLINE void operator()(TS &ts) const noexcept
constexpr SYS_FORCE_INLINE T operator()(const TS &as) const noexcept
constexpr SYS_FORCE_INLINE void operator()(TS &ts, const TS &as) const noexcept
constexpr SYS_FORCE_INLINE void operator()(TS &ts, const T &a) const noexcept
SYS_RemoveCVRef_t< decltype(std::declval< T >()*std::declval< T >()) > R
constexpr bool HasDotFunction_v
#define SIZE
Definition: simple.C:40
constexpr SYS_FORCE_INLINE void operator()(TS &ts, const T &a) const noexcept
constexpr SYS_FORCE_INLINE bool operator()(const TS &as, const UNARY_PREDICATE p) const noexcept
typename Length2< T, SIZE >::R Length2Return_t
constexpr SYS_FORCE_INLINE bool operator()(const TS &as, const TS &bs, const T e) const noexcept
constexpr SYS_FORCE_INLINE int operator()(const TS &as, const TS &bs) const noexcept
constexpr SYS_FORCE_INLINE R operator()(const TS &as, const TS &bs) const noexcept
SYS_RemoveCVRef_t< decltype(dot(std::declval< T >(), std::declval< T >())) > R
GLboolean r
Definition: glcorearb.h:1222
constexpr SYS_FORCE_INLINE void operator()(TS &ts, const TS &as) const noexcept