@itwin/core-geometry 3.6.0-dev.47 → 3.6.0-dev.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/Geometry.d.ts +18 -6
- package/lib/cjs/Geometry.d.ts.map +1 -1
- package/lib/cjs/Geometry.js +18 -6
- package/lib/cjs/Geometry.js.map +1 -1
- package/lib/cjs/geometry3d/Matrix3d.d.ts +221 -159
- package/lib/cjs/geometry3d/Matrix3d.d.ts.map +1 -1
- package/lib/cjs/geometry3d/Matrix3d.js +364 -249
- package/lib/cjs/geometry3d/Matrix3d.js.map +1 -1
- package/lib/esm/Geometry.d.ts +18 -6
- package/lib/esm/Geometry.d.ts.map +1 -1
- package/lib/esm/Geometry.js +18 -6
- package/lib/esm/Geometry.js.map +1 -1
- package/lib/esm/geometry3d/Matrix3d.d.ts +221 -159
- package/lib/esm/geometry3d/Matrix3d.d.ts.map +1 -1
- package/lib/esm/geometry3d/Matrix3d.js +364 -249
- package/lib/esm/geometry3d/Matrix3d.js.map +1 -1
- package/package.json +4 -4
|
@@ -47,7 +47,7 @@ export class PackedMatrix3dOps {
|
|
|
47
47
|
dest[8] = a22;
|
|
48
48
|
}
|
|
49
49
|
/**
|
|
50
|
-
*
|
|
50
|
+
* Multiply 3x3 matrix `a*b`, store in `result`.
|
|
51
51
|
* * All params assumed length 9, allocated by caller.
|
|
52
52
|
* * c may alias either input.
|
|
53
53
|
*/
|
|
@@ -58,7 +58,7 @@ export class PackedMatrix3dOps {
|
|
|
58
58
|
return result;
|
|
59
59
|
}
|
|
60
60
|
/**
|
|
61
|
-
*
|
|
61
|
+
* Multiply 3x3 matrix `a*bTranspose`, store in `result`.
|
|
62
62
|
* * All params assumed length 9, allocated by caller.
|
|
63
63
|
* * c may alias either input.
|
|
64
64
|
*/
|
|
@@ -69,7 +69,7 @@ export class PackedMatrix3dOps {
|
|
|
69
69
|
return result;
|
|
70
70
|
}
|
|
71
71
|
/**
|
|
72
|
-
*
|
|
72
|
+
* Multiply 3x3 matrix `aTranspose*b`, store in `result`.
|
|
73
73
|
* * All params assumed length 9, allocated by caller.
|
|
74
74
|
* * c may alias either input.
|
|
75
75
|
*/
|
|
@@ -79,7 +79,7 @@ export class PackedMatrix3dOps {
|
|
|
79
79
|
PackedMatrix3dOps.loadMatrix(result, (a[0] * b[0] + a[3] * b[3] + a[6] * b[6]), (a[0] * b[1] + a[3] * b[4] + a[6] * b[7]), (a[0] * b[2] + a[3] * b[5] + a[6] * b[8]), (a[1] * b[0] + a[4] * b[3] + a[7] * b[6]), (a[1] * b[1] + a[4] * b[4] + a[7] * b[7]), (a[1] * b[2] + a[4] * b[5] + a[7] * b[8]), (a[2] * b[0] + a[5] * b[3] + a[8] * b[6]), (a[2] * b[1] + a[5] * b[4] + a[8] * b[7]), (a[2] * b[2] + a[5] * b[5] + a[8] * b[8]));
|
|
80
80
|
return result;
|
|
81
81
|
}
|
|
82
|
-
/**
|
|
82
|
+
/** Transpose 3x3 matrix `a` in place */
|
|
83
83
|
static transposeInPlace(a) {
|
|
84
84
|
let q = a[1];
|
|
85
85
|
a[1] = a[3];
|
|
@@ -91,10 +91,14 @@ export class PackedMatrix3dOps {
|
|
|
91
91
|
a[5] = a[7];
|
|
92
92
|
a[7] = q;
|
|
93
93
|
}
|
|
94
|
-
/**
|
|
94
|
+
/**
|
|
95
|
+
* Returns the transpose of 3x3 matrix `a`
|
|
96
|
+
* * If `dest` is passed as argument, then the function copies the transpose of 3x3 matrix `a` into `dest`
|
|
97
|
+
* * `a` is not changed unless also passed as the dest, i.e., copyTransposed(a,a) transposes `a` in place
|
|
98
|
+
*/
|
|
95
99
|
static copyTransposed(a, dest) {
|
|
96
100
|
if (dest === a) {
|
|
97
|
-
PackedMatrix3dOps.transposeInPlace(
|
|
101
|
+
PackedMatrix3dOps.transposeInPlace(dest);
|
|
98
102
|
}
|
|
99
103
|
else {
|
|
100
104
|
if (!dest)
|
|
@@ -111,7 +115,7 @@ export class PackedMatrix3dOps {
|
|
|
111
115
|
}
|
|
112
116
|
return dest;
|
|
113
117
|
}
|
|
114
|
-
/**
|
|
118
|
+
/** Copy matrix `a` entries into `dest` */
|
|
115
119
|
static copy(a, dest) {
|
|
116
120
|
if (dest !== a) {
|
|
117
121
|
dest[0] = a[0];
|
|
@@ -129,29 +133,31 @@ export class PackedMatrix3dOps {
|
|
|
129
133
|
}
|
|
130
134
|
/** A Matrix3d is tagged indicating one of the following states:
|
|
131
135
|
* * unknown: it is not know if the matrix is invertible.
|
|
132
|
-
* * inverseStored: the matrix has its inverse stored
|
|
136
|
+
* * inverseStored: the matrix has its inverse stored.
|
|
133
137
|
* * singular: the matrix is known to be singular.
|
|
134
138
|
* @public
|
|
135
139
|
*/
|
|
136
140
|
export var InverseMatrixState;
|
|
137
141
|
(function (InverseMatrixState) {
|
|
138
142
|
/**
|
|
139
|
-
*
|
|
140
|
-
*
|
|
143
|
+
* The invertibility of the `coffs` array has not been determined.
|
|
144
|
+
* Any `inverseCoffs` contents are random.
|
|
141
145
|
*/
|
|
142
146
|
InverseMatrixState[InverseMatrixState["unknown"] = 0] = "unknown";
|
|
143
|
-
/**
|
|
147
|
+
/**
|
|
148
|
+
* An inverse was computed and stored as the `inverseCoffs`
|
|
149
|
+
*/
|
|
144
150
|
InverseMatrixState[InverseMatrixState["inverseStored"] = 1] = "inverseStored";
|
|
145
151
|
/**
|
|
146
|
-
*
|
|
147
|
-
*
|
|
152
|
+
* The `coffs` array is known to be singular.
|
|
153
|
+
* Any `inverseCoffs` contents are random.
|
|
148
154
|
*/
|
|
149
155
|
InverseMatrixState[InverseMatrixState["singular"] = 2] = "singular";
|
|
150
156
|
})(InverseMatrixState || (InverseMatrixState = {}));
|
|
151
157
|
/** A Matrix3d is a 3x3 matrix.
|
|
152
158
|
* * A very common use is to hold a rigid body rotation (which has no scaling or skew), but the 3x3 contents can
|
|
153
159
|
* also hold scaling and skewing.
|
|
154
|
-
* * The matrix with 2-dimensional layout
|
|
160
|
+
* * The matrix with 2-dimensional layout (note: a 2d array can be shown by a matrix)
|
|
155
161
|
* ```
|
|
156
162
|
* equation
|
|
157
163
|
* \matrixXY{A}
|
|
@@ -163,19 +169,21 @@ export var InverseMatrixState;
|
|
|
163
169
|
* ```
|
|
164
170
|
* * If the matrix inverse is known it is stored in the inverseCoffs array.
|
|
165
171
|
* * The inverse status (`unknown`, `inverseStored`, `singular`) status is indicated by the `inverseState` property.
|
|
166
|
-
* *
|
|
167
|
-
*
|
|
168
|
-
*
|
|
169
|
-
*
|
|
172
|
+
* * Construction methods that are able to trivially construct the inverse, store it immediately and note that in
|
|
173
|
+
* the inverseState.
|
|
174
|
+
* * Constructions (e.g. createRowValues) for which the inverse is not immediately known mark the inverseState as
|
|
175
|
+
* unknown.
|
|
176
|
+
* * Later queries for the inverse, trigger full computation if needed at that time.
|
|
170
177
|
* * Most matrix queries are present with both "column" and "row" variants.
|
|
171
|
-
* * Usage elsewhere in the library is typically "column" based. For example, in a Transform
|
|
172
|
-
*
|
|
178
|
+
* * Usage elsewhere in the library is typically "column" based. For example, in a Transform that carries a
|
|
179
|
+
* coordinate frame, the matrix columns are the unit vectors for the axes.
|
|
173
180
|
* @public
|
|
174
181
|
*/
|
|
175
182
|
export class Matrix3d {
|
|
176
183
|
/**
|
|
177
|
-
*
|
|
178
|
-
* @param coffs optional coefficient array.
|
|
184
|
+
* Constructor
|
|
185
|
+
* @param coffs optional coefficient array.
|
|
186
|
+
* * **WARNING:** coffs is captured (i.e., is now owned by the Matrix3d object and can be modified by it).
|
|
179
187
|
*/
|
|
180
188
|
constructor(coffs) {
|
|
181
189
|
this.coffs = coffs ? coffs : new Float64Array(9);
|
|
@@ -193,14 +201,16 @@ export class Matrix3d {
|
|
|
193
201
|
/** Freeze this Matrix3d. */
|
|
194
202
|
freeze() {
|
|
195
203
|
this.computeCachedInverse(true);
|
|
196
|
-
/*
|
|
204
|
+
/*
|
|
205
|
+
hm.. can't freeze the Float64Arrays..
|
|
197
206
|
Object.freeze(this.coffs);
|
|
198
207
|
if (this.inverseCoffs)
|
|
199
208
|
Object.freeze(this.inverseCoffs);
|
|
200
209
|
*/
|
|
201
210
|
return Object.freeze(this);
|
|
202
211
|
}
|
|
203
|
-
/**
|
|
212
|
+
/**
|
|
213
|
+
* Return a json object containing the 9 numeric entries as a single array in row major order,
|
|
204
214
|
* `[ [1, 2, 3],[ 4, 5, 6], [7, 8, 9] ]`
|
|
205
215
|
*/
|
|
206
216
|
toJSON() {
|
|
@@ -208,46 +218,81 @@ export class Matrix3d {
|
|
|
208
218
|
[this.coffs[3], this.coffs[4], this.coffs[5]],
|
|
209
219
|
[this.coffs[6], this.coffs[7], this.coffs[8]]];
|
|
210
220
|
}
|
|
211
|
-
/**
|
|
221
|
+
/**
|
|
222
|
+
* Copy data from various input forms to this matrix.
|
|
212
223
|
* The source can be:
|
|
213
224
|
* * Another `Matrix3d`
|
|
214
225
|
* * An array of 3 arrays, each of which has the 3 numbers for a row of the matrix.
|
|
215
|
-
* * An array of 9 numbers in row major order.
|
|
226
|
+
* * An array of 4 or 9 numbers in row major order.
|
|
227
|
+
* * **WARNING:** if json is an array of numbers but size is not 4 or 9, the matrix is set to zeros.
|
|
216
228
|
*/
|
|
217
229
|
setFromJSON(json) {
|
|
218
230
|
this.inverseCoffs = undefined;
|
|
231
|
+
// if no json is passed
|
|
219
232
|
if (!json) {
|
|
220
233
|
this.setRowValues(0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
221
234
|
return;
|
|
222
235
|
}
|
|
236
|
+
// if json is Matrix3d
|
|
223
237
|
if (!Array.isArray(json)) {
|
|
224
238
|
if (json instanceof Matrix3d)
|
|
225
239
|
this.setFrom(json);
|
|
226
240
|
return;
|
|
227
241
|
}
|
|
242
|
+
// if json is Matrix3dProps and is an array of arrays
|
|
228
243
|
if (Geometry.isArrayOfNumberArray(json, 3, 3)) {
|
|
229
244
|
const data = json;
|
|
230
245
|
this.setRowValues(data[0][0], data[0][1], data[0][2], data[1][0], data[1][1], data[1][2], data[2][0], data[2][1], data[2][2]);
|
|
231
246
|
return;
|
|
232
247
|
}
|
|
248
|
+
// if json is Matrix3dProps and is an array of numbers
|
|
233
249
|
if (json.length === 9) {
|
|
234
250
|
const data = json;
|
|
235
251
|
this.setRowValues(data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7], data[8]);
|
|
252
|
+
return;
|
|
236
253
|
}
|
|
237
254
|
else if (json.length === 4) {
|
|
238
255
|
const data = json;
|
|
239
256
|
this.setRowValues(data[0], data[1], 0, data[2], data[3], 0, 0, 0, 1);
|
|
257
|
+
return;
|
|
240
258
|
}
|
|
259
|
+
// if json is Matrix3dProps but is not the right size
|
|
260
|
+
this.setRowValues(0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
261
|
+
return;
|
|
262
|
+
}
|
|
263
|
+
/** Return a new Matrix3d constructed from contents of the json value. See `setFromJSON` for layout rules */
|
|
264
|
+
static fromJSON(json) {
|
|
265
|
+
const result = Matrix3d.createIdentity();
|
|
266
|
+
result.setFromJSON(json);
|
|
267
|
+
return result;
|
|
241
268
|
}
|
|
242
|
-
/**
|
|
243
|
-
|
|
244
|
-
/** Test if this Matrix3d and other are within tolerance in all numeric entries.
|
|
269
|
+
/**
|
|
270
|
+
* Test if `this` and `other` are within tolerance in all numeric entries.
|
|
245
271
|
* @param tol optional tolerance for comparisons by Geometry.isDistanceWithinTol
|
|
246
272
|
*/
|
|
247
273
|
isAlmostEqual(other, tol) {
|
|
248
274
|
return Geometry.isDistanceWithinTol(this.maxDiff(other), tol);
|
|
249
275
|
}
|
|
250
|
-
/**
|
|
276
|
+
/**
|
|
277
|
+
* Test if `this` and `other` are within tolerance in the column entries specified by `columnIndex`.
|
|
278
|
+
* @param tol optional tolerance for comparisons by Geometry.isDistanceWithinTol
|
|
279
|
+
*/
|
|
280
|
+
isAlmostEqualColumn(columnIndex, other, tol) {
|
|
281
|
+
const max = Geometry.maxAbsXYZ(this.coffs[columnIndex] - other.coffs[columnIndex], this.coffs[columnIndex + 3] - other.coffs[columnIndex + 3], this.coffs[columnIndex + 6] - other.coffs[columnIndex + 6]);
|
|
282
|
+
return Geometry.isDistanceWithinTol(max, tol);
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Test if column (specified by `columnIndex`) entries of `this` and [ax,ay,az] are within tolerance.
|
|
286
|
+
* @param tol optional tolerance for comparisons by Geometry.isDistanceWithinTol
|
|
287
|
+
*/
|
|
288
|
+
isAlmostEqualColumnXYZ(columnIndex, ax, ay, az, tol) {
|
|
289
|
+
const max = Geometry.maxAbsXYZ(this.coffs[columnIndex] - ax, this.coffs[columnIndex + 3] - ay, this.coffs[columnIndex + 6] - az);
|
|
290
|
+
return Geometry.isDistanceWithinTol(max, tol);
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Test if `this` and `other` have almost equal Z column and have X and Y columns differing only by a
|
|
294
|
+
* rotation of the same angle around that Z.
|
|
295
|
+
* * **WARNING:** X and Y columns have to be perpendicular to Z column in both `this` and `other`.
|
|
251
296
|
* @param tol optional tolerance for comparisons by Geometry.isDistanceWithinTol
|
|
252
297
|
*/
|
|
253
298
|
isAlmostEqualAllowZRotation(other, tol) {
|
|
@@ -255,10 +300,15 @@ export class Matrix3d {
|
|
|
255
300
|
return true;
|
|
256
301
|
if (this.isAlmostEqualColumn(AxisIndex.Z, other, tol)) {
|
|
257
302
|
const radians = Angle.radiansBetweenVectorsXYZ(this.coffs[0], this.coffs[3], this.coffs[6], other.coffs[0], other.coffs[3], other.coffs[6]);
|
|
258
|
-
const angle = Angle.createRadians(radians);
|
|
303
|
+
const angle = Angle.createRadians(radians); // angle between X columns in `this` and `other`
|
|
259
304
|
const columnX = this.columnX();
|
|
260
305
|
const columnY = this.columnY();
|
|
261
306
|
const columnZ = this.columnZ();
|
|
307
|
+
/**
|
|
308
|
+
* Here we rotate this.columnX() around this.columnZ() by "angle" and expect to get other.columnX().
|
|
309
|
+
* Then we rotate this.columnY() around this.columnZ() by the same "angle" and if we get other.columnY(),
|
|
310
|
+
* that means this` and `other` have X and Y columns differing only by a rotation around that Z.
|
|
311
|
+
*/
|
|
262
312
|
let column = Vector3d.createRotateVectorAroundVector(columnX, columnZ, angle);
|
|
263
313
|
if (other.isAlmostEqualColumnXYZ(0, column.x, column.y, column.z, tol)) {
|
|
264
314
|
column = Vector3d.createRotateVectorAroundVector(columnY, columnZ, angle);
|
|
@@ -267,16 +317,10 @@ export class Matrix3d {
|
|
|
267
317
|
}
|
|
268
318
|
return false;
|
|
269
319
|
}
|
|
270
|
-
isAlmostEqualColumn(columnIndex, other, tol) {
|
|
271
|
-
const a = Geometry.maxAbsXYZ(this.coffs[columnIndex] - other.coffs[columnIndex], this.coffs[columnIndex + 3] - other.coffs[columnIndex + 3], this.coffs[columnIndex + 6] - other.coffs[columnIndex + 6]);
|
|
272
|
-
return Geometry.isDistanceWithinTol(a, tol);
|
|
273
|
-
}
|
|
274
|
-
isAlmostEqualColumnXYZ(columnIndex, ax, ay, az, tol) {
|
|
275
|
-
const a = Geometry.maxAbsXYZ(this.coffs[columnIndex] - ax, this.coffs[columnIndex + 3] - ay, this.coffs[columnIndex + 6] - az);
|
|
276
|
-
return Geometry.isDistanceWithinTol(a, tol);
|
|
277
|
-
}
|
|
278
320
|
/** Test for exact (bitwise) equality with other. */
|
|
279
|
-
isExactEqual(other) {
|
|
321
|
+
isExactEqual(other) {
|
|
322
|
+
return this.maxDiff(other) === 0.0;
|
|
323
|
+
}
|
|
280
324
|
/** test if all entries in the z row and column are exact 001, i.e. the matrix only acts in 2d */
|
|
281
325
|
get isXY() {
|
|
282
326
|
return this.coffs[2] === 0.0
|
|
@@ -285,10 +329,16 @@ export class Matrix3d {
|
|
|
285
329
|
&& this.coffs[7] === 0.0
|
|
286
330
|
&& this.coffs[8] === 1.0;
|
|
287
331
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
332
|
+
/**
|
|
333
|
+
* If result is not provided, then the method returns a new (zeroed) matrix; otherwise the result is
|
|
334
|
+
* not zeroed first and is just returned as-is.
|
|
335
|
+
*/
|
|
336
|
+
static _create(result) {
|
|
337
|
+
return result ? result : new Matrix3d();
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* Returns a Matrix3d populated by numeric values given in row-major order.
|
|
341
|
+
* Sets all entries in the matrix from call parameters appearing in row-major order, i.e.
|
|
292
342
|
* ```
|
|
293
343
|
* equation
|
|
294
344
|
* \begin{bmatrix}a_{xx}\ a_{xy}\ a_{xz}\\ a_{yx}\ a_{yy}\ a_{yz}\\ a_{zx}\ a_{zy}\ a_{zz}\end{bmatrix}
|
|
@@ -319,7 +369,7 @@ export class Matrix3d {
|
|
|
319
369
|
}
|
|
320
370
|
/**
|
|
321
371
|
* Create a Matrix3d with caller-supplied coefficients and optional inverse coefficients.
|
|
322
|
-
* * The inputs are captured into the new Matrix3d.
|
|
372
|
+
* * The inputs are captured into (i.e., owned by) the new Matrix3d.
|
|
323
373
|
* * The caller is responsible for validity of the inverse coefficients.
|
|
324
374
|
* @param coffs (required) array of 9 coefficients.
|
|
325
375
|
* @param inverseCoffs (optional) array of 9 coefficients.
|
|
@@ -337,12 +387,15 @@ export class Matrix3d {
|
|
|
337
387
|
return result;
|
|
338
388
|
}
|
|
339
389
|
/**
|
|
340
|
-
*
|
|
390
|
+
* Create a matrix by distributing vectors to columns in one of 6 orders.
|
|
341
391
|
* @param axisOrder identifies where the columns are placed.
|
|
342
|
-
* @param columnA vector to place in the
|
|
343
|
-
* @param columnB vector to place in the
|
|
344
|
-
* @param columnC vector to place in the
|
|
345
|
-
* @param result
|
|
392
|
+
* @param columnA vector to place in the column specified by first letter in the AxisOrder name.
|
|
393
|
+
* @param columnB vector to place in the column specified by second letter in the AxisOrder name.
|
|
394
|
+
* @param columnC vector to place in the column specified by third letter in the AxisOrder name.
|
|
395
|
+
* @param result optional result matrix3d
|
|
396
|
+
* * Example: If you pass AxisOrder.YZX, then result will be [columnC, columnA, columnB] because
|
|
397
|
+
* first letter Y means columnA should go to the second column, second letter Z means columnB should
|
|
398
|
+
* go to the third column, and third letter X means columnC should go to the first column.
|
|
346
399
|
*/
|
|
347
400
|
static createColumnsInAxisOrder(axisOrder, columnA, columnB, columnC, result) {
|
|
348
401
|
if (!result)
|
|
@@ -362,13 +415,26 @@ export class Matrix3d {
|
|
|
362
415
|
else if (axisOrder === AxisOrder.ZYX) {
|
|
363
416
|
result.setColumns(columnC, columnB, columnA);
|
|
364
417
|
}
|
|
365
|
-
else { //
|
|
418
|
+
else { // AxisOrder.XYZ
|
|
366
419
|
result.setColumns(columnA, columnB, columnC);
|
|
367
420
|
}
|
|
368
421
|
return result;
|
|
369
422
|
}
|
|
370
423
|
/**
|
|
371
|
-
|
|
424
|
+
* Copy the transpose of the coffs to the inverseCoffs.
|
|
425
|
+
* * Mark the matrix as inverseStored.
|
|
426
|
+
*/
|
|
427
|
+
setupInverseTranspose() {
|
|
428
|
+
const coffs = this.coffs;
|
|
429
|
+
this.inverseState = InverseMatrixState.inverseStored;
|
|
430
|
+
this.inverseCoffs = Float64Array.from([
|
|
431
|
+
coffs[0], coffs[3], coffs[6],
|
|
432
|
+
coffs[1], coffs[4], coffs[7],
|
|
433
|
+
coffs[2], coffs[5], coffs[8],
|
|
434
|
+
]);
|
|
435
|
+
}
|
|
436
|
+
/**
|
|
437
|
+
* Set all entries in the matrix from call parameters appearing in row-major order.
|
|
372
438
|
* @param axx Row x, column x (0,0) entry
|
|
373
439
|
* @param axy Row x, column y (0,1) entry
|
|
374
440
|
* @param axz Row x, column z (0,2) entry
|
|
@@ -392,15 +458,22 @@ export class Matrix3d {
|
|
|
392
458
|
this.inverseState = InverseMatrixState.unknown;
|
|
393
459
|
}
|
|
394
460
|
/** Set the matrix to an identity. */
|
|
395
|
-
setIdentity() {
|
|
461
|
+
setIdentity() {
|
|
462
|
+
this.setRowValues(1, 0, 0, 0, 1, 0, 0, 0, 1);
|
|
463
|
+
this.setupInverseTranspose();
|
|
464
|
+
}
|
|
396
465
|
/** Set the matrix to all zeros. */
|
|
397
|
-
setZero() {
|
|
398
|
-
|
|
466
|
+
setZero() {
|
|
467
|
+
this.setRowValues(0, 0, 0, 0, 0, 0, 0, 0, 0);
|
|
468
|
+
this.inverseState = InverseMatrixState.singular;
|
|
469
|
+
}
|
|
470
|
+
/** Copy contents from another matrix. */
|
|
399
471
|
setFrom(other) {
|
|
400
472
|
if (other === undefined) {
|
|
401
473
|
this.setIdentity();
|
|
474
|
+
return;
|
|
402
475
|
}
|
|
403
|
-
|
|
476
|
+
if (other !== this) {
|
|
404
477
|
for (let i = 0; i < 9; i++)
|
|
405
478
|
this.coffs[i] = other.coffs[i];
|
|
406
479
|
if (other.inverseState === InverseMatrixState.inverseStored && other.inverseCoffs !== undefined) {
|
|
@@ -412,28 +485,29 @@ export class Matrix3d {
|
|
|
412
485
|
else if (other.inverseState !== InverseMatrixState.inverseStored) {
|
|
413
486
|
this.inverseState = other.inverseState;
|
|
414
487
|
}
|
|
415
|
-
else { // This is reached
|
|
488
|
+
else { // This is reached when other says stored but does not have coffs. This should not happen.
|
|
416
489
|
this.inverseState = InverseMatrixState.unknown;
|
|
417
490
|
}
|
|
418
491
|
}
|
|
419
492
|
}
|
|
420
|
-
/**
|
|
421
|
-
*
|
|
422
|
-
* *
|
|
423
|
-
* * inverse status
|
|
493
|
+
/**
|
|
494
|
+
* Return a clone of this matrix.
|
|
495
|
+
* * Coefficients are copied.
|
|
496
|
+
* * Inverse coefficients and inverse status are copied if stored by `this`.
|
|
424
497
|
*/
|
|
425
498
|
clone(result) {
|
|
426
499
|
result = result ? result : new Matrix3d();
|
|
427
500
|
result.setFrom(this);
|
|
428
501
|
return result;
|
|
429
502
|
}
|
|
430
|
-
/**
|
|
503
|
+
/**
|
|
504
|
+
* Create a matrix with all zeros.
|
|
431
505
|
* * Note that for geometry transformations "all zeros" is not a useful default state.
|
|
432
|
-
* * Hence almost always use `createIdentity` for graphics transformations.
|
|
433
|
-
* * "
|
|
506
|
+
* * Hence, almost always use `createIdentity` for graphics transformations.
|
|
507
|
+
* * "All zeros" is appropriate for summing moment data.
|
|
434
508
|
* ```
|
|
435
509
|
* equation
|
|
436
|
-
* \begin{bmatrix}0 0 0 \\ 0 0 0 \\ 0 0 0\end{bmatrix}
|
|
510
|
+
* \begin{bmatrix}0 & 0 & 0 \\ 0 & 0 & 0 \\ 0 & 0 & 0\end{bmatrix}
|
|
437
511
|
* ```
|
|
438
512
|
*/
|
|
439
513
|
static createZero() {
|
|
@@ -441,13 +515,14 @@ export class Matrix3d {
|
|
|
441
515
|
retVal.inverseState = InverseMatrixState.singular;
|
|
442
516
|
return retVal;
|
|
443
517
|
}
|
|
444
|
-
/**
|
|
445
|
-
*
|
|
446
|
-
* *
|
|
447
|
-
* *
|
|
518
|
+
/**
|
|
519
|
+
* Create an identity matrix.
|
|
520
|
+
* * All diagonal entries (xx,yy,zz) are one
|
|
521
|
+
* * All others are zero.
|
|
522
|
+
* * This (rather than "all zeros") is the useful state for most graphics transformations.
|
|
448
523
|
* ```
|
|
449
524
|
* equation
|
|
450
|
-
* \begin{bmatrix}1 0 0 \\ 0 1 0 \\ 0 0 1\end{bmatrix}
|
|
525
|
+
* \begin{bmatrix}1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1\end{bmatrix}
|
|
451
526
|
* ```
|
|
452
527
|
*
|
|
453
528
|
*/
|
|
@@ -457,55 +532,7 @@ export class Matrix3d {
|
|
|
457
532
|
return result;
|
|
458
533
|
}
|
|
459
534
|
/**
|
|
460
|
-
* Create a matrix with
|
|
461
|
-
* For scale factor _s_,
|
|
462
|
-
* ```
|
|
463
|
-
* equation
|
|
464
|
-
* \begin{bmatrix}s & 0 & 0 \\ 0 & s & 0\\ 0 & 0 & s\end{bmatrix}
|
|
465
|
-
* ```
|
|
466
|
-
*/
|
|
467
|
-
static createUniformScale(scaleFactor) {
|
|
468
|
-
return Matrix3d.createScale(scaleFactor, scaleFactor, scaleFactor);
|
|
469
|
-
}
|
|
470
|
-
/**
|
|
471
|
-
* Construct a rigid matrix using createPerpendicularVectorFavorXYPlane to generate a vector perpendicular to vectorA.
|
|
472
|
-
* *
|
|
473
|
-
*/
|
|
474
|
-
static createRigidHeadsUp(vectorA, axisOrder = AxisOrder.ZXY, result) {
|
|
475
|
-
const vectorB = Matrix3d.createPerpendicularVectorFavorXYPlane(vectorA);
|
|
476
|
-
const matrix = Matrix3d.createRigidFromColumns(vectorA, vectorB, axisOrder, result);
|
|
477
|
-
if (matrix) {
|
|
478
|
-
matrix.setupInverseTranspose();
|
|
479
|
-
return matrix;
|
|
480
|
-
}
|
|
481
|
-
return Matrix3d.createIdentity(result);
|
|
482
|
-
}
|
|
483
|
-
/**
|
|
484
|
-
* return a vector that is perpendicular to the input direction.
|
|
485
|
-
* * Among the infinite number of perpendiculars possible, this method
|
|
486
|
-
* favors having one in the xy plane.
|
|
487
|
-
* * Hence, when vectorA is NOT close to the Z axis, the returned vector is Z cross vectorA.
|
|
488
|
-
* * But vectorA is close to the Z axis, the returned vector is unitY cross vectorA.
|
|
489
|
-
*/
|
|
490
|
-
static createPerpendicularVectorFavorXYPlane(vector, result) {
|
|
491
|
-
const a = vector.magnitude();
|
|
492
|
-
const b = a / 64.0; // A constant from the dawn of time in the CAD industry.
|
|
493
|
-
if (Math.abs(vector.x) < b && Math.abs(vector.y) < b) {
|
|
494
|
-
return Vector3d.createCrossProduct(vector.x, vector.y, vector.z, 0, -1, 0, result);
|
|
495
|
-
}
|
|
496
|
-
return Vector3d.createCrossProduct(0, 0, 1, vector.x, vector.y, vector.z, result);
|
|
497
|
-
}
|
|
498
|
-
/**
|
|
499
|
-
* return a vector that is perpendicular to the input direction.
|
|
500
|
-
* * Among the infinite number of perpendiculars possible, this method
|
|
501
|
-
* favors having one near the Z.
|
|
502
|
-
* That is achieved by crossing "this" vector with the result of createPerpendicularVectorFavorXYPlane.
|
|
503
|
-
*/
|
|
504
|
-
static createPerpendicularVectorFavorPlaneContainingZ(vector, result) {
|
|
505
|
-
result = Matrix3d.createPerpendicularVectorFavorXYPlane(vector, result);
|
|
506
|
-
return vector.crossProduct(result, result);
|
|
507
|
-
}
|
|
508
|
-
/** Create a matrix with distinct x,y,z diagonal (scale) entries.
|
|
535
|
+
* Create a matrix with distinct x,y,z diagonal (scale) entries.
|
|
509
536
|
* ```
|
|
510
537
|
* equation
|
|
511
538
|
* \begin{bmatrix}s_x & 0 & 0 \\ 0 & s_y & 0\\ 0 & 0 & s_z\end{bmatrix}
|
|
@@ -530,7 +557,101 @@ export class Matrix3d {
|
|
|
530
557
|
}
|
|
531
558
|
return result;
|
|
532
559
|
}
|
|
533
|
-
/**
|
|
560
|
+
/**
|
|
561
|
+
* Create a matrix with uniform scale factors for scale factor "s"
|
|
562
|
+
* ```
|
|
563
|
+
* equation
|
|
564
|
+
* \begin{bmatrix}s & 0 & 0 \\ 0 & s & 0\\ 0 & 0 & s\end{bmatrix}
|
|
565
|
+
* ```
|
|
566
|
+
*/
|
|
567
|
+
static createUniformScale(scaleFactor) {
|
|
568
|
+
return Matrix3d.createScale(scaleFactor, scaleFactor, scaleFactor);
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Return a vector that is perpendicular to the input `vectorA`.
|
|
572
|
+
* * Among the infinite number of perpendiculars possible, this method favors having one in the xy plane.
|
|
573
|
+
* * Hence, when `vectorA` is close to the Z axis, the returned vector is `vectorA cross -unitY`
|
|
574
|
+
* but when `vectorA` is NOT close to the Z axis, the returned vector is `unitZ cross vectorA`.
|
|
575
|
+
*/
|
|
576
|
+
static createPerpendicularVectorFavorXYPlane(vectorA, result) {
|
|
577
|
+
const a = vectorA.magnitude();
|
|
578
|
+
const scale = 64.0; // A constant from the dawn of time in the CAD industry
|
|
579
|
+
const b = a / scale;
|
|
580
|
+
// if vectorA is close to the Z axis
|
|
581
|
+
if (Math.abs(vectorA.x) < b && Math.abs(vectorA.y) < b) {
|
|
582
|
+
return Vector3d.createCrossProduct(vectorA.x, vectorA.y, vectorA.z, 0, -1, 0, result);
|
|
583
|
+
}
|
|
584
|
+
// if vectorA is NOT close to the Z axis
|
|
585
|
+
return Vector3d.createCrossProduct(0, 0, 1, vectorA.x, vectorA.y, vectorA.z, result);
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Return a vector that is perpendicular to the input `vectorA`.
|
|
589
|
+
* * Among the infinite number of perpendiculars possible, this method favors having one near the plane
|
|
590
|
+
* containing Z.
|
|
591
|
+
* That is achieved by cross product of `this` vector with the result of createPerpendicularVectorFavorXYPlane.
|
|
592
|
+
*/
|
|
593
|
+
static createPerpendicularVectorFavorPlaneContainingZ(vectorA, result) {
|
|
594
|
+
/**
|
|
595
|
+
* vectorA, result (below), and "vectorA cross result" form a coordinate system where "result" is located on
|
|
596
|
+
* the XY-plane. Once you've got a coordinate system with an axis in the XY-plane, your other two axes form
|
|
597
|
+
* a plane that includes the z-axis.
|
|
598
|
+
*/
|
|
599
|
+
result = Matrix3d.createPerpendicularVectorFavorXYPlane(vectorA, result);
|
|
600
|
+
return vectorA.crossProduct(result, result);
|
|
601
|
+
}
|
|
602
|
+
/**
|
|
603
|
+
* Create a matrix from column vectors, shuffled into place per axisOrder
|
|
604
|
+
* For example, if axisOrder = XYZ then it returns [vectorU, vectorV, vectorW]
|
|
605
|
+
* Another example, if axisOrder = YZX then it returns [vectorW, vectorU, vectorV] because
|
|
606
|
+
* Y is at index 0 so vectorU goes to the column Y (column 2), Z is at index 1 so vectorV goes
|
|
607
|
+
* to the column Z (column 3), and X is at index 2 so vectorW goes to the column X (column 1)
|
|
608
|
+
*/
|
|
609
|
+
static createShuffledColumns(vectorU, vectorV, vectorW, axisOrder, result) {
|
|
610
|
+
const target = Matrix3d._create(result);
|
|
611
|
+
target.setColumn(Geometry.axisOrderToAxis(axisOrder, 0), vectorU);
|
|
612
|
+
target.setColumn(Geometry.axisOrderToAxis(axisOrder, 1), vectorV);
|
|
613
|
+
target.setColumn(Geometry.axisOrderToAxis(axisOrder, 2), vectorW);
|
|
614
|
+
return target;
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Create a new orthogonal matrix (perpendicular columns, unit length, transpose is inverse).
|
|
618
|
+
* * `vectorA1 = Normalized vectorA` is placed in the column specified by **first** letter in
|
|
619
|
+
* the AxisOrder name.
|
|
620
|
+
* * Normalized `vectorC1 = vectorA1 cross vectorB` is placed in the column specified by **third**
|
|
621
|
+
* letter in the AxisOrder name.
|
|
622
|
+
* * Normalized `vectorC1 cross vectorA` is placed in the column specified by **second**
|
|
623
|
+
* letter in the AxisOrder name.
|
|
624
|
+
* * This function internally uses createShuffledColumns.
|
|
625
|
+
*/
|
|
626
|
+
static createRigidFromColumns(vectorA, vectorB, axisOrder, result) {
|
|
627
|
+
const vectorA1 = vectorA.normalize();
|
|
628
|
+
if (vectorA1) {
|
|
629
|
+
const vectorC1 = vectorA1.unitCrossProduct(vectorB);
|
|
630
|
+
if (vectorC1) {
|
|
631
|
+
const vectorB1 = vectorC1.unitCrossProduct(vectorA);
|
|
632
|
+
if (vectorB1) {
|
|
633
|
+
const retVal = Matrix3d.createShuffledColumns(vectorA1, vectorB1, vectorC1, axisOrder, result);
|
|
634
|
+
retVal.setupInverseTranspose();
|
|
635
|
+
return retVal;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
return undefined;
|
|
640
|
+
}
|
|
641
|
+
/**
|
|
642
|
+
* Construct a rigid matrix using vectorA and its 2 perpendicular.
|
|
643
|
+
* * This function internally uses createPerpendicularVectorFavorXYPlane and createRigidFromColumns.
|
|
644
|
+
*/
|
|
645
|
+
static createRigidHeadsUp(vectorA, axisOrder = AxisOrder.ZXY, result) {
|
|
646
|
+
const vectorB = Matrix3d.createPerpendicularVectorFavorXYPlane(vectorA);
|
|
647
|
+
const matrix = Matrix3d.createRigidFromColumns(vectorA, vectorB, axisOrder, result);
|
|
648
|
+
if (matrix) {
|
|
649
|
+
matrix.setupInverseTranspose();
|
|
650
|
+
return matrix;
|
|
651
|
+
}
|
|
652
|
+
return Matrix3d.createIdentity(result);
|
|
653
|
+
}
|
|
654
|
+
/** Return the matrix for rotation of `angle` around `axis` */
|
|
534
655
|
static createRotationAroundVector(axis, angle, result) {
|
|
535
656
|
// Rodriguez formula (matrix form), https://mathworld.wolfram.com/RodriguesRotationFormula.html
|
|
536
657
|
const c = angle.cos();
|
|
@@ -548,6 +669,7 @@ export class Matrix3d {
|
|
|
548
669
|
* @param axisIndex index of axis (AxisIndex.X, AxisIndex.Y, AxisIndex.Z) kept fixed by the rotation.
|
|
549
670
|
* @param angle angle of rotation
|
|
550
671
|
* @param result optional result matrix.
|
|
672
|
+
* * Math details of 3d rotation matrices derivation can be found at docs/learning/geometry/Angle.md
|
|
551
673
|
*/
|
|
552
674
|
static createRotationAroundAxisIndex(axisIndex, angle, result) {
|
|
553
675
|
const c = angle.cos();
|
|
@@ -565,27 +687,77 @@ export class Matrix3d {
|
|
|
565
687
|
myResult.setupInverseTranspose();
|
|
566
688
|
return myResult;
|
|
567
689
|
}
|
|
690
|
+
/**
|
|
691
|
+
* Replace current columns Ui and Uj with (c*Ui - s*Uj) and (c*Uj + s*Ui).
|
|
692
|
+
* * There is no checking for i,j being 0,1,2.
|
|
693
|
+
* * This is used in compute intensive inner loops
|
|
694
|
+
* @param i first row index. **must be 0,1,2** (unchecked)
|
|
695
|
+
* @param j second row index. **must be 0,1,2** (unchecked)
|
|
696
|
+
* @param c fist coefficient
|
|
697
|
+
* @param s second coefficient
|
|
698
|
+
*/
|
|
699
|
+
applyGivensColumnOp(i, j, c, s) {
|
|
700
|
+
const limit = i + 9;
|
|
701
|
+
for (; i < limit; i += 3, j += 3) {
|
|
702
|
+
const a = this.coffs[i];
|
|
703
|
+
const b = this.coffs[j];
|
|
704
|
+
this.coffs[i] = a * c + b * s;
|
|
705
|
+
this.coffs[j] = -a * s + b * c;
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
/**
|
|
709
|
+
* Create a matrix from column vectors.
|
|
710
|
+
* ```
|
|
711
|
+
* equation
|
|
712
|
+
* \begin{bmatrix}U_x & V_x & W_x \\ U_y & V_y & W_y \\ U_z & V_z & W_z \end{bmatrix}
|
|
713
|
+
* ```
|
|
714
|
+
*/
|
|
715
|
+
static createColumns(vectorU, vectorV, vectorW, result) {
|
|
716
|
+
return Matrix3d.createRowValues(vectorU.x, vectorV.x, vectorW.x, vectorU.y, vectorV.y, vectorW.y, vectorU.z, vectorV.z, vectorW.z, result);
|
|
717
|
+
}
|
|
718
|
+
/** Create a matrix with each column's _x,y_ parts given `XAndY` and separate numeric z values.
|
|
719
|
+
* ```
|
|
720
|
+
* equation
|
|
721
|
+
* \begin{bmatrix}U_x & V_x & W_x \\ U_y & V_y & W_y \\ u & v & w \end{bmatrix}
|
|
722
|
+
* ```
|
|
723
|
+
*/
|
|
724
|
+
static createColumnsXYW(vectorU, u, vectorV, v, vectorW, w, result) {
|
|
725
|
+
return Matrix3d.createRowValues(vectorU.x, vectorV.x, vectorW.x, vectorU.y, vectorV.y, vectorW.y, u, v, w, result);
|
|
726
|
+
}
|
|
568
727
|
/** Create a matrix from "as viewed" right and up vectors.
|
|
569
728
|
* * ColumnX points in the rightVector direction
|
|
570
|
-
* * ColumnY points in
|
|
571
|
-
* * ColumnZ is a unit cross product.
|
|
572
|
-
* Optionally rotate the standard cube by 45 to bring its left or right vertical edge to center
|
|
573
|
-
* *
|
|
574
|
-
* *
|
|
575
|
-
*
|
|
576
|
-
*
|
|
577
|
-
*
|
|
578
|
-
*
|
|
579
|
-
*
|
|
580
|
-
*
|
|
581
|
-
*
|
|
582
|
-
*
|
|
583
|
-
* @
|
|
729
|
+
* * ColumnY points in the upVector direction
|
|
730
|
+
* * ColumnZ is a unit cross product of ColumnX and ColumnY.
|
|
731
|
+
* * Optionally rotate the standard cube by 45 degrees ccw around Y to bring its left or right vertical edge to center.
|
|
732
|
+
* * Optionally rotate the standard cube by 35.264 degrees ccw around X (isometric rotation).
|
|
733
|
+
* * This is expected to be used with various principal unit vectors that are perpendicular to each other.
|
|
734
|
+
* * STANDARD TOP VIEW: createViewedAxes(Vector3d.unitX(), Vector3d.unitY(), 0, 0)
|
|
735
|
+
* * STANDARD FRONT VIEW: createViewedAxes(Vector3d.unitX(), Vector3d.unitZ(), 0, 0)
|
|
736
|
+
* * STANDARD BACK VIEW: createViewedAxes(Vector3d.unitX(-1), Vector3d.unitZ(), 0, 0)
|
|
737
|
+
* * STANDARD RIGHT VIEW: createViewedAxes(Vector3d.unitY(), Vector3d.unitZ(), 0, 0)
|
|
738
|
+
* * STANDARD LEFT VIEW: createViewedAxes(Vector3d.unitY(-1), Vector3d.unitZ(), 0, 0)
|
|
739
|
+
* * STANDARD BOTTOM VIEW: createViewedAxes(Vector3d.unitX(), Vector3d.unitY(-1), 0, 0)
|
|
740
|
+
* * Note: createViewedAxes is column-based so always returns local to world
|
|
741
|
+
*
|
|
742
|
+
* @param rightVector ColumnX of the returned matrix. Expected to be perpendicular to upVector.
|
|
743
|
+
* @param upVector ColumnY of the returned matrix. Expected to be perpendicular to rightVector.
|
|
744
|
+
* @param leftNoneRight Specifies the ccw rotation around Y axis. Normally one of "-1", "0", and "1", where
|
|
745
|
+
* "-1" indicates rotation by 45 degrees to bring the left vertical edge to center, "0" means no rotation,
|
|
746
|
+
* and "1" indicates rotation by 45 degrees to bring the right vertical edge to center. Other numbers are
|
|
747
|
+
* used as multiplier for this 45 degree rotation.
|
|
748
|
+
* @param topNoneBottom Specifies the ccw rotation around X axis. Normally one of "-1", "0", and "1", where
|
|
749
|
+
* "-1" indicates isometric rotation (35.264 degrees) to bring the bottom upward, "0" means no rotation,
|
|
750
|
+
* and "1" indicates isometric rotation (35.264 degrees) to bring the top downward. Other numbers are
|
|
751
|
+
* used as multiplier for the 35.264 degree rotation.
|
|
752
|
+
* @returns matrix = [rightVector, upVector, rightVector cross upVector] with the applied rotations specified
|
|
753
|
+
* by leftNoneRight and topNoneBottom. Returns undefined if rightVector and upVector are parallel.
|
|
584
754
|
*/
|
|
585
755
|
static createViewedAxes(rightVector, upVector, leftNoneRight = 0, topNoneBottom = 0) {
|
|
586
756
|
const columnZ = rightVector.crossProduct(upVector);
|
|
587
757
|
if (columnZ.normalizeInPlace()) {
|
|
588
|
-
|
|
758
|
+
// matrix = [rightVector, upVector, rightVector cross upVector]
|
|
759
|
+
const matrix = Matrix3d.createColumns(rightVector, upVector, columnZ);
|
|
760
|
+
// "45 degrees * leftNoneRight" rotation around Y
|
|
589
761
|
if (leftNoneRight !== 0.0) {
|
|
590
762
|
let c = Math.sqrt(0.5);
|
|
591
763
|
let s = leftNoneRight < 0.0 ? -c : c;
|
|
@@ -594,51 +766,63 @@ export class Matrix3d {
|
|
|
594
766
|
c = Math.cos(radians);
|
|
595
767
|
s = Math.sin(radians);
|
|
596
768
|
}
|
|
597
|
-
|
|
769
|
+
matrix.applyGivensColumnOp(2, 0, c, s); // rotate around Y (equivalent to matrix*rotationY)
|
|
598
770
|
}
|
|
771
|
+
// "35.264 degrees * topNoneBottom" rotation around X
|
|
599
772
|
if (topNoneBottom !== 0.0) {
|
|
600
773
|
const theta = topNoneBottom * Math.atan(Math.sqrt(0.5));
|
|
601
774
|
const c = Math.cos(theta);
|
|
602
775
|
const s = Math.sin(theta);
|
|
603
|
-
|
|
776
|
+
matrix.applyGivensColumnOp(1, 2, c, -s); // rotate around X (equivalent to matrix*rotationX)
|
|
604
777
|
}
|
|
605
|
-
return
|
|
778
|
+
return matrix;
|
|
606
779
|
}
|
|
607
780
|
return undefined;
|
|
608
781
|
}
|
|
609
782
|
/**
|
|
610
783
|
* Create a rotation matrix for one of the 8 standard views.
|
|
611
|
-
* *
|
|
612
|
-
* *
|
|
784
|
+
* * Default is TOP view (`local X = world X`, `local Y = world Y`, `local Z = world Z`).
|
|
785
|
+
* * To change view from the TOP to one of the other 7 standard views, we need to multiply "world data" to
|
|
786
|
+
* the corresponding matrix1 provided by `createStandardWorldToView(index, false)` and then
|
|
787
|
+
* `matrix1.multiply(world data)` will returns "local data".
|
|
788
|
+
* * To change view back to the TOP, we need to multiply "local data" to the corresponding matrix2 provided
|
|
789
|
+
* by `createStandardWorldToView(index, true)` and then `matrix2.multiply(local data)` will returns "world data".
|
|
613
790
|
*
|
|
614
|
-
* @param index standard view index `StandardViewIndex.Top, Bottom,
|
|
615
|
-
* @param invert if false (default), the
|
|
791
|
+
* @param index standard view index `StandardViewIndex.Top, Bottom, Left, Right, Front, Back, Iso, RightIso`
|
|
792
|
+
* @param invert if false (default), the return matrix is world to local (view) and if true, the the return
|
|
793
|
+
* matrix is local (view) to world.
|
|
616
794
|
* @param result optional result.
|
|
617
795
|
*/
|
|
618
796
|
static createStandardWorldToView(index, invert = false, result) {
|
|
619
797
|
switch (index) {
|
|
798
|
+
// start with TOP view, ccw rotation by 180 degrees around X
|
|
620
799
|
case StandardViewIndex.Bottom:
|
|
621
800
|
result = Matrix3d.createRowValues(1, 0, 0, 0, -1, 0, 0, 0, -1);
|
|
622
801
|
break;
|
|
802
|
+
// start with TOP view, ccw rotation by -90 degrees around X and by 90 degrees around Z
|
|
623
803
|
case StandardViewIndex.Left:
|
|
624
804
|
result = Matrix3d.createRowValues(0, -1, 0, 0, 0, 1, -1, 0, 0);
|
|
625
805
|
break;
|
|
806
|
+
// start with TOP view, ccw rotation by -90 degrees around X and by -90 degrees around Z
|
|
626
807
|
case StandardViewIndex.Right:
|
|
627
808
|
result = Matrix3d.createRowValues(0, 1, 0, 0, 0, 1, 1, 0, 0);
|
|
628
809
|
break;
|
|
629
|
-
|
|
810
|
+
// start with TOP view, ccw rotation by -90 degrees around X
|
|
811
|
+
case StandardViewIndex.Front:
|
|
630
812
|
result = Matrix3d.createRowValues(1, 0, 0, 0, 0, 1, 0, -1, 0);
|
|
631
813
|
break;
|
|
632
|
-
|
|
814
|
+
// start with TOP view, ccw rotation by -90 degrees around X and by 180 degrees around Z
|
|
815
|
+
case StandardViewIndex.Back:
|
|
633
816
|
result = Matrix3d.createRowValues(-1, 0, 0, 0, 0, 1, 0, 1, 0);
|
|
634
817
|
break;
|
|
635
818
|
case StandardViewIndex.Iso:
|
|
819
|
+
// start with FRONT view, ccw rotation by -45 degrees around Y and by 35.264 degrees around X
|
|
636
820
|
result = Matrix3d.createRowValues(0.707106781186548, -0.70710678118654757, 0.00000000000000000, 0.408248290463863, 0.40824829046386302, 0.81649658092772603, -0.577350269189626, -0.57735026918962573, 0.57735026918962573);
|
|
637
821
|
break;
|
|
638
822
|
case StandardViewIndex.RightIso:
|
|
639
823
|
result = Matrix3d.createRowValues(0.707106781186548, 0.70710678118654757, 0.00000000000000000, -0.408248290463863, 0.40824829046386302, 0.81649658092772603, 0.577350269189626, -0.57735026918962573, 0.57735026918962573);
|
|
640
824
|
break;
|
|
641
|
-
case StandardViewIndex.Top:
|
|
825
|
+
case StandardViewIndex.Top: // no rotation
|
|
642
826
|
default:
|
|
643
827
|
result = Matrix3d.createIdentity(result);
|
|
644
828
|
}
|
|
@@ -715,7 +899,7 @@ export class Matrix3d {
|
|
|
715
899
|
*/
|
|
716
900
|
/**
|
|
717
901
|
* Compute the (unit vector) axis and angle of rotation.
|
|
718
|
-
* @returns Returns with result.ok === true when the conversion succeeded.
|
|
902
|
+
* @returns Returns axis and angle of rotation with result.ok === true when the conversion succeeded.
|
|
719
903
|
*/
|
|
720
904
|
getAxisAndAngleOfRotation() {
|
|
721
905
|
const trace = this.coffs[0] + this.coffs[4] + this.coffs[8];
|
|
@@ -898,7 +1082,7 @@ export class Matrix3d {
|
|
|
898
1082
|
columnZCrossVector(vector, result) {
|
|
899
1083
|
return Geometry.crossProductXYZXYZ(this.coffs[2], this.coffs[5], this.coffs[8], vector.x, vector.y, vector.z, result);
|
|
900
1084
|
}
|
|
901
|
-
|
|
1085
|
+
/*
|
|
902
1086
|
* Replace current rows Ui Uj with (c*Ui - s*Uj) and (c*Uj + s*Ui).
|
|
903
1087
|
* @param i first row index. must be 0,1,2 (unchecked)
|
|
904
1088
|
* @param j second row index. must be 0,1,2 (unchecked)
|
|
@@ -916,23 +1100,6 @@ export class Matrix3d {
|
|
|
916
1100
|
this.coffs[jj] = -a * s + b * c;
|
|
917
1101
|
}
|
|
918
1102
|
}
|
|
919
|
-
/**
|
|
920
|
-
* Replace current columns Ui Uj with (c*Ui - s*Uj) and (c*Uj + s*Ui).
|
|
921
|
-
* * This is used in compute intensive inner loops -- there is no checking for i,j being 0,1,2.
|
|
922
|
-
* @param i first row index. must be 0,1,2 (unchecked)
|
|
923
|
-
* @param j second row index. must be 0,1,2 (unchecked)
|
|
924
|
-
* @param c fist coefficient
|
|
925
|
-
* @param s second coefficient
|
|
926
|
-
*/
|
|
927
|
-
applyGivensColumnOp(i, j, c, s) {
|
|
928
|
-
const limit = i + 9;
|
|
929
|
-
for (; i < limit; i += 3, j += 3) {
|
|
930
|
-
const a = this.coffs[i];
|
|
931
|
-
const b = this.coffs[j];
|
|
932
|
-
this.coffs[i] = a * c + b * s;
|
|
933
|
-
this.coffs[j] = -a * s + b * c;
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
1103
|
/**
|
|
937
1104
|
* create a rigid coordinate frame column z parallel to (_x_,_y_,_z_) and column x in the xy plane.
|
|
938
1105
|
* * column z points from origin to x,y,z
|
|
@@ -1165,33 +1332,14 @@ export class Matrix3d {
|
|
|
1165
1332
|
}
|
|
1166
1333
|
return false;
|
|
1167
1334
|
}
|
|
1168
|
-
/**
|
|
1169
|
-
* Create a matrix from column vectors.
|
|
1170
|
-
* ```
|
|
1171
|
-
* equation
|
|
1172
|
-
* \begin{bmatrix}U_x & V_x & W_x \\ U_y & V_y & W_y \\ U_z & V_z & W_z \end{bmatrix}
|
|
1173
|
-
* ```
|
|
1174
|
-
*/
|
|
1175
|
-
static createColumns(vectorU, vectorV, vectorW, result) {
|
|
1176
|
-
return Matrix3d.createRowValues(vectorU.x, vectorV.x, vectorW.x, vectorU.y, vectorV.y, vectorW.y, vectorU.z, vectorV.z, vectorW.z, result);
|
|
1177
|
-
}
|
|
1178
|
-
/** Create a matrix with each column's _x,y_ parts given `XAndY` and separate numeric z values.
|
|
1179
|
-
* ```
|
|
1180
|
-
* equation
|
|
1181
|
-
* \begin{bmatrix}U_x & V_x & W_x \\ U_y & V_y & W_y \\ u & v & w \end{bmatrix}
|
|
1182
|
-
* ```
|
|
1183
|
-
*/
|
|
1184
|
-
static createColumnsXYW(vectorU, u, vectorV, v, vectorW, w, result) {
|
|
1185
|
-
return Matrix3d.createRowValues(vectorU.x, vectorV.x, vectorW.x, vectorU.y, vectorV.y, vectorW.y, u, v, w, result);
|
|
1186
|
-
}
|
|
1187
1335
|
/** Install data from xyz parts of Point4d (w part of Point4d ignored) */
|
|
1188
1336
|
setColumnsPoint4dXYZ(vectorU, vectorV, vectorW) {
|
|
1189
1337
|
this.inverseState = InverseMatrixState.unknown;
|
|
1190
1338
|
this.setRowValues(vectorU.x, vectorV.x, vectorW.x, vectorU.y, vectorV.y, vectorW.y, vectorU.z, vectorV.z, vectorW.z);
|
|
1191
1339
|
}
|
|
1192
1340
|
/**
|
|
1193
|
-
*
|
|
1194
|
-
* @param columnIndex column index
|
|
1341
|
+
* Set entries in one column of the matrix.
|
|
1342
|
+
* @param columnIndex column index (this is interpreted cyclically. See Geometry.cyclic3dAxis for more info).
|
|
1195
1343
|
* @param value x,yz, values for column. If undefined, zeros are installed.
|
|
1196
1344
|
*/
|
|
1197
1345
|
setColumn(columnIndex, value) {
|
|
@@ -1240,14 +1388,6 @@ export class Matrix3d {
|
|
|
1240
1388
|
const index = 3 * Geometry.cyclic3dAxis(columnIndex);
|
|
1241
1389
|
return Vector3d.create(this.coffs[index], this.coffs[index + 1], this.coffs[index + 2], result);
|
|
1242
1390
|
}
|
|
1243
|
-
/** Create a matrix from column vectors, shuffled into place per AxisTriple */
|
|
1244
|
-
static createShuffledColumns(vectorU, vectorV, vectorW, axisOrder, result) {
|
|
1245
|
-
const target = Matrix3d._create(result);
|
|
1246
|
-
target.setColumn(Geometry.axisOrderToAxis(axisOrder, 0), vectorU);
|
|
1247
|
-
target.setColumn(Geometry.axisOrderToAxis(axisOrder, 1), vectorV);
|
|
1248
|
-
target.setColumn(Geometry.axisOrderToAxis(axisOrder, 2), vectorW);
|
|
1249
|
-
return target;
|
|
1250
|
-
}
|
|
1251
1391
|
/** Create a matrix from row vectors.
|
|
1252
1392
|
* ```
|
|
1253
1393
|
* equation
|
|
@@ -1679,7 +1819,11 @@ export class Matrix3d {
|
|
|
1679
1819
|
this.multiplyMatrixMatrix(other.matrix, result.matrix);
|
|
1680
1820
|
return result;
|
|
1681
1821
|
}
|
|
1682
|
-
/**
|
|
1822
|
+
/**
|
|
1823
|
+
* Return the transpose of `this` matrix.
|
|
1824
|
+
* If `result` is passed as argument, then the function copies the transpose of `this` into `result`
|
|
1825
|
+
* `this` is not changed unless also passed as the result, i.e., this.transpose(this) transposes `this` in place
|
|
1826
|
+
*/
|
|
1683
1827
|
transpose(result) {
|
|
1684
1828
|
if (!result)
|
|
1685
1829
|
result = new Matrix3d();
|
|
@@ -1694,8 +1838,8 @@ export class Matrix3d {
|
|
|
1694
1838
|
}
|
|
1695
1839
|
return result;
|
|
1696
1840
|
}
|
|
1697
|
-
/**
|
|
1698
|
-
*
|
|
1841
|
+
/**
|
|
1842
|
+
* Transpose this matrix in place.
|
|
1699
1843
|
*/
|
|
1700
1844
|
transposeInPlace() {
|
|
1701
1845
|
PackedMatrix3dOps.transposeInPlace(this.coffs);
|
|
@@ -1726,18 +1870,6 @@ export class Matrix3d {
|
|
|
1726
1870
|
result.inverseState = this.inverseState;
|
|
1727
1871
|
return result;
|
|
1728
1872
|
}
|
|
1729
|
-
/** copy the transpose of the coffs to the inverseCoffs.
|
|
1730
|
-
* * mark the matrix as inverseStored.
|
|
1731
|
-
*/
|
|
1732
|
-
setupInverseTranspose() {
|
|
1733
|
-
const coffs = this.coffs;
|
|
1734
|
-
this.inverseState = InverseMatrixState.inverseStored;
|
|
1735
|
-
this.inverseCoffs = Float64Array.from([
|
|
1736
|
-
coffs[0], coffs[3], coffs[6],
|
|
1737
|
-
coffs[1], coffs[4], coffs[7],
|
|
1738
|
-
coffs[2], coffs[5], coffs[8]
|
|
1739
|
-
]);
|
|
1740
|
-
}
|
|
1741
1873
|
/* Alternate implementation of computedCachedInverse - more direct addressing of arrays.
|
|
1742
1874
|
This is indeed 10% faster than using static work areas. */
|
|
1743
1875
|
// take the cross product of two rows of source.
|
|
@@ -1845,8 +1977,10 @@ export class Matrix3d {
|
|
|
1845
1977
|
markSingular() {
|
|
1846
1978
|
this.inverseState = InverseMatrixState.singular;
|
|
1847
1979
|
}
|
|
1848
|
-
/**
|
|
1849
|
-
*
|
|
1980
|
+
/**
|
|
1981
|
+
* Create the inverseCoffs member (filled with zeros)
|
|
1982
|
+
* This is for use by matrix * matrix multiplications which need to be sure the member is there to be
|
|
1983
|
+
* filled with method-specific content.
|
|
1850
1984
|
*/
|
|
1851
1985
|
createInverseCoffsWithZeros() {
|
|
1852
1986
|
if (!this.inverseCoffs) {
|
|
@@ -1995,7 +2129,7 @@ export class Matrix3d {
|
|
|
1995
2129
|
/**
|
|
1996
2130
|
* add scaled values from other Matrix3d to this Matrix3d
|
|
1997
2131
|
* @param other Matrix3d with values to be added
|
|
1998
|
-
* @param scale scale factor to apply to
|
|
2132
|
+
* @param scale scale factor to apply to the added values.
|
|
1999
2133
|
*/
|
|
2000
2134
|
addScaledInPlace(other, scale) {
|
|
2001
2135
|
for (let i = 0; i < 9; i++)
|
|
@@ -2058,18 +2192,18 @@ export class Matrix3d {
|
|
|
2058
2192
|
/** Return the sum of squares of all entries */
|
|
2059
2193
|
sumSquares() {
|
|
2060
2194
|
let i = 0;
|
|
2061
|
-
let
|
|
2195
|
+
let sum = 0;
|
|
2062
2196
|
for (i = 0; i < 9; i++)
|
|
2063
|
-
|
|
2064
|
-
return
|
|
2197
|
+
sum += this.coffs[i] * this.coffs[i];
|
|
2198
|
+
return sum;
|
|
2065
2199
|
}
|
|
2066
2200
|
/** Return the sum of squares of diagonal entries */
|
|
2067
2201
|
sumDiagonalSquares() {
|
|
2068
2202
|
let i = 0;
|
|
2069
|
-
let
|
|
2203
|
+
let sum = 0;
|
|
2070
2204
|
for (i = 0; i < 9; i += 4)
|
|
2071
|
-
|
|
2072
|
-
return
|
|
2205
|
+
sum += this.coffs[i] * this.coffs[i];
|
|
2206
|
+
return sum;
|
|
2073
2207
|
}
|
|
2074
2208
|
/** Return the sum of diagonal entries (also known as the trace) */
|
|
2075
2209
|
sumDiagonal() {
|
|
@@ -2078,18 +2212,18 @@ export class Matrix3d {
|
|
|
2078
2212
|
/** Return the Maximum absolute value of any single entry */
|
|
2079
2213
|
maxAbs() {
|
|
2080
2214
|
let i = 0;
|
|
2081
|
-
let
|
|
2215
|
+
let max = 0;
|
|
2082
2216
|
for (i = 0; i < 9; i++)
|
|
2083
|
-
|
|
2084
|
-
return
|
|
2217
|
+
max = Math.max(max, Math.abs(this.coffs[i]));
|
|
2218
|
+
return max;
|
|
2085
2219
|
}
|
|
2086
|
-
/** Return the maximum absolute difference between corresponding entries */
|
|
2220
|
+
/** Return the maximum absolute difference between corresponding entries of `this` and `other` */
|
|
2087
2221
|
maxDiff(other) {
|
|
2088
2222
|
let i = 0;
|
|
2089
|
-
let
|
|
2223
|
+
let max = 0;
|
|
2090
2224
|
for (i = 0; i < 9; i++)
|
|
2091
|
-
|
|
2092
|
-
return
|
|
2225
|
+
max = Math.max(max, Math.abs(this.coffs[i] - other.coffs[i]));
|
|
2226
|
+
return max;
|
|
2093
2227
|
}
|
|
2094
2228
|
/** Test if the matrix is (very near to) an identity */
|
|
2095
2229
|
get isIdentity() {
|
|
@@ -2180,25 +2314,6 @@ export class Matrix3d {
|
|
|
2180
2314
|
const product = this.multiplyMatrixMatrixTranspose(this);
|
|
2181
2315
|
return product.isIdentity;
|
|
2182
2316
|
}
|
|
2183
|
-
/** create a new orthogonal matrix (perpendicular columns, unit length, transpose is inverse).
|
|
2184
|
-
* vectorA is placed in the first column of the axis order.
|
|
2185
|
-
* vectorB is projected perpendicular to vectorA within their plane and placed in the second column.
|
|
2186
|
-
*/
|
|
2187
|
-
static createRigidFromColumns(vectorA, vectorB, axisOrder, result) {
|
|
2188
|
-
const vectorA1 = vectorA.normalize();
|
|
2189
|
-
if (vectorA1) {
|
|
2190
|
-
const vectorC1 = vectorA1.unitCrossProduct(vectorB);
|
|
2191
|
-
if (vectorC1) {
|
|
2192
|
-
const vectorB1 = vectorC1.unitCrossProduct(vectorA);
|
|
2193
|
-
if (vectorB1) {
|
|
2194
|
-
const retVal = Matrix3d.createShuffledColumns(vectorA1, vectorB1, vectorC1, axisOrder, result);
|
|
2195
|
-
retVal.setupInverseTranspose();
|
|
2196
|
-
return retVal;
|
|
2197
|
-
}
|
|
2198
|
-
}
|
|
2199
|
-
}
|
|
2200
|
-
return undefined;
|
|
2201
|
-
}
|
|
2202
2317
|
/** Adjust the matrix in place so that:
|
|
2203
2318
|
* * columns are perpendicular and have unit length
|
|
2204
2319
|
* * transpose equals inverse
|
|
@@ -2239,8 +2354,8 @@ export class Matrix3d {
|
|
|
2239
2354
|
return coff;
|
|
2240
2355
|
}
|
|
2241
2356
|
/** create a matrix from a quaternion.
|
|
2242
|
-
* WARNING
|
|
2243
|
-
* WARNING
|
|
2357
|
+
* **WARNING:** There is frequent confusion over whether a "from quaternion" matrix is organized by rows and columns.
|
|
2358
|
+
* **WARNING:** If you find that the matrix seems to rotate by the opposite angle expect it, transpose it.
|
|
2244
2359
|
*/
|
|
2245
2360
|
static createFromQuaternion(quat) {
|
|
2246
2361
|
const qqx = quat.x * quat.x;
|
|
@@ -2259,8 +2374,8 @@ export class Matrix3d {
|
|
|
2259
2374
|
}
|
|
2260
2375
|
/** convert the matrix to a quaternion.
|
|
2261
2376
|
* @note This calculation requires the matrix to have unit length rows and columns.
|
|
2262
|
-
* WARNING
|
|
2263
|
-
* WARNING
|
|
2377
|
+
* **WARNING:** There is frequent confusion over whether a "from quaternion" matrix is organized by rows and columns.
|
|
2378
|
+
* **WARNING:** If you find that the matrix seems to rotate by the opposite angle expect it, transpose it.
|
|
2264
2379
|
*/
|
|
2265
2380
|
toQuaternion() {
|
|
2266
2381
|
const result = Point4d.createZero();
|
|
@@ -2314,9 +2429,9 @@ export class Matrix3d {
|
|
|
2314
2429
|
}
|
|
2315
2430
|
/** Control flag for whether this class uses cached inverse of matrices. */
|
|
2316
2431
|
Matrix3d.useCachedInverse = true; // cached inverse can be suppressed for testing.
|
|
2317
|
-
/**
|
|
2432
|
+
/** Total number of times a cached inverse was used to avoid recompute */
|
|
2318
2433
|
Matrix3d.numUseCache = 0;
|
|
2319
|
-
/**
|
|
2434
|
+
/** Total number of times a cached inverse was computed. */
|
|
2320
2435
|
Matrix3d.numComputeCache = 0;
|
|
2321
2436
|
Matrix3d._productBuffer = new Float64Array(9);
|
|
2322
2437
|
//# sourceMappingURL=Matrix3d.js.map
|