zincjs 1.0.13 → 1.0.15

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 (45) hide show
  1. package/build/zinc.frontend.js +1 -1
  2. package/build/zinc.js +43 -35
  3. package/build/zinc.js.map +1 -1
  4. package/package.json +3 -3
  5. package/src/assets/disc.png +0 -0
  6. package/src/assets/mapMarker.svg +11 -0
  7. package/src/controls.js +1594 -0
  8. package/src/geometryCSG.js +148 -0
  9. package/src/glyphsetCSG.js +84 -0
  10. package/src/loaders/GLTFToZincJSLoader.js +85 -0
  11. package/src/loaders/JSONLoader.js +697 -0
  12. package/src/loaders/OBJLoader.js +911 -0
  13. package/src/loaders/STLLoader.js +399 -0
  14. package/src/loaders/primitivesLoader.js +46 -0
  15. package/src/minimap.js +82 -0
  16. package/src/primitives/augmentShader.js +22 -0
  17. package/src/primitives/geometry.js +109 -0
  18. package/src/primitives/glyph.js +150 -0
  19. package/src/primitives/glyphset.js +657 -0
  20. package/src/primitives/label.js +51 -0
  21. package/src/primitives/lines.js +35 -0
  22. package/src/primitives/marker.js +88 -0
  23. package/src/primitives/pointset.js +53 -0
  24. package/src/primitives/texturePrimitive.js +16 -0
  25. package/src/primitives/textureSlides.js +118 -0
  26. package/src/primitives/zincObject.js +573 -0
  27. package/src/region.js +554 -0
  28. package/src/renderer.js +612 -0
  29. package/src/scene.js +963 -0
  30. package/src/sceneExporter.js +32 -0
  31. package/src/sceneLoader.js +842 -0
  32. package/src/texture/texture.js +57 -0
  33. package/src/texture/textureArray.js +85 -0
  34. package/src/three/GLTFExporter.js +2448 -0
  35. package/src/three/Geometry.js +2084 -0
  36. package/src/three/Loader.js +344 -0
  37. package/src/three/Points.js +223 -0
  38. package/src/three/line/Line.js +293 -0
  39. package/src/three/line/LineSegments.js +65 -0
  40. package/src/three-js-csg.js +564 -0
  41. package/src/utilities.js +321 -0
  42. package/src/videoHandler.js +92 -0
  43. package/src/workers/geometryCSG.worker.js +73 -0
  44. package/src/workers/geometryCSGInternal.js +58 -0
  45. package/src/zinc.js +38 -0
