-
Notifications
You must be signed in to change notification settings - Fork 208
/
Map4d.ts
188 lines (186 loc) · 7.26 KB
/
Map4d.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
* @module Numerics
*/
import { BeJSONFunctions } from "../Geometry";
import { Matrix3d } from "../geometry3d/Matrix3d";
import { Point3d, Vector3d } from "../geometry3d/Point3dVector3d";
import { Transform } from "../geometry3d/Transform";
import { Matrix4d } from "./Matrix4d";
/**
* Map4 carries two Matrix4d which are inverses of each other.
* @public
*/
export class Map4d implements BeJSONFunctions {
private _matrix0: Matrix4d;
private _matrix1: Matrix4d;
private constructor(matrix0: Matrix4d, matrix1: Matrix4d) {
this._matrix0 = matrix0;
this._matrix1 = matrix1;
}
/** Return a reference to (not copy of) the "forward" Matrix4d */
public get transform0(): Matrix4d {
return this._matrix0;
}
/** Return a reference to (not copy of) the "reverse" Matrix4d */
public get transform1(): Matrix4d {
return this._matrix1;
}
/** Create a Map4d, capturing the references to the two matrices. */
public static createRefs(matrix0: Matrix4d, matrix1: Matrix4d) {
return new Map4d(matrix0, matrix1);
}
/** Create an identity map. */
public static createIdentity(): Map4d {
return new Map4d(Matrix4d.createIdentity(), Matrix4d.createIdentity());
}
/**
* Create a Map4d with given transform pair.
* @returns undefined if the transforms are not inverses of each other.
*/
public static createTransform(transform0: Transform, transform1?: Transform): Map4d | undefined {
if (transform1 === undefined) {
transform1 = transform0.inverse();
if (transform1 === undefined)
return undefined;
} else {
const product = transform0.multiplyTransformTransform(transform1);
if (!product.isIdentity)
return undefined;
}
return new Map4d(Matrix4d.createTransform(transform0), Matrix4d.createTransform(transform1));
}
/**
* Create a mapping the scales and translates (no rotation) between boxes.
* @param lowA low point of box A
* @param highA high point of box A
* @param lowB low point of box B
* @param highB high point of box B
*/
public static createBoxMap(
lowA: Point3d, highA: Point3d, lowB: Point3d, highB: Point3d, result?: Map4d,
): Map4d | undefined {
const t0 = Matrix4d.createBoxToBox(lowA, highA, lowB, highB, result ? result.transform0 : undefined);
const t1 = Matrix4d.createBoxToBox(lowB, highB, lowA, highA, result ? result.transform1 : undefined);
if (t0 && t1) {
if (result)
return result;
return new Map4d(t0, t1);
}
return undefined;
}
/** Copy contents from another Map4d */
public setFrom(other: Map4d) {
this._matrix0.setFrom(other._matrix0);
this._matrix1.setFrom(other._matrix1);
}
/** Return a clone of this Map4d */
public clone(): Map4d {
return new Map4d(this._matrix0.clone(), this._matrix1.clone());
}
/** Reinitialize this Map4d as an identity. */
public setIdentity() {
this._matrix0.setIdentity();
this._matrix1.setIdentity();
}
/** Set this map4d from a json object that the two Matrix4d values as properties named matrix0 and matrix1 */
public setFromJSON(json: any): void {
if (json.matrix0 && json.matrix1) {
this._matrix0.setFromJSON(json.matrix0);
this._matrix1.setFromJSON(json.matrix1);
} else
this.setIdentity();
}
/** Create a map4d from a json object that the two Matrix4d values as properties named matrix0 and matrix1 */
public static fromJSON(json?: any): Map4d {
const result = new Map4d(Matrix4d.createIdentity(), Matrix4d.createIdentity());
result.setFromJSON(json);
return result;
}
/** Return a json object `{matrix0: value0, matrix1: value1}` */
public toJSON(): any {
return { matrix0: this._matrix0.toJSON(), matrix1: this._matrix1.toJSON() };
}
/** Test if both matrices are almost equal to those */
public isAlmostEqual(other: Map4d) {
return this._matrix0.isAlmostEqual(other._matrix0) && this._matrix1.isAlmostEqual(other._matrix1);
}
/**
* Create a map between a frustum and world coordinates.
* @param origin lower left of frustum
* @param uVector Vector from lower left rear to lower right rear.
* @param vVector Vector from lower left rear to upper left rear.
* @param wVector Vector from lower left rear to lower left front, i.e. lower left rear towards eye.
* @param fraction front size divided by rear size.
*/
public static createVectorFrustum(
origin: Point3d, uVector: Vector3d, vVector: Vector3d, wVector: Vector3d, fraction: number,
): Map4d | undefined {
fraction = Math.max(fraction, 1.0e-8);
const slabToWorld = Transform.createOriginAndMatrix(origin, Matrix3d.createColumns(uVector, vVector, wVector));
const worldToSlab = slabToWorld.inverse();
if (!worldToSlab)
return undefined;
const worldToSlabMap = new Map4d(Matrix4d.createTransform(worldToSlab), Matrix4d.createTransform(slabToWorld));
const slabToNPCMap = new Map4d(
Matrix4d.createRowValues(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, fraction, 0, 0, 0, fraction - 1.0, 1),
Matrix4d.createRowValues(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1.0 / fraction, 0, 0, 0, (1.0 - fraction) / fraction, 1),
);
const result = slabToNPCMap.multiplyMapMap(worldToSlabMap);
/*
let numIdentity = 0;
const productA = worldToSlabMap.matrix0.multiplyMatrixMatrix(worldToSlabMap.matrix1);
if (productA.isIdentity())
numIdentity++;
const productB = slabToNPCMap.matrix0.multiplyMatrixMatrix(slabToNPCMap.matrix1);
if (productB.isIdentity())
numIdentity++;
const product = result.matrix0.multiplyMatrixMatrix(result.matrix1);
if (product.isIdentity())
numIdentity++;
if (numIdentity === 3)
return result;
*/
return result;
}
/**
* Multiply this*other. The output matrices are
* * output matrix0 = `this.matrix0 * other.matrix0`
* * output matrix1 = 'other.matrix1 * this.matrix1`
*/
public multiplyMapMap(other: Map4d): Map4d {
return new Map4d(
this._matrix0.multiplyMatrixMatrix(other._matrix0),
other._matrix1.multiplyMatrixMatrix(this._matrix1),
);
}
/** Exchange the two matrices of the map. */
public reverseInPlace() {
const temp = this._matrix0;
this._matrix0 = this._matrix1;
this._matrix1 = temp;
}
/**
* Return a Map4d whose transform0 is
* other.transform0 * this.transform0 * other.transform1
*/
public sandwich0This1(other: Map4d): Map4d {
return new Map4d(
other._matrix0.multiplyMatrixMatrix(this._matrix0.multiplyMatrixMatrix(other._matrix1)),
other._matrix0.multiplyMatrixMatrix(this._matrix1.multiplyMatrixMatrix(other._matrix1)),
);
}
/**
* Return a Map4d whose transform0 is
* other.transform1 * this.transform0 * other.transform0
*/
public sandwich1This0(other: Map4d): Map4d {
return new Map4d(
other._matrix1.multiplyMatrixMatrix(this._matrix0.multiplyMatrixMatrix(other._matrix0)),
other._matrix1.multiplyMatrixMatrix(this._matrix1.multiplyMatrixMatrix(other._matrix0)),
);
}
}