@shapediver/viewer.rendering-engine.camera-engine 1.15.6 → 2.0.1

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.
Files changed (81) hide show
  1. package/dist/implementation/CameraEngine.d.ts +15 -12
  2. package/dist/implementation/CameraEngine.d.ts.map +1 -1
  3. package/dist/implementation/CameraEngine.js +53 -40
  4. package/dist/implementation/CameraEngine.js.map +1 -1
  5. package/dist/implementation/camera/AbstractCamera.d.ts +23 -46
  6. package/dist/implementation/camera/AbstractCamera.d.ts.map +1 -1
  7. package/dist/implementation/camera/AbstractCamera.js +11 -6
  8. package/dist/implementation/camera/AbstractCamera.js.map +1 -1
  9. package/dist/implementation/camera/OrthographicCamera.d.ts +10 -5
  10. package/dist/implementation/camera/OrthographicCamera.d.ts.map +1 -1
  11. package/dist/implementation/camera/OrthographicCamera.js +29 -15
  12. package/dist/implementation/camera/OrthographicCamera.js.map +1 -1
  13. package/dist/implementation/camera/PerspectiveCamera.d.ts +10 -4
  14. package/dist/implementation/camera/PerspectiveCamera.d.ts.map +1 -1
  15. package/dist/implementation/camera/PerspectiveCamera.js +27 -15
  16. package/dist/implementation/camera/PerspectiveCamera.js.map +1 -1
  17. package/dist/implementation/controls/AbstractCameraControls.d.ts +6 -12
  18. package/dist/implementation/controls/AbstractCameraControls.d.ts.map +1 -1
  19. package/dist/implementation/controls/AbstractCameraControls.js +5 -5
  20. package/dist/implementation/controls/AbstractCameraControls.js.map +1 -1
  21. package/dist/implementation/controls/OrthographicCameraControls.d.ts +2 -2
  22. package/dist/implementation/controls/OrthographicCameraControls.d.ts.map +1 -1
  23. package/dist/implementation/controls/OrthographicCameraControls.js +3 -4
  24. package/dist/implementation/controls/OrthographicCameraControls.js.map +1 -1
  25. package/dist/implementation/controls/PerspectiveCameraControls.d.ts +2 -2
  26. package/dist/implementation/controls/PerspectiveCameraControls.d.ts.map +1 -1
  27. package/dist/implementation/controls/PerspectiveCameraControls.js +3 -4
  28. package/dist/implementation/controls/PerspectiveCameraControls.js.map +1 -1
  29. package/dist/implementation/interpolation/CameraInterpolationManager.d.ts +2 -8
  30. package/dist/implementation/interpolation/CameraInterpolationManager.d.ts.map +1 -1
  31. package/dist/implementation/interpolation/CameraInterpolationManager.js +0 -1
  32. package/dist/implementation/interpolation/CameraInterpolationManager.js.map +1 -1
  33. package/dist/index.d.ts +3 -3
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +2 -2
  36. package/dist/index.js.map +1 -1
  37. package/dist/interfaces/ICameraEngine.d.ts +4 -3
  38. package/dist/interfaces/ICameraEngine.d.ts.map +1 -1
  39. package/dist/interfaces/ICameraEngine.js +6 -6
  40. package/dist/interfaces/ICameraEngine.js.map +1 -1
  41. package/dist/interfaces/camera/ICamera.d.ts +37 -33
  42. package/dist/interfaces/camera/ICamera.d.ts.map +1 -1
  43. package/dist/interfaces/camera/IOrthographicCamera.d.ts +1 -0
  44. package/dist/interfaces/camera/IOrthographicCamera.d.ts.map +1 -1
  45. package/dist/interfaces/camera/IPerspectiveCamera.d.ts +1 -0
  46. package/dist/interfaces/camera/IPerspectiveCamera.d.ts.map +1 -1
  47. package/dist/interfaces/controls/ICameraControls.d.ts +29 -0
  48. package/dist/interfaces/controls/ICameraControls.d.ts.map +1 -1
  49. package/dist/interfaces/controls/ICameraControlsUsage.d.ts +2 -9
  50. package/dist/interfaces/controls/ICameraControlsUsage.d.ts.map +1 -1
  51. package/package.json +15 -12
  52. package/src/implementation/CameraEngine.ts +324 -0
  53. package/src/implementation/camera/AbstractCamera.ts +314 -0
  54. package/src/implementation/camera/OrthographicCamera.ts +276 -0
  55. package/src/implementation/camera/PerspectiveCamera.ts +250 -0
  56. package/src/implementation/controls/AbstractCameraControls.ts +329 -0
  57. package/src/implementation/controls/OrthographicCameraControls.ts +131 -0
  58. package/src/implementation/controls/PerspectiveCameraControls.ts +263 -0
  59. package/src/implementation/controls/orthographic/CameraControlsEventDistribution.ts +205 -0
  60. package/src/implementation/controls/orthographic/CameraControlsLogic.ts +279 -0
  61. package/src/implementation/controls/perspective/CameraControlsEventDistribution.ts +221 -0
  62. package/src/implementation/controls/perspective/CameraControlsLogic.ts +478 -0
  63. package/src/implementation/interpolation/CameraInterpolationManager.ts +154 -0
  64. package/src/implementation/interpolation/interpolationMethods/CameraCylindricalInterpolation.ts +86 -0
  65. package/src/implementation/interpolation/interpolationMethods/CameraLinearInterpolation.ts +42 -0
  66. package/src/implementation/interpolation/interpolationMethods/CameraMultipleInterpolation.ts +63 -0
  67. package/src/implementation/interpolation/interpolationMethods/CameraOrthographicInterpolation.ts +43 -0
  68. package/src/implementation/interpolation/interpolationMethods/CameraSphericalInterpolation.ts +67 -0
  69. package/src/index.ts +31 -0
  70. package/src/interfaces/ICameraEngine.ts +19 -0
  71. package/src/interfaces/camera/ICamera.ts +77 -0
  72. package/src/interfaces/camera/IOrthographicCamera.ts +18 -0
  73. package/src/interfaces/camera/IPerspectiveCamera.ts +10 -0
  74. package/src/interfaces/controls/ICameraControls.ts +37 -0
  75. package/src/interfaces/controls/ICameraControlsEventDistribution.ts +8 -0
  76. package/src/interfaces/controls/ICameraControlsLogic.ts +8 -0
  77. package/src/interfaces/controls/ICameraControlsUsage.ts +30 -0
  78. package/src/interfaces/controls/IOrthographicCameraControls.ts +13 -0
  79. package/src/interfaces/controls/IPerspectiveCameraControls.ts +25 -0
  80. package/src/interfaces/interpolation/ICameraInterpolation.ts +5 -0
  81. package/tsconfig.json +17 -0