@@ -0,0 +1,1594 @@
1
+ const THREE = require('three');
2
+ const resolveURL = require('./utilities').resolveURL;
3
+
4
+ const Viewport = function () {
5
+ this.nearPlane = 0.168248;
6
+ this.farPlane = 6.82906;
7
+ this.eyePosition = [0.5, -2.86496, 0.5];
8
+ this.targetPosition = [0.5, 0.5, 0.5];
9
+ this.upVector = [ 0.0, 0.0, 1.0];
10
+ const _this = this;
11
+
12
+ this.setFromObject = ({ nearPlane, farPlane, eyePosition, targetPosition, upVector }) => {
13
+ _this.nearPlane = nearPlane;
14
+ _this.farPlane = farPlane;
15
+ _this.eyePosition = eyePosition;
16
+ _this.targetPosition = targetPosition;
17
+ _this.upVector = upVector;
18
+ }
19
+
20
+ };
21
+
22
+ const CameraControls = function ( object, domElement, renderer, scene ) {
23
+ const MODE = { NONE: -1, DEFAULT: 0, PATH: 1, SMOOTH_CAMERA_TRANSITION: 2, AUTO_TUMBLE: 3, ROTATE_TRANSITION: 4, MINIMAP: 5, SYNC_CONTROL: 6 };
24
+ const STATE = { NONE: -1, ROTATE: 0, ZOOM: 1, PAN: 2, TOUCH_ROTATE: 3, TOUCH_ZOOM: 4, TOUCH_PAN: 5, SCROLL: 6 };
25
+ const ROTATE_DIRECTION = { NONE: -1, FREE: 1, HORIZONTAL: 2, VERTICAL: 3 };
26
+ const CLICK_ACTION = {};
27
+ CLICK_ACTION.MAIN = STATE.ROTATE;
28
+ CLICK_ACTION.AUXILIARY = STATE.ZOOM;
29
+ CLICK_ACTION.SECONDARY = STATE.PAN;
30
+ this.cameraObject = object;
31
+ this.domElement = ( domElement !== undefined ) ? domElement : document;
32
+ this.renderer = renderer;
33
+ this.scene = scene ;
34
+ this.tumble_rate = 1.5;
35
+ this.pointer_x = 0;
36
+ this.pointer_y = 0;
37
+ this.pointer_x_start = 0;
38
+ this.pointer_y_start = 0;
39
+ this.previous_pointer_x = 0;
40
+ this.previous_pointer_y = 0;
41
+ this.near_plane_fly_debt = 0.0;
42
+ this.touchZoomDistanceStart = 0;
43
+ this.touchZoomDistanceEnd = 0;
44
+ this.directionalLight = 0;
45
+ this.scrollRate = 50;
46
+ let duration = 6000;
47
+ let inbuildTime = 0;
48
+ let cameraPath = undefined;
49
+ let numberOfCameraPoint = undefined;
50
+ let updateLightWithPathFlag = false;
51
+ let playRate = 500;
52
+ let deviceOrientationControl = undefined;
53
+ let defaultViewport = "default";
54
+ let currentMode = MODE.DEFAULT;
55
+ let smoothCameraTransitionObject = undefined;
56
+ let rotateCameraTransitionObject = undefined;
57
+ let cameraAutoTumbleObject = undefined;
58
+ let mouseScroll = 0;
59
+ let rotateMode = ROTATE_DIRECTION.FREE;
60
+ this._state = STATE.NONE;
61
+ let zincRayCaster = undefined;
62
+ this.targetTouchId = -1;
63
+ let rect = undefined;
64
+ const _a = new THREE.Vector3();
65
+ const _b = new THREE.Vector3();
66
+ const _c = new THREE.Vector3();
67
+ const _new_b = new THREE.Vector3();
68
+ const _new_c = new THREE.Vector3();
69
+ const _axis = new THREE.Vector3();
70
+ const _v = new THREE.Vector3();
71
+ const _rel_eye = new THREE.Vector3();
72
+ const sceneSphere = new THREE.Sphere();
73
+ const _tempEye = new THREE.Vector3();
74
+ let ndcControl = undefined;
75
+ let maxDist = 0;
76
+ const viewports = {
77
+ "default" : new Viewport()
78
+ };
79
+ viewports.default.nearPlane = 0.1;
80
+ viewports.default.farPlane = 2000;
81
+ viewports.default.eyePosition = [0, 0, 0];
82
+ viewports.default.targetPosition = [0, 0, -1.0];
83
+ viewports.default.upVector = [ 0.0, 1.0, 0.0];
84
+
85
+ //Add the target property
86
+ if (this.cameraObject.target === undefined)
87
+ this.cameraObject.target = new THREE.Vector3( ...viewports.default.targetPosition );
88
+
89
+ //Calculate the max distanc allowed, it is the longer
90
+ //of 6 times the radius of the current scene and
91
+ //the current distance between scene centroid and the postion
92
+ //of the camera.
93
+ this.calculateMaxAllowedDistance = (scene) => {
94
+ const box = scene.getBoundingBox();
95
+ if (box) {
96
+ box.getBoundingSphere(sceneSphere);
97
+ maxDist = sceneSphere.radius * 6;
98
+ let currentDist = 0;
99
+ if (this.cameraObject) {
100
+ currentDist = this.cameraObject.position.distanceTo(sceneSphere.center);
101
+ }
102
+ maxDist = currentDist > maxDist ? currentDist : maxDist;
103
+ } else {
104
+ maxDist = 0;
105
+ }
106
+ }
107
+
108
+ this.addViewport = (viewportName, viewport) => {
109
+ if (viewportName && viewport)
110
+ viewports[viewportName] = viewport;
111
+ }
112
+
113
+ this.setDefaultViewport = defaultName => {
114
+ if (defaultName && (defaultName in viewports)) {
115
+ defaultViewport = defaultName;
116
+ }
117
+ }
118
+
119
+ this.getDefaultViewport = () => {
120
+ return defaultViewport;
121
+ }
122
+
123
+ this.getViewportOfName = name => {
124
+ return viewports[name];
125
+ }
126
+
127
+ this.setCurrentViewport = name => {
128
+ if (name in viewports) {
129
+ this.setCurrentCameraSettings(viewports[name])
130
+ return true;
131
+ }
132
+ return false;
133
+ }
134
+
135
+ this.setRotationMode = mode => {
136
+ switch (mode) {
137
+ case "none":
138
+ rotateMode = ROTATE_DIRECTION.NONE;
139
+ break;
140
+ case "horizontal":
141
+ rotateMode = ROTATE_DIRECTION.HORIZONTAL;
142
+ break;
143
+ case "vertical":
144
+ rotateMode = ROTATE_DIRECTION.VERTICAL;
145
+ break;
146
+ case "free":
147
+ default:
148
+ rotateMode = ROTATE_DIRECTION.FREE;
149
+ }
150
+ }
151
+
152
+ this.onResize = () => {
153
+ if (rect)
154
+ rect = undefined;
155
+ if (ndcControl)
156
+ ndcControl.setCurrentCameraSettings(this.cameraObject,
157
+ viewports[defaultViewport]);
158
+ }
159
+
160
+ //Get the NDC coordinates from the given dom coordiantes
161
+ this.getNDCFromDocumentCoords = (x, y, positionIn) => {
162
+
163
+ const position = positionIn ? positionIn : new THREE.Vector2();
164
+ position.x = ((x - rect.left) / rect.width) * 2 - 1;
165
+ position.y = -((y - rect.top) / rect.height) * 2 + 1;
166
+ return position;
167
+ }
168
+
169
+ this.getRelativeCoordsFromNDC = (x, y, positionIn) => {
170
+ if (rect === undefined)
171
+ rect = this.domElement.getBoundingClientRect();
172
+ const position = positionIn ? positionIn : new THREE.Vector2();
173
+ position.x = (x + 1) * rect.width / 2.0;
174
+ position.y = (1 - y) * rect.height / 2.0;
175
+ return position;
176
+ }
177
+
178
+ this.setMouseButtonAction = (buttonName, actionName) => {
179
+ CLICK_ACTION[buttonName] = STATE[actionName];
180
+ }
181
+
182
+ //Make sure the camera does not travel beyond limit
183
+ const checkTravelDistance = () => {
184
+ if (maxDist > 0) {
185
+ const newDist = _tempEye.distanceTo(sceneSphere.center);
186
+ return (maxDist > newDist ||
187
+ this.cameraObject.position.distanceTo(sceneSphere.center) > newDist );
188
+ }
189
+ return true;
190
+ }
191
+
192
+ const translateViewport = translation => {
193
+ _tempEye.copy(this.cameraObject.position).add(translation);
194
+ if (checkTravelDistance()) {
195
+ this.cameraObject.target.add(translation);
196
+ this.cameraObject.position.add(translation);
197
+ this.updateDirectionalLight();
198
+ }
199
+ }
200
+
201
+ const onDocumentMouseDown = event => {
202
+ if (rect === undefined)
203
+ rect = this.domElement.getBoundingClientRect();
204
+ // Check if mouse event hapens inside the minimap
205
+ let minimapCoordinates = undefined;
206
+ if (currentMode === MODE.DEFAULT)
207
+ minimapCoordinates = this.scene.getNormalisedMinimapCoordinates(
208
+ this.renderer, event);
209
+ if (!minimapCoordinates) {
210
+ if (event.button == 0) {
211
+ if (event.ctrlKey)
212
+ this._state = CLICK_ACTION.AUXILIARY;
213
+ else if (event.shiftKey)
214
+ this._state = CLICK_ACTION.SECONDARY;
215
+ else
216
+ this._state = CLICK_ACTION.MAIN;
217
+ } else if (event.button == 1) {
218
+ event.preventDefault();
219
+ this._state = CLICK_ACTION.AUXILIARY;
220
+ }
221
+ else if (event.button == 2) {
222
+ this._state = CLICK_ACTION.SECONDARY;
223
+ }
224
+ this.pointer_x = event.clientX - rect.left;
225
+ this.pointer_y = event.clientY - rect.top;
226
+ this.pointer_x_start = this.pointer_x;
227
+ this.pointer_y_start = this.pointer_y;
228
+ this.previous_pointer_x = this.pointer_x;
229
+ this.previous_pointer_y= this.pointer_y;
230
+ } else {
231
+ currentMode = MODE.MINIMAP;
232
+ let translation = this.scene.getMinimapDiffFromNormalised(
233
+ minimapCoordinates.x, minimapCoordinates.y);
234
+ translateViewport(translation);
235
+ }
236
+ }
237
+
238
+ const onDocumentMouseMove = event => {
239
+ if (rect === undefined)
240
+ rect = this.domElement.getBoundingClientRect();
241
+ this.pointer_x = event.clientX - rect.left;
242
+ this.pointer_y = event.clientY - rect.top;
243
+ if (currentMode === MODE.MINIMAP) {
244
+ let minimapCoordinates = this.scene.getNormalisedMinimapCoordinates(this.renderer, event);
245
+ if (minimapCoordinates) {
246
+ let translation = this.scene.getMinimapDiffFromNormalised(
247
+ minimapCoordinates.x, minimapCoordinates.y);
248
+ translateViewport(translation);
249
+ }
250
+ } else {
251
+ if ((this._state === STATE.NONE) && (zincRayCaster !== undefined)) {
252
+ zincRayCaster.move(this, event.clientX, event.clientY, this.renderer);
253
+ }
254
+ }
255
+ }
256
+
257
+ const onDocumentMouseUp = event => {
258
+ this._state = STATE.NONE;
259
+ if (currentMode == MODE.MINIMAP)
260
+ currentMode = MODE.DEFAULT;
261
+ if (zincRayCaster !== undefined) {
262
+ if (this.pointer_x_start==(event.clientX - rect.left) && this.pointer_y_start==(event.clientY- rect.top)) {
263
+ zincRayCaster.pick(this, event.clientX, event.clientY, this.renderer);
264
+ }
265
+ }
266
+ }
267
+
268
+ const onDocumentMouseLeave = event => {
269
+ this._state = STATE.NONE;
270
+ }
271
+
272
+ const onDocumentTouchStart = event => {
273
+ if (rect === undefined)
274
+ rect = this.domElement.getBoundingClientRect();
275
+ const len = event.touches.length;
276
+ if (len == 1) {
277
+ this._state = STATE.TOUCH_ROTATE;
278
+ this.pointer_x = event.touches[0].clientX - rect.left;
279
+ this.pointer_y = event.touches[0].clientY - rect.top;
280
+ this.pointer_x_start = this.pointer_x;
281
+ this.pointer_y_start = this.pointer_y;
282
+ this.previous_pointer_x = this.pointer_x;
283
+ this.previous_pointer_y= this.pointer_y;
284
+ } else if (len == 2) {
285
+ this._state = STATE.TOUCH_ZOOM;
286
+ const dx = event.touches[ 0 ].clientX - event.touches[ 1 ].clientX;
287
+ const dy = event.touches[ 0 ].clientY - event.touches[ 1 ].clientY;
288
+ this.touchZoomDistanceEnd = this.touchZoomDistanceStart = Math.sqrt( dx * dx + dy * dy );
289
+ } else if (len == 3) {
290
+ this._state = STATE.TOUCH_PAN;
291
+ this.targetTouchId = event.touches[0].identifier;
292
+ this.pointer_x = event.touches[0].clientX - rect.left;
293
+ this.pointer_y = event.touches[0].clientY - rect.top;
294
+ this.previous_pointer_x = this.pointer_x;
295
+ this.previous_pointer_y= this.pointer_y;
296
+ }
297
+ }
298
+
299
+ const onDocumentTouchMove = event => {
300
+ event.preventDefault();
301
+ event.stopPropagation();
302
+ const len = event.touches.length;
303
+ if (len == 1) {
304
+ this.pointer_x = event.touches[0].clientX - rect.left;
305
+ this.pointer_y = event.touches[0].clientY - rect.top;
306
+ } else if (len == 2) {
307
+ if (this._state === STATE.TOUCH_ZOOM) {
308
+ const dx = event.touches[ 0 ].clientX - event.touches[ 1 ].clientX;
309
+ const dy = event.touches[ 0 ].clientY - event.touches[ 1 ].clientY;
310
+ this.touchZoomDistanceEnd = Math.sqrt( dx * dx + dy * dy );
311
+ }
312
+ } else if (len == 3) {
313
+ if (this._state === STATE.TOUCH_PAN) {
314
+ for (let i = 0; i < 3; i++) {
315
+ if (event.touches[i].identifier == this.targetTouchId) {
316
+ this.pointer_x = event.touches[0].clientX - rect.left;
317
+ this.pointer_y = event.touches[0].clientY - rect.top;
318
+ }
319
+ }
320
+ }
321
+ }
322
+ }
323
+
324
+ const onDocumentTouchEnd = event => {
325
+ const len = event.touches.length;
326
+ this.touchZoomDistanceStart = this.touchZoomDistanceEnd = 0;
327
+ this.targetTouchId = -1;
328
+ this._state = STATE.NONE;
329
+ if (len == 1) {
330
+ if (zincRayCaster !== undefined) {
331
+ if (this.pointer_x_start==(event.touches[0].clientX- rect.left) && this.pointer_y_start==(event.touches[0].clientY- rect.top)) {
332
+ zincRayCaster.pick(this.cameraObject, event.touches[0].clientX, event.touches[0].clientY, this.renderer);
333
+ }
334
+ }
335
+ }
336
+ }
337
+
338
+ const onDocumentWheelEvent = event => {
339
+ if (rect === undefined)
340
+ rect = this.domElement.getBoundingClientRect();
341
+ this._state = STATE.SCROLL;
342
+ let changes = 0;
343
+ if (event.deltaY > 0)
344
+ changes = this.scrollRate;
345
+ else if (event.deltaY < 0)
346
+ changes = this.scrollRate * -1;
347
+ mouseScroll = mouseScroll + changes;
348
+ event.preventDefault();
349
+ event.stopImmediatePropagation();
350
+ }
351
+
352
+ const translate = () => {
353
+ if (typeof this.cameraObject !== "undefined")
354
+ {
355
+ const height = rect.height;
356
+ const distance = this.cameraObject.position.distanceTo(this.cameraObject.target);
357
+ let fact = 0.0;
358
+ if ((this.cameraObject.far > this.cameraObject.near) && (distance >= this.cameraObject.near) &&
359
+ (distance <= this.cameraObject.far))
360
+ {
361
+ fact = (distance-this.cameraObject.near)/(this.cameraObject.far-this.cameraObject.near);
362
+ }
363
+ //_b == old_near, _c = old_far, _new_b = new_near, _new_c = new_far
364
+ _b.set(this.previous_pointer_x,height - this.previous_pointer_y,0.0);
365
+ _c.set(this.previous_pointer_x, height - this.previous_pointer_y,1.0);
366
+ _new_b.set(this.pointer_x,height - this.pointer_y,0.0);
367
+ _new_c.set(this.pointer_x,height - this.pointer_y,1.0);
368
+ _b.unproject(this.cameraObject);
369
+ _c.unproject(this.cameraObject);
370
+ _new_b.unproject(this.cameraObject);
371
+ _new_c.unproject( this.cameraObject);
372
+ const translate_rate = -0.002;
373
+ _new_b.sub(_b).multiplyScalar(1.0-fact);
374
+ _new_c.sub(_c).multiplyScalar(fact);
375
+ _new_b.add(_new_c).multiplyScalar(translate_rate);
376
+ translateViewport(_new_b);
377
+ }
378
+ this.previous_pointer_x = this.pointer_x;
379
+ this.previous_pointer_y = this.pointer_y;
380
+ }
381
+
382
+ this.getVectorsFromRotateAboutLookAtPoints = (axis, angle) => {
383
+ axis.normalize();
384
+ _v.copy(this.cameraObject.position).sub(this.cameraObject.target);
385
+ _rel_eye.copy(_v);
386
+ _v.normalize()
387
+ if (0.8 < Math.abs(_v.dot(axis))) {
388
+ _v.copy(this.cameraObject.up);
389
+ }
390
+ _b.crossVectors(axis, _v).normalize();
391
+ _c.crossVectors(axis, _b);
392
+ const rel_eyea = axis.dot(_rel_eye);
393
+ const rel_eyeb = _b.dot(_rel_eye);
394
+ const rel_eyec = _c.dot(_rel_eye);
395
+ const upa = axis.dot(this.cameraObject.up);
396
+ const upb = _b.dot(this.cameraObject.up);
397
+ const upc = _c.dot(this.cameraObject.up);
398
+ const cos_angle = Math.cos(angle);
399
+ const sin_angle = Math.sin(angle);
400
+ _new_b.set(cos_angle*_b.x+sin_angle*_c.x,
401
+ cos_angle*_b.y+sin_angle*_c.y,
402
+ cos_angle*_b.z+sin_angle*_c.z);
403
+ _new_c.set(cos_angle*_c.x-sin_angle*_b.x,
404
+ cos_angle*_c.y-sin_angle*_b.y,
405
+ cos_angle*_c.z-sin_angle*_b.z);
406
+ _v.copy(this.cameraObject.target);
407
+ _v.x = _v.x + axis.x*rel_eyea + _new_b.x*rel_eyeb+_new_c.x*rel_eyec;
408
+ _v.y = _v.y + axis.y*rel_eyea + _new_b.y*rel_eyeb+_new_c.y*rel_eyec;
409
+ _v.z = _v.z + axis.z*rel_eyea + _new_b.z*rel_eyeb+_new_c.z*rel_eyec;
410
+ _a.set(axis.x*upa+_new_b.x*upb+_new_c.x*upc,
411
+ axis.y*upa+_new_b.y*upb+_new_c.y*upc,
412
+ axis.z*upa+_new_b.z*upb+_new_c.z*upc);
413
+ return {position: _v, up: _a};
414
+ }
415
+
416
+ this.rotateAboutLookAtpoint = (axis, angle) => {
417
+ const returned_values = this.getVectorsFromRotateAboutLookAtPoints(axis, angle);
418
+ this.cameraObject.position.copy(returned_values.position);
419
+ this.updateDirectionalLight();
420
+ this.cameraObject.up.copy(returned_values.up);
421
+ }
422
+
423
+ const tumble = () => {
424
+ if (typeof this.cameraObject !== "undefined")
425
+ {
426
+ const width = rect.width;
427
+ const height = rect.height;
428
+ if ((0<width)&&(0<height))
429
+ {
430
+ const radius=0.25*(width+height);
431
+ let delta_x = 0;
432
+ let delta_y = 0;
433
+ if (rotateMode === ROTATE_DIRECTION.FREE ||
434
+ rotateMode === ROTATE_DIRECTION.HORIZONTAL)
435
+ delta_x=this.pointer_x-this.previous_pointer_x;
436
+ if (rotateMode === ROTATE_DIRECTION.FREE ||
437
+ rotateMode === ROTATE_DIRECTION.VERTICAL)
438
+ delta_y=this.previous_pointer_y-this.pointer_y;
439
+ const tangent_dist = Math.sqrt(delta_x*delta_x + delta_y*delta_y);
440
+ if (tangent_dist > 0)
441
+ {
442
+ const dx=-delta_y*1.0/tangent_dist;
443
+ const dy=delta_x*1.0/tangent_dist;
444
+ let d = 0;
445
+ // Do not allow rotation on other direction around the origin if rotateMode is not free
446
+ if (rotateMode === ROTATE_DIRECTION.FREE) {
447
+ let d=dx*(this.pointer_x-0.5*(width-1))+dy*(0.5*(height-1)-this.pointer_y);
448
+ if (d > radius) {
449
+ d = radius;
450
+ }
451
+ else {
452
+ if (d < -radius) {
453
+ d = -radius;
454
+ }
455
+ }
456
+ }
457
+ const phi=Math.acos(d/radius)-0.5*Math.PI;
458
+ const angle=this.tumble_rate*tangent_dist/radius;
459
+ _a.copy(this.cameraObject.position).sub(this.cameraObject.target).normalize();
460
+ _b.copy(this.cameraObject.up).normalize();
461
+ _c.copy(_b).cross(_a).normalize().multiplyScalar(dx);
462
+ _b.multiplyScalar(dy);
463
+ _axis.addVectors(_c, _b).multiplyScalar(Math.cos(phi));
464
+ _a.multiplyScalar(Math.sin(phi));
465
+ _axis.add(_a);
466
+ this.rotateAboutLookAtpoint(_axis, -angle);
467
+ }
468
+ }
469
+ }
470
+ this.previous_pointer_x = this.pointer_x;
471
+ this.previous_pointer_y = this.pointer_y;
472
+ }
473
+
474
+ const calculateZoomDelta = () => {
475
+ let delta = 0;
476
+ if (this._state === STATE.ZOOM)
477
+ {
478
+ delta = this.previous_pointer_y-this.pointer_y;
479
+ } else if (this._state === STATE.SCROLL) {
480
+ delta = mouseScroll;
481
+ } else {
482
+ delta = -1.0 * (this.touchZoomDistanceEnd - this.touchZoomDistanceStart);
483
+ this.touchZoomDistanceStart = this.touchZoomDistanceEnd;
484
+ }
485
+ return delta;
486
+ }
487
+
488
+ this.changeZoomByScrollRateUnit = unit => {
489
+ const delta_y = unit * this.scrollRate;
490
+ this.changeZoomByValue(delta_y);
491
+ }
492
+
493
+ this.changeZoomByValue = delta_y => {
494
+ if (typeof this.cameraObject !== "undefined")
495
+ {
496
+ const width = rect.width;
497
+ const height = rect.height;
498
+
499
+ const a = this.cameraObject.position.clone();
500
+ a.sub(this.cameraObject.target);
501
+ const dist = a.length();
502
+ const dy = 1.5 * delta_y/height;
503
+ if ((dist + dy*dist) > 0.01) {
504
+ a.normalize()
505
+ _tempEye.copy(this.cameraObject.position);
506
+ _tempEye.x += a.x*dy*dist;
507
+ _tempEye.y += a.y*dy*dist;
508
+ _tempEye.z += a.z*dy*dist;
509
+ if (checkTravelDistance()) {
510
+ this.cameraObject.position.copy(_tempEye);
511
+ this.updateDirectionalLight();
512
+ const near_far_minimum_ratio = 0.00001;
513
+ if ((near_far_minimum_ratio * this.cameraObject.far) <
514
+ (this.cameraObject.near + dy*dist + this.near_plane_fly_debt)) {
515
+ if (this.near_plane_fly_debt != 0.0) {
516
+ this.near_plane_fly_debt += dy*dist;
517
+ if (this.near_plane_fly_debt > 0.0) {
518
+ this.cameraObject.near += this.near_plane_fly_debt;
519
+ this.cameraObject.far += this.near_plane_fly_debt;
520
+ this.near_plane_fly_debt = 0.0;
521
+ }
522
+ else {
523
+ this.cameraObject.near += dy*dist;
524
+ this.cameraObject.far += dy*dist;
525
+ }
526
+ }
527
+ }
528
+ else {
529
+ if (this.near_plane_fly_debt == 0.0) {
530
+ const diff = this.cameraObject.near - near_far_minimum_ratio * this.cameraObject.far;
531
+ this.cameraObject.near = near_far_minimum_ratio * this.cameraObject.far;
532
+ this.cameraObject.far -= diff;
533
+ this.near_plane_fly_debt -= near_far_minimum_ratio * this.cameraObject.far;
534
+ }
535
+ this.near_plane_fly_debt += dy*dist;
536
+ }
537
+ }
538
+ }
539
+ }
540
+ }
541
+
542
+ const flyZoom = () => {
543
+ const delta_y = calculateZoomDelta();
544
+ this.changeZoomByValue(delta_y);
545
+
546
+ if (this._state === STATE.ZOOM) {
547
+ this.previous_pointer_x = this.pointer_x;
548
+ this.previous_pointer_y = this.pointer_y;
549
+ }
550
+ if (this._state === STATE.SCROLL) {
551
+ mouseScroll = 0;
552
+ this._state = STATE.NONE;
553
+ }
554
+ }
555
+
556
+ this.setDirectionalLight = directionalLightIn => {
557
+ this.directionalLight = directionalLightIn;
558
+ };
559
+
560
+ this.updateDirectionalLight = () => {
561
+ if (this.directionalLight != 0) {
562
+ this.directionalLight.position.set(this.cameraObject.position.x,
563
+ this.cameraObject.position.y,
564
+ this.cameraObject.position.z);
565
+ }
566
+ }
567
+
568
+
569
+ this.enable = function () {
570
+ enabled = true;
571
+ if (this.domElement && this.domElement.addEventListener) {
572
+ this.domElement.addEventListener( 'mousedown', onDocumentMouseDown, false );
573
+ this.domElement.addEventListener( 'mousemove', onDocumentMouseMove, false );
574
+ this.domElement.addEventListener( 'mouseup', onDocumentMouseUp, false );
575
+ this.domElement.addEventListener( 'mouseleave', onDocumentMouseLeave, false );
576
+ this.domElement.addEventListener( 'touchstart', onDocumentTouchStart, false);
577
+ this.domElement.addEventListener( 'touchmove', onDocumentTouchMove, false);
578
+ this.domElement.addEventListener( 'touchend', onDocumentTouchEnd, false);
579
+ this.domElement.addEventListener( 'wheel', onDocumentWheelEvent, false);
580
+ this.domElement.addEventListener( 'contextmenu', event => { event.preventDefault(); }, false );
581
+ }
582
+ }
583
+
584
+ this.disable = function () {
585
+ enabled = false;
586
+ if (this.domElement && this.domElement.removeEventListener) {
587
+ this.domElement.removeEventListener( 'mousedown', onDocumentMouseDown, false );
588
+ this.domElement.removeEventListener( 'mousemove', onDocumentMouseMove, false );
589
+ this.domElement.removeEventListener( 'mouseup', onDocumentMouseUp, false );
590
+ this.domElement.removeEventListener( 'mouseleave', onDocumentMouseLeave, false );
591
+ this.domElement.removeEventListener( 'touchstart', onDocumentTouchStart, false);
592
+ this.domElement.removeEventListener( 'touchmove', onDocumentTouchMove, false);
593
+ this.domElement.removeEventListener( 'touchend', onDocumentTouchEnd, false);
594
+ this.domElement.removeEventListener( 'wheel', onDocumentWheelEvent, false);
595
+ this.domElement.removeEventListener( 'contextmenu', event => { event.preventDefault(); }, false );
596
+ }
597
+ }
598
+
599
+ this.loadPath = pathData => {
600
+ cameraPath = pathData.CameraPath;
601
+ numberOfCameraPoint = pathData.NumberOfPoints;
602
+ }
603
+
604
+ this.loadPathURL = (path_url, finishCallback) => {
605
+ const xmlhttp = new XMLHttpRequest();
606
+ xmlhttp.onreadystatechange = () => {
607
+ if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
608
+ const pathData = JSON.parse(xmlhttp.responseText);
609
+ this.loadPath(pathData);
610
+ if (finishCallback != undefined && (typeof finishCallback == 'function'))
611
+ finishCallback();
612
+ }
613
+ }
614
+ requestURL = resolveURL(path_url);
615
+ xmlhttp.open("GET", requestURL, true);
616
+ xmlhttp.send();
617
+ }
618
+
619
+ this.setPathDuration = durationIn => {
620
+ duration = durationIn;
621
+ if (smoothCameraTransitionObject)
622
+ smoothCameraTransitionObject.setDuration(duration);
623
+ if (rotateCameraTransitionObject)
624
+ rotateCameraTransitionObject.setDuration(duration);
625
+ }
626
+
627
+ this.getPlayRate = () => {
628
+ return playRate;
629
+ }
630
+
631
+ this.setPlayRate = playRateIn => {
632
+ playRate = playRateIn;
633
+ }
634
+
635
+ const updateTime = delta => {
636
+ let targetTime = inbuildTime + delta;
637
+ if (targetTime > duration)
638
+ targetTime = targetTime - duration
639
+ inbuildTime = targetTime;
640
+ };
641
+
642
+ this.getTime = () => {
643
+ return inbuildTime;
644
+ }
645
+
646
+ this.setTime = timeIn => {
647
+ if (timeIn > duration)
648
+ inbuildTime = duration;
649
+ else if (timeIn < 0.0)
650
+ inbuildTime = 0.0;
651
+ else
652
+ inbuildTime = timeIn;
653
+ }
654
+
655
+ this.getNumberOfTimeFrame = () => {
656
+ return numberOfCameraPoint;
657
+ }
658
+
659
+ this.getCurrentTimeFrame = () => {
660
+ if (numberOfCameraPoint > 2) {
661
+ const current_time = inbuildTime/duration * (numberOfCameraPoint - 1);
662
+ const bottom_frame = Math.floor(current_time);
663
+ const proportion = 1 - (current_time - bottom_frame);
664
+ const top_frame = Math.ceil(current_time);
665
+ if (bottom_frame == top_frame) {
666
+ if (bottom_frame == numberOfCameraPoint - 1) {
667
+ return [bottom_frame - 1, top_frame, 0];
668
+ } else {
669
+ return [bottom_frame, top_frame + 1, 1.0];
670
+ }
671
+ }
672
+ return [bottom_frame, top_frame, proportion];
673
+ } else if (numberOfCameraPoint == 1) {
674
+ return [0, 0, 0];
675
+ }
676
+
677
+ return undefined;
678
+ }
679
+
680
+ this.setCurrentTimeFrame = targetTimeFrame => {
681
+ if (numberOfCameraPoint > 2) {
682
+ inbuildTime = duration * targetTimeFrame / (numberOfCameraPoint - 1);
683
+ if (inbuildTime < 0.0)
684
+ inbuildTime = 0.0;
685
+ if (inbuildTime > duration)
686
+ inbuildTime = duration;
687
+ }
688
+ }
689
+
690
+ const updatePath = delta => {
691
+ if (currentMode === MODE.PATH) {
692
+ updateTime(delta);
693
+ if (cameraPath) {
694
+ const time_frame = this.getCurrentTimeFrame();
695
+ const bottom_frame = time_frame[0];
696
+ const top_frame = time_frame[1];
697
+ const proportion = time_frame[2];
698
+ const bot_pos = [cameraPath[bottom_frame*3], cameraPath[bottom_frame*3+1], cameraPath[bottom_frame*3+2]];
699
+ const top_pos = [cameraPath[top_frame*3], cameraPath[top_frame*3+1], cameraPath[top_frame*3+2]];
700
+ const current_positions = [];
701
+ for (let i = 0; i < bot_pos.length; i++) {
702
+ current_positions.push(proportion * bot_pos[i] + (1.0 - proportion) * top_pos[i]);
703
+ }
704
+ this.cameraObject.position.set(current_positions[0], current_positions[1], current_positions[2]);
705
+ this.cameraObject.target.set(top_pos[0], top_pos[1], top_pos[2]);
706
+ if (deviceOrientationControl)
707
+ this.cameraObject.lookAt( this.cameraObject.target );
708
+ if (updateLightWithPathFlag) {
709
+ this.directionalLight.position.set(current_positions[0], current_positions[1], current_positions[2]);
710
+ this.directionalLight.target.position.set(top_pos[0], top_pos[1], top_pos[2]);
711
+ }
712
+ }
713
+ }
714
+ };
715
+
716
+ this.calculatePathNow = () => {
717
+ updatePath(0.0);
718
+ }
719
+
720
+ handleSyncControl = () => {
721
+ if ((this._state === STATE.ROTATE) || (this._state === STATE.TOUCH_ROTATE)){
722
+ //rotateion does not trigger callback
723
+ tumble();
724
+ } else if ((this._state === STATE.PAN) || (this._state === STATE.TOUCH_PAN)){
725
+ translate();
726
+ ndcControl.triggerCallback();
727
+ } else if ((this._state === STATE.ZOOM) || (this._state === STATE.TOUCH_ZOOM) || (this._state === STATE.SCROLL)){
728
+ ndcControl.zoom(calculateZoomDelta());
729
+ this.previous_pointer_x = this.pointer_x;
730
+ this.previous_pointer_y = this.pointer_y;
731
+ if (this._state === STATE.SCROLL) {
732
+ this._state = STATE.NONE;
733
+ }
734
+ mouseScroll = 0;
735
+ ndcControl.triggerCallback();
736
+ }
737
+ }
738
+
739
+ this.update = timeChanged => {
740
+ const delta = timeChanged * playRate;
741
+ let controlEnabled = enabled;
742
+ if (currentMode === MODE.PATH) {
743
+ updatePath(delta);
744
+ } else if (currentMode === MODE.SMOOTH_CAMERA_TRANSITION && smoothCameraTransitionObject) {
745
+ smoothCameraTransitionObject.update(delta);
746
+ if (smoothCameraTransitionObject.isTransitionCompleted()) {
747
+ smoothCameraTransitionObject == undefined;
748
+ currentMode = MODE.DEFAULT;
749
+ }
750
+ controlEnabled = false;
751
+ } else if (currentMode === MODE.ROTATE_CAMERA_TRANSITION && rotateCameraTransitionObject) {
752
+ rotateCameraTransitionObject.update(delta);
753
+ if (rotateCameraTransitionObject.isTransitionCompleted()) {
754
+ rotateCameraTransitionObject == undefined;
755
+ currentMode = MODE.DEFAULT;
756
+ }
757
+ controlEnabled = false;
758
+ } else if (currentMode === MODE.AUTO_TUMBLE && cameraAutoTumbleObject) {
759
+ cameraAutoTumbleObject.update(delta);
760
+ } else if (currentMode === MODE.SYNC_CONTROL && ndcControl) {
761
+ handleSyncControl();
762
+ controlEnabled = false;
763
+ }
764
+ if (controlEnabled) {
765
+ if ((this._state === STATE.ROTATE) || (this._state === STATE.TOUCH_ROTATE)){
766
+ tumble();
767
+ } else if ((this._state === STATE.PAN) || (this._state === STATE.TOUCH_PAN)){
768
+ translate();
769
+ } else if ((this._state === STATE.ZOOM) || (this._state === STATE.TOUCH_ZOOM) || (this._state === STATE.SCROLL)){
770
+ flyZoom();
771
+ }
772
+ if (this._state !== STATE.NONE) {
773
+ if (currentMode === MODE.AUTO_TUMBLE && cameraAutoTumbleObject &&
774
+ cameraAutoTumbleObject.stopOnCameraInput) {
775
+ }
776
+ }
777
+ if (this._state === STATE.SCROLL)
778
+ this._state = STATE.NONE;
779
+ }
780
+ if (deviceOrientationControl) {
781
+ deviceOrientationControl.update();
782
+ //this.directionalLight.target.position.set(this.cameraObject.target.x,
783
+ // this.cameraObject.target.y, this.cameraObject.target.z);
784
+ } else {
785
+ this.cameraObject.lookAt( this.cameraObject.target );
786
+ }
787
+ };
788
+
789
+ this.playPath = () => {
790
+ currentMode = MODE.PATH;
791
+ }
792
+
793
+ this.stopPath = () => {
794
+ currentMode = MODE.DEFAULT;
795
+ }
796
+
797
+ this.isPlayingPath = () => {
798
+ return (currentMode === MODE.PATH);
799
+ }
800
+
801
+ this.enableDirectionalLightUpdateWithPath = flag => {
802
+ updateLightWithPathFlag = flag;
803
+ }
804
+
805
+ this.enableDeviceOrientation = () => {
806
+ if (!deviceOrientationControl)
807
+ deviceOrientationControl = new ModifiedDeviceOrientationControls(this.cameraObject);
808
+ }
809
+
810
+ this.disableDeviceOrientation = () => {
811
+ if (deviceOrientationControl) {
812
+ deviceOrientationControl.dispose();
813
+ deviceOrientationControl = undefined;
814
+ }
815
+ }
816
+
817
+ this.isDeviceOrientationEnabled = () => {
818
+ if (deviceOrientationControl) {
819
+ return true;
820
+ }
821
+ return false;
822
+ }
823
+
824
+ this.resetView = () => {
825
+ const viewport = viewports[defaultViewport];
826
+ this.cameraObject.near = viewport.nearPlane;
827
+ this.cameraObject.far = viewport.farPlane;
828
+ this.cameraObject.position.set( viewport.eyePosition[0], viewport.eyePosition[1],
829
+ viewport.eyePosition[2]);
830
+ this.cameraObject.target.set( viewport.targetPosition[0],
831
+ viewport.targetPosition[1], viewport.targetPosition[2] );
832
+ this.cameraObject.up.set( viewport.upVector[0], viewport.upVector[1],
833
+ viewport.upVector[2]);
834
+ this.cameraObject.updateProjectionMatrix();
835
+ this.updateDirectionalLight();
836
+ }
837
+
838
+
839
+ this.setCurrentCameraSettings = newViewport => {
840
+ if (newViewport.nearPlane)
841
+ this.cameraObject.near = newViewport.nearPlane;
842
+ if (newViewport.farPlane)
843
+ this.cameraObject.far = newViewport.farPlane;
844
+ if (newViewport.eyePosition)
845
+ this.cameraObject.position.set( newViewport.eyePosition[0],
846
+ newViewport.eyePosition[1], newViewport.eyePosition[2]);
847
+ if (newViewport.targetPosition)
848
+ this.cameraObject.target.set( newViewport.targetPosition[0],
849
+ newViewport.targetPosition[1], newViewport.targetPosition[2] );
850
+ if (newViewport.upVector)
851
+ this.cameraObject.up.set( newViewport.upVector[0], newViewport.upVector[1],
852
+ newViewport.upVector[2]);
853
+ this.cameraObject.updateProjectionMatrix();
854
+ this.updateDirectionalLight();
855
+ }
856
+
857
+ this.getViewportFromCentreAndRadius = (centreX, centreY, centreZ, radius, view_angle, clip_distance) => {
858
+ let eyex = this.cameraObject.position.x-this.cameraObject.target.x;
859
+ let eyey = this.cameraObject.position.y-this.cameraObject.target.y;
860
+ let eyez = this.cameraObject.position.z-this.cameraObject.target.z;
861
+ const fact = 1.0/Math.sqrt(eyex*eyex+eyey*eyey+eyez*eyez);
862
+ eyex = eyex * fact;
863
+ eyey = eyey * fact;
864
+ eyez = eyez * fact;
865
+ /* look at the centre of the sphere */
866
+ const localTargetPosition = [centreX, centreY, centreZ];
867
+ /* shift the eye position to achieve the desired view_angle */
868
+ const eye_distance = radius/Math.tan(view_angle*Math.PI/360.0);
869
+ const localEyePosition = [ centreX + eyex*eye_distance, centreY + eyey*eye_distance,
870
+ centreZ + eyez*eye_distance];
871
+ const localFarPlane = eye_distance+clip_distance;
872
+ let localNearPlane = 0.0;
873
+ const nearClippingFactor = 0.95;
874
+ if (clip_distance > nearClippingFactor*eye_distance)
875
+ {
876
+ localNearPlane = (1.0 - nearClippingFactor)*eye_distance;
877
+ }
878
+ else
879
+ {
880
+ localNearPlane = eye_distance - clip_distance;
881
+ }
882
+ const newViewport = new Viewport();
883
+ newViewport.nearPlane = localNearPlane;
884
+ newViewport.farPlane = localFarPlane;
885
+ newViewport.eyePosition = localEyePosition;
886
+ newViewport.targetPosition = localTargetPosition;
887
+ newViewport.upVector = [this.cameraObject.up.x, this.cameraObject.up.y,
888
+ this.cameraObject.up.z];
889
+
890
+ return newViewport;
891
+ }
892
+
893
+ this.getCurrentViewport = () => {
894
+ const currentViewport = new Viewport();
895
+ currentViewport.nearPlane = this.cameraObject.near;
896
+ currentViewport.farPlane = this.cameraObject.far;
897
+ currentViewport.eyePosition[0] = this.cameraObject.position.x;
898
+ currentViewport.eyePosition[1] = this.cameraObject.position.y;
899
+ currentViewport.eyePosition[2] = this.cameraObject.position.z;
900
+ currentViewport.targetPosition[0] = this.cameraObject.target.x;
901
+ currentViewport.targetPosition[1] = this.cameraObject.target.y;
902
+ currentViewport.targetPosition[2] = this.cameraObject.target.z;
903
+ currentViewport.upVector[0] = this.cameraObject.up.x;
904
+ currentViewport.upVector[1] = this.cameraObject.up.y;
905
+ currentViewport.upVector[2] = this.cameraObject.up.z;
906
+ return currentViewport;
907
+ }
908
+
909
+ this.getDefaultEyePosition = () => {
910
+ return eyePosition;
911
+ }
912
+
913
+ this.getDefaultTargetPosition = () => {
914
+ return targetPosition;
915
+ }
916
+
917
+ this.cameraTransition = (startingViewport, endingViewport, durationIn) => {
918
+ if (rotateCameraTransitionObject == undefined)
919
+ smoothCameraTransitionObject = new SmoothCameraTransition(startingViewport, endingViewport,
920
+ this, durationIn);
921
+ }
922
+
923
+ this.rotateCameraTransition = (axis, angle, duration) => {
924
+ if (smoothCameraTransitionObject == undefined)
925
+ rotateCameraTransitionObject = new RotateCameraTransition(axis, angle,
926
+ this, duration);
927
+ }
928
+
929
+ this.enableCameraTransition = () => {
930
+ if (smoothCameraTransitionObject)
931
+ currentMode = MODE.SMOOTH_CAMERA_TRANSITION;
932
+ if (rotateCameraTransitionObject)
933
+ currentMode = MODE.ROTATE_CAMERA_TRANSITION;
934
+ }
935
+
936
+ this.pauseCameraTransition = () => {
937
+ currentMode = MODE.DEFAULT;
938
+ }
939
+
940
+ this.stopCameraTransition = () => {
941
+ currentMode = MODE.DEFAULT;
942
+ smoothCameraTransitionObject = undefined;
943
+ rotateCameraTransitionObject = undefined;
944
+ }
945
+
946
+ this.isTransitioningCamera = () => {
947
+ return (currentMode === MODE.SMOOTH_CAMERA_TRANSITION ||
948
+ currentMode === MODE.ROTATE_CAMERA_TRANSITION);
949
+ }
950
+
951
+ /* tumble rate is in radians per second */
952
+ this.autoTumble = (tumbleDirectionIn, tumbleRateIn, stopOnCameraInputIn) => {
953
+ cameraAutoTumbleObject = new CameraAutoTumble(tumbleDirectionIn, tumbleRateIn, stopOnCameraInputIn, this);
954
+ }
955
+
956
+ this.enableAutoTumble = () => {
957
+ currentMode = MODE.AUTO_TUMBLE;
958
+ }
959
+
960
+ this.stopAutoTumble = () => {
961
+ currentMode = MODE.DEFAULT;
962
+ cameraAutoTumbleObject = undefined;
963
+ }
964
+
965
+ this.updateAutoTumble = () => {
966
+ if (cameraAutoTumbleObject)
967
+ cameraAutoTumbleObject.requireUpdate = true;
968
+ }
969
+
970
+ this.isAutoTumble = () => {
971
+ return (currentMode === MODE.AUTO_TUMBLE);
972
+ }
973
+
974
+ this.enableRaycaster = (sceneIn, callbackFunctionIn, hoverCallbackFunctionIn) => {
975
+ if (zincRayCaster == undefined)
976
+ zincRayCaster = new RayCaster(sceneIn, this.scene, callbackFunctionIn, hoverCallbackFunctionIn, this.renderer);
977
+ }
978
+
979
+ this.disableRaycaster = () => {
980
+ zincRayCaster.disable();
981
+ zincRayCaster = undefined;
982
+ }
983
+
984
+ this.isSyncControl = () => {
985
+ return currentMpde === MODE.SYNC_CONTROL;
986
+ }
987
+
988
+ this.enableSyncControl = () => {
989
+ currentMode = MODE.SYNC_CONTROL;
990
+ if (!ndcControl)
991
+ ndcControl = new NDCCameraControl();
992
+ ndcControl.setCurrentCameraSettings(this.cameraObject,
993
+ viewports[defaultViewport]);
994
+ return ndcControl;
995
+ }
996
+
997
+ this.disableSyncControl = () => {
998
+ currentMode = MODE.DEFAULT;
999
+ this.cameraObject.zoom = 1;
1000
+ this.cameraObject.updateProjectionMatrix();
1001
+ }
1002
+
1003
+ this.enable();
1004
+
1005
+ };
1006
+
1007
+ const SmoothCameraTransition = function(startingViewport, endingViewport, targetCameraIn, durationIn) {
1008
+ const startingEyePosition = startingViewport.eyePosition;
1009
+ const startingTargetPosition = startingViewport.targetPosition;
1010
+ const startingUp = startingViewport.upVector;
1011
+ const endingEyePosition = endingViewport.eyePosition;
1012
+ const endingTargetPosition = endingViewport.targetPosition;
1013
+ const endingUp = endingViewport.upVector;
1014
+ const targetCamera = targetCameraIn;
1015
+ let duration = durationIn;
1016
+ let inbuildTime = 0;
1017
+ const enabled = true;
1018
+ const updateLightWithPathFlag = true;
1019
+ let completed = false;
1020
+ targetCamera.near = Math.min(startingViewport.nearPlane, endingViewport.nearPlane);
1021
+ targetCamera.far = Math.max(startingViewport.farPlane, endingViewport.farPlane);
1022
+ targetCamera.cameraObject.up.set( endingViewport.upVector[0], endingViewport.upVector[1],
1023
+ endingViewport.upVector[2]);
1024
+
1025
+ this.setDuration = newDuration => {
1026
+ duration = newDuration;
1027
+ }
1028
+
1029
+ const updateTime = delta => {
1030
+ let targetTime = inbuildTime + delta;
1031
+ if (targetTime > duration)
1032
+ targetTime = duration;
1033
+ inbuildTime = targetTime;
1034
+ };
1035
+
1036
+ const updateCameraSettings = () => {
1037
+ const ratio = inbuildTime / duration;
1038
+ const eyePosition = [startingEyePosition[0] * (1.0 - ratio) + endingEyePosition[0] * ratio,
1039
+ startingEyePosition[1] * (1.0 - ratio) + endingEyePosition[1] * ratio,
1040
+ startingEyePosition[2] * (1.0 - ratio) + endingEyePosition[2] * ratio];
1041
+ const targetPosition = [startingTargetPosition[0] * (1.0 - ratio) + endingTargetPosition[0] * ratio,
1042
+ startingTargetPosition[1] * (1.0 - ratio) + endingTargetPosition[1] * ratio,
1043
+ startingTargetPosition[2] * (1.0 - ratio) + endingTargetPosition[2] * ratio];
1044
+ const upVector = [startingUp[0] * (1.0 - ratio) + endingUp[0] * ratio,
1045
+ startingUp[1] * (1.0 - ratio) + endingUp[1] * ratio,
1046
+ startingUp[2] * (1.0 - ratio) + endingUp[2] * ratio];
1047
+ targetCamera.cameraObject.position.set( eyePosition[0], eyePosition[1], eyePosition[2]);
1048
+ targetCamera.cameraObject.target.set( targetPosition[0], targetPosition[1], targetPosition[2] );
1049
+ };
1050
+
1051
+ this.update = delta => {
1052
+
1053
+ if ( this.enabled === false ) return;
1054
+
1055
+ updateTime(delta);
1056
+
1057
+ updateCameraSettings();
1058
+
1059
+ if (inbuildTime == duration) {
1060
+ completed = true;
1061
+ }
1062
+
1063
+ }
1064
+
1065
+ this.isTransitionCompleted = () => {
1066
+ return completed;
1067
+ }
1068
+
1069
+ };
1070
+
1071
+ const RotateCameraTransition = function(axisIn, angleIn, targetCameraIn, durationIn) {
1072
+ const axis = axisIn;
1073
+ const angle = angleIn;
1074
+ const targetCamera = targetCameraIn;
1075
+ let duration = durationIn;
1076
+ let inbuildTime = 0;
1077
+ const enabled = true;
1078
+ const ratio = inbuildTime / duration;
1079
+ let completed = false;
1080
+
1081
+ this.setDuration = newDuration => {
1082
+ duration = newDuration;
1083
+ }
1084
+
1085
+ const updateCameraSettings = delta => {
1086
+ const previousTime = inbuildTime;
1087
+ let targetTime = inbuildTime + delta;
1088
+ if (targetTime > duration)
1089
+ targetTime = duration;
1090
+ inbuildTime = targetTime;
1091
+ const actualDelta = inbuildTime - previousTime;
1092
+ const ratio = actualDelta / duration;
1093
+ const alpha = ratio * angle;
1094
+ targetCamera.rotateAboutLookAtpoint(axis, alpha);
1095
+ };
1096
+
1097
+ this.update = delta => {
1098
+
1099
+ if ( this.enabled === false ) return;
1100
+
1101
+ updateCameraSettings(delta);
1102
+
1103
+ if (inbuildTime == duration) {
1104
+ completed = true;
1105
+ }
1106
+
1107
+ }
1108
+
1109
+ this.isTransitionCompleted = () => {
1110
+ return completed;
1111
+ }
1112
+ }
1113
+
1114
+ const RayCaster = function (sceneIn, hostSceneIn, callbackFunctionIn, hoverCallbackFunctionIn, rendererIn) {
1115
+ const scene = sceneIn;
1116
+ const hostScene = hostSceneIn;
1117
+ const renderer = rendererIn;
1118
+ const callbackFunction = callbackFunctionIn;
1119
+ const hoverCallbackFunction = hoverCallbackFunctionIn;
1120
+ const enabled = true;
1121
+ const raycaster = new THREE.Raycaster();
1122
+ raycaster.params.Line.threshold = 0.1;
1123
+ raycaster.params.Points.threshold = 0.1;
1124
+ const mouse = new THREE.Vector2();
1125
+ let awaiting = false;
1126
+ let lastHoveredDate = new Date();
1127
+ let lastHoveredEmpty = false;
1128
+ let timeDiff = 0;
1129
+ let pickedObjects = new Array();
1130
+ let lastPosition = { zincCamera: undefined, x: -1 ,y: -1};
1131
+
1132
+ this.enable = () => {
1133
+ enable = true;
1134
+ }
1135
+
1136
+ this.disable = () => {
1137
+ enable = false;
1138
+ }
1139
+
1140
+ const getIntersectsObject = (zincCamera, x, y) => {
1141
+ zincCamera.getNDCFromDocumentCoords(x, y, mouse);
1142
+ if (hostScene !== scene) {
1143
+ const threejsScene = scene.getThreeJSScene();
1144
+ renderer.render(threejsScene, zincCamera.cameraObject);
1145
+ }
1146
+ raycaster.setFromCamera( mouse, zincCamera.cameraObject);
1147
+ let objects = scene.getPickableThreeJSObjects();
1148
+ //Reset pickedObjects array
1149
+ pickedObjects.length = 0;
1150
+ return raycaster.intersectObjects( objects, true, pickedObjects );
1151
+ };
1152
+
1153
+ this.pick = (zincCamera, x, y) => {
1154
+ if (enabled && renderer && scene && zincCamera && callbackFunction) {
1155
+ getIntersectsObject(zincCamera, x, y);
1156
+ callbackFunction(pickedObjects, x, y);
1157
+ }
1158
+ }
1159
+
1160
+ let hovered = (zincCamera, x, y) => {
1161
+ if (enabled && renderer && scene && zincCamera && hoverCallbackFunction) {
1162
+ getIntersectsObject(zincCamera, x, y);
1163
+ lastHoveredDate.setTime(Date.now());
1164
+ if (pickedObjects.length === 0) {
1165
+ //skip hovered callback if the previous one is empty
1166
+ if (lastHoveredEmpty)
1167
+ return
1168
+ lastHoveredEmpty = true;
1169
+ } else {
1170
+ lastHoveredEmpty = false;
1171
+ }
1172
+ hoverCallbackFunction(pickedObjects, x, y);
1173
+ }
1174
+ }
1175
+
1176
+ this.move = (zincCamera, x, y) => {
1177
+ if (enabled && renderer && scene && zincCamera && hoverCallbackFunction) {
1178
+ if (scene.displayMarkers) {
1179
+ hovered(zincCamera, x, y);
1180
+ } else {
1181
+ lastPosition.zincCamera = zincCamera;
1182
+ lastPosition.x = x;
1183
+ lastPosition.y = y;
1184
+ if (!awaiting) {
1185
+ timeDiff = lastHoveredDate ? Date.now() - lastHoveredDate.getTime() : 250;
1186
+ if (timeDiff >= 250) {
1187
+ hovered(zincCamera, x, y);
1188
+ } else {
1189
+ awaiting = true;
1190
+ setTimeout(awaitMove(lastPosition), timeDiff);
1191
+ }
1192
+ }
1193
+ }
1194
+ }
1195
+ }
1196
+
1197
+ let awaitMove = (lastPosition) => {
1198
+ return function() {
1199
+ awaiting = false;
1200
+ hovered(lastPosition.zincCamera, lastPosition.x, lastPosition.y);
1201
+ }
1202
+ }
1203
+ };
1204
+
1205
+ const CameraAutoTumble = function (tumbleDirectionIn, tumbleRateIn, stopOnCameraInputIn, targetCameraIn) {
1206
+ const tumbleAxis = new THREE.Vector3();
1207
+ const angle = -tumbleRateIn;
1208
+ const targetCamera = targetCameraIn;
1209
+ const enabled = true;
1210
+ const updateLightWithPathFlag = true;
1211
+ const tumbleDirection = tumbleDirectionIn;
1212
+ this.stopOnCameraInput = stopOnCameraInputIn;
1213
+ this.requireUpdate = true;
1214
+ const b = new THREE.Vector3();
1215
+ const c = new THREE.Vector3();
1216
+
1217
+ const computeTumbleAxisAngle = tumbleDirection => {
1218
+ const tangent_dist = Math.sqrt(tumbleDirection[0]*tumbleDirection[0] +
1219
+ tumbleDirection[1]*tumbleDirection[1]);
1220
+ const width = Math.abs(tumbleDirection[0]) * 4.0;
1221
+ const height = Math.abs(tumbleDirection[1]) * 4.0;
1222
+ const radius = 0.25 * (width + height);
1223
+ const dx = -tumbleDirection[1]/tangent_dist;
1224
+ const dy = tumbleDirection[0]/tangent_dist;
1225
+ let d = dx*(tumbleDirection[0])+dy*(-tumbleDirection[1]);
1226
+
1227
+ if (d > radius)
1228
+ {
1229
+ d = radius;
1230
+ }
1231
+ else
1232
+ {
1233
+ if (d < -radius)
1234
+ {
1235
+ d = -radius;
1236
+ }
1237
+ }
1238
+
1239
+ const phi=Math.acos(d/radius)-0.5*Math.PI;
1240
+ /* get axis to rotate about */
1241
+ tumbleAxis.copy(targetCamera.cameraObject.position).sub(
1242
+ targetCamera.cameraObject.target).normalize();
1243
+ b.copy(targetCamera.cameraObject.up).normalize();
1244
+ c.crossVectors(b, tumbleAxis).normalize().multiplyScalar(dx);
1245
+ b.multiplyScalar(dy);
1246
+ b.add(c).multiplyScalar(Math.cos(phi));
1247
+ tumbleAxis.multiplyScalar(Math.sin(phi)).add(b);
1248
+ };
1249
+
1250
+ this.update = delta => {
1251
+
1252
+ if ( this.enabled === false ) return;
1253
+
1254
+ if (this.requireUpdate) {
1255
+ computeTumbleAxisAngle(tumbleDirection);
1256
+ this.requireUpdate = false;
1257
+ }
1258
+ targetCamera.rotateAboutLookAtpoint(tumbleAxis, angle * delta/1000);
1259
+
1260
+ }
1261
+
1262
+ };
1263
+
1264
+ /**
1265
+ * @author mrdoob / http://mrdoob.com/
1266
+ */
1267
+ StereoCameraZoomFixed = function () {
1268
+
1269
+ this.type = 'StereoCamera';
1270
+
1271
+ this.aspect = 1;
1272
+
1273
+ this.cameraL = new THREE.PerspectiveCamera();
1274
+ this.cameraL.layers.enable( 1 );
1275
+ this.cameraL.matrixAutoUpdate = false;
1276
+
1277
+ this.cameraR = new THREE.PerspectiveCamera();
1278
+ this.cameraR.layers.enable( 2 );
1279
+ this.cameraR.matrixAutoUpdate = false;
1280
+
1281
+ };
1282
+
1283
+ Object.assign( StereoCameraZoomFixed.prototype, {
1284
+
1285
+ update: (() => {
1286
+
1287
+ let focus, fov, aspect, near, far, zoom;
1288
+
1289
+ const eyeRight = new THREE.Matrix4();
1290
+ const eyeLeft = new THREE.Matrix4();
1291
+
1292
+ return function update( camera ) {
1293
+
1294
+ const needsUpdate = focus !== camera.focus || fov !== camera.fov ||
1295
+ aspect !== camera.aspect * this.aspect || near !== camera.near ||
1296
+ far !== camera.far || zoom !== camera.zoom;
1297
+
1298
+ if ( needsUpdate ) {
1299
+
1300
+ focus = camera.focus;
1301
+ fov = camera.fov;
1302
+ aspect = camera.aspect * this.aspect;
1303
+ near = camera.near;
1304
+ far = camera.far;
1305
+ zoom = camera.zoom;
1306
+
1307
+ // Off-axis stereoscopic effect based on
1308
+ // http://paulbourke.net/stereographics/stereorender/
1309
+
1310
+ const projectionMatrix = camera.projectionMatrix.clone();
1311
+ const eyeSep = 0.064 / 2;
1312
+ const eyeSepOnProjection = eyeSep * near / focus;
1313
+ const ymax = near * Math.tan( THREE.Math.DEG2RAD * fov * 0.5 ) / camera.zoom;
1314
+ let xmin, xmax;
1315
+
1316
+ // translate xOffset
1317
+
1318
+ eyeLeft.elements[ 12 ] = - eyeSep;
1319
+ eyeRight.elements[ 12 ] = eyeSep;
1320
+
1321
+ // for left eye
1322
+
1323
+ xmin = - ymax * aspect + eyeSepOnProjection;
1324
+ xmax = ymax * aspect + eyeSepOnProjection;
1325
+
1326
+ projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin );
1327
+ projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
1328
+
1329
+ this.cameraL.projectionMatrix.copy( projectionMatrix );
1330
+
1331
+ // for right eye
1332
+
1333
+ xmin = - ymax * aspect - eyeSepOnProjection;
1334
+ xmax = ymax * aspect - eyeSepOnProjection;
1335
+
1336
+ projectionMatrix.elements[ 0 ] = 2 * near / ( xmax - xmin );
1337
+ projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );
1338
+
1339
+ this.cameraR.projectionMatrix.copy( projectionMatrix );
1340
+
1341
+ }
1342
+
1343
+ this.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( eyeLeft );
1344
+ this.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( eyeRight );
1345
+
1346
+ };
1347
+
1348
+ })()
1349
+
1350
+ } );
1351
+
1352
+ /** the following StereoEffect is written by third party */
1353
+ /**
1354
+ * @author alteredq / http://alteredqualia.com/
1355
+ * @authod mrdoob / http://mrdoob.com/
1356
+ * @authod arodic / http://aleksandarrodic.com/
1357
+ * @authod fonserbc / http://fonserbc.github.io/
1358
+ */
1359
+ const StereoEffect = function ( renderer ) {
1360
+
1361
+ const _stereo = new StereoCameraZoomFixed();
1362
+ _stereo.aspect = 0.5;
1363
+
1364
+ this.setSize = (width, height) => {
1365
+
1366
+ renderer.setSize( width, height );
1367
+
1368
+ };
1369
+
1370
+ this.render = (scene, camera) => {
1371
+
1372
+ scene.updateMatrixWorld();
1373
+
1374
+ if ( camera.parent === null ) camera.updateMatrixWorld();
1375
+
1376
+ _stereo.update( camera );
1377
+
1378
+ const size = renderer.getSize();
1379
+
1380
+ renderer.setScissorTest( true );
1381
+ renderer.clear();
1382
+
1383
+ renderer.setScissor( 0, 0, size.width / 2, size.height );
1384
+ renderer.setViewport( 0, 0, size.width / 2, size.height );
1385
+ renderer.render( scene, _stereo.cameraL );
1386
+
1387
+ renderer.setScissor( size.width / 2, 0, size.width / 2, size.height );
1388
+ renderer.setViewport( size.width / 2, 0, size.width / 2, size.height );
1389
+ renderer.render( scene, _stereo.cameraR );
1390
+
1391
+ renderer.setScissorTest( false );
1392
+
1393
+ };
1394
+
1395
+ };
1396
+
1397
+
1398
+ /**
1399
+ * @author richt / http://richt.me
1400
+ * @author WestLangley / http://github.com/WestLangley
1401
+ *
1402
+ * W3C Device Orientation control (http://w3c.github.io/deviceorientation/spec-source-orientation.html)
1403
+ */
1404
+
1405
+ ModifiedDeviceOrientationControls = function ( object ) {
1406
+
1407
+ const scope = this;
1408
+
1409
+ this.object = object;
1410
+ this.object.rotation.reorder( "YXZ" );
1411
+
1412
+ this.enabled = true;
1413
+
1414
+ this.deviceOrientation = {};
1415
+ this.screenOrientation = 0;
1416
+
1417
+ const onDeviceOrientationChangeEvent = event => {
1418
+
1419
+ scope.deviceOrientation = event;
1420
+
1421
+ };
1422
+
1423
+ const onScreenOrientationChangeEvent = () => {
1424
+ if (typeof(window) !== 'undefined')
1425
+ scope.screenOrientation = window.orientation || 0;
1426
+
1427
+ };
1428
+
1429
+ // The angles alpha, beta and gamma form a set of intrinsic Tait-Bryan angles of type Z-X'-Y''
1430
+
1431
+ const setObjectQuaternion = (() => {
1432
+
1433
+ const zee = new THREE.Vector3( 0, 0, 1 );
1434
+
1435
+ const euler = new THREE.Euler();
1436
+
1437
+ const q0 = new THREE.Quaternion();
1438
+
1439
+ const q1 = new THREE.Quaternion( - Math.sqrt( 0.5 ), 0, 0, Math.sqrt( 0.5 ) ); // - PI/2 around the x-axis
1440
+
1441
+ return (cameraObject, alpha, beta, gamma, orient) => {
1442
+
1443
+ const vector = new THREE.Vector3(0, 0, 1);
1444
+
1445
+ vector.subVectors(cameraObject.target, cameraObject.position);
1446
+
1447
+ euler.set( beta, alpha, - gamma, 'YXZ' ); // 'ZXY' for the device, but 'YXZ' for us
1448
+
1449
+ const quaternion = new THREE.Quaternion();
1450
+
1451
+ quaternion.setFromEuler( euler ); // orient the device
1452
+
1453
+ quaternion.multiply( q1 ); // camera looks out the back of the device, not the top
1454
+
1455
+ quaternion.multiply( q0.setFromAxisAngle( zee, - orient ) ); // adjust for screen orientation
1456
+
1457
+ vector.applyQuaternion(quaternion);
1458
+
1459
+ vector.addVectors(cameraObject.position, vector);
1460
+
1461
+ cameraObject.lookAt(vector);
1462
+
1463
+ };
1464
+
1465
+ })();
1466
+
1467
+ this.connect = () => {
1468
+
1469
+ onScreenOrientationChangeEvent(); // run once on load
1470
+ if (typeof(window) !== 'undefined') {
1471
+ window.addEventListener( 'orientationchange', onScreenOrientationChangeEvent, false );
1472
+ window.addEventListener( 'deviceorientation', onDeviceOrientationChangeEvent, false );
1473
+ }
1474
+ scope.enabled = true;
1475
+
1476
+ };
1477
+
1478
+ this.disconnect = () => {
1479
+ if (typeof(window) !== 'undefined') {
1480
+ window.removeEventListener( 'orientationchange', onScreenOrientationChangeEvent, false );
1481
+ window.removeEventListener( 'deviceorientation', onDeviceOrientationChangeEvent, false );
1482
+ }
1483
+ scope.enabled = false;
1484
+
1485
+ };
1486
+
1487
+ this.update = () => {
1488
+
1489
+ if ( scope.enabled === false ) return;
1490
+
1491
+ const alpha = scope.deviceOrientation.alpha ? THREE.Math.degToRad( scope.deviceOrientation.alpha ) : 0; // Z
1492
+ const beta = scope.deviceOrientation.beta ? THREE.Math.degToRad( scope.deviceOrientation.beta ) : 0; // X'
1493
+ const gamma = scope.deviceOrientation.gamma ? THREE.Math.degToRad( scope.deviceOrientation.gamma ) : 0; // Y''
1494
+ const orient = scope.screenOrientation ? THREE.Math.degToRad( scope.screenOrientation ) : 0; // O
1495
+
1496
+ setObjectQuaternion( scope.object, alpha, beta, gamma, orient );
1497
+
1498
+ };
1499
+
1500
+ this.dispose = function () {
1501
+
1502
+ this.disconnect();
1503
+
1504
+ };
1505
+
1506
+ this.connect();
1507
+
1508
+ };
1509
+
1510
+ const NDCCameraControl = function () {
1511
+ let camera = undefined;
1512
+ let targetCamera = undefined;
1513
+ let defaultViewport = undefined;
1514
+ const position = new THREE.Vector3();
1515
+ const target = new THREE.Vector3();
1516
+ const v1 = new THREE.Vector3();
1517
+ const v2 = new THREE.Vector3();
1518
+ let eventCallback = undefined;
1519
+
1520
+ this.setCurrentCameraSettings = (cameraIn, defaultViewportIn) => {
1521
+ camera = cameraIn.clone();
1522
+ targetCamera = cameraIn;
1523
+ defaultViewport = defaultViewportIn;
1524
+ camera.near = defaultViewport.nearPlane;
1525
+ if (defaultViewport.farPlane)
1526
+ camera.far = defaultViewport.farPlane;
1527
+ if (defaultViewport.eyePosition)
1528
+ camera.position.set(defaultViewport.eyePosition[0],
1529
+ defaultViewport.eyePosition[1], defaultViewport.eyePosition[2]);
1530
+ if (defaultViewport.upVector)
1531
+ camera.up.set(defaultViewport.upVector[0], defaultViewport.upVector[1],
1532
+ defaultViewport.upVector[2]);
1533
+ if (defaultViewport.targetPosition) {
1534
+ camera.target = new THREE.Vector3(defaultViewport.targetPosition[0],
1535
+ defaultViewport.targetPosition[1], defaultViewport.targetPosition[2]);
1536
+ camera.lookAt(camera.target);
1537
+ }
1538
+ camera.updateProjectionMatrix();
1539
+ position.copy(camera.position).project(camera);
1540
+ target.copy(camera.target).project(camera);
1541
+ }
1542
+
1543
+ this.getCurrentPosition = () => {
1544
+ target.copy(targetCamera.target).project(camera);
1545
+ return [target.x, target.y];
1546
+ }
1547
+
1548
+ this.zoom = delta => {
1549
+ let scaledDelta = delta * 0.002;
1550
+ let zoom = Math.max(targetCamera.zoom - scaledDelta, 1.0);
1551
+ targetCamera.zoom = zoom;
1552
+ targetCamera.updateProjectionMatrix();
1553
+ }
1554
+
1555
+ this.zoomToBox = (box, zoom) => {
1556
+ box.getCenter(v1);
1557
+ v1.project(camera);
1558
+ this.setCenterZoom([v1.x, v1.y], zoom);
1559
+ }
1560
+
1561
+ //return top left and size
1562
+ this.getPanZoom = () => {
1563
+ return {target: this.getCurrentPosition(), zoom: targetCamera.zoom };
1564
+ }
1565
+
1566
+ this.setCenterZoom = (center, zoom) => {
1567
+ v1.set(center[0], center[1], target.z).unproject(camera);
1568
+ v2.copy(v1).sub(targetCamera.target);
1569
+ targetCamera.target.copy(v1);
1570
+ targetCamera.lookAt(targetCamera.target);
1571
+ targetCamera.position.add(v2);
1572
+ targetCamera.zoom = zoom;
1573
+ targetCamera.updateProjectionMatrix();
1574
+ }
1575
+
1576
+ this.setEventCallback = (callback) => {
1577
+ if (callback === undefined || (typeof callback == 'function'))
1578
+ eventCallback = callback;
1579
+ }
1580
+
1581
+ this.triggerCallback = () => {
1582
+ if (eventCallback !== undefined && (typeof eventCallback == 'function'))
1583
+ eventCallback();
1584
+ }
1585
+ };
1586
+
1587
+ exports.Viewport = Viewport
1588
+ exports.CameraControls = CameraControls
1589
+ exports.SmoothCameraTransition = SmoothCameraTransition
1590
+ exports.RotateCameraTransition = RotateCameraTransition
1591
+ exports.RayCaster = RayCaster
1592
+ exports.CameraAutoTumble = CameraAutoTumble
1593
+ exports.StereoEffect = StereoEffect
1594
+ exports.NDCCameraControl = NDCCameraControl