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 
20 IMATH_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 
115 template <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     IMATH_HOSTDEVICE ~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
baseTypeLowest()266     IMATH_HOSTDEVICE constexpr static T baseTypeLowest() IMATH_NOEXCEPT { return std::numeric_limits<T>::lowest(); }
267 
268     /// Largest possible positive value
baseTypeMax()269     IMATH_HOSTDEVICE constexpr static T baseTypeMax() IMATH_NOEXCEPT { return std::numeric_limits<T>::max(); }
270 
271     /// Smallest possible positive value
baseTypeSmallest()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
baseTypeEpsilon()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
dimensions()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)"
288 template <class T> std::ostream& operator<< (std::ostream& s, const Shear6<T>& h);
289 
290 /// Reverse multiplication: scalar * Shear6<T>
291 template <class S, class T>
292 IMATH_HOSTDEVICE constexpr Shear6<T> operator* (S a, const Shear6<T>& h);
293 
294 /// 3D shear of type float
295 typedef Vec3<float> Shear3f;
296 
297 /// 3D shear of type double
298 typedef Vec3<double> Shear3d;
299 
300 /// Shear6 of type float
301 typedef Shear6<float> Shear6f;
302 
303 /// Shear6 of type double
304 typedef Shear6<double> Shear6d;
305 
306 //-----------------------
307 // Implementation of Shear6
308 //-----------------------
309 
310 template <class T>
311 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline T&
312 Shear6<T>::operator[] (int i)
313 {
314     return (&xy)[i]; // NOSONAR - suppress SonarCloud bug report.
315 }
316 
317 template <class T>
318 IMATH_HOSTDEVICE constexpr inline const T&
319 Shear6<T>::operator[] (int i) const
320 {
321     return (&xy)[i]; // NOSONAR - suppress SonarCloud bug report.
322 }
323 
Shear6()324 template <class T> IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline Shear6<T>::Shear6()
325 {
326     xy = xz = yz = yx = zx = zy = 0;
327 }
328 
Shear6(T XY,T XZ,T YZ)329 template <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 
Shear6(const Vec3<T> & v)339 template <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 
349 template <class T>
350 template <class S>
Shear6(const Vec3<S> & v)351 IMATH_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 
Shear6(T XY,T XZ,T YZ,T YX,T ZX,T ZY)361 template <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 
Shear6(const Shear6 & h)371 template <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 
381 template <class T>
382 template <class S>
Shear6(const Shear6<S> & h)383 IMATH_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 
393 template <class T>
394 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
395 Shear6<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 
406 template <class T>
407 template <class S>
408 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
409 Shear6<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 
420 template <class T>
421 template <class S>
422 IMATH_HOSTDEVICE inline void
setValue(S XY,S XZ,S YZ,S YX,S ZX,S ZY)423 Shear6<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 
433 template <class T>
434 template <class S>
435 IMATH_HOSTDEVICE inline void
setValue(const Shear6<S> & h)436 Shear6<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 
446 template <class T>
447 template <class S>
448 IMATH_HOSTDEVICE inline void
getValue(S & XY,S & XZ,S & YZ,S & YX,S & ZX,S & ZY)449 Shear6<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 
459 template <class T>
460 template <class S>
461 IMATH_HOSTDEVICE inline void
getValue(Shear6<S> & h)462 Shear6<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 
472 template <class T>
473 IMATH_HOSTDEVICE inline T*
getValue()474 Shear6<T>::getValue()
475 {
476     return (T*) &xy;
477 }
478 
479 template <class T>
480 IMATH_HOSTDEVICE inline const T*
getValue()481 Shear6<T>::getValue() const
482 {
483     return (const T*) &xy;
484 }
485 
486 template <class T>
487 template <class S>
488 IMATH_HOSTDEVICE constexpr inline bool
489 Shear6<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 
494 template <class T>
495 template <class S>
496 IMATH_HOSTDEVICE constexpr inline bool
497 Shear6<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 
502 template <class T>
503 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
equalWithAbsError(const Shear6<T> & h,T e)504 Shear6<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 
513 template <class T>
514 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline bool
equalWithRelError(const Shear6<T> & h,T e)515 Shear6<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 
524 template <class T>
525 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
526 Shear6<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 
537 template <class T>
538 IMATH_HOSTDEVICE constexpr inline Shear6<T>
539 Shear6<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 
544 template <class T>
545 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
546 Shear6<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 
557 template <class T>
558 IMATH_HOSTDEVICE constexpr inline Shear6<T>
559 Shear6<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 
564 template <class T>
565 IMATH_HOSTDEVICE constexpr inline Shear6<T>
566 Shear6<T>::operator-() const
567 {
568     return Shear6 (-xy, -xz, -yz, -yx, -zx, -zy);
569 }
570 
571 template <class T>
572 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
negate()573 Shear6<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 
584 template <class T>
585 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
586 Shear6<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 
597 template <class T>
598 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
599 Shear6<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 
610 template <class T>
611 IMATH_HOSTDEVICE constexpr inline Shear6<T>
612 Shear6<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 
617 template <class T>
618 IMATH_HOSTDEVICE constexpr inline Shear6<T>
619 Shear6<T>::operator* (T a) const
620 {
621     return Shear6 (xy * a, xz * a, yz * a, yx * a, zx * a, zy * a);
622 }
623 
624 template <class T>
625 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
626 Shear6<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 
637 template <class T>
638 IMATH_HOSTDEVICE IMATH_CONSTEXPR14 inline const Shear6<T>&
639 Shear6<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 
650 template <class T>
651 IMATH_HOSTDEVICE constexpr inline Shear6<T>
652 Shear6<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 
657 template <class T>
658 IMATH_HOSTDEVICE constexpr inline Shear6<T>
659 Shear6<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 
668 template <class T>
669 std::ostream&
670 operator<< (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 
680 template <class S, class T>
681 IMATH_HOSTDEVICE constexpr inline Shear6<T>
682 operator* (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 
687 IMATH_INTERNAL_NAMESPACE_HEADER_EXIT
688 
689 #endif // INCLUDED_IMATHSHEAR_H
690