@@ -0,0 +1,276 @@
1
+ import {
2
+ Converter,
3
+ DomEventEngine,
4
+ Logger,
5
+ LOGGING_TOPIC,
6
+ SettingsEngine,
7
+ ShapeDiverViewerCameraError,
8
+ StateEngine,
9
+ } from '@shapediver/viewer.shared.services'
10
+ import { container } from 'tsyringe'
11
+ import { mat4, vec2, vec3 } from 'gl-matrix'
12
+ import { Box, IBox } from '@shapediver/viewer.shared.math'
13
+ import { IOrthographicCameraSettingsV3 } from '@shapediver/viewer.settings'
14
+ import { IRenderingEngine } from '@shapediver/viewer.rendering-engine.rendering-engine'
15
+ import { ITree, Tree } from '@shapediver/viewer.shared.node-tree'
16
+
17
+ import { CAMERA_TYPE } from '../../interfaces/ICameraEngine'
18
+ import { AbstractCamera } from './AbstractCamera'
19
+ import { OrthographicCameraControls } from '../controls/OrthographicCameraControls'
20
+ import { IOrthographicCamera, ORTHOGRAPHIC_CAMERA_DIRECTION } from '../../interfaces/camera/IOrthographicCamera'
21
+ import { IOrthographicCameraControls } from '../../interfaces/controls/IOrthographicCameraControls'
22
+
23
+ export class OrthographicCamera extends AbstractCamera implements IOrthographicCamera {
24
+ // #region Properties (7)
25
+
26
+ private readonly _converter: Converter = <Converter>container.resolve(Converter);
27
+ private readonly _logger: Logger = <Logger>container.resolve(Logger);
28
+ private readonly _tree: ITree = <ITree>container.resolve(Tree);
29
+
30
+ private _domEventListenerToken?: string;
31
+ private _domEventEngine?: DomEventEngine;
32
+
33
+ private _bottom: number = 100;
34
+ private _direction: ORTHOGRAPHIC_CAMERA_DIRECTION = ORTHOGRAPHIC_CAMERA_DIRECTION.TOP;
35
+ private _left: number = 100;
36
+ private _right: number = 100;
37
+ private _top: number = 100;
38
+ private _up: vec3 = vec3.fromValues(0, 1, 0);
39
+ protected _controls: IOrthographicCameraControls;
40
+
41
+ // #endregion Properties (7)
42
+
43
+ // #region Constructors (1)
44
+
45
+ constructor(id: string) {
46
+ super(id, CAMERA_TYPE.ORTHOGRAPHIC);
47
+ this._controls = new OrthographicCameraControls(this, true);
48
+ }
49
+
50
+ // #endregion Constructors (1)
51
+
52
+ // #region Public Accessors (12)
53
+
54
+ public get bottom(): number {
55
+ return this._bottom;
56
+ }
57
+
58
+ public set bottom(value: number) {
59
+ this._bottom = value;
60
+ }
61
+
62
+ public get controls(): IOrthographicCameraControls {
63
+ return this._controls;
64
+ }
65
+
66
+ public set controls(value: IOrthographicCameraControls) {
67
+ this._controls = value;
68
+ }
69
+
70
+ public get direction(): ORTHOGRAPHIC_CAMERA_DIRECTION {
71
+ return this._direction;
72
+ }
73
+
74
+ public set direction(value: ORTHOGRAPHIC_CAMERA_DIRECTION) {
75
+ const changedDirection = this._direction !== value;
76
+
77
+ this._direction = value;
78
+ switch (this._direction) {
79
+ case ORTHOGRAPHIC_CAMERA_DIRECTION.TOP:
80
+ case ORTHOGRAPHIC_CAMERA_DIRECTION.BOTTOM:
81
+ this.up = vec3.fromValues(0, 1, 0);
82
+ break;
83
+ case ORTHOGRAPHIC_CAMERA_DIRECTION.RIGHT:
84
+ this.up = vec3.fromValues(0, 0, 1);
85
+ break;
86
+ case ORTHOGRAPHIC_CAMERA_DIRECTION.LEFT:
87
+ this.up = vec3.fromValues(0, 0, 1);
88
+ break;
89
+ case ORTHOGRAPHIC_CAMERA_DIRECTION.BACK:
90
+ this.up = vec3.fromValues(0, 0, 1);
91
+ break;
92
+ case ORTHOGRAPHIC_CAMERA_DIRECTION.FRONT:
93
+ this.up = vec3.fromValues(0, 0, 1);
94
+ break;
95
+ default:
96
+ this.up = vec3.fromValues(0, -1, 0);
97
+ }
98
+
99
+ if (changedDirection) {
100
+ const { position, target } = this.calculateZoomTo(undefined);
101
+ this.defaultPosition = vec3.clone(position);
102
+ this.defaultTarget = vec3.clone(target);
103
+
104
+ this.position = vec3.clone(position);
105
+ this.target = vec3.clone(target);
106
+ }
107
+ }
108
+
109
+ public get left(): number {
110
+ return this._left;
111
+ }
112
+
113
+ public set left(value: number) {
114
+ this._left = value;
115
+ }
116
+
117
+ public get right(): number {
118
+ return this._right;
119
+ }
120
+
121
+ public set right(value: number) {
122
+ this._right = value;
123
+ }
124
+
125
+ public get top(): number {
126
+ return this._top;
127
+ }
128
+
129
+ public set top(value: number) {
130
+ this._top = value;
131
+ }
132
+
133
+ public get up(): vec3 {
134
+ return this._up;
135
+ }
136
+
137
+ public set up(value: vec3) {
138
+ this._up = value;
139
+ }
140
+
141
+ // #endregion Public Accessors (12)
142
+
143
+ // #region Public Methods (6)
144
+
145
+ public applySettings(settingsEngine: SettingsEngine) {
146
+ const cameraSetting = <IOrthographicCameraSettingsV3>settingsEngine.camera.cameras[this.id];
147
+ if (cameraSetting) {
148
+ this.autoAdjust = cameraSetting.autoAdjust;
149
+ this.cameraMovementDuration = cameraSetting.cameraMovementDuration;
150
+ this.enableCameraControls = cameraSetting.enableCameraControls;
151
+ this.revertAtMouseUp = cameraSetting.revertAtMouseUp;
152
+ this.revertAtMouseUpDuration = cameraSetting.revertAtMouseUpDuration;
153
+ this.zoomExtentsFactor = cameraSetting.zoomExtentsFactor;
154
+
155
+ let position = this._converter.toVec3(cameraSetting.position);
156
+ let target = this._converter.toVec3(cameraSetting.target);
157
+ this.defaultPosition = vec3.clone(position);
158
+ this.defaultTarget = vec3.clone(target);
159
+
160
+ this.position = position;
161
+ this.target = target;
162
+ }
163
+
164
+ if (this.position[0] === this.target[0] && this.position[1] === this.target[1] && this.position[2] === this.target[2]) {
165
+ if(this._viewportId) {
166
+ this._stateEngine.renderingEngines[this._viewportId].boundingBoxCreated.then(async () => {
167
+ await this.zoomTo(undefined, { duration: 0 });
168
+ this.defaultPosition = vec3.clone(this._controls.position);
169
+ this.defaultTarget = vec3.clone(this._controls.target);
170
+ })
171
+ }
172
+ }
173
+ (<OrthographicCameraControls>this._controls).applySettings(settingsEngine);
174
+ }
175
+
176
+ public assignViewer(viewportId: string): void {
177
+ const renderingEngines = (<IRenderingEngine[]>container.resolveAll('renderingEngine'));
178
+ let renderingEngine: IRenderingEngine | undefined = renderingEngines.find(r => r.id === viewportId && r.closed === false);
179
+ if(!renderingEngine) {
180
+ const error = new ShapeDiverViewerCameraError(`OrthographicCamera(${this.id}).assignViewer: Viewer with id ${viewportId} not found.`);
181
+ throw this._logger.handleError(LOGGING_TOPIC.CAMERA, `OrthographicCamera(${this.id}).assignViewer`, error);
182
+ }
183
+
184
+ this.assignViewerInternal(viewportId, renderingEngine.canvas);
185
+ this._controls.assignViewer(viewportId, renderingEngine.canvas);
186
+
187
+ if (this._domEventListenerToken && this._domEventEngine)
188
+ this._domEventEngine.removeDomEventListener(this._domEventListenerToken);
189
+
190
+ this._domEventEngine = renderingEngine.domEventEngine;
191
+ this._domEventListenerToken = this._domEventEngine.addDomEventListener((<OrthographicCameraControls>this._controls).cameraControlsEventDistribution);
192
+
193
+ this.boundingBox = this._tree.root.boundingBox.clone();
194
+
195
+ this._stateEngine.renderingEngines[viewportId].boundingBoxCreated.then(async () => {
196
+ if (this.position[0] === this.target[0] && this.position[1] === this.target[1] && this.position[2] === this.target[2])
197
+ await this.zoomTo(undefined, { duration: 0 });
198
+ })
199
+ }
200
+
201
+ public clone(): IOrthographicCamera {
202
+ return new OrthographicCamera(this.id);
203
+ }
204
+
205
+ public calculateZoomTo(zoomTarget?: Box, startingPosition?: vec3, startingTarget?: vec3): { position: vec3; target: vec3; } {
206
+ let box: IBox;
207
+
208
+ // Part 1 - calculate the bounding box that we should zoom to
209
+ if (!zoomTarget) {
210
+ // complete scene
211
+ box = this._boundingBox.clone();
212
+ } else {
213
+ // specified Box
214
+ box = zoomTarget.clone();
215
+ }
216
+
217
+ const factor = 2 * box.boundingSphere.radius * this.zoomExtentsFactor;
218
+
219
+ const center = vec3.clone(box.boundingSphere.center);
220
+ switch (this._direction) {
221
+ case ORTHOGRAPHIC_CAMERA_DIRECTION.TOP:
222
+ return {
223
+ position: vec3.fromValues(center[0], center[1], center[2] + factor),
224
+ target: vec3.clone(center)
225
+ }
226
+ case ORTHOGRAPHIC_CAMERA_DIRECTION.BOTTOM:
227
+ return {
228
+ position: vec3.fromValues(center[0], center[1], center[2] - factor),
229
+ target: vec3.clone(center)
230
+ }
231
+ case ORTHOGRAPHIC_CAMERA_DIRECTION.RIGHT:
232
+ return {
233
+ position: vec3.fromValues(center[0] + factor, center[1], center[2]),
234
+ target: vec3.clone(center)
235
+ }
236
+ case ORTHOGRAPHIC_CAMERA_DIRECTION.LEFT:
237
+ return {
238
+ position: vec3.fromValues(center[0] - factor, center[1], center[2]),
239
+ target: vec3.clone(center)
240
+ }
241
+ case ORTHOGRAPHIC_CAMERA_DIRECTION.BACK:
242
+ return {
243
+ position: vec3.fromValues(center[0], center[1] + factor, center[2]),
244
+ target: vec3.clone(center)
245
+ }
246
+ case ORTHOGRAPHIC_CAMERA_DIRECTION.FRONT:
247
+ return {
248
+ position: vec3.fromValues(center[0], center[1] - factor, center[2]),
249
+ target: vec3.clone(center)
250
+ }
251
+ default:
252
+ return {
253
+ position: vec3.fromValues(center[0], center[1], center[2] + factor),
254
+ target: vec3.clone(center)
255
+ }
256
+ }
257
+ }
258
+
259
+ public project(pos: vec3): vec2 {
260
+ const m = mat4.targetTo(mat4.create(), this.position, this.target, this.up);
261
+ const p = mat4.ortho(mat4.create(), this.left, this.right, this.bottom, this.top, this.near, this.far);
262
+ vec3.transformMat4(pos, pos, mat4.invert(m, m))
263
+ vec3.transformMat4(pos, pos, p)
264
+ return vec2.fromValues(pos[0], pos[1])
265
+ }
266
+
267
+ public unproject(pos: vec3, position = this.position, target = this.target): vec3 {
268
+ const m = mat4.targetTo(mat4.create(), this.position, this.target, this.up);
269
+ const p = mat4.ortho(mat4.create(), this.left, this.right, this.bottom, this.top, this.near, this.far);
270
+ vec3.transformMat4(pos, pos, mat4.invert(p, p))
271
+ vec3.transformMat4(pos, pos, m)
272
+ return vec3.clone(pos);
273
+ }
274
+
275
+ // #endregion Public Methods (6)
276
+ }
@@ -0,0 +1,250 @@
1
+ import {
2
+ Converter,
3
+ DomEventEngine,
4
+ Logger,
5
+ LOGGING_TOPIC,
6
+ SettingsEngine,
7
+ ShapeDiverViewerCameraError,
8
+ StateEngine,
9
+ } from '@shapediver/viewer.shared.services'
10
+ import { container } from 'tsyringe'
11
+ import { mat4, quat, vec2, vec3 } from 'gl-matrix'
12
+ import { Box, IBox, Plane } from '@shapediver/viewer.shared.math'
13
+ import { IPerspectiveCameraSettingsV3 } from '@shapediver/viewer.settings'
14
+ import { IRenderingEngine } from '@shapediver/viewer.rendering-engine.rendering-engine'
15
+ import { ITree, Tree } from '@shapediver/viewer.shared.node-tree'
16
+
17
+ import { CAMERA_TYPE } from '../../interfaces/ICameraEngine'
18
+ import { AbstractCamera } from './AbstractCamera'
19
+ import { PerspectiveCameraControls } from '../controls/PerspectiveCameraControls'
20
+ import { IPerspectiveCamera } from '../../interfaces/camera/IPerspectiveCamera'
21
+ import { IPerspectiveCameraControls } from '../../interfaces/controls/IPerspectiveCameraControls'
22
+
23
+ export class PerspectiveCamera extends AbstractCamera implements IPerspectiveCamera {
24
+ // #region Properties (3)
25
+
26
+ private readonly _converter: Converter = <Converter>container.resolve(Converter);
27
+ private readonly _logger: Logger = <Logger>container.resolve(Logger);
28
+ private readonly _tree: ITree = <ITree>container.resolve(Tree);
29
+
30
+ protected _controls: IPerspectiveCameraControls;
31
+
32
+ private _domEventListenerToken?: string;
33
+ private _domEventEngine?: DomEventEngine;
34
+
35
+ private _aspect: number | undefined;
36
+ private _fov: number = 60;
37
+
38
+ // #endregion Properties (3)
39
+
40
+ // #region Constructors (1)
41
+
42
+ constructor(id: string) {
43
+ super(id, CAMERA_TYPE.PERSPECTIVE);
44
+ this._controls = new PerspectiveCameraControls(this, true);
45
+ }
46
+
47
+ // #endregion Constructors (1)
48
+
49
+ // #region Public Accessors (4)
50
+
51
+ public get aspect(): number | undefined {
52
+ return this._aspect;
53
+ }
54
+
55
+ public set aspect(value: number | undefined) {
56
+ this._aspect = value;
57
+ }
58
+
59
+ public get controls(): IPerspectiveCameraControls {
60
+ return this._controls;
61
+ }
62
+
63
+ public set controls(value: IPerspectiveCameraControls) {
64
+ this._controls = value;
65
+ }
66
+
67
+ public get fov(): number {
68
+ return this._fov;
69
+ }
70
+
71
+ public set fov(value: number) {
72
+ this._fov = value;
73
+ }
74
+
75
+ // #endregion Public Accessors (4)
76
+
77
+ // #region Public Methods (6)
78
+
79
+ public applySettings(settingsEngine: SettingsEngine) {
80
+ const cameraSetting = <IPerspectiveCameraSettingsV3>settingsEngine.camera.cameras[this.id];
81
+ if (cameraSetting) {
82
+ this.autoAdjust = cameraSetting.autoAdjust;
83
+ this.cameraMovementDuration = cameraSetting.cameraMovementDuration;
84
+ this.enableCameraControls = cameraSetting.enableCameraControls;
85
+ this.revertAtMouseUp = cameraSetting.revertAtMouseUp;
86
+ this.revertAtMouseUpDuration = cameraSetting.revertAtMouseUpDuration;
87
+ this.zoomExtentsFactor = cameraSetting.zoomExtentsFactor;
88
+
89
+ let position = this._converter.toVec3(cameraSetting.position);
90
+ let target = this._converter.toVec3(cameraSetting.target);
91
+ this.defaultPosition = vec3.clone(position);
92
+ this.defaultTarget = vec3.clone(target);
93
+
94
+ this.position = position;
95
+ this.target = target;
96
+ this.fov = cameraSetting.fov;
97
+ }
98
+
99
+ if (this.position[0] === this.target[0] && this.position[1] === this.target[1] && this.position[2] === this.target[2]) {
100
+ if(this._viewportId) {
101
+ this._stateEngine.renderingEngines[this._viewportId].boundingBoxCreated.then(async () => {
102
+ await this.zoomTo(undefined, { duration: 0 });
103
+ this.defaultPosition = vec3.clone(this._controls.position);
104
+ this.defaultTarget = vec3.clone(this._controls.target);
105
+ })
106
+ }
107
+ }
108
+ (<PerspectiveCameraControls>this._controls).applySettings(settingsEngine);
109
+ }
110
+
111
+ public assignViewer(viewportId: string): void {
112
+ const renderingEngines = (<IRenderingEngine[]>container.resolveAll('renderingEngine'));
113
+ let renderingEngine: IRenderingEngine | undefined = renderingEngines.find(r => r.id === viewportId && r.closed === false);
114
+ if(!renderingEngine) {
115
+ const error = new ShapeDiverViewerCameraError(`OrthographicCamera(${this.id}).assignViewer: Viewer with id ${viewportId} not found.`);
116
+ throw this._logger.handleError(LOGGING_TOPIC.CAMERA, `OrthographicCamera(${this.id}).assignViewer`, error);
117
+ }
118
+
119
+ this.assignViewerInternal(viewportId, renderingEngine.canvas);
120
+ this._controls.assignViewer(viewportId, renderingEngine.canvas);
121
+
122
+ if (this._domEventListenerToken && this._domEventEngine)
123
+ this._domEventEngine.removeDomEventListener(this._domEventListenerToken);
124
+
125
+ this._domEventEngine = renderingEngine.domEventEngine;
126
+ this._domEventListenerToken = this._domEventEngine.addDomEventListener((<PerspectiveCameraControls>this._controls).cameraControlsEventDistribution);
127
+
128
+ this.boundingBox = this._tree.root.boundingBox.clone();
129
+
130
+ this._stateEngine.renderingEngines[viewportId].boundingBoxCreated.then(async () => {
131
+ if (this.position[0] === this.target[0] && this.position[1] === this.target[1] && this.position[2] === this.target[2])
132
+ await this.zoomTo(undefined, { duration: 0 });
133
+ })
134
+ }
135
+
136
+ public clone(): IPerspectiveCamera {
137
+ return new PerspectiveCamera(this.id);
138
+ }
139
+
140
+ public calculateZoomTo(zoomTarget?: Box, startingPosition: vec3 = this.position, startingTarget: vec3 = this.target): { position: vec3, target: vec3 } {
141
+ let box: IBox;
142
+
143
+ // Part 1 - calculate the bounding box that we should zoom to
144
+ if (!zoomTarget) {
145
+ // complete scene
146
+ box = this._boundingBox.clone();
147
+ } else {
148
+ // specified Box
149
+ box = zoomTarget.clone();
150
+ }
151
+
152
+ if (box.isEmpty()) return { position: vec3.create(), target: vec3.create() }
153
+
154
+ const samePosition = startingPosition[0] === startingTarget[0] && startingPosition[1] === startingTarget[1] && startingPosition[2] === startingTarget[2];
155
+ let target = vec3.fromValues((box.max[0] + box.min[0]) / 2, (box.max[1] + box.min[1]) / 2, (box.max[2] + box.min[2]) / 2);
156
+
157
+ // if the camera position and the target are the same, we set a corner position
158
+ if (startingPosition[0] === startingTarget[0] && startingPosition[1] === startingTarget[1] && startingPosition[2] === startingTarget[2])
159
+ startingPosition = vec3.fromValues(target[0], target[1] - 7.5, target[2] + 5);
160
+
161
+ // extend box by the factor
162
+ const boxDir = vec3.subtract(vec3.create(), box.max, target)
163
+ vec3.multiply(boxDir, boxDir, samePosition ? vec3.fromValues(2, 2, 2) : vec3.fromValues(this.zoomExtentsFactor, this.zoomExtentsFactor, this.zoomExtentsFactor));
164
+ box = new Box(vec3.subtract(vec3.create(), target, boxDir), vec3.add(vec3.create(), target, boxDir))
165
+
166
+ const direction = vec3.normalize(vec3.create(), vec3.subtract(vec3.create(), target, startingPosition));
167
+
168
+ let cross = vec3.normalize(vec3.create(), vec3.cross(vec3.create(), vec3.fromValues(0, 0, 1), direction));
169
+ let up = vec3.normalize(vec3.create(), vec3.cross(vec3.create(), cross, direction));
170
+
171
+ let position = vec3.add(vec3.create(), target, vec3.multiply(vec3.create(), direction, vec3.fromValues(-0.00000001, -0.00000001, -0.00000001)));
172
+
173
+ let points = [];
174
+ points.push(vec3.fromValues(box.min[0], box.min[1], box.min[2]));
175
+ points.push(vec3.fromValues(box.min[0], box.min[1], box.max[2]));
176
+ points.push(vec3.fromValues(box.min[0], box.max[1], box.min[2]));
177
+ points.push(vec3.fromValues(box.min[0], box.max[1], box.max[2]));
178
+ points.push(vec3.fromValues(box.max[0], box.min[1], box.min[2]));
179
+ points.push(vec3.fromValues(box.max[0], box.min[1], box.max[2]));
180
+ points.push(vec3.fromValues(box.max[0], box.max[1], box.min[2]));
181
+ points.push(vec3.fromValues(box.max[0], box.max[1], box.max[2]));
182
+
183
+ let fovDown = vec3.normalize(vec3.create(), vec3.transformQuat(vec3.create(), direction, quat.setAxisAngle(quat.create(), cross, (this.fov / 2) * (Math.PI / 180))));
184
+ let fovUp = vec3.normalize(vec3.create(), vec3.transformQuat(vec3.create(), direction, quat.setAxisAngle(quat.create(), cross, -(this.fov / 2) * (Math.PI / 180))));
185
+
186
+ const aspect = samePosition ? 1.5 : this.aspect || 1.5;
187
+ let hFoV = 2 * Math.atan(Math.tan(this.fov * Math.PI / 180 / 2) * aspect);
188
+ let fovRight = vec3.normalize(vec3.create(), vec3.transformQuat(vec3.create(), direction, quat.setAxisAngle(quat.create(), up, hFoV / 2)));
189
+ let fovLeft = vec3.normalize(vec3.create(), vec3.transformQuat(vec3.create(), direction, quat.setAxisAngle(quat.create(), up, -hFoV / 2)));
190
+
191
+ let planeCross = new Plane(vec3.clone(cross), 0);
192
+ planeCross.setFromNormalAndCoplanarPoint(vec3.clone(cross), vec3.clone(target));
193
+
194
+ let planeUp = new Plane(vec3.fromValues(0, 0, 1), 0);
195
+ planeUp.setFromNormalAndCoplanarPoint(vec3.clone(up), vec3.clone(target));
196
+
197
+ let distanceCamera = 0.0;
198
+ for (let i = 0; i < points.length; i++) {
199
+ let projected = planeCross.clampPoint(points[i]);
200
+ let toP = vec3.normalize(vec3.create(), vec3.subtract(vec3.create(), projected, position));
201
+
202
+ if (vec3.dot(direction, fovDown) > vec3.dot(direction, toP)) {
203
+ const currentDir = vec3.multiply(vec3.create(), vec3.dot(fovDown, toP) > vec3.dot(fovUp, toP) ? fovDown : fovUp, vec3.fromValues(-1, -1, -1));
204
+ const distance = planeUp.intersect(projected, currentDir)
205
+ if (distance) {
206
+ const cameraPoint = vec3.add(vec3.create(), vec3.multiply(vec3.create(), currentDir, vec3.fromValues(distance, distance, distance)), projected);
207
+ distanceCamera = Math.max(distanceCamera, vec3.distance(target, cameraPoint));
208
+ }
209
+ }
210
+
211
+ projected = planeUp.clampPoint(points[i]);
212
+ toP = vec3.normalize(vec3.create(), vec3.subtract(vec3.create(), projected, position));
213
+
214
+ if (vec3.dot(direction, fovRight) > vec3.dot(direction, toP)) {
215
+ const currentDir = vec3.multiply(vec3.create(), vec3.dot(fovRight, toP) > vec3.dot(fovLeft, toP) ? fovRight : fovLeft, vec3.fromValues(-1, -1, -1));
216
+ const distance = planeCross.intersect(projected, currentDir)
217
+ if (distance) {
218
+ const cameraPoint = vec3.add(vec3.create(), vec3.multiply(vec3.create(), currentDir, vec3.fromValues(distance, distance, distance)), projected);
219
+ distanceCamera = Math.max(distanceCamera, vec3.distance(target, cameraPoint));
220
+ }
221
+ }
222
+ }
223
+
224
+ position = vec3.add(vec3.create(), target, vec3.multiply(vec3.create(), direction, vec3.fromValues(-distanceCamera, -distanceCamera, -distanceCamera)));
225
+
226
+ return {
227
+ position, target
228
+ }
229
+ }
230
+
231
+ public project(pos: vec3, position = this.position, target = this.target): vec2 {
232
+ const m = mat4.targetTo(mat4.create(), position, target, vec3.fromValues(0, 0, 1));
233
+ const aspect = this.aspect || 1.5;
234
+ const p = mat4.perspective(mat4.create(), this.fov / (180 / Math.PI), aspect, this.near, this.far);
235
+ vec3.transformMat4(pos, pos, mat4.invert(m, m))
236
+ vec3.transformMat4(pos, pos, p)
237
+ return vec2.fromValues(pos[0], pos[1])
238
+ }
239
+
240
+ public unproject(pos: vec3, position = this.position, target = this.target): vec3 {
241
+ const m = mat4.targetTo(mat4.create(), position, target, vec3.fromValues(0, 0, 1));
242
+ const aspect = this.aspect || 1.5;
243
+ const p = mat4.perspective(mat4.create(), this.fov / (180 / Math.PI), aspect, this.near, this.far);
244
+ vec3.transformMat4(pos, pos, mat4.invert(p, p))
245
+ vec3.transformMat4(pos, pos, m)
246
+ return vec3.clone(pos);
247
+ }
248
+
249
+ // #endregion Public Methods (6)
250
+ }