Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
TransformCalculus2D.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreTypes.h"
6#include "Misc/AssertionMacros.h"
7#include "Math/UnrealMathUtility.h"
8#include "Math/Vector2D.h"
9#include "Math/TransformCalculus.h"
10
11//////////////////////////////////////////////////////////////////////////
12// Transform calculus for 2D types. UE4 already has a 2D Vector class that we
13// will adapt to be interpreted as a translate transform. The rest we create
14// new classes for.
15//
16// The following types are supported
17// * float/double -> represents a uniform scale.
18// * FScale2D -> represents a 2D non-uniform scale.
19// * FVector2D -> represents a 2D translation.
20// * FShear2D -> represents a "2D shear", interpreted as a shear parallel to the X axis followed by a shear parallel to the Y axis.
21// * FQuat2D -> represents a pure 2D rotation.
22// * FMatrix2x2 -> represents a general 2D transform.
23//
24//////////////////////////////////////////////////////////////////////////
25
26template<typename T> class TMatrix2x2;
27
28
29//////////////////////////////////////////////////////////////////////////
30// Adapters for TVector2.
31//
32// Since it is an existing UE4 types, we cannot rely on the default
33// template that calls member functions. Instead, we provide direct overloads.
34//////////////////////////////////////////////////////////////////////////
35
36namespace UE
37{
38namespace Math
39{
40
41/** Specialization for concatenating two 2D Translations. */
42template<typename T>
43inline UE::Math::TVector2<T> Concatenate(const UE::Math::TVector2<T>& LHS, const UE::Math::TVector2<T>& RHS)
44{
45 return LHS + RHS;
46}
47
48} // namespace UE::Math
49} // namespace UE
50
51/** Specialization for inverting a 2D translation. */
52template<typename T>
53inline UE::Math::TVector2<T> Inverse(const UE::Math::TVector2<T>& Transform)
54{
55 return -Transform;
56}
57
58/** Specialization for TVector2 Translation. */
59template<typename T>
60inline UE::Math::TVector2<T> TransformPoint(const UE::Math::TVector2<T>& Transform, const UE::Math::TVector2<T>& Point)
61{
62 return Transform + Point;
63}
64
65/** Specialization for FVector2D Translation (does nothing). */
66template<typename T>
67inline const UE::Math::TVector2<T>& TransformVector(const UE::Math::TVector2<T>& Transform, const UE::Math::TVector2<T>& Vector)
68{
69 return Vector;
70}
71
72//////////////////////////////////////////////////////////////////////////
73// Adapters for 2D uniform scale.
74//
75// Since it is a fundamental type, we cannot rely on the default
76// template that calls member functions. Instead, we provide direct overloads.
77//////////////////////////////////////////////////////////////////////////
78
79/**
80* Specialization for uniform Scale.
81*/
82template<typename PositionType>
83inline UE::Math::TVector2<PositionType> TransformPoint(float Transform, const UE::Math::TVector2<PositionType>& Point)
84{
85 return Transform * Point;
86}
87
88template<typename PositionType>
89inline UE::Math::TVector2<PositionType> TransformPoint(double Transform, const UE::Math::TVector2<PositionType>& Point)
90{
91 return Transform * Point;
92}
93
94/**
95* Specialization for uniform Scale.
96*/
97template<typename VectorType>
98inline UE::Math::TVector2<VectorType> TransformVector(float Transform, const UE::Math::TVector2<VectorType>& Vector)
99{
100 return Transform * Vector;
101}
102
103template<typename VectorType>
104inline UE::Math::TVector2<VectorType> TransformVector(double Transform, const UE::Math::TVector2<VectorType>& Vector)
105{
106 return Transform * Vector;
107}
108
109/** Represents a 2D non-uniform scale (to disambiguate from an FVector2D, which is used for translation) */
110template<typename T>
112{
113 static_assert(std::is_floating_point_v<T>, "T must be floating point");
114
115public:
116 using FReal = T;
117 using Vector2Type = UE::Math::TVector2<T>;
118
119 /** Ctor. initialize to an identity scale, 1.0. */
120 TScale2() : Scale(1.0f, 1.0f) {}
121 /** Ctor. initialize from a uniform scale. */
122 explicit TScale2(T InScale) :Scale(InScale, InScale) {}
123 /** Ctor. initialize from a non-uniform scale. */
124 explicit TScale2(T InScaleX, T InScaleY) :Scale(InScaleX, InScaleY) {}
125 /** Ctor. initialize from an FVector defining the 3D scale. */
126 template<typename ArgType>
127 explicit TScale2(const UE::Math::TVector2<ArgType>& InScale) :Scale(InScale) {}
128
129 /** Transform 2D Point */
130 template<typename ArgType>
131 UE::Math::TVector2<ArgType> TransformPoint(const UE::Math::TVector2<ArgType>& Point) const
132 {
133 return UE::Math::TVector2<ArgType>(Scale) * Point;
134 }
135
136 /** Transform 2D Vector*/
137 template<typename ArgType>
138 UE::Math::TVector2<ArgType> TransformVector(const UE::Math::TVector2<ArgType>& Vector) const
139 {
140 return TransformPoint(Vector);
141 }
142
143 /** Concatenate two scales. */
144 TScale2 Concatenate(const TScale2& RHS) const
145 {
146 return TScale2(Scale * RHS.Scale);
147 }
148 /** Invert the scale. */
150 {
151 return TScale2(1.0f / Scale.X, 1.0f / Scale.Y);
152 }
153
154 /** Equality. */
155 bool operator==(const TScale2& Other) const
156 {
157 return Scale == Other.Scale;
158 }
159
160 /** Inequality. */
161 bool operator!=(const TScale2& Other) const
162 {
163 return !operator==(Other);
164 }
165
166 /** Access to the underlying FVector2D that stores the scale. */
167 const Vector2Type& GetVector() const { return Scale; }
168
169private:
170 /** Underlying storage of the 2D scale. */
171 Vector2Type Scale;
172};
173
174/** Base typedefs */
175typedef TScale2<float> FScale2f;
176typedef TScale2<double> FScale2d;
177typedef FScale2f FScale2D; // Default type (for backwards compat)
178
179/** concatenation rules for 2D scales. */
180template<typename T> struct ConcatenateRules<float , TScale2<T> > { typedef TScale2<T> ResultType; };
181template<typename T> struct ConcatenateRules<double , TScale2<T> > { typedef TScale2<T> ResultType; };
182/** concatenation rules for 2D scales. */
183template<typename T> struct ConcatenateRules<TScale2<T> , float > { typedef TScale2<T> ResultType; };
184template<typename T> struct ConcatenateRules<TScale2<T> , double > { typedef TScale2<T> ResultType; };
185
186/**
187 * Represents a 2D shear:
188 * [1 YY]
189 * [XX 1]
190 * XX represents a shear parallel to the X axis. YY represents a shear parallel to the Y axis.
191 */
192template<typename T>
194{
195 static_assert(std::is_floating_point_v<T>, "T must be floating point");
196
197public:
198 using FReal = T;
199 using Vector2Type = UE::Math::TVector2<T>;
200
201 /** Ctor. initialize to an identity. */
202 TShear2() :Shear(0, 0) {}
203 /** Ctor. initialize from a set of shears parallel to the X and Y axis, respectively. */
204 explicit TShear2(T ShearX, T ShearY) :Shear(ShearX, ShearY) {}
205 /** Ctor. initialize from a 2D vector representing a set of shears parallel to the X and Y axis, respectively. */
206 template<typename VType>
207 explicit TShear2(const UE::Math::TVector2<VType>& InShear) :Shear((Vector2Type)InShear) {}
208
209 /**
210 * Generates a shear structure based on angles instead of slope.
211 * @param InShearAngles The angles of shear.
212 * @return the sheare structure.
213 */
214 template<typename VType>
215 static TShear2 FromShearAngles(const UE::Math::TVector2<VType>& InShearAngles)
216 {
217 // Compute the M (Shear Slot) = CoTan(90 - SlopeAngle)
218
219 // 0 is a special case because Tan(90) == infinity
220 T ShearX = InShearAngles.X == 0 ? 0 : (1.0f / FMath::Tan(FMath::DegreesToRadians(90 - FMath::Clamp<T>((T)InShearAngles.X, -89.0f, 89.0f))));
221 T ShearY = InShearAngles.Y == 0 ? 0 : (1.0f / FMath::Tan(FMath::DegreesToRadians(90 - FMath::Clamp<T>((T)InShearAngles.Y, -89.0f, 89.0f))));
222
223 return TShear2(ShearX, ShearY);
224 }
225
226 /**
227 * Transform 2D Point
228 * [X Y] * [1 YY] == [X+Y*XX Y+X*YY]
229 * [XX 1]
230 */
231 template<typename ArgType>
232 UE::Math::TVector2<ArgType> TransformPoint(const UE::Math::TVector2<ArgType>& Point) const
233 {
235 }
236 /** Transform 2D Vector*/
237 template<typename ArgType>
238 UE::Math::TVector2<ArgType> TransformVector(const UE::Math::TVector2<ArgType>& Vector) const
239 {
240 return TransformPoint(Vector);
241 }
242
243 /**
244 * Concatenate two shears. The result is NOT a shear, but must be represented by a generalized 2x2 transform.
245 * Defer the implementation until we can declare a 2x2 matrix.
246 * [1 YYA] * [1 YYB] == [1+YYA*XXB YYB*YYA]
247 * [XXA 1] [XXB 1] [XXA+XXB XXA*XXB+1]
248 */
249 inline TMatrix2x2<T> Concatenate(const TShear2& RHS) const;
250
251 /**
252 * Invert the shear. The result is NOT a shear, but must be represented by a generalized 2x2 transform.
253 * Defer the implementation until we can declare a 2x2 matrix.
254 * [1 YY]^-1 == 1/(1-YY*XX) * [1 -YY]
255 * [XX 1] [-XX 1]
256 */
257 TMatrix2x2<T> Inverse() const;
258
259
260 /** Equality. */
261 bool operator==(const TShear2& Other) const
262 {
263 return Shear == Other.Shear;
264 }
265
266 /** Inequality. */
267 bool operator!=(const TShear2& Other) const
268 {
269 return !operator==(Other);
270 }
271
272 /** Access to the underlying FVector2D that stores the scale. */
273 const Vector2Type& GetVector() const { return Shear; }
274
275private:
276 /** Underlying storage of the 2D shear. */
277 Vector2Type Shear;
278};
279
280/** Base typedefs */
281typedef TShear2<float> FShear2f;
282typedef TShear2<double> FShear2d;
283typedef FShear2f FShear2D; // Default type (for backwards compat)
284
285
286/**
287 * Represents a 2D rotation as a complex number (analagous to quaternions).
288 * Rot(theta) == cos(theta) + i * sin(theta)
289 * General transformation follows complex number algebra from there.
290 * Does not use "spinor" notation using theta/2 as we don't need that decomposition for our purposes.
291 * This makes the implementation for straightforward and efficient for 2D.
292 */
293template<typename T>
295{
296 static_assert(std::is_floating_point_v<T>, "T must be floating point");
297
298public:
299 using FReal = T;
300 using Vector2Type = UE::Math::TVector2<T>;
301
302 /** Ctor. initialize to an identity rotation. */
303 TQuat2() :Rot(1.0f, 0.0f) {}
304 /** Ctor. initialize from a rotation in radians. */
305 explicit TQuat2(T RotRadians) :Rot(FMath::Cos(RotRadians), FMath::Sin(RotRadians)) {}
306 /** Ctor. initialize from an FVector2D, representing a complex number. */
307 template<typename VType>
308 explicit TQuat2(const UE::Math::TVector2<VType>& InRot) :Rot((Vector2Type)InRot) {}
309
310 /**
311 * Transform a 2D point by the 2D complex number representing the rotation:
312 * In imaginary land: (x + yi) * (u + vi) == (xu - yv) + (xv + yu)i
313 *
314 * Looking at this as a matrix, x == cos(A), y == sin(A)
315 *
316 * [x y] * [ cosA sinA] == [x y] * [ u v] == [xu-yv xv+yu]
317 * [-sinA cosA] [-v u]
318 *
319 * Looking at the above results, we see the equivalence with matrix multiplication.
320 */
321 template<typename ArgType>
322 UE::Math::TVector2<ArgType> TransformPoint(const UE::Math::TVector2<ArgType>& Point) const
323 {
324 return UE::Math::TVector2<ArgType>(
325 Point.X * (ArgType)Rot.X - Point.Y * (ArgType)Rot.Y,
326 Point.X * (ArgType)Rot.Y + Point.Y * (ArgType)Rot.X);
327 }
328 /**
329 * Vector rotation is equivalent to rotating a point.
330 */
331 template<typename ArgType>
332 UE::Math::TVector2<ArgType> TransformVector(const UE::Math::TVector2<ArgType>& Vector) const
333 {
334 return TransformPoint(Vector);
335 }
336 /**
337 * Transform 2 rotations defined by complex numbers:
338 * In imaginary land: (A + Bi) * (C + Di) == (AC - BD) + (AD + BC)i
339 *
340 * Looking at this as a matrix, A == cos(theta), B == sin(theta), C == cos(sigma), D == sin(sigma):
341 *
342 * [ A B] * [ C D] == [ AC-BD AD+BC]
343 * [-B A] [-D C] [-(AD+BC) AC-BD]
344 *
345 * If you look at how the vector multiply works out: [X(AC-BD)+Y(-BC-AD) X(AD+BC)+Y(-BD+AC)]
346 * you can see it follows the same form of the imaginary form. Indeed, check out how the matrix nicely works
347 * out to [ A B] for a visual proof of the results.
348 * [-B A]
349 */
350 TQuat2 Concatenate(const TQuat2& RHS) const
351 {
353 }
354 /**
355 * Invert the rotation defined by complex numbers:
356 * In imaginary land, an inverse is a complex conjugate, which is equivalent to reflecting about the X axis:
357 * Conj(A + Bi) == A - Bi
358 */
360 {
361 return TQuat2(Vector2Type(Rot.X, -Rot.Y));
362 }
363
364 /** Equality. */
365 bool operator==(const TQuat2& Other) const
366 {
367 return Rot == Other.Rot;
368 }
369
370 /** Inequality. */
371 bool operator!=(const TQuat2& Other) const
372 {
373 return !operator==(Other);
374 }
375
376 /** Access to the underlying FVector2D that stores the complex number. */
377 const Vector2Type& GetVector() const { return Rot; }
378
379private:
380 /** Underlying storage of the rotation (X = cos(theta), Y = sin(theta). */
381 Vector2Type Rot;
382};
383
384/** Base typedefs */
385typedef TQuat2<float> FQuat2f;
386typedef TQuat2<double> FQuat2d;
387typedef FQuat2f FQuat2D; // Default type (for backwards compat)
388
389/**
390 * 2x2 generalized matrix. As FMatrix, we assume row vectors, row major storage:
391 * [X Y] * [m00 m01]
392 * [m10 m11]
393 */
394template<typename T>
395class TMatrix2x2
396{
397 static_assert(std::is_floating_point_v<T>, "T must be floating point");
398
399public:
400 using FReal = T;
401 using Vector2Type = UE::Math::TVector2<T>;
402
403 /** Ctor. initialize to an identity. */
405 {
406 M[0][0] = 1; M[0][1] = 0;
407 M[1][0] = 0; M[1][1] = 1;
408 }
409
410 TMatrix2x2(T m00, T m01, T m10, T m11)
411 {
412 M[0][0] = m00; M[0][1] = m01;
413 M[1][0] = m10; M[1][1] = m11;
414 }
415
416
417 /** Ctor. initialize from a scale. */
418 explicit TMatrix2x2(T UniformScale)
419 {
420 M[0][0] = UniformScale; M[0][1] = 0;
421 M[1][0] = 0; M[1][1] = UniformScale;
422 }
423
424 /** Ctor. initialize from a scale. */
425 explicit TMatrix2x2(const TScale2<T>& Scale)
426 {
427 T ScaleX = (T)Scale.GetVector().X;
428 T ScaleY = (T)Scale.GetVector().Y;
429 M[0][0] = ScaleX; M[0][1] = 0;
430 M[1][0] = 0; M[1][1] = ScaleY;
431 }
432
433 /** Factory function. initialize from a 2D shear. */
434 explicit TMatrix2x2(const TShear2<T>& Shear)
435 {
436 T XX = (T)Shear.GetVector().X;
437 T YY = (T)Shear.GetVector().Y;
438 M[0][0] = 1; M[0][1] =YY;
439 M[1][0] =XX; M[1][1] = 1;
440 }
441
442 /** Ctor. initialize from a rotation. */
443 explicit TMatrix2x2(const FQuat2D& Rotation)
444 {
445 T CosAngle = (T)Rotation.GetVector().X;
446 T SinAngle = (T)Rotation.GetVector().Y;
447 M[0][0] = CosAngle; M[0][1] = SinAngle;
448 M[1][0] = -SinAngle; M[1][1] = CosAngle;
449 }
450
451 /**
452 * Transform a 2D point
453 * [X Y] * [m00 m01]
454 * [m10 m11]
455 */
456 template<typename ArgType>
457 UE::Math::TVector2<ArgType> TransformPoint(const UE::Math::TVector2<ArgType>& Point) const
458 {
459 return UE::Math::TVector2<ArgType>(
460 Point.X * (ArgType)M[0][0] + Point.Y * (ArgType)M[1][0],
461 Point.X * (ArgType)M[0][1] + Point.Y * (ArgType)M[1][1]);
462 }
463 /**
464 * Vector transformation is equivalent to point transformation as our matrix is not homogeneous.
465 */
466 template<typename ArgType>
467 UE::Math::TVector2<ArgType> TransformVector(const UE::Math::TVector2<ArgType>& Vector) const
468 {
469 return TransformPoint(Vector);
470 }
471 /**
472 * Concatenate 2 matrices:
473 * [A B] * [E F] == [AE+BG AF+BH]
474 * [C D] [G H] [CE+DG CF+DH]
475 */
476 TMatrix2x2 Concatenate(const TMatrix2x2& RHS) const
477 {
478 T A, B, C, D;
479 GetMatrix(A, B, C, D);
480 T E, F, G, H;
481 RHS.GetMatrix(E, F, G, H);
482 return TMatrix2x2(
483 A*E + B*G, A*F + B*H,
484 C*E + D*G, C*F + D*H);
485 }
486 /**
487 * Invert the transform.
488 */
489 TMatrix2x2 Inverse() const
490 {
491 T A, B, C, D;
492 GetMatrix(A, B, C, D);
493 T InvDet = InverseDeterminant();
494 return TMatrix2x2(
495 D*InvDet, -B*InvDet,
496 -C*InvDet, A*InvDet);
497 }
498
499 /** Equality. */
500 bool operator==(const TMatrix2x2& RHS) const
501 {
502 T A, B, C, D;
503 GetMatrix(A, B, C, D);
504 T E, F, G, H;
505 RHS.GetMatrix(E, F, G, H);
506 return
507 FMath::IsNearlyEqual(A, E, UE_KINDA_SMALL_NUMBER) &&
508 FMath::IsNearlyEqual(B, F, UE_KINDA_SMALL_NUMBER) &&
509 FMath::IsNearlyEqual(C, G, UE_KINDA_SMALL_NUMBER) &&
510 FMath::IsNearlyEqual(D, H, UE_KINDA_SMALL_NUMBER);
511 }
512
513 /** Inequality. */
514 bool operator!=(const TMatrix2x2& Other) const
515 {
516 return !operator==(Other);
517 }
518
519 void GetMatrix(float& A, float& B, float& C, float& D) const
520 {
521 A = (float)M[0][0]; B = (float)M[0][1];
522 C = (float)M[1][0]; D = (float)M[1][1];
523 }
524
525 void GetMatrix(double& A, double& B, double& C, double& D) const
526 {
527 A = (double)M[0][0]; B = (double)M[0][1];
528 C = (double)M[1][0]; D = (double)M[1][1];
529 }
530
531 T Determinant() const
532 {
533 T A, B, C, D;
534 GetMatrix(A, B, C, D);
535 return (A*D - B*C);
536 }
537
539 {
540 T Det = Determinant();
541 checkSlow(Det != 0.0f);
542 return 1.0f / Det;
543 }
544
545 /** Extracts the squared scale from the matrix (avoids sqrt). */
547 {
548 T A, B, C, D;
549 GetMatrix(A, B, C, D);
550 return TScale2<T>(A*A + B*B, C*C + D*D);
551 }
552
553 /** Gets the scale from the matrix. */
554 TScale2<T> GetScale() const
555 {
556 TScale2<T> ScaleSquared = GetScaleSquared();
557 return TScale2<T>(FMath::Sqrt(ScaleSquared.GetVector().X), FMath::Sqrt(ScaleSquared.GetVector().Y));
558 }
559
560 /** Gets the rotation angle of the matrix. */
562 {
563 T A, B, C, D;
564 GetMatrix(A, B, C, D);
565 return FMath::Atan(C / D);
566 }
567
568 /** Determines if the matrix is identity or not. Uses exact float comparison, so rounding error is not considered. */
569 bool IsIdentity() const
570 {
571 return M[0][0] == 1.0f && M[0][1] == 0.0f
572 && M[1][0] == 0.0f && M[1][1] == 1.0f;
573 }
574
575 bool IsNearlyIdentity(T ErrorTolerance = UE_KINDA_SMALL_NUMBER) const
576 {
577 return
578 FMath::IsNearlyEqual(M[0][0], 1.0f, ErrorTolerance) &&
579 FMath::IsNearlyEqual(M[0][1], 0.0f, ErrorTolerance) &&
580 FMath::IsNearlyEqual(M[1][0], 0.0f, ErrorTolerance) &&
581 FMath::IsNearlyEqual(M[1][1], 1.0f, ErrorTolerance);
582 }
583
584private:
585 T M[2][2];
586};
587
588/** Base typedefs */
589typedef TMatrix2x2<float> FMatrix2x2f;
590typedef TMatrix2x2<double> FMatrix2x2d;
591typedef FMatrix2x2f FMatrix2x2; // Default type (for backwards compat)
592
593
594template<typename T>
595inline TMatrix2x2<T> TShear2<T>::Concatenate(const TShear2<T>& RHS) const
596{
597 T XXA = (T)Shear.X;
598 T YYA = (T)Shear.Y;
599 T XXB = (T)RHS.Shear.X;
600 T YYB = (T)RHS.Shear.Y;
601 return TMatrix2x2<T>(
602 1+YYA*XXB, YYB*YYA,
603 XXA+XXB, XXA*XXB+1);
604}
605
606template<typename T>
607inline TMatrix2x2<T> TShear2<T>::Inverse() const
608{
609 T InvDet = 1.0f / T(1.0f - Shear.X*Shear.Y);
610 return TMatrix2x2<T>(
611 InvDet, T(-Shear.Y * InvDet),
612 T(-Shear.X * InvDet), InvDet);
613}
614
615/** Concatenation rules for Matrix2x2 and any other type, */
616template<typename T> struct ConcatenateRules<float , TMatrix2x2<T> > { typedef TMatrix2x2<T> ResultType; };
617template<typename T> struct ConcatenateRules<double , TMatrix2x2<T> > { typedef TMatrix2x2<T> ResultType; };
618template<typename T> struct ConcatenateRules<TScale2<T> , TMatrix2x2<T> > { typedef TMatrix2x2<T> ResultType; };
619template<typename T> struct ConcatenateRules<TShear2<T> , TMatrix2x2<T> > { typedef TMatrix2x2<T> ResultType; };
620template<typename T> struct ConcatenateRules<TQuat2<T> , TMatrix2x2<T> > { typedef TMatrix2x2<T> ResultType; };
621template<typename T> struct ConcatenateRules<TMatrix2x2<T> , float > { typedef TMatrix2x2<T> ResultType; };
622template<typename T> struct ConcatenateRules<TMatrix2x2<T> , double > { typedef TMatrix2x2<T> ResultType; };
623template<typename T> struct ConcatenateRules<TMatrix2x2<T> , TScale2<T> > { typedef TMatrix2x2<T> ResultType; };
624template<typename T> struct ConcatenateRules<TMatrix2x2<T> , TShear2<T> > { typedef TMatrix2x2<T> ResultType; };
625template<typename T> struct ConcatenateRules<TMatrix2x2<T> , TQuat2<T> > { typedef TMatrix2x2<T> ResultType; };
626
627/** Concatenation rules for 2x2 transform types. Convert to 2x2 matrix as the fully decomposed math is not that perf critical right now. */
628template<typename T> struct ConcatenateRules<TScale2<T> , TShear2<T> > { typedef TMatrix2x2<T> ResultType; };
629template<typename T> struct ConcatenateRules<TScale2<T> , TQuat2<T> > { typedef TMatrix2x2<T> ResultType; };
630template<typename T> struct ConcatenateRules<TShear2<T> , TScale2<T> > { typedef TMatrix2x2<T> ResultType; };
631template<typename T> struct ConcatenateRules<TQuat2<T> , TScale2<T> > { typedef TMatrix2x2<T> ResultType; };
632template<typename T> struct ConcatenateRules<TShear2<T> , TQuat2<T> > { typedef TMatrix2x2<T> ResultType; };
633template<typename T> struct ConcatenateRules<TQuat2<T> , TShear2<T> > { typedef TMatrix2x2<T> ResultType; };
634
635 /**
636 * Support for generalized 2D affine transforms.
637 * Implemented as a 2x2 transform followed by translation. In matrix form:
638 * [A B 0]
639 * [C D 0]
640 * [X Y 1]
641 */
642template<typename T>
644{
645 static_assert(std::is_floating_point_v<T>, "T must be floating point");
646
647public:
648 using FReal = T;
649 using Vector2Type = UE::Math::TVector2<T>;
650 using Matrix2Type = TMatrix2x2<T>;
651
652 /** Initialize the transform using an identity matrix and a translation. */
653 template<typename VType = float>
654 TTransform2(const UE::Math::TVector2<VType>& Translation = UE::Math::TVector2<VType>(0.f, 0.f))
656 {
657 }
658
659 /** Initialize the transform using a uniform scale and a translation. */
660 template<typename VType = float>
661 explicit TTransform2(T UniformScale, const UE::Math::TVector2<VType>& Translation = UE::Math::TVector2<VType>(0.f, 0.f))
663 {
664 }
665
666 /** Initialize the transform using a 2D scale and a translation. */
667 template<typename VType = float>
668 explicit TTransform2(const TScale2<T>& Scale, const UE::Math::TVector2<VType>& Translation = UE::Math::TVector2<VType>(0.f, 0.f))
670 {
671 }
672
673 /** Initialize the transform using a 2D shear and a translation. */
674 template<typename VType = float>
675 explicit TTransform2(const TShear2<T>& Shear, const UE::Math::TVector2<VType>& Translation = UE::Math::TVector2<VType>(0.f, 0.f))
677 {
678 }
679
680 /** Initialize the transform using a 2D rotation and a translation. */
681 template<typename VType = float>
682 explicit TTransform2(const TQuat2<T>& Rot, const UE::Math::TVector2<VType>& Translation = UE::Math::TVector2<VType>(0.f, 0.f))
684 {
685 }
686
687 /** Initialize the transform using a general 2x2 transform and a translation. */
688 template<typename VType = float>
689 explicit TTransform2(const TMatrix2x2<T>& Transform, const UE::Math::TVector2<VType>& Translation = UE::Math::TVector2<VType>(0.f, 0.f))
691 {
692 }
693
694 /**
695 * 2D transformation of a point. Transforms position, rotation, and scale.
696 */
697 template<typename VType>
698 UE::Math::TVector2<VType> TransformPoint(const UE::Math::TVector2<VType>& Point) const
699 {
701 }
702
703 /**
704 * 2D transformation of a vector. Transforms rotation and scale.
705 */
706 template<typename VType>
707 UE::Math::TVector2<VType> TransformVector(const UE::Math::TVector2<VType>& Vector) const
708 {
710 }
711
712 /**
713 * Concatenates two transforms. Result is equivalent to transforming first by this, followed by RHS.
714 * Concat(A,B) == (P * MA + TA) * MB + TB
715 * == (P * MA * MB) + TA*MB + TB
716 * NewM == MA * MB
717 * NewT == TA * MB + TB
718 */
720 {
721 return TTransform2(
722 ::Concatenate(M, RHS.M),
724 }
725
726 /**
727 * Inverts a transform. So a transform from space A to space B results in a transform from space B to space A.
728 * Since this class applies the 2x2 transform followed by translation, our inversion logic needs to be able to recast
729 * the result as a M * T. It does it using the following identity:
730 * (M * T)^-1 == T^-1 * M^-1
731 *
732 * In homogeneous form, we represent our affine transform like so:
733 * M * T
734 * [A B 0] [1 0 0] [A B 0]
735 * [C D 0] * [0 1 0] = [C D 0]. This class simply decomposes the 2x2 transform and translation.
736 * [0 0 1] [X Y 1] [X Y 1]
737 *
738 * But if we were applying the transforms in reverse order (as we need to for the inverse identity above):
739 * T^-1 * M^-1
740 * [1 0 0] [A B 0] [A B 0] where [X' Y'] = [X Y] * [A B]
741 * [0 1 0] * [C D 0] = [C D 0] [C D]
742 * [X Y 1] [0 0 1] [X' Y' 1]
743 *
744 * This can be conceptualized by seeing that a translation effectively defines a new local origin for that
745 * frame of reference. Since there is a 2x2 transform AFTER that, the concatenated frame of reference has an origin
746 * that is the old origin transformed by the 2x2 transform.
747 *
748 * In the last equation:
749 * We know that [X Y] is the translation induced by inverting T, or -Translate.
750 * We know that [[A B][C D]] == Inverse(M), so we can represent T^-1 * M^-1 as M'* T' where:
751 * M' == Inverse(M)
752 * T' == Inverse(Translate) * Inverse(M)
753 */
755 {
758 return TTransform2(InvM, InvTrans);
759 }
760
761 /** Equality. */
762 bool operator==(const TTransform2& Other) const
763 {
764 return M == Other.M && Trans == Other.Trans;
765 }
766
767 /** Inequality. */
768 bool operator!=(const TTransform2& Other) const
769 {
770 return !operator==(Other);
771 }
772
773 /** Access to the 2x2 transform */
774 const Matrix2Type& GetMatrix() const { return M; }
775 /** Access to the translation */
776 //const Vector2Type GetTranslation() const { return Vector2Type(Trans); }
777 const FVector2D GetTranslation() const { return (FVector2D)Trans; } // TODO: should be Vector2Type in general, but retaining FVector2D for now for compilation backwards compat.
778
779 template<typename VType>
780 void SetTranslation(const UE::Math::TVector2<VType>& InTrans) { Trans = (Vector2Type)InTrans; }
781
782 /**
783 * Specialized function to determine if a transform is precisely the identity transform. Uses exact float comparison, so rounding error is not considered.
784 */
785 bool IsIdentity() const
786 {
787 return M.IsIdentity() && Trans == Vector2Type::ZeroVector;
788 }
789
790 /**
791 * Converts this affine 2D Transform into an affine 3D transform.
792 */
793 UE::Math::TMatrix<T> To3DMatrix() const
794 {
795 T A, B, C, D;
796 M.GetMatrix(A, B, C, D);
797
798 return UE::Math::TMatrix<T>(
799 UE::Math::TPlane<T>( A, B, 0.0f, 0.0f),
800 UE::Math::TPlane<T>( C, D, 0.0f, 0.0f),
801 UE::Math::TPlane<T>( 0.0f, 0.0f, 1.0f, 0.0f),
802 UE::Math::TPlane<T>(Trans.X, Trans.Y, 0.0f, 1.0f)
803 );
804 }
805
806private:
807 Matrix2Type M;
808 Vector2Type Trans;
809};
810
811/** Core typedefs */
813typedef TTransform2<double> FTransform2d;
814typedef FTransform2f FTransform2D; // default type, for backwards compat
815
816template<> struct TIsPODType<FTransform2f> { enum { Value = true }; };
817template<> struct TIsPODType<FTransform2d> { enum { Value = true }; };
818
819//////////////////////////////////////////////////////////////////////////
820// Concatenate overloads.
821//
822// Efficient overloads for concatenating 2D affine transforms.
823// Better than simply upcasting both to FTransform2D first.
824//////////////////////////////////////////////////////////////////////////
825
826/** Specialization for concatenating a 2D scale and 2D Translation. */
827template<typename T, typename V>
828inline TTransform2<T> Concatenate(const TScale2<T>& Scale, const UE::Math::TVector2<V>& Translation)
829{
830 return TTransform2<T>(Scale, Translation);
831}
832
833/** Specialization for concatenating a 2D shear and 2D Translation. */
834template<typename T, typename V>
835inline TTransform2<T> Concatenate(const TShear2<T>& Shear, const UE::Math::TVector2<V>& Translation)
836{
837 return TTransform2<T>(Shear, Translation);
838}
839
840/** Specialization for concatenating 2D Rotation and 2D Translation. */
841template<typename T, typename V>
842inline TTransform2<T> Concatenate(const TQuat2<T>& Rot, const UE::Math::TVector2<V>& Translation)
843{
844 return TTransform2<T>(Rot, Translation);
845}
846
847/** Specialization for concatenating 2D generalized transform and 2D Translation. */
848template<typename T, typename V>
849inline TTransform2<T> Concatenate(const TMatrix2x2<T>& Transform, const UE::Math::TVector2<V>& Translation)
850{
851 return TTransform2<T>(Transform, Translation);
852}
853
854/** Specialization for concatenating transform and 2D Translation. */
855template<typename T, typename V>
856inline TTransform2<T> Concatenate(const TTransform2<T>& Transform, const UE::Math::TVector2<V>& Translation)
857{
858 return TTransform2<T>(Transform.GetMatrix(), Concatenate((UE::Math::TVector2<T>)Transform.GetTranslation(), (UE::Math::TVector2<T>)Translation));
859}
860
861/** Specialization for concatenating a 2D Translation and 2D scale. */
862template<typename T, typename V>
863inline TTransform2<T> Concatenate(const UE::Math::TVector2<V>& Translation, const TScale2<T>& Scale)
864{
865 return TTransform2<T>(Scale, ::TransformPoint(Scale, Translation));
866}
867
868/** Specialization for concatenating a 2D Translation and 2D shear. */
869template<typename T, typename V>
870inline TTransform2<T> Concatenate(const UE::Math::TVector2<V>& Translation, const TShear2<T>& Shear)
871{
872 return TTransform2<T>(Shear, ::TransformPoint(Shear, Translation));
873}
874
875/** Specialization for concatenating 2D Translation and 2D Rotation. */
876template<typename T, typename V>
877inline TTransform2<T> Concatenate(const UE::Math::TVector2<V>& Translation, const TQuat2<T>& Rot)
878{
879 return TTransform2<T>(Rot, ::TransformPoint(Rot, Translation));
880}
881
882/** Specialization for concatenating 2D Translation and 2D generalized transform. See docs for TTransform2<T>::Inverse for details on how this math is derived. */
883template<typename T, typename V>
884inline TTransform2<T> Concatenate(const UE::Math::TVector2<V>& Translation, const TMatrix2x2<T>& Transform)
885{
886 return TTransform2<T>(Transform, ::TransformPoint(Transform, Translation));
887}
888
889/** Specialization for concatenating 2D Translation and transform. See docs for TTransform2<T>::Inverse for details on how this math is derived. */
890template<typename T, typename V>
891inline TTransform2<T> Concatenate(const UE::Math::TVector2<V>& Translation, const TTransform2<T>& Transform)
892{
893 return TTransform2<T>(Transform.GetMatrix(), Concatenate(::TransformPoint(Transform.GetMatrix(), (UE::Math::TVector2<T>)Translation), (UE::Math::TVector2<T>)Transform.GetTranslation()));
894}
895
896/** Helper to determine if a type is based on TTransform2 */
898{
899 template<typename T>
901 {
902 enum { Value = false };
903 };
904
905 template<> struct TIsTransform2< FTransform2f > { enum { Value = true }; };
906 template<> struct TIsTransform2< FTransform2d > { enum { Value = true }; };
907}
908
909/** Partial specialization of ConcatenateRules for FTransform2D and any other type via Upcast to FTransform2D first. Requires a conversion ctor on FTransform2D. Funky template logic so we don't hide the default rule for NULL conversions. */
910template<typename TransformType> struct ConcatenateRules<typename TEnableIf<!TransformCalculusHelper::TIsTransform2<TransformType>::Value, FTransform2f>::Type, TransformType > { typedef FTransform2f ResultType; };
911template<typename TransformType> struct ConcatenateRules<typename TEnableIf<!TransformCalculusHelper::TIsTransform2<TransformType>::Value, FTransform2d>::Type, TransformType > { typedef FTransform2d ResultType; };
912template<typename TransformType> struct ConcatenateRules<TransformType, typename TEnableIf<!TransformCalculusHelper::TIsTransform2<TransformType>::Value, FTransform2f>::Type > { typedef FTransform2f ResultType; };
913template<typename TransformType> struct ConcatenateRules<TransformType, typename TEnableIf<!TransformCalculusHelper::TIsTransform2<TransformType>::Value, FTransform2d>::Type > { typedef FTransform2d ResultType; };
#define checkSlow(expr)
TTransform2< T > Concatenate(const TMatrix2x2< T > &Transform, const UE::Math::TVector2< V > &Translation)
TTransform2< double > FTransform2d
TQuat2< float > FQuat2f
TMatrix2x2< double > FMatrix2x2d
UE::Math::TVector2< VectorType > TransformVector(float Transform, const UE::Math::TVector2< VectorType > &Vector)
TQuat2< double > FQuat2d
TTransform2< T > Concatenate(const UE::Math::TVector2< V > &Translation, const TTransform2< T > &Transform)
TTransform2< T > Concatenate(const TTransform2< T > &Transform, const UE::Math::TVector2< V > &Translation)
TTransform2< T > Concatenate(const UE::Math::TVector2< V > &Translation, const TScale2< T > &Scale)
TShear2< float > FShear2f
const UE::Math::TVector2< T > & TransformVector(const UE::Math::TVector2< T > &Transform, const UE::Math::TVector2< T > &Vector)
UE::Math::TVector2< PositionType > TransformPoint(float Transform, const UE::Math::TVector2< PositionType > &Point)
UE::Math::TVector2< VectorType > TransformVector(double Transform, const UE::Math::TVector2< VectorType > &Vector)
TTransform2< T > Concatenate(const UE::Math::TVector2< V > &Translation, const TMatrix2x2< T > &Transform)
TMatrix2x2< float > FMatrix2x2f
TTransform2< float > FTransform2f
FScale2f FScale2D
TScale2< double > FScale2d
TScale2< float > FScale2f
TTransform2< T > Concatenate(const TShear2< T > &Shear, const UE::Math::TVector2< V > &Translation)
UE::Math::TVector2< T > Inverse(const UE::Math::TVector2< T > &Transform)
FTransform2f FTransform2D
TShear2< double > FShear2d
UE::Math::TVector2< T > TransformPoint(const UE::Math::TVector2< T > &Transform, const UE::Math::TVector2< T > &Point)
TTransform2< T > Concatenate(const TQuat2< T > &Rot, const UE::Math::TVector2< V > &Translation)
TTransform2< T > Concatenate(const UE::Math::TVector2< V > &Translation, const TQuat2< T > &Rot)
TTransform2< T > Concatenate(const UE::Math::TVector2< V > &Translation, const TShear2< T > &Shear)
FMatrix2x2f FMatrix2x2
TTransform2< T > Concatenate(const TScale2< T > &Scale, const UE::Math::TVector2< V > &Translation)
UE::Math::TVector2< PositionType > TransformPoint(double Transform, const UE::Math::TVector2< PositionType > &Point)
FShear2f FShear2D
FQuat2f FQuat2D
#define UE_KINDA_SMALL_NUMBER
bool operator!=(const TMatrix2x2 &Other) const
void GetMatrix(float &A, float &B, float &C, float &D) const
TScale2< T > GetScaleSquared() const
bool IsNearlyIdentity(T ErrorTolerance=UE_KINDA_SMALL_NUMBER) const
UE::Math::TVector2< ArgType > TransformPoint(const UE::Math::TVector2< ArgType > &Point) const
TMatrix2x2(const TScale2< T > &Scale)
T Determinant() const
TMatrix2x2(const FQuat2D &Rotation)
T InverseDeterminant() const
void GetMatrix(double &A, double &B, double &C, double &D) const
bool operator==(const TMatrix2x2 &RHS) const
bool IsIdentity() const
TMatrix2x2(T UniformScale)
TMatrix2x2 Concatenate(const TMatrix2x2 &RHS) const
T GetRotationAngle() const
TMatrix2x2(T m00, T m01, T m10, T m11)
TMatrix2x2(const TShear2< T > &Shear)
UE::Math::TVector2< ArgType > TransformVector(const UE::Math::TVector2< ArgType > &Vector) const
TScale2< T > GetScale() const
TMatrix2x2 Inverse() const
UE::Math::TVector2< ArgType > TransformPoint(const UE::Math::TVector2< ArgType > &Point) const
bool operator==(const TQuat2 &Other) const
TQuat2 Inverse() const
TQuat2(T RotRadians)
TQuat2(const UE::Math::TVector2< VType > &InRot)
const Vector2Type & GetVector() const
UE::Math::TVector2< ArgType > TransformVector(const UE::Math::TVector2< ArgType > &Vector) const
Vector2Type Rot
bool operator!=(const TQuat2 &Other) const
TQuat2 Concatenate(const TQuat2 &RHS) const
const Vector2Type & GetVector() const
TScale2(const UE::Math::TVector2< ArgType > &InScale)
UE::Math::TVector2< ArgType > TransformVector(const UE::Math::TVector2< ArgType > &Vector) const
TScale2 Inverse() const
bool operator==(const TScale2 &Other) const
TScale2(T InScale)
TScale2(T InScaleX, T InScaleY)
bool operator!=(const TScale2 &Other) const
UE::Math::TVector2< ArgType > TransformPoint(const UE::Math::TVector2< ArgType > &Point) const
Vector2Type Scale
TScale2 Concatenate(const TScale2 &RHS) const
TMatrix2x2< T > Inverse() const
TShear2(T ShearX, T ShearY)
bool operator==(const TShear2 &Other) const
TShear2(const UE::Math::TVector2< VType > &InShear)
bool operator!=(const TShear2 &Other) const
TMatrix2x2< T > Concatenate(const TShear2 &RHS) const
static TShear2 FromShearAngles(const UE::Math::TVector2< VType > &InShearAngles)
Vector2Type Shear
UE::Math::TVector2< ArgType > TransformPoint(const UE::Math::TVector2< ArgType > &Point) const
const Vector2Type & GetVector() const
UE::Math::TVector2< ArgType > TransformVector(const UE::Math::TVector2< ArgType > &Vector) const
void SetTranslation(const UE::Math::TVector2< VType > &InTrans)
bool IsIdentity() const
TTransform2(const TQuat2< T > &Rot, const UE::Math::TVector2< VType > &Translation=UE::Math::TVector2< VType >(0.f, 0.f))
bool operator!=(const TTransform2 &Other) const
TTransform2(const TShear2< T > &Shear, const UE::Math::TVector2< VType > &Translation=UE::Math::TVector2< VType >(0.f, 0.f))
const FVector2D GetTranslation() const
TTransform2(const UE::Math::TVector2< VType > &Translation=UE::Math::TVector2< VType >(0.f, 0.f))
TTransform2 Inverse() const
UE::Math::TVector2< VType > TransformVector(const UE::Math::TVector2< VType > &Vector) const
TTransform2(const TScale2< T > &Scale, const UE::Math::TVector2< VType > &Translation=UE::Math::TVector2< VType >(0.f, 0.f))
TTransform2(const TMatrix2x2< T > &Transform, const UE::Math::TVector2< VType > &Translation=UE::Math::TVector2< VType >(0.f, 0.f))
bool operator==(const TTransform2 &Other) const
const Matrix2Type & GetMatrix() const
TTransform2(T UniformScale, const UE::Math::TVector2< VType > &Translation=UE::Math::TVector2< VType >(0.f, 0.f))
UE::Math::TVector2< VType > TransformPoint(const UE::Math::TVector2< VType > &Point) const
TTransform2 Concatenate(const TTransform2 &RHS) const
UE::Math::TMatrix< T > To3DMatrix() const
UE::Math::TVector2< T > Concatenate(const UE::Math::TVector2< T > &LHS, const UE::Math::TVector2< T > &RHS)
Definition Vector.h:40
Definition json.hpp:4518