@xeokit/xeokit-sdk 2.6.28 → 2.6.30

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 (58) hide show
  1. package/README.md +1 -0
  2. package/dist/xeokit-sdk.cjs.js +1425 -649
  3. package/dist/xeokit-sdk.es.js +1420 -650
  4. package/dist/xeokit-sdk.es5.js +629 -552
  5. package/dist/xeokit-sdk.min.cjs.js +5 -5
  6. package/dist/xeokit-sdk.min.es.js +5 -5
  7. package/dist/xeokit-sdk.min.es5.js +4 -4
  8. package/package.json +1 -1
  9. package/src/extras/PointerCircle/PointerCircle.js +1 -1
  10. package/src/plugins/AngleMeasurementsPlugin/AngleMeasurementsMouseControl.js +22 -41
  11. package/src/plugins/AngleMeasurementsPlugin/AngleMeasurementsTouchControl.js +3 -18
  12. package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsMouseControl.js +20 -41
  13. package/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsTouchControl.js +4 -20
  14. package/src/plugins/DistanceMeasurementsPlugin/index.js +1 -1
  15. package/src/plugins/GLTFLoaderPlugin/GLTFLoaderPlugin.js +2 -110
  16. package/src/plugins/GLTFLoaderPlugin/GLTFSceneModelLoader.js +252 -222
  17. package/src/plugins/StoreyViewsPlugin/StoreyViewsPlugin.js +31 -1
  18. package/src/plugins/XKTLoaderPlugin/XKTLoaderPlugin.js +20 -8
  19. package/src/plugins/ZonesPlugin/ZonesPlugin.js +1939 -0
  20. package/src/plugins/ZonesPlugin/index.js +1 -1875
  21. package/src/viewer/Viewer.js +2 -2
  22. package/src/viewer/metadata/MetaScene.js +0 -2
  23. package/src/viewer/scene/math/MeshSurfaceArea.js +90 -0
  24. package/src/viewer/scene/math/MeshVolume.js +102 -0
  25. package/src/viewer/scene/math/index.js +3 -0
  26. package/src/viewer/scene/math/isTriangleMeshSolid.js +162 -0
  27. package/src/viewer/scene/math/math.js +8 -0
  28. package/src/viewer/scene/model/SceneModel.js +73 -34
  29. package/src/viewer/scene/model/SceneModelEntity.js +46 -1
  30. package/src/viewer/scene/model/SceneModelMesh.js +74 -1
  31. package/src/viewer/scene/model/SceneModelTextureSet.js +5 -0
  32. package/src/viewer/scene/model/dtx/lines/DTXLinesLayer.js +7 -1
  33. package/src/viewer/scene/model/dtx/triangles/DTXTrianglesLayer.js +77 -1
  34. package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesSnapInitRenderer.js +8 -0
  35. package/src/viewer/scene/model/dtx/triangles/renderers/DTXTrianglesSnapRenderer.js +8 -0
  36. package/src/viewer/scene/model/vbo/VBORenderer.js +10 -1
  37. package/src/viewer/scene/model/vbo/batching/lines/VBOBatchingLinesLayer.js +6 -1
  38. package/src/viewer/scene/model/vbo/batching/lines/renderers/VBOBatchingLinesSnapRenderer.js +1 -1
  39. package/src/viewer/scene/model/vbo/batching/points/VBOBatchingPointsLayer.js +6 -1
  40. package/src/viewer/scene/model/vbo/batching/triangles/VBOBatchingTrianglesLayer.js +59 -18
  41. package/src/viewer/scene/model/vbo/batching/triangles/renderers/Renderers.js +40 -12
  42. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesBatchingRenderer.js +2 -3
  43. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesColorTextureRenderer.js +25 -7
  44. package/src/viewer/scene/model/vbo/batching/triangles/renderers/TrianglesSnapRenderer.js +1 -1
  45. package/src/viewer/scene/model/vbo/instancing/lines/VBOInstancingLinesLayer.js +6 -1
  46. package/src/viewer/scene/model/vbo/instancing/lines/renderers/VBOInstancingLinesSnapRenderer.js +1 -1
  47. package/src/viewer/scene/model/vbo/instancing/points/VBOInstancingPointsLayer.js +6 -1
  48. package/src/viewer/scene/model/vbo/instancing/triangles/VBOInstancingTrianglesLayer.js +48 -14
  49. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/Renderers.js +74 -47
  50. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesColorTextureRenderer.js +29 -14
  51. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesInstancingRenderer.js +5 -4
  52. package/src/viewer/scene/model/vbo/instancing/triangles/renderers/TrianglesSnapRenderer.js +1 -1
  53. package/src/viewer/scene/scene/Scene.js +16 -5
  54. package/src/viewer/scene/webgl/occlusion/OcclusionLayer.js +1 -1
  55. package/src/viewer/scene/webgl/occlusion/OcclusionTester.js +1 -5
  56. package/types/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.d.ts +7 -0
  57. package/types/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsPlugin.d.ts +26 -1
  58. package/types/plugins/DistanceMeasurementsPlugin/index.d.ts +3 -1
