1//
2// SPDX-License-Identifier: BSD-3-Clause
3// Copyright Contributors to the OpenEXR Project.
4//
5
6//
7// A representation of a shear transformation
8//
9
10#ifndef INCLUDED_IMATHSHEAR_H
11#define INCLUDED_IMATHSHEAR_H
12
13#include "ImathExport.h"
14#include "ImathNamespace.h"
15
16#include "ImathMath.h"
17#include "ImathVec.h"
18#include <iostream>
19
20IMATH_INTERNAL_NAMESPACE_HEADER_ENTER
21
22///
23/// Shear6 class template.
24///
25/// A shear matrix is technically defined as having a single nonzero
26/// off-diagonal element; more generally, a shear transformation is
27/// defined by those off-diagonal elements, so in 3D, that means there
28/// are 6 possible elements/coefficients:
29///
30/// | X' | | 1 YX ZX 0 | | X |
31/// | Y' | | XY 1 ZY 0 | | Y |
32/// | Z' | = | XZ YZ 1 0 | = | Z |
33/// | 1 | | 0 0 0 1 | | 1 |
34///
35/// X' = X + YX * Y + ZX * Z
36/// Y' = YX * X + Y + ZY * Z
37/// Z` = XZ * X + YZ * Y + Z
38///
39/// See
40/// https://www.cs.drexel.edu/~david/Classes/CS430/Lectures/L-04_3DTransformations.6.pdf
41///
42/// Those variable elements correspond to the 6 values in a Shear6.
43/// So, looking at those equations, "Shear YX", for example, means
44/// that for any point transformed by that matrix, its X values will
45/// have some of their Y values added. If you're talking
46/// about "Axis A has values from Axis B added to it", there are 6
47/// permutations for A and B (XY, XZ, YX, YZ, ZX, ZY).
48///
49/// Not that Maya has only three values, which represent the
50/// lower/upper (depending on column/row major) triangle of the
51/// matrix. Houdini is the same as Maya (see
52/// https://www.sidefx.com/docs/houdini/props/obj.html) in this
53/// respect.
54///
55/// There's another way to look at it. A general affine transformation
56/// in 3D has 12 degrees of freedom - 12 "available" elements in the
57/// 4x4 matrix since a single row/column must be (0,0,0,1). If you
58/// add up the degrees of freedom from Maya:
59///
60/// - 3 translation
61/// - 3 rotation
62/// - 3 scale
63/// - 3 shear
64///
65/// You obviously get the full 12. So technically, the Shear6 option
66/// of having all 6 shear options is overkill; Imath/Shear6 has 15
67/// values for a 12-degree-of-freedom transformation. This means that
68/// any nonzero values in those last 3 shear coefficients can be
69/// represented in those standard 12 degrees of freedom. Here's a
70/// python example of how to do that:
71///
72///
73/// >>> import imath
74/// >>> M = imath.M44f()
75/// >>> s = imath.V3f()
76/// >>> h = imath.V3f()
77/// >>> r = imath.V3f()
78/// >>> t = imath.V3f()
79/// # Use Shear.YX (index 3), which is an "extra" shear value
80/// >>> M.setShear((0,0,0,1,0,0))
81/// M44f((1, 1, 0, 0), (0, 1, 0, 0), (0, 0, 1, 0), (0, 0, 0, 1))
82/// >>> M.extractSHRT(s, h, r, t)
83/// 1
84/// >>> s
85/// V3f(1.41421354, 0.707106769, 1)
86/// >>> h
87/// V3f(1, 0, 0)
88/// >>> r
89/// V3f(0, -0, 0.785398185)
90/// >>> t
91/// V3f(0, 0, 0)
92///
93/// That shows how to decompose a transform matrix with one of those
94/// "extra" shear coefficients into those standard 12 degrees of
95/// freedom. But it's not necessarily intuitive; in this case, a
96/// single non-zero shear coefficient resulted in a transform that has
97/// non-uniform scale, a single "standard" shear value, and some
98/// rotation.
99///
100/// So, it would seem that any transform with those extra shear
101/// values set could be translated into Maya to produce the exact same
102/// transformation matrix; but doing this is probably pretty
103/// undesirable, since the result would have some surprising values on
104/// the other transformation attributes, despite being technically
105/// correct.
106///
107/// This usage of "degrees of freedom" is a bit hand-wavey here;
108/// having a total of 12 inputs into the construction of a standard
109/// transformation matrix doesn't necessarily mean that the matrix has
110/// 12 true degrees of freedom, but the standard
111/// translation/rotation/scale/shear matrices have the right
112/// construction to ensure that.
113///
114
115template <class T> class IMATH_EXPORT_TEMPLATE_TYPE Shear6
116{
117 public:
118
119 /// @{
120 /// @name Direct access to members
121
122 T xy, xz, yz, yx, zx, zy;
123
124 /// @}
125
126 /// Element access
127 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 T& operator[] (int i);
128
129 /// Element access
130 IMATH_HOSTDEVICE constexpr const T& operator[] (int i) const;
131
132 /// @{
133 /// @name Constructors and Assignment
134
135 /// Initialize to 0
136 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Shear6();
137
138 /// Initialize to the given XY, XZ, YZ values
139 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Shear6 (T XY, T XZ, T YZ);
140
141 /// Initialize to the given XY, XZ, YZ values held in (v.x, v.y, v.z)
142 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Shear6 (const Vec3<T>& v);
143
144 /// Initialize to the given XY, XZ, YZ values held in (v.x, v.y, v.z)
145 template <class S>
146 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Shear6 (const Vec3<S>& v);
147
148 /// Initialize to the given (XY XZ YZ YX ZX ZY) values
149 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Shear6 (T XY,
150 T XZ,
151 T YZ,
152 T YX,
153 T ZX,
154 T ZY);
155
156 /// Copy constructor
157 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Shear6 (const Shear6& h);
158
159 /// Construct from a Shear6 object of another base type
160 template <class S> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 Shear6 (const Shear6<S>& h);
161
162 /// Assignment
163 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Shear6& operator= (const Shear6& h);
164
165 /// Assignment from vector
166 template <class S>
167 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Shear6& operator= (const Vec3<S>& v);
168
169 /// Destructor
170 ~Shear6() = default;
171
172 /// @}
173
174 /// @{
175 /// @name Compatibility with Sb
176
177 /// Set the value
178 template <class S> IMATH_HOSTDEVICE void setValue (S XY, S XZ, S YZ, S YX, S ZX, S ZY);
179
180 /// Set the value
181 template <class S> IMATH_HOSTDEVICE void setValue (const Shear6<S>& h);
182
183 /// Return the values
184 template <class S>
185 IMATH_HOSTDEVICE void getValue (S& XY, S& XZ, S& YZ, S& YX, S& ZX, S& ZY) const;
186
187 /// Return the value in `h`
188 template <class S> IMATH_HOSTDEVICE void getValue (Shear6<S>& h) const;
189
190 /// Return a raw pointer to the array of values
191 IMATH_HOSTDEVICE T* getValue();
192
193 /// Return a raw pointer to the array of values
194 IMATH_HOSTDEVICE const T* getValue() const;
195
196 /// @}
197
198 /// @{
199 /// @name Arithmetic and Comparison
200
201 /// Equality
202 template <class S> IMATH_HOSTDEVICE constexpr bool operator== (const Shear6<S>& h) const;
203
204 /// Inequality
205 template <class S> IMATH_HOSTDEVICE constexpr bool operator!= (const Shear6<S>& h) const;
206
207 /// Compare two shears and test if they are "approximately equal":
208 /// @return True if the coefficients of this and h are the same with
209 /// an absolute error of no more than e, i.e., for all i
210 /// abs (this[i] - h[i]) <= e
211 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithAbsError (const Shear6<T>& h, T e) const;
212
213 /// Compare two shears and test if they are "approximately equal":
214 /// @return True if the coefficients of this and h are the same with
215 /// a relative error of no more than e, i.e., for all i
216 /// abs (this[i] - h[i]) <= e * abs (this[i])
217 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 bool equalWithRelError (const Shear6<T>& h, T e) const;
218
219 /// Component-wise addition
220 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Shear6& operator+= (const Shear6& h);
221
222 /// Component-wise addition
223 IMATH_HOSTDEVICE constexpr Shear6 operator+ (const Shear6& h) const;
224
225 /// Component-wise subtraction
226 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Shear6& operator-= (const Shear6& h);
227
228 /// Component-wise subtraction
229 IMATH_HOSTDEVICE constexpr Shear6 operator- (const Shear6& h) const;
230
231 /// Component-wise multiplication by -1
232 IMATH_HOSTDEVICE constexpr Shear6 operator-() const;
233
234 /// Component-wise multiplication by -1
235 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Shear6& negate();
236
237 /// Component-wise multiplication
238 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Shear6& operator*= (const Shear6& h);
239 /// Scalar multiplication
240 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Shear6& operator*= (T a);
241
242 /// Component-wise multiplication
243 IMATH_HOSTDEVICE constexpr Shear6 operator* (const Shear6& h) const;
244
245 /// Scalar multiplication
246 IMATH_HOSTDEVICE constexpr Shear6 operator* (T a) const;
247
248 /// Component-wise division
249 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Shear6& operator/= (const Shear6& h);
250
251 /// Scalar division
252 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 const Shear6& operator/= (T a);
253
254 /// Component-wise division
255 IMATH_HOSTDEVICE constexpr Shear6 operator/ (const Shear6& h) const;
256
257 /// Scalar division
258 IMATH_HOSTDEVICE constexpr Shear6 operator/ (T a) const;
259
260 /// @}
261
262 /// @{
263 /// @name Numerical Limits
264
265 /// Largest possible negative value
266 IMATH_HOSTDEVICE constexpr static T baseTypeLowest() IMATH_NOEXCEPT { return std::numeric_limits<T>::lowest(); }
267
268 /// Largest possible positive value
269 IMATH_HOSTDEVICE constexpr static T baseTypeMax() IMATH_NOEXCEPT { return std::numeric_limits<T>::max(); }
270
271 /// Smallest possible positive value
272 IMATH_HOSTDEVICE constexpr static T baseTypeSmallest() IMATH_NOEXCEPT { return std::numeric_limits<T>::min(); }
273
274 /// Smallest possible e for which 1+e != 1
275 IMATH_HOSTDEVICE constexpr static T baseTypeEpsilon() IMATH_NOEXCEPT { return std::numeric_limits<T>::epsilon(); }
276
277 /// @}
278
279 /// Return the number of dimensions, i.e. 6
280 IMATH_HOSTDEVICE constexpr static unsigned int dimensions() { return 6; }
281
282 /// The base type: In templates that accept a parameter `V` (could
283 /// be a Color4), you can refer to `T` as `V::BaseType`
284 typedef T BaseType;
285};
286
287/// Stream output, as "(xy xz yz yx zx zy)"
288template <class T> std::ostream& operator<< (std::ostream& s, const Shear6<T>& h);
289
290/// Reverse multiplication: scalar * Shear6<T>
291template <class S, class T>
292IMATH_HOSTDEVICE constexpr Shear6<T> operator* (S a, const Shear6<T>& h);
293
294/// 3D shear of type float
295typedef Vec3<float> Shear3f;
296
297/// 3D shear of type double
298typedef Vec3<double> Shear3d;
299
300/// Shear6 of type float
301typedef Shear6<float> Shear6f;
302
303/// Shear6 of type double
304typedef Shear6<double> Shear6d;
305
306//-----------------------
307// Implementation of Shear6
308//-----------------------
309
310template <class T>
311IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T&
312Shear6<T>::operator[] (int i)
313{
314 return (&xy)[i]; // NOSONAR - suppress SonarCloud bug report.
315}
316
317template <class T>
318IMATH_HOSTDEVICE constexpr inline const T&
319Shear6<T>::operator[] (int i) const
320{
321 return (&xy)[i]; // NOSONAR - suppress SonarCloud bug report.
322}
323
324template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Shear6<T>::Shear6()
325{
326 xy = xz = yz = yx = zx = zy = 0;
327}
328
329template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Shear6<T>::Shear6 (T XY, T XZ, T YZ)
330{
331 xy = XY;
332 xz = XZ;
333 yz = YZ;
334 yx = 0;
335 zx = 0;
336 zy = 0;
337}
338
339template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Shear6<T>::Shear6 (const Vec3<T>& v)
340{
341 xy = v.x;
342 xz = v.y;
343 yz = v.z;
344 yx = 0;
345 zx = 0;
346 zy = 0;
347}
348
349template <class T>
350template <class S>
351IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Shear6<T>::Shear6 (const Vec3<S>& v)
352{
353 xy = T (v.x);
354 xz = T (v.y);
355 yz = T (v.z);
356 yx = 0;
357 zx = 0;
358 zy = 0;
359}
360
361template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Shear6<T>::Shear6 (T XY, T XZ, T YZ, T YX, T ZX, T ZY)
362{
363 xy = XY;
364 xz = XZ;
365 yz = YZ;
366 yx = YX;
367 zx = ZX;
368 zy = ZY;
369}
370
371template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Shear6<T>::Shear6 (const Shear6& h)
372{
373 xy = h.xy;
374 xz = h.xz;
375 yz = h.yz;
376 yx = h.yx;
377 zx = h.zx;
378 zy = h.zy;
379}
380
381template <class T>
382template <class S>
383IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Shear6<T>::Shear6 (const Shear6<S>& h)
384{
385 xy = T (h.xy);
386 xz = T (h.xz);
387 yz = T (h.yz);
388 yx = T (h.yx);
389 zx = T (h.zx);
390 zy = T (h.zy);
391}
392
393template <class T>
394IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
395Shear6<T>::operator= (const Shear6& h)
396{
397 xy = h.xy;
398 xz = h.xz;
399 yz = h.yz;
400 yx = h.yx;
401 zx = h.zx;
402 zy = h.zy;
403 return *this;
404}
405
406template <class T>
407template <class S>
408IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
409Shear6<T>::operator= (const Vec3<S>& v)
410{
411 xy = T (v.x);
412 xz = T (v.y);
413 yz = T (v.z);
414 yx = 0;
415 zx = 0;
416 zy = 0;
417 return *this;
418}
419
420template <class T>
421template <class S>
422IMATH_HOSTDEVICE inline void
423Shear6<T>::setValue (S XY, S XZ, S YZ, S YX, S ZX, S ZY)
424{
425 xy = T (XY);
426 xz = T (XZ);
427 yz = T (YZ);
428 yx = T (YX);
429 zx = T (ZX);
430 zy = T (ZY);
431}
432
433template <class T>
434template <class S>
435IMATH_HOSTDEVICE inline void
436Shear6<T>::setValue (const Shear6<S>& h)
437{
438 xy = T (h.xy);
439 xz = T (h.xz);
440 yz = T (h.yz);
441 yx = T (h.yx);
442 zx = T (h.zx);
443 zy = T (h.zy);
444}
445
446template <class T>
447template <class S>
448IMATH_HOSTDEVICE inline void
449Shear6<T>::getValue (S& XY, S& XZ, S& YZ, S& YX, S& ZX, S& ZY) const
450{
451 XY = S (xy);
452 XZ = S (xz);
453 YZ = S (yz);
454 YX = S (yx);
455 ZX = S (zx);
456 ZY = S (zy);
457}
458
459template <class T>
460template <class S>
461IMATH_HOSTDEVICE inline void
462Shear6<T>::getValue (Shear6<S>& h) const
463{
464 h.xy = S (xy);
465 h.xz = S (xz);
466 h.yz = S (yz);
467 h.yx = S (yx);
468 h.zx = S (zx);
469 h.zy = S (zy);
470}
471
472template <class T>
473IMATH_HOSTDEVICE inline T*
474Shear6<T>::getValue()
475{
476 return (T*) &xy;
477}
478
479template <class T>
480IMATH_HOSTDEVICE inline const T*
481Shear6<T>::getValue() const
482{
483 return (const T*) &xy;
484}
485
486template <class T>
487template <class S>
488IMATH_HOSTDEVICE constexpr inline bool
489Shear6<T>::operator== (const Shear6<S>& h) const
490{
491 return xy == h.xy && xz == h.xz && yz == h.yz && yx == h.yx && zx == h.zx && zy == h.zy;
492}
493
494template <class T>
495template <class S>
496IMATH_HOSTDEVICE constexpr inline bool
497Shear6<T>::operator!= (const Shear6<S>& h) const
498{
499 return xy != h.xy || xz != h.xz || yz != h.yz || yx != h.yx || zx != h.zx || zy != h.zy;
500}
501
502template <class T>
503IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
504Shear6<T>::equalWithAbsError (const Shear6<T>& h, T e) const
505{
506 for (int i = 0; i < 6; i++)
507 if (!IMATH_INTERNAL_NAMESPACE::equalWithAbsError ((*this)[i], h[i], e))
508 return false;
509
510 return true;
511}
512
513template <class T>
514IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
515Shear6<T>::equalWithRelError (const Shear6<T>& h, T e) const
516{
517 for (int i = 0; i < 6; i++)
518 if (!IMATH_INTERNAL_NAMESPACE::equalWithRelError ((*this)[i], h[i], e))
519 return false;
520
521 return true;
522}
523
524template <class T>
525IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
526Shear6<T>::operator+= (const Shear6& h)
527{
528 xy += h.xy;
529 xz += h.xz;
530 yz += h.yz;
531 yx += h.yx;
532 zx += h.zx;
533 zy += h.zy;
534 return *this;
535}
536
537template <class T>
538IMATH_HOSTDEVICE constexpr inline Shear6<T>
539Shear6<T>::operator+ (const Shear6& h) const
540{
541 return Shear6 (xy + h.xy, xz + h.xz, yz + h.yz, yx + h.yx, zx + h.zx, zy + h.zy);
542}
543
544template <class T>
545IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
546Shear6<T>::operator-= (const Shear6& h)
547{
548 xy -= h.xy;
549 xz -= h.xz;
550 yz -= h.yz;
551 yx -= h.yx;
552 zx -= h.zx;
553 zy -= h.zy;
554 return *this;
555}
556
557template <class T>
558IMATH_HOSTDEVICE constexpr inline Shear6<T>
559Shear6<T>::operator- (const Shear6& h) const
560{
561 return Shear6 (xy - h.xy, xz - h.xz, yz - h.yz, yx - h.yx, zx - h.zx, zy - h.zy);
562}
563
564template <class T>
565IMATH_HOSTDEVICE constexpr inline Shear6<T>
566Shear6<T>::operator-() const
567{
568 return Shear6 (-xy, -xz, -yz, -yx, -zx, -zy);
569}
570
571template <class T>
572IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
573Shear6<T>::negate()
574{
575 xy = -xy;
576 xz = -xz;
577 yz = -yz;
578 yx = -yx;
579 zx = -zx;
580 zy = -zy;
581 return *this;
582}
583
584template <class T>
585IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
586Shear6<T>::operator*= (const Shear6& h)
587{
588 xy *= h.xy;
589 xz *= h.xz;
590 yz *= h.yz;
591 yx *= h.yx;
592 zx *= h.zx;
593 zy *= h.zy;
594 return *this;
595}
596
597template <class T>
598IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
599Shear6<T>::operator*= (T a)
600{
601 xy *= a;
602 xz *= a;
603 yz *= a;
604 yx *= a;
605 zx *= a;
606 zy *= a;
607 return *this;
608}
609
610template <class T>
611IMATH_HOSTDEVICE constexpr inline Shear6<T>
612Shear6<T>::operator* (const Shear6& h) const
613{
614 return Shear6 (xy * h.xy, xz * h.xz, yz * h.yz, yx * h.yx, zx * h.zx, zy * h.zy);
615}
616
617template <class T>
618IMATH_HOSTDEVICE constexpr inline Shear6<T>
619Shear6<T>::operator* (T a) const
620{
621 return Shear6 (xy * a, xz * a, yz * a, yx * a, zx * a, zy * a);
622}
623
624template <class T>
625IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
626Shear6<T>::operator/= (const Shear6& h)
627{
628 xy /= h.xy;
629 xz /= h.xz;
630 yz /= h.yz;
631 yx /= h.yx;
632 zx /= h.zx;
633 zy /= h.zy;
634 return *this;
635}
636
637template <class T>
638IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
639Shear6<T>::operator/= (T a)
640{
641 xy /= a;
642 xz /= a;
643 yz /= a;
644 yx /= a;
645 zx /= a;
646 zy /= a;
647 return *this;
648}
649
650template <class T>
651IMATH_HOSTDEVICE constexpr inline Shear6<T>
652Shear6<T>::operator/ (const Shear6& h) const
653{
654 return Shear6 (xy / h.xy, xz / h.xz, yz / h.yz, yx / h.yx, zx / h.zx, zy / h.zy);
655}
656
657template <class T>
658IMATH_HOSTDEVICE constexpr inline Shear6<T>
659Shear6<T>::operator/ (T a) const
660{
661 return Shear6 (xy / a, xz / a, yz / a, yx / a, zx / a, zy / a);
662}
663
664//-----------------------------
665// Stream output implementation
666//-----------------------------
667
668template <class T>
669std::ostream&
670operator<< (std::ostream& s, const Shear6<T>& h)
671{
672 return s << '(' << h.xy << ' ' << h.xz << ' ' << h.yz << h.yx << ' ' << h.zx << ' ' << h.zy
673 << ')';
674}
675
676//-----------------------------------------
677// Implementation of reverse multiplication
678//-----------------------------------------
679
680template <class S, class T>
681IMATH_HOSTDEVICE constexpr inline Shear6<T>
682operator* (S a, const Shear6<T>& h)
683{
684 return Shear6<T> (a * h.xy, a * h.xz, a * h.yz, a * h.yx, a * h.zx, a * h.zy);
685}
686
687IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
688
689#endif // INCLUDED_IMATHSHEAR_H
690

source code of include/Imath/ImathShear.h