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
package/src/scene.js ADDED
@@ -0,0 +1,963 @@
1
+ const THREE = require('three');
2
+ const SceneLoader = require('./sceneLoader').SceneLoader;
3
+ const SceneExporter = require('./sceneExporter').SceneExporter;
4
+ const Viewport = require('./controls').Viewport;
5
+
6
+ const defaultMetadata = function() {
7
+ return {
8
+ Duration: "6 secs",
9
+ OriginalDuration: "-",
10
+ TimeStamps: {}
11
+ }
12
+ };
13
+
14
+ const defaultDuration = 6000;
15
+
16
+ /**
17
+ * A Zinc.Scene contains {@link Zinc.Geometry}, {@link Zinc.Glyphset} and
18
+ * {@link Zinc.CameraControls} which controls the viewport and additional features.
19
+ * It is the main object used for controlling what is and what is not displayed
20
+ * on the renderer.
21
+ *
22
+ * @class
23
+ * @param {Object} containerIn - Container to create the renderer on.
24
+ * @author Alan Wu
25
+ * @return {Zinc.Scene}
26
+ */
27
+ exports.Scene = function (containerIn, rendererIn) {
28
+ const container = containerIn;
29
+ let videoHandler = undefined;
30
+ let sceneLoader = new SceneLoader(this);
31
+ let minimap = undefined;
32
+ const scene = new THREE.Scene();
33
+ const rootRegion = new (require('./region').Region)();
34
+ scene.add(rootRegion.getGroup());
35
+ /**
36
+ * A {@link THREE.DirectionalLight} object for controlling lighting of this scene.
37
+ */
38
+ this.directionalLight = undefined;
39
+ /**
40
+ * a {@link THREE.AmbientLight} for controlling the ambient lighting of this scene.
41
+ */
42
+ this.ambient = undefined;
43
+ this.camera = undefined;
44
+ let duration = 6000;
45
+ let zincCameraControls = undefined;
46
+ this.sceneName = undefined;
47
+ let stereoEffectFlag = false;
48
+ let stereoEffect = undefined;
49
+ this.autoClearFlag = true;
50
+ this.displayMarkers = false;
51
+ this.displayMinimap = false;
52
+ this.minimapScissor = {
53
+ x_offset: 16,
54
+ y_offset: 16,
55
+ width: 128,
56
+ height: 128,
57
+ align: "top-left",
58
+ updateRequired: true
59
+ };
60
+ let scissor = {x: 0, y: 0};
61
+ let metadata = defaultMetadata();
62
+ let _markerTarget = new THREE.Vector2();
63
+ let pickableObjectsList = [];
64
+ this.forcePickableObjectsUpdate = false;
65
+
66
+ const getDrawingWidth = () => {
67
+ if (container)
68
+ if (typeof container.clientWidth !== "undefined")
69
+ return container.clientWidth;
70
+ else
71
+ return container.width;
72
+ return 0;
73
+ }
74
+
75
+
76
+ const getDrawingHeight = () => {
77
+ if (container)
78
+ if (typeof container.clientHeight !== "undefined")
79
+ return container.clientHeight;
80
+ else
81
+ return container.height;
82
+ return 0;
83
+ }
84
+
85
+ /**
86
+ * This function returns a three component array, which contains
87
+ * [totalsize, totalLoaded and errorDownload] of all the downloads happening
88
+ * in this scene.
89
+ * @returns {Array}
90
+ */
91
+ this.getDownloadProgress = () => {
92
+ return sceneLoader.getDownloadProgress();
93
+ }
94
+
95
+ //called from Renderer when panel has been resized
96
+ this.onWindowResize = () => {
97
+ this.camera.aspect = getDrawingWidth() / getDrawingHeight();
98
+ this.camera.updateProjectionMatrix();
99
+ this.minimapScissor.updateRequired = true;
100
+ zincCameraControls.onResize();
101
+ }
102
+
103
+ /**
104
+ * Reset the viewport of this scene to its original state.
105
+ */
106
+ this.resetView = () => {
107
+ this.onWindowResize();
108
+ zincCameraControls.resetView();
109
+ }
110
+
111
+ /**
112
+ * Set the zoom level by unit scroll rate
113
+ */
114
+ this.changeZoomByScrollRateUnit = unit => {
115
+ zincCameraControls.changeZoomByScrollRateUnit(unit);
116
+ }
117
+
118
+ //Setup the camera for this scene, it also initialise the lighting
119
+ const setupCamera = () => {
120
+ this.camera = new THREE.PerspectiveCamera(40, getDrawingWidth() / getDrawingHeight(), 0.0, 10.0);
121
+ this.ambient = new THREE.AmbientLight(0xffffff, 0.2);
122
+ scene.add(this.ambient);
123
+
124
+ this.directionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
125
+ scene.add(this.directionalLight);
126
+ zincCameraControls = new (require('./controls').CameraControls)(this.camera, rendererIn.domElement, rendererIn, this);
127
+
128
+ zincCameraControls.setDirectionalLight(this.directionalLight);
129
+ zincCameraControls.resetView();
130
+
131
+ minimap = new (require('./minimap').Minimap)(this);
132
+ };
133
+
134
+ setupCamera();
135
+
136
+ /**
137
+ * Load the viewport Data from the argument {@link Zinc.Viewport} and set it as
138
+ * the default viewport of this scene.
139
+ *
140
+ * @param {Zinc.Viewport} viewData - Viewport data to be loaded.
141
+ */
142
+ this.loadView = settings => {
143
+ const viewPort = new Viewport();
144
+ viewPort.setFromObject(settings);
145
+ zincCameraControls.setCurrentCameraSettings(viewPort);
146
+ return true;
147
+ }
148
+
149
+ /**
150
+ * Set up multiple views.
151
+ *
152
+ * @param {Zinc.Viewport} viewData - Viewport data to be loaded.
153
+ */
154
+ this.setupMultipleViews = (defaultView, entries) => {
155
+ for (const [name, settings] of Object.entries(entries)) {
156
+ const viewport = new Viewport();
157
+ viewport.setFromObject(settings);
158
+ zincCameraControls.addViewport(name, viewport);
159
+ }
160
+ zincCameraControls.setDefaultViewport(defaultView);
161
+ }
162
+
163
+ /**
164
+ * Get the bounding box of all the object in this scene only.
165
+ *
166
+ * @returns {THREE.Box3}
167
+ */
168
+ this.getBoundingBox = () => {
169
+ return rootRegion.getBoundingBox(true);
170
+ }
171
+
172
+ /**
173
+ * Adjust the viewport to display the desired volume provided by the bounding box.
174
+ *
175
+ * @param {THREE.Box3} boundingBox - The bounding box which describes the volume of
176
+ * which we the viewport should be displaying.
177
+ */
178
+ this.viewAllWithBoundingBox = boundingBox => {
179
+ if (boundingBox) {
180
+ // enlarge radius to keep image within edge of window
181
+ const radius = boundingBox.min.distanceTo(boundingBox.max) / 2.0;
182
+ const centreX = (boundingBox.min.x + boundingBox.max.x) / 2.0;
183
+ const centreY = (boundingBox.min.y + boundingBox.max.y) / 2.0;
184
+ const centreZ = (boundingBox.min.z + boundingBox.max.z) / 2.0;
185
+ const clip_factor = 4.0;
186
+ const viewport = zincCameraControls.getViewportFromCentreAndRadius(centreX, centreY, centreZ, radius, 40, radius * clip_factor);
187
+
188
+ zincCameraControls.setCurrentCameraSettings(viewport);
189
+ }
190
+ }
191
+
192
+ /**
193
+ * Adjust zoom distance to include all primitives in scene only.
194
+ */
195
+ this.viewAll = () => {
196
+ const boundingBox = this.getBoundingBox();
197
+ this.viewAllWithBoundingBox(boundingBox);
198
+ }
199
+
200
+ /**
201
+ * A function which iterates through the list of geometries and call the callback
202
+ * function with the geometries as the argument.
203
+ * @param {Function} callbackFunction - Callback function with the geometry
204
+ * as an argument.
205
+ */
206
+ this.forEachGeometry = callbackFunction => {
207
+ rootRegion.forEachGeometry(callbackFunction, true);
208
+ }
209
+
210
+ /**
211
+ * A function which iterates through the list of glyphsets and call the callback
212
+ * function with the glyphset as the argument.
213
+ * @param {Function} callbackFunction - Callback function with the glyphset
214
+ * as an argument.
215
+ */
216
+ this.forEachGlyphset = callbackFunction => {
217
+ rootRegion.forEachGlyphset(callbackFunction, true);
218
+ }
219
+
220
+ /**
221
+ * A function which iterates through the list of pointsets and call the callback
222
+ * function with the pointset as the argument.
223
+ * @param {Function} callbackFunction - Callback function with the pointset
224
+ * as an argument.
225
+ */
226
+ this.forEachPointset = callbackFunction => {
227
+ rootRegion.forEachPointset(callbackFunction, true);
228
+ }
229
+
230
+ /**
231
+ * A function which iterates through the list of lines and call the callback
232
+ * function with the lines as the argument.
233
+ * @param {Function} callbackFunction - Callback function with the lines
234
+ * as an argument.
235
+ */
236
+ this.forEachLine = callbackFunction => {
237
+ rootRegion.forEachLine(callbackFunction, true);
238
+ }
239
+
240
+ /**
241
+ * Find and return all geometries in this scene with the matching GroupName.
242
+ *
243
+ * @param {String} GroupName - Groupname to match with.
244
+ * @returns {Array}
245
+ */
246
+ this.findGeometriesWithGroupName = GroupName => {
247
+ return rootRegion.findGeometriesWithGroupName(GroupName, true);
248
+ }
249
+
250
+ /**
251
+ * Find and return all pointsets in this scene with the matching GroupName.
252
+ *
253
+ * @param {String} GroupName - Groupname to match with.
254
+ * @returns {Array}
255
+ */
256
+ this.findPointsetsWithGroupName = GroupName => {
257
+ return rootRegion.findPointsetsWithGroupName(GroupName, true);
258
+ }
259
+ /**
260
+ * Find and return all glyphsets in this scene with the matching GroupName.
261
+ *
262
+ * @param {String} GroupName - Groupname to match with.
263
+ * @returns {Array}
264
+ */
265
+ this.findGlyphsetsWithGroupName = GroupName => {
266
+ return rootRegion.findGlyphsetsWithGroupName(GroupName, true);
267
+ }
268
+
269
+ /**
270
+ * Find and return all lines in this scene with the matching GroupName.
271
+ *
272
+ * @param {String} GroupName - Groupname to match with.
273
+ * @returns {Array}
274
+ */
275
+ this.findLinesWithGroupName = GroupName => {
276
+ return rootRegion.findLinesWithGroupName(GroupName, true);
277
+ }
278
+
279
+ this.findObjectsWithGroupName = GroupName => {
280
+ return rootRegion.findObjectsWithGroupName(GroupName, true);
281
+ }
282
+
283
+ this.findObjectsWithAnatomicalId = anatomicalId => {
284
+ return rootRegion.findObjectsWithAnatomicalId(anatomicalId, true);
285
+ }
286
+
287
+ this.getBoundingBoxOfZincObjects = objectsArray => {
288
+ let boundingBox = undefined;
289
+ for (let i = 0; i < objectsArray.length; i++) {
290
+ let box = objectsArray[i].getBoundingBox();
291
+ if (box) {
292
+ if (!boundingBox)
293
+ boundingBox = box;
294
+ else
295
+ boundingBox.union(box);
296
+ }
297
+ }
298
+ return boundingBox;
299
+ }
300
+
301
+ this.vectorToScreenXY = point => {
302
+ point.project(this.camera);
303
+ let width = getDrawingWidth();
304
+ let height = getDrawingHeight();
305
+ let widthHalf = (width / 2);
306
+ let heightHalf = (height / 2);
307
+ point.x = (point.x * widthHalf) + widthHalf;
308
+ point.y = - (point.y * heightHalf) + heightHalf;
309
+ return point;
310
+ }
311
+
312
+ this.getObjectsScreenXY = zincObjects => {
313
+ if (zincObjects && zincObjects.length > 0) {
314
+ let boundingBox = this.getBoundingBoxOfZincObjects(zincObjects);
315
+ const center = new THREE.Vector3();
316
+ boundingBox.getCenter(center);
317
+ return this.vectorToScreenXY(center);
318
+ }
319
+ return undefined;
320
+ }
321
+
322
+ this.getNamedObjectsScreenXY = name => {
323
+ let zincObjects = this.findObjectsWithGroupName(name);
324
+ return this.getObjectsScreenXY(zincObjects);
325
+ };
326
+
327
+ this.addZincObject = zincObject => {
328
+ if (zincObject) {
329
+ rootRegion.addZincObject(zincObject);
330
+ if (zincCameraControls)
331
+ zincCameraControls.calculateMaxAllowedDistance(this);
332
+ }
333
+ }
334
+
335
+ /**
336
+ * Load a glyphset into this scene object.
337
+ *
338
+ * @param {String} metaurl - Provide informations such as transformations, colours
339
+ * and others for each of the glyph in the glyphsset.
340
+ * @param {String} glyphurl - regular json model file providing geometry of the glyph.
341
+ * @param {String} groupName - name to assign the glyphset's groupname to.
342
+ * @param {Function} finishCallback - Callback function which will be called
343
+ * once the glyphset is succssfully load in.
344
+ */
345
+ this.loadGlyphsetURL = (metaurl, glyphurl, groupName, finishCallback) => {
346
+ sceneLoader.loadGlyphsetURL(rootRegion, metaurl, glyphurl, groupName, finishCallback);
347
+ }
348
+
349
+ /**
350
+ * Load a pointset into this scene object.
351
+ *
352
+ * @param {String} metaurl - Provide informations such as transformations, colours
353
+ * and others for each of the glyph in the glyphsset.
354
+ * @param {Boolean} timeEnabled - Indicate if morphing is enabled.
355
+ * @param {Boolean} morphColour - Indicate if color morphing is enabled.
356
+ * @param {STRING} groupName - name to assign the pointset's groupname to.
357
+ * @param {Function} finishCallback - Callback function which will be called
358
+ * once the glyphset is succssfully load in.
359
+ */
360
+ this.loadPointsetURL = (url, timeEnabled, morphColour, groupName, finishCallback) => {
361
+ sceneLoader.loadPointsetURL(rootRegion, url, timeEnabled, morphColour, groupName, finishCallback);
362
+ }
363
+
364
+ /**
365
+ * Load lines into this scene object.
366
+ *
367
+ * @param {String} metaurl - Provide informations such as transformations, colours
368
+ * and others for each of the glyph in the glyphsset.
369
+ * @param {Boolean} timeEnabled - Indicate if morphing is enabled.
370
+ * @param {Boolean} morphColour - Indicate if color morphing is enabled.
371
+ * @param {STRING} groupName - name to assign the pointset's groupname to.
372
+ * @param {Function} finishCallback - Callback function which will be called
373
+ * once the glyphset is succssfully load in.
374
+ */
375
+ this.loadLinesURL = (url, timeEnabled, morphColour, groupName, finishCallback) => {
376
+ sceneLoader.loadLinesURL(rootRegion, url, timeEnabled, morphColour, groupName, finishCallback);
377
+ }
378
+
379
+ /**
380
+ * Read a STL file into this scene, the geometry will be presented as
381
+ * {@link Zinc.Geometry}.
382
+ *
383
+ * @param {STRING} url - location to the STL file.
384
+ * @param {STRING} groupName - name to assign the geometry's groupname to.
385
+ * @param {Function} finishCallback - Callback function which will be called
386
+ * once the STL geometry is succssfully loaded.
387
+ */
388
+ this.loadSTL = (url, groupName, finishCallback) => {
389
+ sceneLoader.loadSTL(rootRegion, url, groupName, finishCallback);
390
+ }
391
+
392
+ /**
393
+ * Read a OBJ file into this scene, the geometry will be presented as
394
+ * {@link Zinc.Geometry}.
395
+ *
396
+ * @param {STRING} url - location to the STL file.
397
+ * @param {STRING} groupName - name to assign the geometry's groupname to.
398
+ * @param {Function} finishCallback - Callback function which will be called
399
+ * once the OBJ geometry is succssfully loaded.
400
+ */
401
+ this.loadOBJ = (url, groupName, finishCallback) => {
402
+ sceneLoader.loadOBJ(rootRegion, url, groupName, finishCallback);
403
+ }
404
+
405
+ /**
406
+ * Load a metadata file from the provided URL into this scene. Once
407
+ * succssful scene proceeds to read each items into scene for visualisations.
408
+ *
409
+ * @param {String} url - Location of the metafile
410
+ * @param {Function} finishCallback - Callback function which will be called
411
+ * for each glyphset and geometry that has been written in.
412
+ */
413
+ this.loadMetadataURL = (url, finishCallback, allCompletedCallback) => {
414
+ sceneLoader.loadMetadataURL(rootRegion, url, finishCallback, allCompletedCallback);
415
+ }
416
+
417
+ /**
418
+ * Load a legacy model(s) format with the provided URLs and parameters. This only loads the geometry
419
+ * without any of the metadata. Therefore, extra parameters should be provided.
420
+ *
421
+ * @deprecated
422
+ */
423
+ this.loadModelsURL = (urls, colours, opacities, timeEnabled, morphColour, finishCallback) => {
424
+ sceneLoader.loadModelsURL(rootRegion. urls, colours, opacities, timeEnabled, morphColour, finishCallback);
425
+ }
426
+
427
+ /**
428
+ * Load the viewport from an external location provided by the url.
429
+ * @param {String} URL - address to the file containing viewport information.
430
+ */
431
+ this.loadViewURL = url => {
432
+ sceneLoader.loadViewURL(url);
433
+ }
434
+
435
+ /**
436
+ * Load a legacy file format containing the viewport and its meta file from an external
437
+ * location provided by the url. Use the new metadata format with
438
+ * {@link Zinc.Scene#loadMetadataURL} instead.
439
+ *
440
+ * @param {String} URL - address to the file containing viewport and model information.
441
+ * @deprecated
442
+ */
443
+ this.loadFromViewURL = (jsonFilePrefix, finishCallback) => {
444
+ sceneLoader.loadFromViewURL(jsonFilePrefix, finishCallback);
445
+ }
446
+
447
+ /**
448
+ * Load GLTF into this scene object.
449
+ */
450
+ this.loadGLTF = (url, finishCallback, options) => {
451
+ sceneLoader.loadGLTF(rootRegion, url, finishCallback, options);
452
+ }
453
+
454
+ //Update the directional light for this scene.
455
+ this.updateDirectionalLight = () => {
456
+ zincCameraControls.updateDirectionalLight();
457
+ }
458
+
459
+ /**
460
+ * Add any {THREE.Object} into this scene.
461
+ * @param {THREE.Object} object - to be addded into this scene.
462
+ */
463
+ this.addObject = object => {
464
+ scene.add(object);
465
+ }
466
+
467
+ /**
468
+ * Remove any {THREE.Object} from this scene.
469
+ * @param {THREE.Object} object - to be removed from this scene.
470
+ */
471
+ this.removeObject = object => {
472
+ scene.remove(object);
473
+ }
474
+
475
+ /**
476
+ * Get the current time of the scene.
477
+ * @return {Number}
478
+ */
479
+ this.getCurrentTime = () => {
480
+ if (videoHandler != undefined) {
481
+ return videoHandler.getCurrentTime(duration);
482
+ }
483
+ const time = rootRegion.getCurrentTime();
484
+ if (time !== -1)
485
+ return time;
486
+
487
+ return 0;
488
+ }
489
+
490
+ /**
491
+ * Set the current time of all the geometries and glyphsets of this scene.
492
+ * @param {Number} time - Value to set the time to.
493
+ */
494
+ this.setMorphsTime = (time) => {
495
+ if (videoHandler != undefined) {
496
+ videoHandler.setMorphTime(time, duration);
497
+ }
498
+ rootRegion.setMorphTime(time, true);
499
+ }
500
+
501
+ /**
502
+ * Check if any object in this scene is time varying.
503
+ *
504
+ * @return {Boolean}
505
+ */
506
+ this.isTimeVarying = () => {
507
+ if (videoHandler && videoHandler.video && !videoHandler.video.error) {
508
+ return true;
509
+ }
510
+ return rootRegion.isTimeVarying();
511
+ }
512
+
513
+ /**
514
+ * Update geometries and glyphsets based on the calculated time.
515
+ * @private
516
+ */
517
+ this.renderGeometries = (playRate, delta, playAnimation) => {
518
+ // Let video dictates the progress if one is present
519
+ let options = {};
520
+ options.camera = zincCameraControls;
521
+ options.displayMarkers = this.displayMarkers;
522
+ options.markerDepths = [];
523
+ if (videoHandler) {
524
+ if (videoHandler.isReadyToPlay()) {
525
+ if (playAnimation) {
526
+ videoHandler.video.play();
527
+ } else {
528
+ videoHandler.video.pause();
529
+ }
530
+ const currentTime = videoHandler.video.currentTime /
531
+ videoHandler.getVideoDuration() * duration;
532
+ if (0 == sceneLoader.toBeDownloaded) {
533
+ zincCameraControls.setTime(currentTime);
534
+ zincCameraControls.update(0);
535
+ rootRegion.setMorphTime(currentTime, true);
536
+ rootRegion.renderGeometries(0, 0, playAnimation, undefined, true);
537
+ } else {
538
+ zincCameraControls.update(0);
539
+ }
540
+ //console.log(videoHandler.video.currentTime / videoHandler.getVideoDuration() * 6000);
541
+ } else {
542
+ myPlayRate = 0;
543
+ }
544
+ } else {
545
+ if (0 == sceneLoader.toBeDownloaded) {
546
+ zincCameraControls.update(delta);
547
+ rootRegion.renderGeometries(playRate, delta, playAnimation, options, true);
548
+ } else {
549
+ zincCameraControls.update(0);
550
+ }
551
+ }
552
+ }
553
+
554
+ /**
555
+ * Return the internal {THREE.Scene}.
556
+ * @return {THREE.Scene}
557
+ */
558
+ this.getThreeJSScene = () => {
559
+ return scene;
560
+ }
561
+
562
+ this.setVideoHandler = (videoHandlerIn) => {
563
+ if (!videoHandler)
564
+ videoHandler = videoHandlerIn;
565
+ }
566
+
567
+ /**
568
+ * Set a group of scenes into this parent scene. This group of
569
+ * scenes will also be rendered when this scene is rendered.
570
+ * @private
571
+ */
572
+ this.setAdditionalScenesGroup = scenesGroup => {
573
+ scene.add(scenesGroup);
574
+ }
575
+
576
+ let getWindowsPosition = (align, x_offset, y_offset, width, height,
577
+ renderer_width, renderer_height) => {
578
+ let x = 0;
579
+ let y = 0;
580
+ if (align.includes("top")) {
581
+ y = renderer_height - height - y_offset;
582
+ } else if (align.includes("bottom")) {
583
+ y = y_offset;
584
+ } else {
585
+ y = Math.floor((renderer_height - height) / 2.0);
586
+ }
587
+ if (align.includes("left")) {
588
+ x = x_offset;
589
+ } else if (align.includes("right")) {
590
+ x = renderer_width - x_offset- width;
591
+ } else {
592
+ x = Math.floor((renderer_width - width) / 2.0);
593
+ }
594
+ return {x: x, y: y};
595
+ }
596
+
597
+ const renderMinimap = renderer => {
598
+ if (this.displayMinimap === true) {
599
+ renderer.setScissorTest(true);
600
+ renderer.getSize(_markerTarget);
601
+ if (this.minimapScissor.updateRequired) {
602
+ scissor = getWindowsPosition(this.minimapScissor.align,
603
+ this.minimapScissor.x_offset,
604
+ this.minimapScissor.y_offset,
605
+ this.minimapScissor.width,
606
+ this.minimapScissor.height,
607
+ _markerTarget.x, _markerTarget.y);
608
+ this.minimapScissor.updateRequired = false;
609
+ }
610
+ renderer.setScissor(
611
+ scissor.x,
612
+ scissor.y,
613
+ this.minimapScissor.width,
614
+ this.minimapScissor.height);
615
+ renderer.setViewport(
616
+ scissor.x,
617
+ scissor.y,
618
+ this.minimapScissor.width,
619
+ this.minimapScissor.height);
620
+ minimap.updateCamera();
621
+ scene.add(minimap.mask);
622
+ renderer.render(scene, minimap.camera);
623
+ scene.remove(minimap.mask);
624
+ renderer.setScissorTest(false);
625
+ renderer.setViewport(0, 0, _markerTarget.x, _markerTarget.y);
626
+ }
627
+ }
628
+
629
+ /**
630
+ * Render the scene.
631
+ * @private
632
+ */
633
+ this.render = renderer => {
634
+ if (this.autoClearFlag)
635
+ renderer.clear();
636
+ if (stereoEffectFlag && stereoEffect) {
637
+ stereoEffect.render(scene, this.camera);
638
+ } else {
639
+ renderer.render(scene, this.camera);
640
+ renderMinimap(renderer);
641
+ }
642
+ }
643
+
644
+ /**
645
+ * Enable or disable interactive control, this is on by default.
646
+ *
647
+ * @param {Boolean} flag - Indicate either interactive control
648
+ * should be enabled or disabled.
649
+ */
650
+ this.setInteractiveControlEnable = flag => {
651
+ if (flag == true)
652
+ zincCameraControls.enable();
653
+ else
654
+ zincCameraControls.disable();
655
+ }
656
+
657
+ /**
658
+ * Get the camera control of this scene.
659
+ * @return {Zinc.CameraControls}
660
+ */
661
+ this.getZincCameraControls = () => {
662
+ return zincCameraControls;
663
+ }
664
+
665
+ /**
666
+ * Get the internal {THREE.Scene}.
667
+ * @return {THREE.Scene}
668
+ */
669
+ this.getThreeJSScene = () => {
670
+ return scene;
671
+ }
672
+
673
+ /**
674
+ * Set the default duration value for geometries and glyphsets
675
+ * that are to be loaded into this scene.
676
+ * @param {Number} durationIn - duration of the scene.
677
+ */
678
+ this.setDuration = durationIn => {
679
+ rootRegion.setDuration(durationIn);
680
+ duration = durationIn;
681
+ zincCameraControls.setPathDuration(durationIn);
682
+ sceneLoader.duration = durationIn;
683
+ }
684
+
685
+ /**
686
+ * Get the default duration value.
687
+ * returns {Number}
688
+ */
689
+ this.getDuration = () => {
690
+ return duration;
691
+ }
692
+
693
+ /**
694
+ * Enable or disable stereo effect of this scene.
695
+ * @param {Boolean} flag - Indicate either stereo effect control
696
+ * should be enabled or disabled.
697
+ */
698
+ this.setStereoEffectEnable = stereoFlag => {
699
+ if (stereoFlag == true) {
700
+ if (!stereoEffect) {
701
+ stereoEffect = new require('./controls').StereoEffect(rendererIn);
702
+ }
703
+ }
704
+ rendererIn.setSize(getDrawingWidth(), getDrawingHeight());
705
+ this.camera.updateProjectionMatrix();
706
+ stereoEffectFlag = stereoFlag;
707
+ }
708
+
709
+ this.objectIsInScene = zincObject => {
710
+ return rootRegion.objectIsInRegion(zincObject, true);
711
+ }
712
+
713
+ this.alignBoundingBoxToCameraView = (boundingBox, transitionTime) => {
714
+ if (boundingBox) {
715
+ const center = new THREE.Vector3();
716
+ boundingBox.getCenter(center);
717
+ const viewport = this.getZincCameraControls().getCurrentViewport();
718
+ const target = new THREE.Vector3(viewport.targetPosition[0],
719
+ viewport.targetPosition[1], viewport.targetPosition[2]);
720
+ const eyePosition = new THREE.Vector3(viewport.eyePosition[0],
721
+ viewport.eyePosition[1], viewport.eyePosition[2]);
722
+ const upVector = new THREE.Vector3(viewport.upVector[0],
723
+ viewport.upVector[1], viewport.upVector[2]);
724
+ const newVec1 = new THREE.Vector3();
725
+ const newVec2 = new THREE.Vector3();
726
+ newVec1.subVectors(target, eyePosition).normalize();
727
+ newVec2.subVectors(target, center).normalize();
728
+ const newVec3 = new THREE.Vector3();
729
+ newVec3.crossVectors(newVec1, newVec2);
730
+ const angle = newVec1.angleTo(newVec2);
731
+ if (transitionTime > 0) {
732
+ this.getZincCameraControls().rotateCameraTransition(newVec3,
733
+ angle, transitionTime);
734
+ this.getZincCameraControls().enableCameraTransition();
735
+ } else {
736
+ this.getZincCameraControls().rotateAboutLookAtpoint(newVec3, angle);
737
+ }
738
+ }
739
+ }
740
+
741
+ this.alignObjectToCameraView = (zincObject, transitionTime) => {
742
+ if (this.objectIsInScene(zincObject)) {
743
+ const boundingBox = zincObject.getBoundingBox();
744
+ this.alignBoundingBoxToCameraView(boundingBox, transitionTime);
745
+ }
746
+ }
747
+
748
+ this.setCameraTargetToObject = zincObject => {
749
+ if (this.objectIsInScene(zincObject)) {
750
+ const center = new THREE.Vector3();
751
+ const boundingBox = zincObject.getBoundingBox();
752
+ const viewport = this.getZincCameraControls().getCurrentViewport();
753
+ boundingBox.getCenter(center);
754
+ const target = new THREE.Vector3(viewport.targetPosition[0],
755
+ viewport.targetPosition[1], viewport.targetPosition[2]);
756
+ const eyePosition = new THREE.Vector3(viewport.eyePosition[0],
757
+ viewport.eyePosition[1], viewport.eyePosition[2]);
758
+ const newVec1 = new THREE.Vector3();
759
+ const newVec2 = new THREE.Vector3();
760
+ newVec1.subVectors(eyePosition, target);
761
+ newVec2.addVectors(center, newVec1);
762
+ viewport.eyePosition[0] = newVec2.x;
763
+ viewport.eyePosition[1] = newVec2.y;
764
+ viewport.eyePosition[2] = newVec2.z;
765
+ viewport.targetPosition[0] = center.x;
766
+ viewport.targetPosition[1] = center.y;
767
+ viewport.targetPosition[2] = center.z;
768
+ this.getZincCameraControls().setCurrentCameraSettings(viewport);
769
+ }
770
+ }
771
+
772
+ /**
773
+ * Check if stereo effect is enabled.
774
+ * @returns {Boolean}
775
+ */
776
+ this.isStereoEffectEnable = () => {
777
+ return stereoEffectFlag;
778
+ }
779
+
780
+ /**
781
+ * Remove a ZincObject from this scene if it presents. This will eventually
782
+ * destroy the object and free up the memory.
783
+ * @param {Zinc.Object} zincObject - object to be removed from this scene.
784
+ */
785
+ this.removeZincObject = zincObject => {
786
+ rootRegion.removeZincObject(zincObject);
787
+ if (zincCameraControls)
788
+ zincCameraControls.calculateMaxAllowedDistance(this);
789
+ }
790
+
791
+ /**
792
+ * Update pickable objects list
793
+ */
794
+ this.updatePickableThreeJSObjects = () => {
795
+ pickableObjectsList.splice(0, pickableObjectsList.length);
796
+ rootRegion.getPickableThreeJSObjects(pickableObjectsList,
797
+ this.displayMarkers, true);
798
+ this.forcePickableObjectsUpdate = false;
799
+ }
800
+
801
+ /**
802
+ * Get all pickable objects.
803
+ */
804
+ this.getPickableThreeJSObjects = () => {
805
+ //The list will only be updated if changes have been made
806
+ //in region or a flag has been raise
807
+ if (this.forcePickableObjectsUpdate ||
808
+ rootRegion.checkPickableUpdateRequred(true)) {
809
+ this.updatePickableThreeJSObjects();
810
+ }
811
+ return pickableObjectsList;
812
+ }
813
+
814
+ /**
815
+ * Get the Normalised coordinates on minimap if mouse event is
816
+ * inside the minimap
817
+ */
818
+ this.getNormalisedMinimapCoordinates = (renderer, event) => {
819
+ if (this.displayMinimap) {
820
+ const target = new THREE.Vector2();
821
+ renderer.getSize(target);
822
+ let offsetY = target.y - event.clientY;
823
+ if (((scissor.x + this.minimapScissor.width) > event.clientX) &&
824
+ (event.clientX > scissor.x) &&
825
+ ((scissor.y + this.minimapScissor.height) > offsetY) &&
826
+ (offsetY > scissor.y)) {
827
+ let x = ((event.clientX - scissor.x) /
828
+ this.minimapScissor.width) * 2.0 - 1.0;
829
+ let y = ((offsetY - scissor.y) /
830
+ this.minimapScissor.height) * 2.0 - 1.0;
831
+ return {"x": x, "y": y};
832
+ }
833
+ }
834
+ return undefined;
835
+ }
836
+
837
+ /**
838
+ * Get the coordinates difference of the current viewing
839
+ * point and projected coordinates.
840
+ */
841
+ this.getMinimapDiffFromNormalised = (x, y) => {
842
+ if (minimap)
843
+ return minimap.getDiffFromNormalised(x, y);
844
+ return undefined;
845
+ }
846
+
847
+ this.isWebGL2 = () => {
848
+ return rendererIn.isWebGL2();
849
+ }
850
+
851
+ /**
852
+ * Remove all objects that are created with ZincJS APIs and it will free the memory allocated.
853
+ * This does not remove obejcts that are added using the addObject APIs.
854
+ */
855
+ this.clearAll = () => {
856
+ rootRegion.clear(true);
857
+ sceneLoader.toBeDwonloaded = 0;
858
+ if (zincCameraControls)
859
+ zincCameraControls.calculateMaxAllowedDistance(this);
860
+ }
861
+
862
+ /**
863
+ * All time stamp to the metadata TimeStamps field.
864
+ */
865
+ this.addMetadataTimeStamp = (key, time) => {
866
+ metadata["TimeStamps"][key] = convertDurationObjectTomSec(time);
867
+ }
868
+
869
+ /**
870
+ * Get a specific metadata field.
871
+ */
872
+ this.getMetadataTag = key => {
873
+ return metadata[key];
874
+ }
875
+
876
+ /**
877
+ * Get all metadata set for the scene.
878
+ */
879
+ this.getMetadata = () => {
880
+ return metadata;
881
+ }
882
+
883
+ /**
884
+ * Set a specific metadata field.
885
+ */
886
+ this.setMetadataTag = (key, value) => {
887
+ metadata[key] = value;
888
+ }
889
+
890
+ /**
891
+ * Remove a specific metadata field.
892
+ */
893
+ this.removeMetadataTag = key => {
894
+ delete metadata[key];
895
+ }
896
+
897
+ /**
898
+ * Reset all metadata fields to original value.
899
+ */
900
+ this.resetMetadata = () => {
901
+ metadata = defaultMetadata();
902
+ }
903
+
904
+ /**
905
+ * Reset duration of scene to default value.
906
+ */
907
+ this.resetDuration = () => {
908
+ this.setDuration(defaultDuration);
909
+ }
910
+
911
+ // Turn the object into a readable string {years: years,months: months,
912
+ // weeks: weeks, days: days, hours: hours, mins: mins, secs: secs }
913
+ const convertDurationObjectToString = duration => {
914
+ return [
915
+ ...(duration.years ? [`${duration.years}years`] : []),
916
+ ...(duration.months ? [`${duration.months}months`] : []),
917
+ ...(duration.weeks ? [`${duration.weeks}weeks`] : []),
918
+ ...(duration.days ? [`${duration.days}days`] : []),
919
+ ...(duration.hours ? [`${duration.hours}hours`] : []),
920
+ ...(duration.mins ? [`${duration.mins}mins`] : []),
921
+ ...(duration.secs ? [`${duration.secs}secs`] : []),
922
+ ].join(' ');
923
+ }
924
+
925
+ // Turn the object into a number representing milliesecond {years: years,months: months,
926
+ // weeks: weeks, days: days, hours: hours, mins: mins, secs: secs }
927
+ const convertDurationObjectTomSec = duration => {
928
+ return duration.years ? duration.years * 31536000000 : 0 +
929
+ duration.months ? duration.months * 2592000000 : 0 +
930
+ duration.weeks ? duration.weeks * 604800000 : 0 +
931
+ duration.days ? duration.days * 86400000 : 0 +
932
+ duration.hours ? duration.hours * 3600000 : 0 +
933
+ duration.mins ? duration.mins * 60000 : 0 +
934
+ duration.secs ? duration.secs * 1000 : 0;
935
+ }
936
+
937
+ // Set the readable duration and timer using an object
938
+ // with the following format {years: years,months: months, weeks: weeks, days: days,
939
+ // hours: hours, mins: mins, secs: secs }
940
+ this.setDurationFromObject = duration => {
941
+ const string = convertDurationObjectToString(duration);
942
+ const millisec = convertDurationObjectTomSec(duration);
943
+ this.setMetadataTag("Duration", string);
944
+ this.setDuration(millisec);
945
+ }
946
+
947
+ // Set the readable original duration using an object
948
+ // with the following format {years: years,months: months, weeks: weeks, days: days,
949
+ // hours: hours, mins: mins, secs: secs }
950
+ this.setOriginalDurationFromObject = duration => {
951
+ const string = convertDurationObjectToString(duration);
952
+ this.setMetadataTag("OriginalDuration", string);
953
+ }
954
+
955
+ this.exportGLTF = (binary) => {
956
+ const exporter = new SceneExporter(this);
957
+ return exporter.exportGLTF(binary);
958
+ }
959
+
960
+ this.getRootRegion = () => {
961
+ return rootRegion;
962
+ }
963
+ }