@@ -65,42 +65,6 @@ class GLTFSceneModelLoader {
65
65
  }
66
66
  }
67
67
 
68
- function getMetaModelCorrections(metaModelJSON) {
69
- const eachRootStats = {};
70
- const eachChildRoot = {};
71
- const metaObjects = metaModelJSON.metaObjects || [];
72
- const metaObjectsMap = {};
73
- for (let i = 0, len = metaObjects.length; i < len; i++) {
74
- const metaObject = metaObjects[i];
75
- metaObjectsMap[metaObject.id] = metaObject;
76
- }
77
- for (let i = 0, len = metaObjects.length; i < len; i++) {
78
- const metaObject = metaObjects[i];
79
- if (metaObject.parent !== undefined && metaObject.parent !== null) {
80
- const metaObjectParent = metaObjectsMap[metaObject.parent];
81
- if (metaObject.type === metaObjectParent.type) {
82
- let rootMetaObject = metaObjectParent;
83
- while (rootMetaObject.parent && metaObjectsMap[rootMetaObject.parent].type === rootMetaObject.type) {
84
- rootMetaObject = metaObjectsMap[rootMetaObject.parent];
85
- }
86
- const rootStats = eachRootStats[rootMetaObject.id] || (eachRootStats[rootMetaObject.id] = {
87
- numChildren: 0,
88
- countChildren: 0
89
- });
90
- rootStats.numChildren++;
91
- eachChildRoot[metaObject.id] = rootMetaObject;
92
- } else {
93
-
94
- }
95
- }
96
- }
97
- return {
98
- metaObjectsMap,
99
- eachRootStats,
100
- eachChildRoot
101
- };
102
- }
103
-
104
68
  function loadGLTF(plugin, src, metaModelJSON, options, sceneModel, ok, error) {
105
69
  const spinner = plugin.viewer.scene.canvas.spinner;
106
70
  spinner.processes++;
@@ -142,7 +106,9 @@ function parseGLTF(plugin, src, gltf, metaModelJSON, options, sceneModel, ok) {
142
106
  const ctx = {
143
107
  src: src,
144
108
  entityId: options.entityId,
145
- metaModelCorrections: metaModelJSON ? getMetaModelCorrections(metaModelJSON) : null,
109
+ metaModelJSON,
110
+ autoMetaModel: options.autoMetaModel,
111
+ metaObjects: [],
146
112
  loadBuffer: options.loadBuffer,
147
113
  basePath: options.basePath,
148
114
  handlenode: options.handlenode,
@@ -161,8 +127,20 @@ function parseGLTF(plugin, src, gltf, metaModelJSON, options, sceneModel, ok) {
161
127
  };
162
128
  loadTextures(ctx);
163
129
  loadMaterials(ctx);
130
+ if (options.autoMetaModel) {
131
+ ctx.metaObjects.push({
132
+ id: sceneModel.id,
133
+ type: "Default",
134
+ name: sceneModel.id
135
+ });
136
+ }
164
137
  loadDefaultScene(ctx);
165
138
  sceneModel.finalize();
139
+ if (options.autoMetaModel) {
140
+ plugin.viewer.metaScene.createMetaModel(sceneModel.id, {
141
+ metaObjects: ctx.metaObjects
142
+ });
143
+ }
166
144
  spinner.processes--;
167
145
  ok();
168
146
  });
@@ -291,23 +269,21 @@ function loadTextureSet(ctx, material) {
291
269
  if (material.emissiveTexture) {
292
270
  textureSetCfg.emissiveTextureId = material.emissiveTexture.texture._textureId;
293
271
  }
294
- // const alphaMode = material.alphaMode;
295
- // switch (alphaMode) {
296
- // case "NORMAL_OPAQUE":
297
- // materialCfg.alphaMode = "opaque";
298
- // break;
299
- // case "MASK":
300
- // materialCfg.alphaMode = "mask";
301
- // break;
302
- // case "BLEND":
303
- // materialCfg.alphaMode = "blend";
304
- // break;
305
- // default:
306
- // }
307
- // const alphaCutoff = material.alphaCutoff;
308
- // if (alphaCutoff !== undefined) {
309
- // materialCfg.alphaCutoff = alphaCutoff;
310
- // }
272
+
273
+ switch (material.alphaMode) {
274
+ case "OPAQUE":
275
+ break;
276
+ case "MASK":
277
+ const alphaCutoff = material.alphaCutoff;
278
+ // Default from the spec https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#reference-material
279
+ textureSetCfg.alphaCutoff = (alphaCutoff !== undefined) ? alphaCutoff : 0.5;
280
+ break;
281
+ case "BLEND":
282
+ break;
283
+ default:
284
+ break;
285
+ }
286
+
311
287
  const metallicPBR = material.pbrMetallicRoughness;
312
288
  if (material.pbrMetallicRoughness) {
313
289
  const pbrMetallicRoughness = material.pbrMetallicRoughness;
@@ -356,7 +332,7 @@ function loadMaterialAttributes(ctx, material) { // Substitute RGBA for material
356
332
  opacity: 1,
357
333
  metallic: 0,
358
334
  roughness: 1,
359
- doubleSided : true
335
+ doubleSided: true
360
336
  };
361
337
  if (extensions) {
362
338
  const specularPBR = extensions["KHR_materials_pbrSpecularGlossiness"];
@@ -430,9 +406,22 @@ function loadScene(ctx, scene) {
430
406
  const node = nodes[i];
431
407
  countMeshUsage(ctx, node);
432
408
  }
433
- for (let i = 0, len = nodes.length; i < len; i++) {
409
+ for (let i = 0, len = nodes.length; i < len && !ctx.nodesHaveNames; i++) {
434
410
  const node = nodes[i];
435
- loadNode(ctx, node, 0, null);
411
+ if (testIfNodesHaveNames(node)) {
412
+ ctx.nodesHaveNames = true;
413
+ }
414
+ }
415
+ if (!ctx.nodesHaveNames) {
416
+ for (let i = 0, len = nodes.length; i < len; i++) {
417
+ const node = nodes[i];
418
+ parseNodesWithoutNames(ctx, node, 0, null);
419
+ }
420
+ } else {
421
+ for (let i = 0, len = nodes.length; i < len; i++) {
422
+ const node = nodes[i];
423
+ parseNodesWithNames(ctx, node, 0, null);
424
+ }
436
425
  }
437
426
  }
438
427
 
@@ -454,10 +443,133 @@ function countMeshUsage(ctx, node) {
454
443
  }
455
444
  }
456
445
 
457
- const deferredMeshIds = [];
446
+ function testIfNodesHaveNames(node) {
447
+ if (node.name) {
448
+ return true;
449
+ }
450
+ if (node.children) {
451
+ const children = node.children;
452
+ for (let i = 0, len = children.length; i < len; i++) {
453
+ const childNode = children[i];
454
+ if (testIfNodesHaveNames(childNode)) {
455
+ return true;
456
+ }
457
+ }
458
+ }
459
+ return false;
460
+ }
458
461
 
459
- function loadNode(ctx, node, depth, matrix) {
460
- const gltfData = ctx.gltfData;
462
+ /**
463
+ * Parses a glTF node hierarchy that is known to NOT contain "name" attributes on the nodes.
464
+ * Create a SceneMesh for each mesh primitive, and a single SceneObject.
465
+ */
466
+ const parseNodesWithoutNames = (function () {
467
+ const meshIds = [];
468
+ return function (ctx, node, depth, matrix, parentNode) {
469
+ matrix = parseNodeMatrix(node, matrix);
470
+ if (node.mesh) {
471
+ parseNodeMesh(node, ctx, matrix, meshIds);
472
+ }
473
+ if (node.children) {
474
+ const children = node.children;
475
+ for (let i = 0, len = children.length; i < len; i++) {
476
+ const childNode = children[i];
477
+ parseNodesWithoutNames(ctx, childNode, depth + 1, matrix, node);
478
+ }
479
+ }
480
+ if (depth === 0) {
481
+ let entityId = "entity-" + ctx.nextId++;
482
+ if (meshIds && meshIds.length > 0) {
483
+ ctx.sceneModel.createEntity({
484
+ id: entityId,
485
+ meshIds,
486
+ isObject: true
487
+ });
488
+ if (ctx.autoMetaModel) {
489
+ ctx.metaObjects.push({
490
+ id: entityId,
491
+ type: "Default",
492
+ name: entityId,
493
+ parent: ctx.sceneModel.id
494
+ });
495
+ }
496
+ meshIds.length = 0;
497
+ }
498
+ }
499
+ }
500
+ })();
501
+
502
+ const parseNodesWithNames = (function () {
503
+
504
+ const objectIdStack = [];
505
+ const meshIdsStack = [];
506
+ let meshIds = null;
507
+
508
+ return function (ctx, node, depth, matrix) {
509
+ matrix = parseNodeMatrix(node, matrix);
510
+ if (meshIds && node.mesh) {
511
+ parseNodeMesh(node, ctx, matrix, meshIds);
512
+ }
513
+
514
+ if (node.name) {
515
+ meshIds = [];
516
+ let entityId = node.name;
517
+ if (!!entityId && ctx.sceneModel.objects[entityId]) {
518
+ // ctx.log(`Warning: Two or more glTF nodes found with same 'name' attribute: '${entityId} - will randomly-generating an object ID in XKT`);
519
+ }
520
+ while (!entityId || ctx.sceneModel.objects[entityId]) {
521
+ entityId = "entity-" + ctx.nextId++;
522
+ }
523
+ objectIdStack.push(entityId);
524
+ meshIdsStack.push(meshIds);
525
+ }
526
+
527
+ if (node.children) {
528
+ const children = node.children;
529
+ for (let i = 0, len = children.length; i < len; i++) {
530
+ const childNode = children[i];
531
+ parseNodesWithNames(ctx, childNode, depth + 1, matrix);
532
+ }
533
+ }
534
+
535
+ // Post-order visit scene node
536
+
537
+ const nodeName = node.name;
538
+ if ((nodeName !== undefined && nodeName !== null) || depth === 0) {
539
+ let entityId = objectIdStack.pop();
540
+ if (!entityId) { // For when there are no nodes with names
541
+ entityId = "entity-" + ctx.nextId++;
542
+ }
543
+ let entityMeshIds = meshIdsStack.pop();
544
+ if (meshIds && meshIds.length > 0) {
545
+ ctx.sceneModel.createEntity({
546
+ id: entityId,
547
+ meshIds: entityMeshIds,
548
+ isObject: true
549
+ });
550
+ if (ctx.autoMetaModel) {
551
+ ctx.metaObjects.push({
552
+ id: entityId,
553
+ type: "Default",
554
+ name: entityId,
555
+ parent: ctx.sceneModel.id
556
+ });
557
+ }
558
+ }
559
+ meshIds = meshIdsStack.length > 0 ? meshIdsStack[meshIdsStack.length - 1] : null;
560
+ }
561
+ };
562
+ })();
563
+
564
+
565
+ /**
566
+ * Parses transform at the given glTF node.
567
+ *
568
+ * @param node the glTF node
569
+ * @param matrix Transfor matrix from parent nodes
570
+ * @returns {*} Transform matrix for the node
571
+ */
572
+ function parseNodeMatrix(node, matrix) {
461
573
  let localMatrix;
462
574
  if (node.matrix) {
463
575
  localMatrix = node.matrix;
@@ -491,174 +603,92 @@ function loadNode(ctx, node, depth, matrix) {
491
603
  matrix = localMatrix;
492
604
  }
493
605
  }
606
+ return matrix;
607
+ }
494
608
 
495
- const sceneModel = ctx.sceneModel;
496
- if (node.mesh) {
497
- const mesh = node.mesh;
498
- let createEntity;
499
- if (ctx.handlenode) {
500
- const actions = {};
501
- if (!ctx.handlenode(ctx.sceneModel.id, node, actions)) {
502
- return;
609
+ /**
610
+ * Parses primitives referenced by the mesh belonging to the given node, creating XKTMeshes in the XKTModel.
611
+ *
612
+ * @param node glTF node
613
+ * @param ctx Parsing context
614
+ * @param matrix Matrix for the XKTMeshes
615
+ * @param meshIds returns IDs of the new XKTMeshes
616
+ */
617
+ function parseNodeMesh(node, ctx, matrix, meshIds) {
618
+ const mesh = node.mesh;
619
+ if (!mesh) {
620
+ return;
621
+ }
622
+ const numPrimitives = mesh.primitives.length;
623
+ if (numPrimitives > 0) {
624
+ for (let i = 0; i < numPrimitives; i++) {
625
+ const primitive = mesh.primitives[i];
626
+ if (primitive.mode < 4) {
627
+ continue;
503
628
  }
504
- if (actions.createEntity) {
505
- createEntity = actions.createEntity;
629
+ const meshCfg = {
630
+ id: ctx.sceneModel.id + "." + ctx.numObjects++
631
+ };
632
+ const material = primitive.material;
633
+ if (material) {
634
+ meshCfg.textureSetId = material._textureSetId;
635
+ meshCfg.color = material._attributes.color;
636
+ meshCfg.opacity = material._attributes.opacity;
637
+ meshCfg.metallic = material._attributes.metallic;
638
+ meshCfg.roughness = material._attributes.roughness;
639
+ } else {
640
+ meshCfg.color = new Float32Array([1.0, 1.0, 1.0]);
641
+ meshCfg.opacity = 1.0;
506
642
  }
507
- }
508
- const worldMatrix = matrix ? matrix.slice() : math.identityMat4();
509
- const numPrimitives = mesh.primitives.length;
510
-
511
- if (numPrimitives > 0) {
512
-
513
- for (let i = 0; i < numPrimitives; i++) {
514
-
515
- const primitive = mesh.primitives[i];
516
- if (primitive.mode < 4) {
517
- continue;
518
- }
519
-
520
- const meshCfg = {
521
- id: sceneModel.id + "." + ctx.numObjects++
522
- };
523
-
524
- const material = primitive.material;
525
- if (material) {
526
- meshCfg.textureSetId = material._textureSetId;
527
- meshCfg.color = material._attributes.color;
528
- meshCfg.opacity = material._attributes.opacity;
529
- meshCfg.metallic = material._attributes.metallic;
530
- meshCfg.roughness = material._attributes.roughness;
531
- } else {
532
- meshCfg.color = new Float32Array([1.0, 1.0, 1.0]);
533
- meshCfg.opacity = 1.0;
534
- }
535
-
536
- const backfaces = ((ctx.backfaces !== false) || (material && material.doubleSided !== false));
537
-
538
- switch (primitive.mode) {
539
- case 0: // POINTS
540
- meshCfg.primitive = "points";
541
- break;
542
- case 1: // LINES
543
- meshCfg.primitive = "lines";
544
- break;
545
- case 2: // LINE_LOOP
546
- meshCfg.primitive = "lines";
547
- break;
548
- case 3: // LINE_STRIP
549
- meshCfg.primitive = "lines";
550
- break;
551
- case 4: // TRIANGLES
552
- meshCfg.primitive = backfaces ? "triangles" : "solid";
553
- break;
554
- case 5: // TRIANGLE_STRIP
555
- meshCfg.primitive = backfaces ? "triangles" : "solid";
556
- break;
557
- case 6: // TRIANGLE_FAN
558
- meshCfg.primitive = backfaces ? "triangles" : "solid";
559
- break;
560
- default:
561
- meshCfg.primitive = backfaces ? "triangles" : "solid";
562
- }
563
-
564
- const POSITION = primitive.attributes.POSITION;
565
- if (!POSITION) {
566
- continue;
567
- }
568
- meshCfg.localPositions = POSITION.value;
569
- meshCfg.positions = new Float64Array(meshCfg.localPositions.length);
570
-
571
- if (primitive.attributes.NORMAL) {
572
- meshCfg.normals = primitive.attributes.NORMAL.value;
573
- }
574
-
575
- if (primitive.attributes.TEXCOORD_0) {
576
- meshCfg.uv = primitive.attributes.TEXCOORD_0.value;
577
- }
578
-
579
- if (primitive.indices) {
580
- meshCfg.indices = primitive.indices.value;
581
- }
582
-
583
- math.transformPositions3(worldMatrix, meshCfg.localPositions, meshCfg.positions);
584
- const origin = math.vec3();
585
- const rtcNeeded = worldToRTCPositions(meshCfg.positions, meshCfg.positions, origin); // Small cellsize guarantees better accuracy
586
- if (rtcNeeded) {
587
- meshCfg.origin = origin;
588
- }
589
-
590
- sceneModel.createMesh(meshCfg);
591
- deferredMeshIds.push(meshCfg.id);
643
+ const backfaces = ((ctx.backfaces !== false) || (material && material.doubleSided !== false));
644
+ switch (primitive.mode) {
645
+ case 0: // POINTS
646
+ meshCfg.primitive = "points";
647
+ break;
648
+ case 1: // LINES
649
+ meshCfg.primitive = "lines";
650
+ break;
651
+ case 2: // LINE_LOOP
652
+ meshCfg.primitive = "lines";
653
+ break;
654
+ case 3: // LINE_STRIP
655
+ meshCfg.primitive = "lines";
656
+ break;
657
+ case 4: // TRIANGLES
658
+ meshCfg.primitive = backfaces ? "triangles" : "solid";
659
+ break;
660
+ case 5: // TRIANGLE_STRIP
661
+ meshCfg.primitive = backfaces ? "triangles" : "solid";
662
+ break;
663
+ case 6: // TRIANGLE_FAN
664
+ meshCfg.primitive = backfaces ? "triangles" : "solid";
665
+ break;
666
+ default:
667
+ meshCfg.primitive = backfaces ? "triangles" : "solid";
592
668
  }
593
- }
594
- }
595
-
596
- if (node.children) {
597
- const children = node.children;
598
- for (let i = 0, len = children.length; i < len; i++) {
599
- const childNode = children[i];
600
- loadNode(ctx, childNode, depth + 1, matrix);
601
- }
602
- }
603
-
604
- // Post-order visit scene node
605
-
606
- if (ctx.entityId) {
607
- if (depth ===0) {
608
- sceneModel.createEntity({
609
- id: ctx.entityId,
610
- meshIds: deferredMeshIds,
611
- isObject: true
612
- });
613
- deferredMeshIds.length = 0;
614
- }
615
- } else {
616
- const nodeName = node.name;
617
- if (((nodeName !== undefined && nodeName !== null) || depth === 0) && deferredMeshIds.length > 0) {
618
- if (nodeName === undefined || nodeName === null) {
619
- ctx.log(`Warning: 'name' properties not found on glTF scene nodes - will randomly-generate object IDs in XKT`);
669
+ const POSITION = primitive.attributes.POSITION;
670
+ if (!POSITION) {
671
+ continue;
620
672
  }
621
- let entityId = nodeName; // Fall back on generated ID when `name` not found on glTF scene node(s)
622
- // if (!!entityId && sceneModel.entities[entityId]) {
623
- // ctx.log(`Warning: Two or more glTF nodes found with same 'name' attribute: '${nodeName} - will randomly-generating an object ID in XKT`);
624
- // }
625
- // while (!entityId || sceneModel.entities[entityId]) {
626
- // entityId = "entity-" + ctx.nextId++;
627
- // }
628
- if (ctx.metaModelCorrections) {
629
- // Merging meshes into XKTObjects that map to metaobjects
630
- const rootMetaObject = ctx.metaModelCorrections.eachChildRoot[entityId];
631
- if (rootMetaObject) {
632
- const rootMetaObjectStats = ctx.metaModelCorrections.eachRootStats[rootMetaObject.id];
633
- rootMetaObjectStats.countChildren++;
634
- if (rootMetaObjectStats.countChildren >= rootMetaObjectStats.numChildren) {
635
- sceneModel.createEntity({
636
- id: rootMetaObject.id,
637
- meshIds: deferredMeshIds,
638
- isObject: true
639
- });
640
- deferredMeshIds.length = 0;
641
- }
642
- } else {
643
- const metaObject = ctx.metaModelCorrections.metaObjectsMap[entityId];
644
- if (metaObject) {
645
- sceneModel.createEntity({
646
- id: entityId,
647
- meshIds: deferredMeshIds,
648
- isObject: true
649
- });
650
- deferredMeshIds.length = 0;
651
- }
652
- }
653
- } else {
654
- // Create an XKTObject from the meshes at each named glTF node, don't care about metaobjects
655
- sceneModel.createEntity({
656
- id: entityId,
657
- meshIds: deferredMeshIds,
658
- isObject: true
659
- });
660
- deferredMeshIds.length = 0;
673
+ meshCfg.localPositions = POSITION.value;
674
+ meshCfg.positions = new Float64Array(meshCfg.localPositions.length);
675
+ if (primitive.attributes.NORMAL) {
676
+ meshCfg.normals = primitive.attributes.NORMAL.value;
677
+ }
678
+ if (primitive.attributes.TEXCOORD_0) {
679
+ meshCfg.uv = primitive.attributes.TEXCOORD_0.value;
680
+ }
681
+ if (primitive.indices) {
682
+ meshCfg.indices = primitive.indices.value;
683
+ }
684
+ math.transformPositions3(matrix, meshCfg.localPositions, meshCfg.positions);
685
+ const origin = math.vec3();
686
+ const rtcNeeded = worldToRTCPositions(meshCfg.positions, meshCfg.positions, origin); // Small cellsize guarantees better accuracy
687
+ if (rtcNeeded) {
688
+ meshCfg.origin = origin;
661
689
  }
690
+ ctx.sceneModel.createMesh(meshCfg);
691
+ meshIds.push(meshCfg.id);
662
692
  }
663
693
  }
664
694
  }
@@ -675,13 +675,43 @@ class StoreyViewsPlugin extends Plugin {
675
675
  getStoreyContainingWorldPos(worldPos) {
676
676
  for (var storeyId in this.storeys) {
677
677
  const storey = this.storeys[storeyId];
678
- if (math.point3AABB3Intersect(storey.storeyAABB, worldPos)) {
678
+ if (math.point3AABB3AbsoluteIntersect(storey.storeyAABB, worldPos)) {
679
679
  return storeyId;
680
680
  }
681
681
  }
682
682
  return null;
683
683
  }
684
684
 
685
+ /**
686
+ * Gets the ID of the storey which's bounding box contains the y point of the world position
687
+ *
688
+ * @param {Number[]} worldPos 3D World-space position.
689
+ * @returns {String} ID of the storey containing the position, or null if the position falls outside all the storeys.
690
+ */
691
+ getStoreyInVerticalRange(worldPos) {
692
+ for(let storeyId in this.storeys) {
693
+ const storey = this.storeys[storeyId];
694
+ const aabb = [0,0,0,0,0,0], pos = [0,0,0];
695
+ aabb[1] = storey.storeyAABB[1];
696
+ aabb[4] = storey.storeyAABB[4];
697
+ pos[1] = worldPos[1];
698
+ if (math.point3AABB3AbsoluteIntersect(aabb, pos)) {
699
+ return storeyId;
700
+ }
701
+ }
702
+ return null;
703
+ }
704
+
705
+ isPositionAboveOrBelowBuilding(worldPos){
706
+ const keys = Object.keys(this.storeys);
707
+ const ids = [keys[0], keys[keys.length-1]];
708
+ if(worldPos[1] < this.storeys[ids[0]].storeyAABB[1])
709
+ return ids[0];
710
+ else if (worldPos[1] > this.storeys[ids[1]].storeyAABB[4])
711
+ return ids[1];
712
+ return null;
713
+ }
714
+
685
715
  /**
686
716
  * Converts a 3D World-space position to a 2D position within a StoreyMap image.
687
717
  *
@@ -942,6 +942,9 @@ class XKTLoaderPlugin extends Plugin {
942
942
  this.viewer.scene.canvas.spinner.processes++;
943
943
 
944
944
  const finish = () => {
945
+ if (sceneModel.destroyed) {
946
+ return;
947
+ }
945
948
  // this._createDefaultMetaModelIfNeeded(sceneModel, params, options);
946
949
  sceneModel.finalize();
947
950
  metaModel.finalize();
@@ -1023,7 +1026,9 @@ class XKTLoaderPlugin extends Plugin {
1023
1026
  const loadJSONs = (metaDataFiles, done, error) => {
1024
1027
  let i = 0;
1025
1028
  const loadNext = () => {
1026
- if (i >= metaDataFiles.length) {
1029
+ if (sceneModel.destroyed) {
1030
+ done();
1031
+ } else if (i >= metaDataFiles.length) {
1027
1032
  done();
1028
1033
  } else {
1029
1034
  this._dataSource.getMetaModel(`${baseDir}${metaDataFiles[i]}`, (metaModelData) => {
@@ -1033,7 +1038,7 @@ class XKTLoaderPlugin extends Plugin {
1033
1038
  globalizeObjectIds: options.globalizeObjectIds
1034
1039
  });
1035
1040
  i++;
1036
- this.scheduleTask(loadNext, 100);
1041
+ this.scheduleTask(loadNext, 200);
1037
1042
  }, error);
1038
1043
  }
1039
1044
  }
@@ -1042,13 +1047,16 @@ class XKTLoaderPlugin extends Plugin {
1042
1047
  const loadXKTs_excludeTheirMetaModels = (xktFiles, done, error) => { // Load XKTs, ignore metamodels in the XKT
1043
1048
  let i = 0;
1044
1049
  const loadNext = () => {
1045
- if (i >= xktFiles.length) {
1050
+ if (sceneModel.destroyed) {
1051
+ done();
1052
+ } else if (i >= xktFiles.length) {
1046
1053
  done();
1047
1054
  } else {
1048
1055
  this._dataSource.getXKT(`${baseDir}${xktFiles[i]}`, (arrayBuffer) => {
1049
1056
  this._parseModel(arrayBuffer, params, options, sceneModel, null /* Ignore metamodel in XKT */, manifestCtx);
1057
+ sceneModel.preFinalize();
1050
1058
  i++;
1051
- this.scheduleTask(loadNext, 100);
1059
+ this.scheduleTask(loadNext, 200);
1052
1060
  }, error);
1053
1061
  }
1054
1062
  }
@@ -1057,13 +1065,16 @@ class XKTLoaderPlugin extends Plugin {
1057
1065
  const loadXKTs_includeTheirMetaModels = (xktFiles, done, error) => { // Load XKTs, parse metamodels from the XKT
1058
1066
  let i = 0;
1059
1067
  const loadNext = () => {
1060
- if (i >= xktFiles.length) {
1068
+ if (sceneModel.destroyed) {
1069
+ done();
1070
+ } else if (i >= xktFiles.length) {
1061
1071
  done();
1062
1072
  } else {
1063
1073
  this._dataSource.getXKT(`${baseDir}${xktFiles[i]}`, (arrayBuffer) => {
1064
1074
  this._parseModel(arrayBuffer, params, options, sceneModel, metaModel, manifestCtx);
1075
+ sceneModel.preFinalize();
1065
1076
  i++;
1066
- this.scheduleTask(loadNext, 100);
1077
+ this.scheduleTask(loadNext, 200);
1067
1078
  }, error);
1068
1079
  }
1069
1080
  }
@@ -1113,11 +1124,12 @@ class XKTLoaderPlugin extends Plugin {
1113
1124
  _loadModel(src, params, options, sceneModel, metaModel, manifestCtx, done, error) {
1114
1125
  this._dataSource.getXKT(params.src, (arrayBuffer) => {
1115
1126
  this._parseModel(arrayBuffer, params, options, sceneModel, metaModel, manifestCtx);
1127
+ sceneModel.preFinalize();
1116
1128
  done();
1117
1129
  }, error);
1118
1130
  }
1119
1131
 
1120
- _parseModel(arrayBuffer, params, options, sceneModel, metaModel, manifestCtx) {
1132
+ async _parseModel(arrayBuffer, params, options, sceneModel, metaModel, manifestCtx) {
1121
1133
  if (sceneModel.destroyed) {
1122
1134
  return;
1123
1135
  }
@@ -1129,7 +1141,7 @@ class XKTLoaderPlugin extends Plugin {
1129
1141
  this.error("Unsupported .XKT file version: " + xktVersion + " - this XKTLoaderPlugin supports versions " + Object.keys(parsers));
1130
1142
  return;
1131
1143
  }
1132
- this.log("Loading .xkt V" + xktVersion);
1144
+ // this.log("Loading .xkt V" + xktVersion);
1133
1145
  const numElements = dataView.getUint32(4, true);
1134
1146
  const elements = [];
1135
1147
  let byteOffset = (numElements + 2) * 4;