@shapediver/viewer.rendering-engine.camera-engine 1.15.7 → 2.0.2
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/dist/implementation/CameraEngine.d.ts +15 -12
- package/dist/implementation/CameraEngine.d.ts.map +1 -1
- package/dist/implementation/CameraEngine.js +53 -40
- package/dist/implementation/CameraEngine.js.map +1 -1
- package/dist/implementation/camera/AbstractCamera.d.ts +23 -46
- package/dist/implementation/camera/AbstractCamera.d.ts.map +1 -1
- package/dist/implementation/camera/AbstractCamera.js +11 -6
- package/dist/implementation/camera/AbstractCamera.js.map +1 -1
- package/dist/implementation/camera/OrthographicCamera.d.ts +10 -5
- package/dist/implementation/camera/OrthographicCamera.d.ts.map +1 -1
- package/dist/implementation/camera/OrthographicCamera.js +29 -15
- package/dist/implementation/camera/OrthographicCamera.js.map +1 -1
- package/dist/implementation/camera/PerspectiveCamera.d.ts +10 -4
- package/dist/implementation/camera/PerspectiveCamera.d.ts.map +1 -1
- package/dist/implementation/camera/PerspectiveCamera.js +27 -15
- package/dist/implementation/camera/PerspectiveCamera.js.map +1 -1
- package/dist/implementation/controls/AbstractCameraControls.d.ts +6 -12
- package/dist/implementation/controls/AbstractCameraControls.d.ts.map +1 -1
- package/dist/implementation/controls/AbstractCameraControls.js +5 -5
- package/dist/implementation/controls/AbstractCameraControls.js.map +1 -1
- package/dist/implementation/controls/OrthographicCameraControls.d.ts +2 -2
- package/dist/implementation/controls/OrthographicCameraControls.d.ts.map +1 -1
- package/dist/implementation/controls/OrthographicCameraControls.js +3 -4
- package/dist/implementation/controls/OrthographicCameraControls.js.map +1 -1
- package/dist/implementation/controls/PerspectiveCameraControls.d.ts +2 -2
- package/dist/implementation/controls/PerspectiveCameraControls.d.ts.map +1 -1
- package/dist/implementation/controls/PerspectiveCameraControls.js +3 -4
- package/dist/implementation/controls/PerspectiveCameraControls.js.map +1 -1
- package/dist/implementation/interpolation/CameraInterpolationManager.d.ts +2 -8
- package/dist/implementation/interpolation/CameraInterpolationManager.d.ts.map +1 -1
- package/dist/implementation/interpolation/CameraInterpolationManager.js +0 -1
- package/dist/implementation/interpolation/CameraInterpolationManager.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/interfaces/ICameraEngine.d.ts +4 -3
- package/dist/interfaces/ICameraEngine.d.ts.map +1 -1
- package/dist/interfaces/ICameraEngine.js +6 -6
- package/dist/interfaces/ICameraEngine.js.map +1 -1
- package/dist/interfaces/camera/ICamera.d.ts +37 -33
- package/dist/interfaces/camera/ICamera.d.ts.map +1 -1
- package/dist/interfaces/camera/IOrthographicCamera.d.ts +1 -0
- package/dist/interfaces/camera/IOrthographicCamera.d.ts.map +1 -1
- package/dist/interfaces/camera/IPerspectiveCamera.d.ts +1 -0
- package/dist/interfaces/camera/IPerspectiveCamera.d.ts.map +1 -1
- package/dist/interfaces/controls/ICameraControls.d.ts +29 -0
- package/dist/interfaces/controls/ICameraControls.d.ts.map +1 -1
- package/dist/interfaces/controls/ICameraControlsUsage.d.ts +2 -9
- package/dist/interfaces/controls/ICameraControlsUsage.d.ts.map +1 -1
- package/package.json +15 -12
- package/src/implementation/CameraEngine.ts +324 -0
- package/src/implementation/camera/AbstractCamera.ts +314 -0
- package/src/implementation/camera/OrthographicCamera.ts +276 -0
- package/src/implementation/camera/PerspectiveCamera.ts +250 -0
- package/src/implementation/controls/AbstractCameraControls.ts +329 -0
- package/src/implementation/controls/OrthographicCameraControls.ts +131 -0
- package/src/implementation/controls/PerspectiveCameraControls.ts +263 -0
- package/src/implementation/controls/orthographic/CameraControlsEventDistribution.ts +205 -0
- package/src/implementation/controls/orthographic/CameraControlsLogic.ts +279 -0
- package/src/implementation/controls/perspective/CameraControlsEventDistribution.ts +221 -0
- package/src/implementation/controls/perspective/CameraControlsLogic.ts +478 -0
- package/src/implementation/interpolation/CameraInterpolationManager.ts +154 -0
- package/src/implementation/interpolation/interpolationMethods/CameraCylindricalInterpolation.ts +86 -0
- package/src/implementation/interpolation/interpolationMethods/CameraLinearInterpolation.ts +42 -0
- package/src/implementation/interpolation/interpolationMethods/CameraMultipleInterpolation.ts +63 -0
- package/src/implementation/interpolation/interpolationMethods/CameraOrthographicInterpolation.ts +43 -0
- package/src/implementation/interpolation/interpolationMethods/CameraSphericalInterpolation.ts +67 -0
- package/src/index.ts +31 -0
- package/src/interfaces/ICameraEngine.ts +19 -0
- package/src/interfaces/camera/ICamera.ts +77 -0
- package/src/interfaces/camera/IOrthographicCamera.ts +18 -0
- package/src/interfaces/camera/IPerspectiveCamera.ts +10 -0
- package/src/interfaces/controls/ICameraControls.ts +37 -0
- package/src/interfaces/controls/ICameraControlsEventDistribution.ts +8 -0
- package/src/interfaces/controls/ICameraControlsLogic.ts +8 -0
- package/src/interfaces/controls/ICameraControlsUsage.ts +30 -0
- package/src/interfaces/controls/IOrthographicCameraControls.ts +13 -0
- package/src/interfaces/controls/IPerspectiveCameraControls.ts +25 -0
- package/src/interfaces/interpolation/ICameraInterpolation.ts +5 -0
- package/tsconfig.json +17 -0
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DomEventEngine,
|
|
3
|
+
EventEngine,
|
|
4
|
+
EVENTTYPE,
|
|
5
|
+
IEvent,
|
|
6
|
+
Logger,
|
|
7
|
+
LOGGING_TOPIC,
|
|
8
|
+
SettingsEngine,
|
|
9
|
+
ShapeDiverViewerCameraError,
|
|
10
|
+
StateEngine,
|
|
11
|
+
UuidGenerator,
|
|
12
|
+
} from '@shapediver/viewer.shared.services'
|
|
13
|
+
import { container, singleton } from 'tsyringe'
|
|
14
|
+
import { Box } from '@shapediver/viewer.shared.math'
|
|
15
|
+
import { vec3 } from 'gl-matrix'
|
|
16
|
+
import { IOrthographicCameraSettingsV3, IPerspectiveCameraSettingsV3 } from '@shapediver/viewer.settings'
|
|
17
|
+
import { ISceneEvent } from '@shapediver/viewer.shared.types'
|
|
18
|
+
import { ITree, ITreeNode, Tree, TreeNode } from '@shapediver/viewer.shared.node-tree'
|
|
19
|
+
|
|
20
|
+
import { CAMERA_TYPE, ICameraEngine } from '../interfaces/ICameraEngine'
|
|
21
|
+
import { AbstractCamera } from './camera/AbstractCamera'
|
|
22
|
+
import { OrthographicCameraControls } from './controls/OrthographicCameraControls'
|
|
23
|
+
import { PerspectiveCamera } from './camera/PerspectiveCamera'
|
|
24
|
+
import { OrthographicCamera } from './camera/OrthographicCamera'
|
|
25
|
+
import { PerspectiveCameraControls } from './controls/PerspectiveCameraControls'
|
|
26
|
+
import { ORTHOGRAPHIC_CAMERA_DIRECTION } from '../interfaces/camera/IOrthographicCamera'
|
|
27
|
+
import { IRenderingEngine } from '@shapediver/viewer.rendering-engine.rendering-engine'
|
|
28
|
+
import { ICamera } from '../interfaces/camera/ICamera'
|
|
29
|
+
|
|
30
|
+
export class CameraEngine implements ICameraEngine {
|
|
31
|
+
// #region Properties (10)
|
|
32
|
+
|
|
33
|
+
private readonly _cameras: {
|
|
34
|
+
[key: string]: ICamera
|
|
35
|
+
} = {};
|
|
36
|
+
private readonly _camerasDomEventListenerToken: {
|
|
37
|
+
[key: string]: string
|
|
38
|
+
} = {};
|
|
39
|
+
private readonly _eventEngine: EventEngine = <EventEngine>container.resolve(EventEngine);
|
|
40
|
+
private readonly _logger: Logger = <Logger>container.resolve(Logger);
|
|
41
|
+
private readonly _settingsEngine: SettingsEngine = <SettingsEngine>container.resolve(SettingsEngine);
|
|
42
|
+
private readonly _stateEngine: StateEngine = <StateEngine>container.resolve(StateEngine);
|
|
43
|
+
private readonly _tree: ITree = <ITree>container.resolve(Tree);
|
|
44
|
+
private readonly _uuidGenerator: UuidGenerator = <UuidGenerator>container.resolve(UuidGenerator);
|
|
45
|
+
|
|
46
|
+
private _camera: ICamera | null = null;
|
|
47
|
+
private _settingsApplied: boolean = false;
|
|
48
|
+
|
|
49
|
+
protected _boundingBox: Box = new Box();
|
|
50
|
+
private _update?: () => void;
|
|
51
|
+
|
|
52
|
+
// #endregion Properties (10)
|
|
53
|
+
|
|
54
|
+
// #region Constructors (1)
|
|
55
|
+
|
|
56
|
+
constructor(private readonly _renderingEngine: IRenderingEngine, private readonly _canvas: HTMLCanvasElement) {
|
|
57
|
+
this._eventEngine.addListener(EVENTTYPE.SCENE.SCENE_BOUNDING_BOX_CHANGE, (e: IEvent) => {
|
|
58
|
+
const viewerEvent = <ISceneEvent>e;
|
|
59
|
+
if (viewerEvent.viewportId === this._renderingEngine.id) {
|
|
60
|
+
this._boundingBox = new Box(viewerEvent.boundingBox!.min, viewerEvent.boundingBox!.max);
|
|
61
|
+
|
|
62
|
+
const cameras = this.cameras;
|
|
63
|
+
for (let c in cameras)
|
|
64
|
+
cameras[c].boundingBox = this._boundingBox.clone();
|
|
65
|
+
}
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
this._eventEngine.addListener(EVENTTYPE.VIEWPORT.VIEWPORT_UPDATED, (e: IEvent) => {
|
|
69
|
+
const viewerEvent = <ISceneEvent>e;
|
|
70
|
+
if (viewerEvent.viewportId === this._renderingEngine.id) {
|
|
71
|
+
this.searchForNewCameras();
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// #endregion Constructors (1)
|
|
77
|
+
|
|
78
|
+
// #region Public Accessors (2)
|
|
79
|
+
|
|
80
|
+
public get camera(): ICamera | null {
|
|
81
|
+
return this._camera;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public get cameras(): {
|
|
85
|
+
[key: string]: ICamera
|
|
86
|
+
} {
|
|
87
|
+
return this._cameras;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
public get update(): (() => void) | undefined {
|
|
91
|
+
return this._update;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
public set update(value: (() => void) | undefined) {
|
|
95
|
+
this._update = value;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// #endregion Public Accessors (2)
|
|
99
|
+
|
|
100
|
+
// #region Public Methods (7)
|
|
101
|
+
|
|
102
|
+
public activateCameraEvents(): void {
|
|
103
|
+
const cameras = this.cameras;
|
|
104
|
+
for(let c in cameras)
|
|
105
|
+
(<PerspectiveCameraControls | OrthographicCameraControls>cameras[c].controls).cameraControlsEventDistribution.activateCameraEvents();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public applySettings(settingsEngine: SettingsEngine) {
|
|
109
|
+
const cameras = this.cameras;
|
|
110
|
+
for (let c in cameras)
|
|
111
|
+
this.removeCamera(c);
|
|
112
|
+
|
|
113
|
+
for(let id in settingsEngine.settings.camera.cameras) {
|
|
114
|
+
const cameraSetting = settingsEngine.settings.camera.cameras[id];
|
|
115
|
+
if(cameraSetting.type === 'perspective') {
|
|
116
|
+
this.createCamera(CAMERA_TYPE.PERSPECTIVE, id);
|
|
117
|
+
} else {
|
|
118
|
+
const camera = this.createCamera(CAMERA_TYPE.ORTHOGRAPHIC, id);
|
|
119
|
+
(<OrthographicCamera>camera).direction = <ORTHOGRAPHIC_CAMERA_DIRECTION>cameraSetting.type;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if(!this._settingsApplied)
|
|
124
|
+
for (let c in cameras)
|
|
125
|
+
cameras[c].applySettings(settingsEngine);
|
|
126
|
+
|
|
127
|
+
const cameraKeys = Object.keys(settingsEngine.settings.camera.cameras);
|
|
128
|
+
|
|
129
|
+
if(cameraKeys.length > 0) {
|
|
130
|
+
if(!settingsEngine.settings.camera.cameraId) {
|
|
131
|
+
this.assignCamera(cameraKeys[0]);
|
|
132
|
+
} else {
|
|
133
|
+
this.assignCamera(settingsEngine.settings.camera.cameraId);
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
const camera = this.createCamera(CAMERA_TYPE.PERSPECTIVE, 'standard');
|
|
137
|
+
this.assignCamera(camera.id);
|
|
138
|
+
camera.applySettings(settingsEngine);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
this._settingsApplied = true;
|
|
142
|
+
if(this._update) this._update();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
public assignCamera(id: string): boolean {
|
|
146
|
+
const camera = this.cameras[id];
|
|
147
|
+
if (!camera) return false;
|
|
148
|
+
this._camera = camera;
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public createCamera(type: CAMERA_TYPE, id?: string): ICamera {
|
|
153
|
+
const cameras = this.cameras;
|
|
154
|
+
const cameraId = id || this._uuidGenerator.create();
|
|
155
|
+
if (cameras[cameraId]) {
|
|
156
|
+
const error = new ShapeDiverViewerCameraError(`CameraEngine.createCamera: Camera (${type}) with this id (${cameraId}) already exists.`);
|
|
157
|
+
throw this._logger.handleError(LOGGING_TOPIC.CAMERA, `CameraEngine.createCamera`, error, false);
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
const camera = CAMERA_TYPE.PERSPECTIVE === type ? new PerspectiveCamera(cameraId) : new OrthographicCamera(cameraId);
|
|
161
|
+
camera.assignViewer(this._renderingEngine.id);
|
|
162
|
+
|
|
163
|
+
cameras[cameraId] = camera;
|
|
164
|
+
if (this._settingsApplied && this._renderingEngine.settingsEngine) {
|
|
165
|
+
camera.applySettings(this._renderingEngine.settingsEngine);
|
|
166
|
+
} else {
|
|
167
|
+
camera.zoomTo(undefined, { duration: 0 });
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if(this._update) this._update();
|
|
171
|
+
return camera;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
public deactivateCameraEvents(): void {
|
|
175
|
+
const cameras = this.cameras;
|
|
176
|
+
for (let c in cameras)
|
|
177
|
+
(<PerspectiveCameraControls | OrthographicCameraControls>cameras[c].controls).cameraControlsEventDistribution.deactivateCameraEvents();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
public removeCamera(id: string): boolean {
|
|
181
|
+
const cameras = this.cameras;
|
|
182
|
+
const camera = cameras[id];
|
|
183
|
+
if (!camera) return false;
|
|
184
|
+
this._renderingEngine.domEventEngine.removeDomEventListener(this._camerasDomEventListenerToken[id])
|
|
185
|
+
if (this._camera && this._camera.id === id)
|
|
186
|
+
this._camera = null;
|
|
187
|
+
|
|
188
|
+
delete cameras[id];
|
|
189
|
+
delete this._camerasDomEventListenerToken[id];
|
|
190
|
+
if(this._update) this._update();
|
|
191
|
+
return true;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
public saveSettings(settingsEngine: SettingsEngine) {
|
|
195
|
+
settingsEngine.settings.camera.cameraId = this._camera ? this._camera.id : 'standard';
|
|
196
|
+
settingsEngine.settings.camera.cameras = {};
|
|
197
|
+
|
|
198
|
+
// TODO: once the platform is ready for it, save all cameras
|
|
199
|
+
// for (let c in this.cameras) {
|
|
200
|
+
if(!this._camera)
|
|
201
|
+
return;
|
|
202
|
+
|
|
203
|
+
const camera = this._camera;
|
|
204
|
+
|
|
205
|
+
if (camera.type === CAMERA_TYPE.PERSPECTIVE) {
|
|
206
|
+
const controls = <PerspectiveCameraControls>(<PerspectiveCamera>camera).controls;
|
|
207
|
+
settingsEngine.camera.cameras[camera.id] = {
|
|
208
|
+
autoAdjust: camera.autoAdjust,
|
|
209
|
+
cameraMovementDuration: camera.cameraMovementDuration,
|
|
210
|
+
enableCameraControls: camera.enableCameraControls,
|
|
211
|
+
revertAtMouseUp: camera.revertAtMouseUp,
|
|
212
|
+
revertAtMouseUpDuration: camera.revertAtMouseUpDuration,
|
|
213
|
+
zoomExtentsFactor: camera.zoomExtentsFactor,
|
|
214
|
+
position: { x: camera.defaultPosition[0], y: camera.defaultPosition[1], z: camera.defaultPosition[2] },
|
|
215
|
+
target: { x: camera.defaultTarget[0], y: camera.defaultTarget[1], z: camera.defaultTarget[2] },
|
|
216
|
+
type: camera.type,
|
|
217
|
+
fov: (<PerspectiveCamera>camera).fov,
|
|
218
|
+
controls: {
|
|
219
|
+
autoRotationSpeed: controls.autoRotationSpeed,
|
|
220
|
+
damping: controls.damping,
|
|
221
|
+
enableAutoRotation: controls.enableAutoRotation,
|
|
222
|
+
enableKeyPan: controls.enableKeyPan,
|
|
223
|
+
enablePan: controls.enablePan,
|
|
224
|
+
enableRotation: controls.enableRotation,
|
|
225
|
+
enableZoom: controls.enableZoom,
|
|
226
|
+
input: controls.input,
|
|
227
|
+
keyPanSpeed: controls.keyPanSpeed,
|
|
228
|
+
movementSmoothness: controls.movementSmoothness,
|
|
229
|
+
rotationSpeed: controls.rotationSpeed,
|
|
230
|
+
panSpeed: controls.panSpeed,
|
|
231
|
+
zoomSpeed: controls.zoomSpeed,
|
|
232
|
+
restrictions: {
|
|
233
|
+
position: {
|
|
234
|
+
cube: {
|
|
235
|
+
min: { x: controls.cubePositionRestriction.min[0], y: controls.cubePositionRestriction.min[1], z: controls.cubePositionRestriction.min[2] },
|
|
236
|
+
max: { x: controls.cubePositionRestriction.max[0], y: controls.cubePositionRestriction.max[1], z: controls.cubePositionRestriction.max[2] },
|
|
237
|
+
},
|
|
238
|
+
sphere: {
|
|
239
|
+
center: { x: controls.spherePositionRestriction.center[0], y: controls.spherePositionRestriction.center[1], z: controls.spherePositionRestriction.center[2] },
|
|
240
|
+
radius: controls.spherePositionRestriction.radius,
|
|
241
|
+
},
|
|
242
|
+
},
|
|
243
|
+
target: {
|
|
244
|
+
cube: {
|
|
245
|
+
min: { x: controls.cubeTargetRestriction.min[0], y: controls.cubeTargetRestriction.min[1], z: controls.cubeTargetRestriction.min[2] },
|
|
246
|
+
max: { x: controls.cubeTargetRestriction.max[0], y: controls.cubeTargetRestriction.max[1], z: controls.cubeTargetRestriction.max[2] },
|
|
247
|
+
},
|
|
248
|
+
sphere: {
|
|
249
|
+
center: { x: controls.sphereTargetRestriction.center[0], y: controls.sphereTargetRestriction.center[1], z: controls.sphereTargetRestriction.center[2] },
|
|
250
|
+
radius: controls.sphereTargetRestriction.radius,
|
|
251
|
+
},
|
|
252
|
+
},
|
|
253
|
+
rotation: controls.rotationRestriction,
|
|
254
|
+
zoom: controls.zoomRestriction,
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
} else {
|
|
260
|
+
if (settingsEngine.camera.cameras[camera.id]) {
|
|
261
|
+
const previousDirection = settingsEngine.camera.cameras[camera.id].type;
|
|
262
|
+
|
|
263
|
+
// if the direction changed, but the default position & target did not, there is an issue
|
|
264
|
+
if (previousDirection !== camera.type && (
|
|
265
|
+
settingsEngine.camera.cameras[camera.id].position.x === camera.defaultPosition[0] &&
|
|
266
|
+
settingsEngine.camera.cameras[camera.id].position.y === camera.defaultPosition[1] &&
|
|
267
|
+
settingsEngine.camera.cameras[camera.id].position.z === camera.defaultPosition[2] &&
|
|
268
|
+
settingsEngine.camera.cameras[camera.id].target.x === camera.defaultTarget[0] &&
|
|
269
|
+
settingsEngine.camera.cameras[camera.id].target.y === camera.defaultTarget[1] &&
|
|
270
|
+
settingsEngine.camera.cameras[camera.id].target.z === camera.defaultTarget[2]
|
|
271
|
+
)) {
|
|
272
|
+
camera.defaultPosition = vec3.clone(camera.position);
|
|
273
|
+
camera.defaultTarget = vec3.clone(camera.target);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
const controls = <OrthographicCameraControls>(<OrthographicCamera>camera).controls;
|
|
277
|
+
|
|
278
|
+
settingsEngine.camera.cameras[camera.id] = {
|
|
279
|
+
autoAdjust: camera.autoAdjust,
|
|
280
|
+
cameraMovementDuration: camera.cameraMovementDuration,
|
|
281
|
+
enableCameraControls: camera.enableCameraControls,
|
|
282
|
+
revertAtMouseUp: camera.revertAtMouseUp,
|
|
283
|
+
revertAtMouseUpDuration: camera.revertAtMouseUpDuration,
|
|
284
|
+
zoomExtentsFactor: camera.zoomExtentsFactor,
|
|
285
|
+
position: { x: camera.defaultPosition[0], y: camera.defaultPosition[1], z: camera.defaultPosition[2] },
|
|
286
|
+
target: { x: camera.defaultTarget[0], y: camera.defaultTarget[1], z: camera.defaultTarget[2] },
|
|
287
|
+
type: (<OrthographicCamera>camera).direction,
|
|
288
|
+
controls: {
|
|
289
|
+
damping: controls.damping,
|
|
290
|
+
enableKeyPan: controls.enableKeyPan,
|
|
291
|
+
enablePan: controls.enablePan,
|
|
292
|
+
enableZoom: controls.enableZoom,
|
|
293
|
+
input: controls.input,
|
|
294
|
+
keyPanSpeed: controls.keyPanSpeed,
|
|
295
|
+
movementSmoothness: controls.movementSmoothness,
|
|
296
|
+
panSpeed: controls.panSpeed,
|
|
297
|
+
zoomSpeed: controls.zoomSpeed,
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
// #endregion Public Methods (7)
|
|
304
|
+
|
|
305
|
+
// #region Private Methods (1)
|
|
306
|
+
|
|
307
|
+
private searchForNewCameras() {
|
|
308
|
+
const getCameraData = (node: ITreeNode) => {
|
|
309
|
+
for(let i = 0; i < node.data.length; i++)
|
|
310
|
+
if((node.data[i] instanceof AbstractCamera) && !this._cameras[node.data[i].id]) {
|
|
311
|
+
const camera = <AbstractCamera>node.data[i];
|
|
312
|
+
if(camera.viewportId === this._renderingEngine.id)
|
|
313
|
+
this._cameras[camera.id] = camera;
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
for(let i = 0; i < node.children.length; i++)
|
|
317
|
+
getCameraData(node.children[i]);
|
|
318
|
+
};
|
|
319
|
+
getCameraData(this._tree.root);
|
|
320
|
+
if(this._update) this._update();
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// #endregion Private Methods (1)
|
|
324
|
+
}
|
|
@@ -0,0 +1,314 @@
|
|
|
1
|
+
import * as detectIt from 'detect-it'
|
|
2
|
+
import { mat4, quat, vec2, vec3 } from 'gl-matrix'
|
|
3
|
+
import {
|
|
4
|
+
DomEventEngine,
|
|
5
|
+
EventEngine,
|
|
6
|
+
EVENTTYPE,
|
|
7
|
+
IEvent,
|
|
8
|
+
SettingsEngine,
|
|
9
|
+
StateEngine,
|
|
10
|
+
} from '@shapediver/viewer.shared.services'
|
|
11
|
+
import { container } from 'tsyringe'
|
|
12
|
+
import { Box, IBox } from '@shapediver/viewer.shared.math'
|
|
13
|
+
import { AbstractTreeNodeData, ITreeNode, TreeNode } from '@shapediver/viewer.shared.node-tree'
|
|
14
|
+
|
|
15
|
+
import { ICameraControls } from '../../interfaces/controls/ICameraControls'
|
|
16
|
+
import { ICamera, ICameraOptions } from '../../interfaces/camera/ICamera'
|
|
17
|
+
import { CAMERA_TYPE } from '../../interfaces/ICameraEngine'
|
|
18
|
+
import { AbstractCameraControls } from '../controls/AbstractCameraControls'
|
|
19
|
+
|
|
20
|
+
export abstract class AbstractCamera extends AbstractTreeNodeData implements ICamera {
|
|
21
|
+
// #region Properties (23)
|
|
22
|
+
|
|
23
|
+
private _autoAdjust: boolean = false;
|
|
24
|
+
private _cameraMovementDuration: number = 800;
|
|
25
|
+
private _defaultPosition: vec3 = vec3.create();
|
|
26
|
+
private _defaultTarget: vec3 = vec3.create();
|
|
27
|
+
private _enableCameraControls: boolean = true;
|
|
28
|
+
private _far: number = 1000;
|
|
29
|
+
private _name?: string;
|
|
30
|
+
private _near: number = 1;
|
|
31
|
+
private _node?: ITreeNode;
|
|
32
|
+
private _useNodeData: boolean = false;
|
|
33
|
+
private _order?: number;
|
|
34
|
+
private _revertAtMouseUp: boolean = false;
|
|
35
|
+
private _revertAtMouseUpDuration: number = 800;
|
|
36
|
+
private _zoomExtentsFactor: number = 1;
|
|
37
|
+
|
|
38
|
+
protected readonly _eventEngine: EventEngine = <EventEngine>container.resolve(EventEngine);
|
|
39
|
+
protected readonly _stateEngine: StateEngine = <StateEngine>container.resolve(StateEngine);
|
|
40
|
+
|
|
41
|
+
protected _boundingBox: IBox = new Box();
|
|
42
|
+
protected _position: vec3 = vec3.create();
|
|
43
|
+
protected _target: vec3 = vec3.create();
|
|
44
|
+
protected _viewportId?: string;
|
|
45
|
+
|
|
46
|
+
protected abstract _controls: ICameraControls;
|
|
47
|
+
|
|
48
|
+
// #endregion Properties (23)
|
|
49
|
+
|
|
50
|
+
// #region Constructors (1)
|
|
51
|
+
|
|
52
|
+
constructor(private readonly _id: string, private readonly _type: CAMERA_TYPE) {
|
|
53
|
+
super(_id);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// #endregion Constructors (1)
|
|
57
|
+
|
|
58
|
+
// #region Public Accessors (39)
|
|
59
|
+
|
|
60
|
+
public get autoAdjust(): boolean {
|
|
61
|
+
return this._autoAdjust;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
public set autoAdjust(value: boolean) {
|
|
65
|
+
this._autoAdjust = value;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
public set boundingBox(value: IBox) {
|
|
69
|
+
this._boundingBox = value;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
public get cameraMovementDuration(): number {
|
|
73
|
+
return this._cameraMovementDuration;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public set cameraMovementDuration(value: number) {
|
|
77
|
+
this._cameraMovementDuration = value;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
public get controls(): ICameraControls {
|
|
81
|
+
return this._controls;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
public get defaultPosition(): vec3 {
|
|
85
|
+
return this._defaultPosition;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public set defaultPosition(value: vec3) {
|
|
89
|
+
this._defaultPosition = value;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
public get defaultTarget(): vec3 {
|
|
93
|
+
return this._defaultTarget;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
public set defaultTarget(value: vec3) {
|
|
97
|
+
this._defaultTarget = value;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
public get enableCameraControls(): boolean {
|
|
101
|
+
return this._enableCameraControls;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
public set enableCameraControls(value: boolean) {
|
|
105
|
+
this._enableCameraControls = value;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
public get far(): number {
|
|
109
|
+
return this._far;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
public set far(value: number) {
|
|
113
|
+
this._far = value;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
public get id(): string {
|
|
117
|
+
return this._id;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
public get name(): string | undefined {
|
|
121
|
+
return this._name;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
public set name(value: string | undefined) {
|
|
125
|
+
this._name = value;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
public get near(): number {
|
|
129
|
+
return this._near;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
public set near(value: number) {
|
|
133
|
+
this._near = value;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
public get node(): ITreeNode | undefined {
|
|
137
|
+
return this._node;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
public set node(value: ITreeNode | undefined) {
|
|
141
|
+
this._node = value;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
public get useNodeData(): boolean {
|
|
145
|
+
return this._useNodeData;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
public set useNodeData(value: boolean) {
|
|
149
|
+
this._useNodeData = value;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public get order(): number | undefined {
|
|
153
|
+
return this._order;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
public set order(value: number | undefined) {
|
|
157
|
+
this._order = value;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
public get position(): vec3 {
|
|
161
|
+
return this._position;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
public set position(value: vec3) {
|
|
165
|
+
this._position = value;
|
|
166
|
+
this._controls.position = value;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
public get revertAtMouseUp(): boolean {
|
|
170
|
+
return this._revertAtMouseUp;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
public set revertAtMouseUp(value: boolean) {
|
|
174
|
+
this._revertAtMouseUp = value;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
public get revertAtMouseUpDuration(): number {
|
|
178
|
+
return this._revertAtMouseUpDuration;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
public set revertAtMouseUpDuration(value: number) {
|
|
182
|
+
this._revertAtMouseUpDuration = value;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
public get target(): vec3 {
|
|
186
|
+
return this._target;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
public set target(value: vec3) {
|
|
190
|
+
this._target = value;
|
|
191
|
+
this._controls.target = value;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
public get type(): CAMERA_TYPE {
|
|
195
|
+
return this._type;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
public get viewportId(): string | undefined {
|
|
199
|
+
return this._viewportId;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
public get zoomExtentsFactor(): number {
|
|
203
|
+
return this._zoomExtentsFactor;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
public set zoomExtentsFactor(value: number) {
|
|
207
|
+
this._zoomExtentsFactor = value;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// #endregion Public Accessors (39)
|
|
211
|
+
|
|
212
|
+
// #region Public Methods (5)
|
|
213
|
+
|
|
214
|
+
public async animate(path: { position: vec3; target: vec3; }[], options?: ICameraOptions): Promise<boolean> {
|
|
215
|
+
if (path.length === 0) return Promise.resolve(false);
|
|
216
|
+
|
|
217
|
+
if (!this._controls.isWithinRestrictions(path[path.length - 1].position, path[path.length - 1].target))
|
|
218
|
+
return Promise.resolve(false);
|
|
219
|
+
|
|
220
|
+
if (!options) options = {};
|
|
221
|
+
options.duration = options.duration! >= 0 ? options.duration : this.cameraMovementDuration;
|
|
222
|
+
|
|
223
|
+
const res = await this._controls.animate(path, options);
|
|
224
|
+
if (res) {
|
|
225
|
+
this._position = this._controls.position;
|
|
226
|
+
this._target = this._controls.target;
|
|
227
|
+
}
|
|
228
|
+
return res;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
public reset(options?: ICameraOptions): Promise<boolean> {
|
|
232
|
+
if ((this.defaultPosition[0] === 0 && this.defaultPosition[1] === 0 && this.defaultPosition[2] === 0) && (this.defaultTarget[0] === 0 && this.defaultTarget[1] === 0 && this.defaultTarget[2] === 0)) {
|
|
233
|
+
return this.zoomTo(undefined, options);
|
|
234
|
+
} else {
|
|
235
|
+
return this.set(vec3.clone(this.defaultPosition), vec3.clone(this.defaultTarget), options);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
public async set(position: vec3, target: vec3, options?: ICameraOptions): Promise<boolean> {
|
|
240
|
+
if (!this._controls.isWithinRestrictions(position, target))
|
|
241
|
+
return Promise.resolve(false);
|
|
242
|
+
|
|
243
|
+
if (!options) options = {};
|
|
244
|
+
options.duration = options.duration! >= 0 ? options.duration : this.cameraMovementDuration;
|
|
245
|
+
|
|
246
|
+
const res = await this._controls.animate([
|
|
247
|
+
{ position: vec3.clone(this.position), target: vec3.clone(this.target) },
|
|
248
|
+
{ position, target }], options);
|
|
249
|
+
if (res) {
|
|
250
|
+
this._position = this._controls.position;
|
|
251
|
+
this._target = this._controls.target;
|
|
252
|
+
}
|
|
253
|
+
return res;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
public update(time: number): boolean {
|
|
257
|
+
if(this.useNodeData && this.node && this._viewportId) {
|
|
258
|
+
return true;
|
|
259
|
+
} else {
|
|
260
|
+
const { position, target } = this._controls.update(time);
|
|
261
|
+
let changed = true;
|
|
262
|
+
if (vec3.equals(position, this.position) && vec3.equals(target, this.target))
|
|
263
|
+
changed = false;
|
|
264
|
+
|
|
265
|
+
this.position = vec3.clone(position);
|
|
266
|
+
this.target = vec3.clone(target);
|
|
267
|
+
return changed;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
public zoomTo(zoomTarget?: Box, options?: ICameraOptions): Promise<boolean> {
|
|
272
|
+
const { position, target } = this.calculateZoomTo(zoomTarget)
|
|
273
|
+
return this.set(position, target, options);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// #endregion Public Methods (5)
|
|
277
|
+
|
|
278
|
+
// #region Public Abstract Methods (5)
|
|
279
|
+
|
|
280
|
+
abstract applySettings(settingsEngine?: SettingsEngine): void;
|
|
281
|
+
abstract assignViewer(viewportId: string): void;
|
|
282
|
+
abstract calculateZoomTo(zoomTarget?: Box, startingPosition?: vec3, startingTarget?: vec3): { position: vec3; target: vec3; };
|
|
283
|
+
abstract project(p: vec3): vec2;
|
|
284
|
+
abstract unproject(p: vec3): vec3;
|
|
285
|
+
|
|
286
|
+
// #endregion Public Abstract Methods (5)
|
|
287
|
+
|
|
288
|
+
// #region Protected Methods (1)
|
|
289
|
+
|
|
290
|
+
protected assignViewerInternal(viewportId: string, canvas: HTMLCanvasElement) {
|
|
291
|
+
this._viewportId = viewportId;
|
|
292
|
+
this._eventEngine.addListener(EVENTTYPE.SESSION.SESSION_CUSTOMIZED, (e: IEvent) => {
|
|
293
|
+
if (this._autoAdjust === true)
|
|
294
|
+
this.zoomTo();
|
|
295
|
+
});
|
|
296
|
+
const revert = () => {
|
|
297
|
+
if (this._revertAtMouseUp === true)
|
|
298
|
+
this.reset({ duration: this._revertAtMouseUpDuration });
|
|
299
|
+
};
|
|
300
|
+
canvas.addEventListener("mouseup", () => revert(), detectIt.supportsPassiveEvents ? { capture: false, passive: true } : false);
|
|
301
|
+
canvas.addEventListener("mouseout", () => revert(), detectIt.supportsPassiveEvents ? { capture: false, passive: true } : false);
|
|
302
|
+
canvas.addEventListener("touchend", () => revert(), detectIt.supportsPassiveEvents ? { capture: false, passive: true } : false);
|
|
303
|
+
|
|
304
|
+
let zoomResizeTimeout: NodeJS.Timeout;
|
|
305
|
+
let mouseWheelEvent = /Firefox/i.test(navigator.userAgent) ? "DOMMouseScroll" : "mousewheel"; //FF doesn't recognize mousewheel as of FF3.x
|
|
306
|
+
canvas.addEventListener(mouseWheelEvent,
|
|
307
|
+
() => {
|
|
308
|
+
clearTimeout(zoomResizeTimeout);
|
|
309
|
+
zoomResizeTimeout = setTimeout(revert, 300);
|
|
310
|
+
}, detectIt.supportsPassiveEvents ? { capture: false, passive: true } : false);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
// #endregion Protected Methods (1)
|
|
314
|
+
}
|