|
@@ -17,160 +17,81 @@
|
17
|
17
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
18
|
18
|
*
|
19
|
19
|
* transform.ts
|
20
|
|
- * 3D geometrical transforms
|
|
20
|
+ * 3D transforms
|
21
|
21
|
*/
|
22
|
22
|
|
23
|
23
|
import Speedy from 'speedy-vision';
|
24
|
24
|
import { SpeedyMatrix } from 'speedy-vision/types/core/speedy-matrix';
|
25
|
|
-import { IllegalArgumentError, IllegalOperationError } from '../utils/errors';
|
|
25
|
+import { Nullable } from '../utils/utils';
|
|
26
|
+import { IllegalArgumentError } from '../utils/errors';
|
|
27
|
+
|
26
|
28
|
|
27
|
29
|
/**
|
28
|
|
- * A 3D transformation
|
|
30
|
+ * A Transform represents a position, a rotation and a scale in 3D space
|
29
|
31
|
*/
|
30
|
|
-abstract class BaseTransform
|
|
32
|
+export class Transform
|
31
|
33
|
{
|
32
|
|
- /** 4x4 matrix describing the transformation */
|
33
|
|
- protected readonly _matrix: SpeedyMatrix;
|
|
34
|
+ /** transformation matrix */
|
|
35
|
+ private readonly _matrix: SpeedyMatrix;
|
|
36
|
+
|
|
37
|
+ /** inverse transform, computed lazily */
|
|
38
|
+ private _inverse: Nullable<Transform>;
|
34
|
39
|
|
35
|
40
|
|
36
|
41
|
|
37
|
42
|
/**
|
38
|
43
|
* Constructor
|
39
|
|
- * @param matrix a 4x4 matrix
|
|
44
|
+ * @param matrix a 4x4 transformation matrix. You should ensure that its form is T * R * S (translation * rotation * scale).
|
40
|
45
|
*/
|
41
|
46
|
constructor(matrix: SpeedyMatrix)
|
42
|
47
|
{
|
43
|
48
|
if(matrix.rows != 4 || matrix.columns != 4)
|
44
|
|
- throw new IllegalArgumentError('A 3D transform expects a 4x4 matrix');
|
|
49
|
+ throw new IllegalArgumentError('A Transform expects a 4x4 transformation matrix');
|
45
|
50
|
|
46
|
51
|
this._matrix = matrix;
|
|
52
|
+ this._inverse = null;
|
47
|
53
|
}
|
48
|
54
|
|
49
|
55
|
/**
|
50
|
|
- * The 4x4 transformation matrix (read-only)
|
|
56
|
+ * The 4x4 transformation matrix
|
51
|
57
|
*/
|
52
|
58
|
get matrix(): SpeedyMatrix
|
53
|
59
|
{
|
54
|
60
|
return this._matrix;
|
55
|
61
|
}
|
56
|
|
-}
|
57
|
62
|
|
58
|
|
-/**
|
59
|
|
- * An invertible 3D transformation
|
60
|
|
- */
|
61
|
|
-class InvertibleTransform extends BaseTransform
|
62
|
|
-{
|
63
|
63
|
/**
|
64
|
|
- * Constructor
|
65
|
|
- * @param matrix a 4x4 matrix
|
|
64
|
+ * The inverse transform
|
66
|
65
|
*/
|
67
|
|
- constructor(matrix: SpeedyMatrix)
|
|
66
|
+ get inverse(): Transform
|
68
|
67
|
{
|
69
|
|
- // WARNING: we do not check if the matrix actually encodes an invertible transform!
|
70
|
|
- super(matrix);
|
71
|
|
- }
|
|
68
|
+ if(this._inverse === null)
|
|
69
|
+ this._inverse = new Transform(Transform._invert(this._matrix));
|
72
|
70
|
|
73
|
|
- /**
|
74
|
|
- * The inverse of the transform
|
75
|
|
- */
|
76
|
|
- get inverse(): InvertibleTransform
|
77
|
|
- {
|
78
|
|
- const inverseMatrix = Speedy.Matrix(this._matrix.inverse());
|
79
|
|
- return new InvertibleTransform(inverseMatrix);
|
|
71
|
+ return this._inverse;
|
80
|
72
|
}
|
81
|
|
-}
|
82
|
|
-
|
83
|
|
-/**
|
84
|
|
- * A 3D transformation described by translation, rotation and scale
|
85
|
|
- */
|
86
|
|
-export class StandardTransform extends InvertibleTransform
|
87
|
|
-{
|
88
|
|
- // TODO: position, rotation and scale attributes
|
89
|
73
|
|
90
|
74
|
/**
|
91
|
|
- * Constructor
|
92
|
|
- * @param matrix a 4x4 matrix
|
|
75
|
+ * Compute the inverse of a transformation matrix
|
|
76
|
+ * @param matrix the transformation matrix to invert
|
|
77
|
+ * @returns the inverse matrix
|
93
|
78
|
*/
|
94
|
|
- constructor(matrix: SpeedyMatrix)
|
95
|
|
- {
|
96
|
|
- // WARNING: we do not check if the matrix actually encodes a standard transform!
|
97
|
|
- super(matrix);
|
98
|
|
- }
|
99
|
|
-
|
100
|
|
- /**
|
101
|
|
- * The inverse of the transform
|
102
|
|
- */
|
103
|
|
- get inverse(): StandardTransform
|
|
79
|
+ private static _invert(matrix: SpeedyMatrix): SpeedyMatrix
|
104
|
80
|
{
|
105
|
81
|
/*
|
106
|
82
|
|
107
|
|
- The inverse of a 4x4 standard transform T * R * S...
|
|
83
|
+ The inverse of a 4x4 transform T * R * S
|
108
|
84
|
|
109
|
85
|
[ RS t ] is [ ZR' -ZR't ]
|
110
|
86
|
[ 0' 1 ] [ 0' 1 ]
|
111
|
87
|
|
112
|
88
|
where S is 3x3, R is 3x3, t is 3x1, 0' is 1x3 and Z is the inverse of S
|
113
|
89
|
|
114
|
|
- */
|
115
|
|
-
|
116
|
|
- return super.inverse as StandardTransform;
|
117
|
|
- }
|
118
|
|
-}
|
119
|
|
-
|
120
|
|
-/**
|
121
|
|
- * A 3D transformation described by position and orientation
|
122
|
|
- */
|
123
|
|
-export class RigidTransform extends StandardTransform
|
124
|
|
-{
|
125
|
|
- // TODO: position and rotation attributes (need to decompose the matrix)
|
126
|
|
-
|
127
|
|
- /**
|
128
|
|
- * Constructor
|
129
|
|
- * @param matrix a 4x4 matrix
|
130
|
|
- */
|
131
|
|
- constructor(matrix: SpeedyMatrix)
|
132
|
|
- {
|
133
|
|
- // WARNING: we do not check if the matrix actually encodes a rigid transform!
|
134
|
|
- super(matrix);
|
135
|
|
- }
|
136
|
|
-
|
137
|
|
- /**
|
138
|
|
- * The inverse of the transform
|
139
|
|
- */
|
140
|
|
- get inverse(): RigidTransform
|
141
|
|
- {
|
142
|
|
- /*
|
143
|
|
-
|
144
|
|
- The inverse of a 4x4 rigid transform
|
145
|
|
-
|
146
|
|
- [ R t ] is [ R' -R't ]
|
147
|
|
- [ 0' 1 ] [ 0' 1 ]
|
148
|
|
-
|
149
|
|
- where R is 3x3, t is 3x1 and 0' is 1x3
|
|
90
|
+ R is a rotation matrix; S is a diagonal matrix
|
150
|
91
|
|
151
|
92
|
*/
|
152
|
93
|
|
153
|
|
- const m = this._matrix.read();
|
154
|
|
- if(m[15] == 0) // error? abs()??
|
155
|
|
- throw new IllegalOperationError('Not a rigid transform');
|
156
|
|
- const s = 1 / m[15]; // should be 1 (normalize homogeneous coordinates)
|
157
|
|
-
|
158
|
|
- const r11 = m[0] * s, r12 = m[4] * s, r13 = m[8] * s;
|
159
|
|
- const r21 = m[1] * s, r22 = m[5] * s, r23 = m[9] * s;
|
160
|
|
- const r31 = m[2] * s, r32 = m[6] * s, r33 = m[10] * s;
|
161
|
|
- const t1 = m[12] * s, t2 = m[13] * s, t3 = m[14] * s;
|
162
|
|
-
|
163
|
|
- const rt1 = r11 * t1 + r21 * t2 + r31 * t3;
|
164
|
|
- const rt2 = r12 * t1 + r22 * t2 + r32 * t3;
|
165
|
|
- const rt3 = r13 * t1 + r23 * t2 + r33 * t3;
|
166
|
|
-
|
167
|
|
- const inverseMatrix = Speedy.Matrix(4, 4, [
|
168
|
|
- r11, r12, r13, 0,
|
169
|
|
- r21, r22, r23, 0,
|
170
|
|
- r31, r32, r33, 0,
|
171
|
|
- -rt1, -rt2, -rt3, 1
|
172
|
|
- ]);
|
173
|
|
-
|
174
|
|
- return new RigidTransform(inverseMatrix);
|
|
94
|
+ // this works, but this inverse is straightforward
|
|
95
|
+ return Speedy.Matrix(matrix.inverse());
|
175
|
96
|
}
|
176
|
|
-}
|
|
97
|
+}
|