@xeokit/xeokit-sdk 2.6.27 → 2.6.29

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 (41) hide show
  1. package/README.md +1 -0
  2. package/dist/xeokit-sdk.cjs.js +916 -221
  3. package/dist/xeokit-sdk.es.js +911 -222
  4. package/dist/xeokit-sdk.es5.js +577 -487
  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/StoreyViewsPlugin/StoreyViewsPlugin.js +31 -1
  16. package/src/plugins/XKTLoaderPlugin/XKTLoaderPlugin.js +20 -8
  17. package/src/plugins/ZonesPlugin/ZonesPlugin.js +1939 -0
  18. package/src/plugins/ZonesPlugin/index.js +1 -1875
  19. package/src/viewer/Viewer.js +2 -2
  20. package/src/viewer/scene/CameraControl/lib/handlers/MousePickHandler.js +1 -1
  21. package/src/viewer/scene/math/MeshSurfaceArea.js +90 -0
  22. package/src/viewer/scene/math/MeshVolume.js +102 -0
  23. package/src/viewer/scene/math/index.js +3 -0
  24. package/src/viewer/scene/math/isTriangleMeshSolid.js +162 -0
  25. package/src/viewer/scene/math/math.js +8 -0
  26. package/src/viewer/scene/model/SceneModel.js +64 -34
  27. package/src/viewer/scene/model/SceneModelEntity.js +46 -1
  28. package/src/viewer/scene/model/SceneModelMesh.js +74 -1
  29. package/src/viewer/scene/model/dtx/lines/DTXLinesLayer.js +7 -1
  30. package/src/viewer/scene/model/dtx/triangles/DTXTrianglesLayer.js +77 -1
  31. package/src/viewer/scene/model/vbo/batching/lines/VBOBatchingLinesLayer.js +6 -1
  32. package/src/viewer/scene/model/vbo/batching/points/VBOBatchingPointsLayer.js +6 -1
  33. package/src/viewer/scene/model/vbo/batching/triangles/VBOBatchingTrianglesLayer.js +33 -12
  34. package/src/viewer/scene/model/vbo/instancing/lines/VBOInstancingLinesLayer.js +6 -1
  35. package/src/viewer/scene/model/vbo/instancing/points/VBOInstancingPointsLayer.js +6 -1
  36. package/src/viewer/scene/model/vbo/instancing/triangles/VBOInstancingTrianglesLayer.js +31 -10
  37. package/src/viewer/scene/scene/Scene.js +16 -5
  38. package/src/viewer/scene/webgl/occlusion/OcclusionTester.js +0 -1
  39. package/types/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.d.ts +7 -0
  40. package/types/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsPlugin.d.ts +26 -1
  41. package/types/plugins/DistanceMeasurementsPlugin/index.d.ts +3 -1
@@ -5284,6 +5284,14 @@ const math = {
5284
5284
  return aabb[0] > p[0] || aabb[3] < p[0] || aabb[1] > p[1] || aabb[4] < p[1] || aabb[2] > p[2] || aabb[5] < p[2];
5285
5285
  },
5286
5286
 
5287
+ point3AABB3AbsoluteIntersect(aabb, p) {
5288
+ return (
5289
+ aabb[0] <= p[0] && aabb[3] >= p[0] &&
5290
+ aabb[1] <= p[1] && aabb[4] >= p[1] &&
5291
+ aabb[2] <= p[2] && aabb[5] >= p[2]
5292
+ );
5293
+ },
5294
+
5287
5295
  /**
5288
5296
  *
5289
5297
  * @param dir
@@ -9289,7 +9297,7 @@ class PointerCircle {
9289
9297
  destroy() {
9290
9298
  if (!this._destroyed) {
9291
9299
  this.stop();
9292
- document.body.removeChild(this._circleDiv);
9300
+ this._circleDiv.parentElement.removeChild(this._circleDiv);
9293
9301
  this._destroyed = true;
9294
9302
  }
9295
9303
  }
@@ -10545,7 +10553,7 @@ class SceneModelEntity {
10545
10553
  for (let i = 0, len = this.meshes.length; i < len; i++) {
10546
10554
  this.meshes[i]._setOffset(this._offset);
10547
10555
  }
10548
- this._aabbDirty = true;
10556
+ this._aabbDirty = true;
10549
10557
  this.model._aabbDirty = true;
10550
10558
  this.scene._aabbDirty = true;
10551
10559
  this.scene._objectOffsetUpdated(this, offset);
@@ -10562,6 +10570,51 @@ class SceneModelEntity {
10562
10570
  }
10563
10571
  }
10564
10572
 
10573
+ getEachIndex(callback) {
10574
+ for (let i = 0, len = this.meshes.length; i < len; i++) {
10575
+ this.meshes[i].getEachIndex(callback);
10576
+ }
10577
+ }
10578
+
10579
+ /**
10580
+ * Returns the volume of this SceneModelEntity.
10581
+ *
10582
+ * Only works when {@link Scene.readableGeometryEnabled | Scene.readableGeometryEnabled} is `true` and the
10583
+ * SceneModelEntity contains solid triangle meshes; returns `0` otherwise.
10584
+ *
10585
+ * @returns {number}
10586
+ */
10587
+ get volume() {
10588
+ let volume = 0;
10589
+ for (let i = 0, len = this.meshes.length; i < len; i++) {
10590
+ const meshVolume = this.meshes[i].volume;
10591
+ if (meshVolume < 0) {
10592
+ return -1;
10593
+ }
10594
+ volume += meshVolume;
10595
+ }
10596
+ return volume;
10597
+ }
10598
+
10599
+ /**
10600
+ * Returns the surface area of this SceneModelEntity.
10601
+ *
10602
+ * Only works when {@link Scene.readableGeometryEnabled | Scene.readableGeometryEnabled} is `true` and the
10603
+ * SceneModelEntity contains triangle meshes; returns `0` otherwise.
10604
+ *
10605
+ * @returns {number}
10606
+ */
10607
+ get surfaceArea() {
10608
+ let surfaceArea = 0;
10609
+ for (let i = 0, len = this.meshes.length; i < len; i++) {
10610
+ const meshSurfaceArea = this.meshes[i].surfaceArea;
10611
+ if (meshSurfaceArea >= 0) {
10612
+ surfaceArea += meshSurfaceArea;
10613
+ }
10614
+ }
10615
+ return surfaceArea > 0 ? surfaceArea : -1;
10616
+ }
10617
+
10565
10618
  _getFlag(flag) {
10566
10619
  return !!(this._flags & flag);
10567
10620
  }
@@ -10626,7 +10679,7 @@ class SceneModelEntity {
10626
10679
  }
10627
10680
  }
10628
10681
 
10629
- const tempVec4a$9 = math.vec4();
10682
+ const tempVec4a$a = math.vec4();
10630
10683
  const tempVec4b$6 = math.vec4();
10631
10684
 
10632
10685
 
@@ -10786,9 +10839,9 @@ class Marker extends Component {
10786
10839
  this.fire("viewPos", this._viewPos);
10787
10840
  }
10788
10841
  if (this._canvasPosDirty) {
10789
- tempVec4a$9.set(this._viewPos);
10790
- tempVec4a$9[3] = 1.0;
10791
- math.transformPoint4(this.scene.camera.projMatrix, tempVec4a$9, tempVec4b$6);
10842
+ tempVec4a$a.set(this._viewPos);
10843
+ tempVec4a$a[3] = 1.0;
10844
+ math.transformPoint4(this.scene.camera.projMatrix, tempVec4a$a, tempVec4b$6);
10792
10845
  const aabb = this.scene.canvas.boundary;
10793
10846
  this._canvasPos[0] = Math.floor((1 + tempVec4b$6[0] / tempVec4b$6[3]) * aabb[2] / 2);
10794
10847
  this._canvasPos[1] = Math.floor((1 - tempVec4b$6[1] / tempVec4b$6[3]) * aabb[3] / 2);
@@ -12618,22 +12671,13 @@ class AngleMeasurementsMouseControl extends AngleMeasurementsControl {
12618
12671
  this.pointerLens = cfg.pointerLens;
12619
12672
 
12620
12673
  this._active = false;
12621
- this._mouseState = MOUSE_FINDING_ORIGIN;
12622
12674
 
12623
12675
  this._currentAngleMeasurement = null;
12624
12676
 
12625
- // init markerDiv element (think about making its style configurable)
12626
12677
  this._initMarkerDiv();
12627
12678
 
12628
- this._onMouseHoverSurface = null;
12629
- this._onHoverNothing = null;
12630
- this._onPickedNothing = null;
12631
- this._onPickedSurface = null;
12632
-
12633
- this._onInputMouseDown = null;
12634
- this._onInputMouseUp = null;
12635
-
12636
12679
  this._snapping = cfg.snapping !== false;
12680
+ this._mouseState = MOUSE_FINDING_ORIGIN;
12637
12681
 
12638
12682
  this._attachPlugin(angleMeasurementsPlugin, cfg);
12639
12683
  }
@@ -12698,20 +12742,10 @@ class AngleMeasurementsMouseControl extends AngleMeasurementsControl {
12698
12742
  *
12699
12743
  * This is `true` by default.
12700
12744
  *
12701
- * Internally, this deactivates then activates the AngleMeasurementsMouseControl when changed, which means that
12702
- * it will destroy any AngleMeasurements currently under construction, and incurs some overhead, since it unbinds
12703
- * and rebinds various input handlers.
12704
- *
12705
12745
  * @param {boolean} snapping Whether to enable snap-to-vertex and snap-edge for this AngleMeasurementsMouseControl.
12706
12746
  */
12707
12747
  set snapping(snapping) {
12708
- if (snapping !== this._snapping) {
12709
- this._snapping = snapping;
12710
- this.deactivate();
12711
- this.activate();
12712
- } else {
12713
- this._snapping = snapping;
12714
- }
12748
+ this._snapping = snapping;
12715
12749
  }
12716
12750
 
12717
12751
  /**
@@ -12755,11 +12789,7 @@ class AngleMeasurementsMouseControl extends AngleMeasurementsControl {
12755
12789
 
12756
12790
  const pagePos = math.vec2();
12757
12791
 
12758
- this._onMouseHoverSurface = cameraControl.on(
12759
- this._snapping
12760
- ? "hoverSnapOrSurface"
12761
- : "hoverSurface",
12762
- event => {
12792
+ const hoverOn = event => {
12763
12793
  if (event.snappedToVertex || event.snappedToEdge) {
12764
12794
  if (pointerLens) {
12765
12795
  pointerLens.visible = true;
@@ -12821,7 +12851,10 @@ class AngleMeasurementsMouseControl extends AngleMeasurementsControl {
12821
12851
  canvas.style.cursor = "pointer";
12822
12852
  break;
12823
12853
  }
12824
- });
12854
+ };
12855
+ this._onHoverSnapOrSurface = cameraControl.on("hoverSnapOrSurface", e => { if (this._snapping) hoverOn(e); });
12856
+ this._onHoverSurface = cameraControl.on("hoverSurface", e => { if (! this._snapping) hoverOn(e); });
12857
+
12825
12858
  canvas.addEventListener('mousedown', this._onMouseDown = (e) => {
12826
12859
  if (e.which !== 1) {
12827
12860
  return;
@@ -12909,11 +12942,8 @@ class AngleMeasurementsMouseControl extends AngleMeasurementsControl {
12909
12942
  break;
12910
12943
  }
12911
12944
  });
12912
- this._onMouseHoverOff = cameraControl.on(
12913
- this._snapping
12914
- ? "hoverSnapOrSurfaceOff"
12915
- : "hoverOff",
12916
- event => {
12945
+
12946
+ const hoverOff = event => {
12917
12947
  mouseHovering = false;
12918
12948
  if (pointerLens) {
12919
12949
  pointerLens.visible = true;
@@ -12943,7 +12973,10 @@ class AngleMeasurementsMouseControl extends AngleMeasurementsControl {
12943
12973
  }
12944
12974
  canvas.style.cursor = "default";
12945
12975
  }
12946
- });
12976
+ };
12977
+ this._onHoverSnapOrSurfaceOff = cameraControl.on("hoverSnapOrSurfaceOff", e => { if (this._snapping) hoverOff(e); });
12978
+ this._onHoverOff = cameraControl.on("hoverOff", e => { if (! this._snapping) hoverOff(e); });
12979
+
12947
12980
  this._active = true;
12948
12981
  }
12949
12982
 
@@ -12956,22 +12989,22 @@ class AngleMeasurementsMouseControl extends AngleMeasurementsControl {
12956
12989
  if (!this._active) {
12957
12990
  return;
12958
12991
  }
12992
+
12959
12993
  if (this.pointerLens) {
12960
12994
  this.pointerLens.visible = false;
12961
12995
  }
12962
- if (this.markerDiv) {
12963
- this._destroyMarkerDiv();
12964
- }
12996
+
12965
12997
  this.reset();
12998
+
12966
12999
  const canvas = this.scene.canvas.canvas;
12967
13000
  canvas.removeEventListener("mousedown", this._onMouseDown);
12968
13001
  canvas.removeEventListener("mouseup", this._onMouseUp);
12969
13002
  const cameraControl = this.angleMeasurementsPlugin.viewer.cameraControl;
12970
- cameraControl.off(this._onMouseHoverSurface);
12971
- cameraControl.off(this._onPickedSurface);
12972
- cameraControl.off(this._onHoverNothing);
12973
- cameraControl.off(this._onPickedNothing);
12974
- this._currentAngleMeasurement = null;
13003
+ cameraControl.off(this._onHoverSnapOrSurface);
13004
+ cameraControl.off(this._onHoverSurface);
13005
+ cameraControl.off(this._onHoverSnapOrSurfaceOff);
13006
+ cameraControl.off(this._onHoverOff);
13007
+
12975
13008
  this._active = false;
12976
13009
  }
12977
13010
 
@@ -12994,6 +13027,7 @@ class AngleMeasurementsMouseControl extends AngleMeasurementsControl {
12994
13027
  this._currentAngleMeasurement.destroy();
12995
13028
  this._currentAngleMeasurement = null;
12996
13029
  }
13030
+
12997
13031
  this._mouseState = MOUSE_FINDING_ORIGIN;
12998
13032
  }
12999
13033
 
@@ -13509,8 +13543,6 @@ class AngleMeasurementsTouchControl extends AngleMeasurementsControl {
13509
13543
 
13510
13544
  this._currentAngleMeasurement = null;
13511
13545
 
13512
- this._onCanvasTouchStart = null;
13513
- this._onCanvasTouchEnd = null;
13514
13546
  this._longTouchTimeoutMs = 300;
13515
13547
  this._snapping = cfg.snapping !== false;
13516
13548
  this._touchState = WAITING_FOR_ORIGIN_TOUCH_START$1;
@@ -13546,20 +13578,10 @@ class AngleMeasurementsTouchControl extends AngleMeasurementsControl {
13546
13578
  *
13547
13579
  * This is `true` by default.
13548
13580
  *
13549
- * Internally, this deactivates then activates the AngleMeasurementsMouseControl when changed, which means that
13550
- * it will destroy any AngleMeasurements currently under construction, and incurs some overhead, since it unbinds
13551
- * and rebinds various input handlers.
13552
- *
13553
13581
  * @param {boolean} snapping Whether to enable snap-to-vertex and snap-edge for this AngleMeasurementsMouseControl.
13554
13582
  */
13555
13583
  set snapping(snapping) {
13556
- if (snapping !== this._snapping) {
13557
- this._snapping = snapping;
13558
- this.deactivate();
13559
- this.activate();
13560
- } else {
13561
- this._snapping = snapping;
13562
- }
13584
+ this._snapping = snapping;
13563
13585
  }
13564
13586
 
13565
13587
  /**
@@ -14329,14 +14351,11 @@ class AngleMeasurementsTouchControl extends AngleMeasurementsControl {
14329
14351
  this.plugin.pointerLens.visible = false;
14330
14352
  }
14331
14353
  this.reset();
14354
+
14332
14355
  const canvas = this.plugin.viewer.scene.canvas.canvas;
14333
14356
  canvas.removeEventListener("touchstart", this._onCanvasTouchStart);
14334
14357
  canvas.removeEventListener("touchend", this._onCanvasTouchEnd);
14335
- if (this._currentAngleMeasurement) {
14336
- this.angleMeasurementsPlugin.fire("measurementCancel", this._currentAngleMeasurement);
14337
- this._currentAngleMeasurement.destroy();
14338
- this._currentAngleMeasurement = null;
14339
- }
14358
+
14340
14359
  this._active = false;
14341
14360
  this.plugin.viewer.cameraControl.active = true;
14342
14361
  }
@@ -23519,7 +23538,7 @@ const tempVec3c$u = math.vec3();
23519
23538
  const tempVec3d$d = math.vec3();
23520
23539
  const tempVec3e$2 = math.vec3();
23521
23540
  const tempVec3f$2 = math.vec3();
23522
- const tempVec4a$8 = math.vec4();
23541
+ const tempVec4a$9 = math.vec4();
23523
23542
  const tempVec4b$5 = math.vec4();
23524
23543
  const tempVec4c$2 = math.vec4();
23525
23544
  const tempMat = math.mat4();
@@ -24385,7 +24404,7 @@ class Camera extends Component {
24385
24404
  * @returns {[number, number]} the canvas position
24386
24405
  */
24387
24406
  projectWorldPos(worldPos) {
24388
- const _worldPos = tempVec4a$8;
24407
+ const _worldPos = tempVec4a$9;
24389
24408
  const viewPos = tempVec4b$5;
24390
24409
  const screenPos = tempVec4c$2;
24391
24410
  _worldPos[0] = worldPos[0];
@@ -30140,6 +30159,8 @@ class Scene extends Component {
30140
30159
 
30141
30160
  this._aabbDirty = true;
30142
30161
 
30162
+ this._readableGeometry = !!cfg.readableGeometryEnabled;
30163
+
30143
30164
  /**
30144
30165
  * The {@link Viewer} this Scene belongs to.
30145
30166
  * @type {Viewer}
@@ -31019,18 +31040,27 @@ class Scene extends Component {
31019
31040
  }
31020
31041
 
31021
31042
  /**
31022
- * Whether precision surface picking is enabled.
31043
+ * Whether geometry is readable.
31023
31044
  *
31024
31045
  * This is set via the {@link Viewer} constructor and is ````false```` by default.
31025
31046
  *
31026
- * The ````pickSurfacePrecision```` option for ````Scene#pick```` only works if this is set ````true````.
31047
+ * The ````readableGeometryEnabled```` option for ````Scene#pick```` only works if this is set ````true````.
31027
31048
  *
31028
31049
  * Note that when ````true````, this configuration will increase the amount of browser memory used by the Viewer.
31029
31050
  *
31030
- * @returns {Boolean} True if precision picking is enabled.
31051
+ * @returns {Boolean} True if geometry is readable.
31052
+ */
31053
+ get readableGeometryEnabled() {
31054
+ return this._readableGeometry;
31055
+ }
31056
+
31057
+ /**
31058
+ * Whether precision surface picking is enabled.
31059
+ * @deprecated
31060
+ * @returns {*|boolean}
31031
31061
  */
31032
31062
  get pickSurfacePrecisionEnabled() {
31033
- return false; // Removed
31063
+ return this._readableGeometry;
31034
31064
  }
31035
31065
 
31036
31066
  /**
@@ -32008,7 +32038,7 @@ class Scene extends Component {
32008
32038
  *
32009
32039
  * @param {*} params Picking parameters.
32010
32040
  * @param {Boolean} [params.pickSurface=false] Whether to find the picked position on the surface of the Entity.
32011
- * @param {Boolean} [params.pickSurfacePrecision=false] When picking an Entity surface position, indicates whether or not we want full-precision {@link PickResult#worldPos}. Only works when {@link Scene#pickSurfacePrecisionEnabled} is ````true````. If pick succeeds, the returned {@link PickResult} will have {@link PickResult#precision} set ````true````, to indicate that it contains full-precision surface pick results.
32041
+ * @param {Boolean} [params.pickSurfacePrecision=false] When picking an Entity surface position, indicates whether or not we want full-precision {@link PickResult#worldPos}. Only works when {@link Scene#readableGeometryEnabled} is ````true````. If pick succeeds, the returned {@link PickResult} will have {@link PickResult#precision} set ````true````, to indicate that it contains full-precision surface pick results.
32012
32042
  * @param {Boolean} [params.pickSurfaceNormal=false] Whether to find the picked normal on the surface of the Entity. Only works if ````pickSurface```` is given.
32013
32043
  * @param {Number[]} [params.canvasPos] Canvas-space coordinates. When ray-picking, this will override the **origin** and ** direction** parameters and will cause the ray to be fired through the canvas at this position, directly along the negative View-space Z-axis.
32014
32044
  * @param {Number[]} [params.origin] World-space ray origin when ray-picking. Ignored when canvasPos given.
@@ -50608,10 +50638,360 @@ class Bitmap extends Component {
50608
50638
  }
50609
50639
  }
50610
50640
 
50641
+ /**
50642
+ * Uses edge adjacency counts to identify if the given triangle mesh can be rendered with backface culling enabled.
50643
+ *
50644
+ * If all edges are connected to exactly two triangles, then the mesh will likely be a closed solid, and we can safely
50645
+ * render it with backface culling enabled.
50646
+ *
50647
+ * Otherwise, the mesh is a surface, and we must render it with backface culling disabled.
50648
+ *
50649
+ * @private
50650
+ */
50651
+ const isTriangleMeshSolid = (indices, positions) => {
50652
+
50653
+ const vertexIndexMapping = [];
50654
+ let edges = [];
50655
+
50656
+ function compareIndexPositions(a, b) {
50657
+ let posA, posB;
50658
+
50659
+ for (let i = 0; i < 3; i++) {
50660
+ posA = positions [a * 3 + i];
50661
+ posB = positions [b * 3 + i];
50662
+
50663
+ if (posA !== posB) {
50664
+ return posB - posA;
50665
+ }
50666
+ }
50667
+
50668
+ return 0;
50669
+ }
50670
+ // Group together indices corresponding to same position coordinates
50671
+ let newIndices = indices.slice().sort(compareIndexPositions);
50672
+
50673
+ // Calculate the mapping:
50674
+ // - from original index in indices array
50675
+ // - to indices-for-unique-positions
50676
+ let uniqueVertexIndex = null;
50677
+
50678
+ for (let i = 0, len = newIndices.length; i < len; i++) {
50679
+ if (i === 0 || 0 !== compareIndexPositions(
50680
+ newIndices[i],
50681
+ newIndices[i - 1],
50682
+ )) {
50683
+ // different position
50684
+ uniqueVertexIndex = newIndices [i];
50685
+ }
50686
+
50687
+ vertexIndexMapping [
50688
+ newIndices[i]
50689
+ ] = uniqueVertexIndex;
50690
+ }
50691
+
50692
+ // Generate the list of edges
50693
+ for (let i = 0, len = indices.length; i < len; i += 3) {
50694
+
50695
+ const a = vertexIndexMapping[indices[i]];
50696
+ const b = vertexIndexMapping[indices[i + 1]];
50697
+ const c = vertexIndexMapping[indices[i + 2]];
50698
+
50699
+ let a2 = a;
50700
+ let b2 = b;
50701
+ let c2 = c;
50702
+
50703
+ if (a > b && a > c) {
50704
+ if (b > c) {
50705
+ a2 = a;
50706
+ b2 = b;
50707
+ c2 = c;
50708
+ } else {
50709
+ a2 = a;
50710
+ b2 = c;
50711
+ c2 = b;
50712
+ }
50713
+ } else if (b > a && b > c) {
50714
+ if (a > c) {
50715
+ a2 = b;
50716
+ b2 = a;
50717
+ c2 = c;
50718
+ } else {
50719
+ a2 = b;
50720
+ b2 = c;
50721
+ c2 = a;
50722
+ }
50723
+ } else if (c > a && c > b) {
50724
+ if (a > b) {
50725
+ a2 = c;
50726
+ b2 = a;
50727
+ c2 = b;
50728
+ } else {
50729
+ a2 = c;
50730
+ b2 = b;
50731
+ c2 = a;
50732
+ }
50733
+ }
50734
+
50735
+ edges[i + 0] = [
50736
+ a2, b2
50737
+ ];
50738
+ edges[i + 1] = [
50739
+ b2, c2
50740
+ ];
50741
+
50742
+ if (a2 > c2) {
50743
+ const temp = c2;
50744
+ c2 = a2;
50745
+ a2 = temp;
50746
+ }
50747
+
50748
+ edges[i + 2] = [
50749
+ c2, a2
50750
+ ];
50751
+ }
50752
+
50753
+ // Group semantically equivalent edgdes together
50754
+ function compareEdges(e1, e2) {
50755
+ let a, b;
50756
+
50757
+ for (let i = 0; i < 2; i++) {
50758
+ a = e1[i];
50759
+ b = e2[i];
50760
+
50761
+ if (b !== a) {
50762
+ return b - a;
50763
+ }
50764
+ }
50765
+
50766
+ return 0;
50767
+ }
50768
+
50769
+ edges = edges.slice(0, indices.length);
50770
+
50771
+ edges.sort(compareEdges);
50772
+
50773
+ // Make sure each edge is used exactly twice
50774
+ let sameEdgeCount = 0;
50775
+
50776
+ for (let i = 0; i < edges.length; i++) {
50777
+ if (i === 0 || 0 !== compareEdges(
50778
+ edges[i], edges[i - 1]
50779
+ )) {
50780
+ // different edge
50781
+ if (0 !== i && sameEdgeCount !== 2) {
50782
+ return false;
50783
+ }
50784
+
50785
+ sameEdgeCount = 1;
50786
+ } else {
50787
+ // same edge
50788
+ sameEdgeCount++;
50789
+ }
50790
+ }
50791
+
50792
+ if (edges.length > 0 && sameEdgeCount !== 2) {
50793
+ return false;
50794
+ }
50795
+
50796
+ // Each edge is used exactly twice, this is a
50797
+ // watertight surface and hence a solid geometry.
50798
+ return true;
50799
+ };
50800
+
50801
+ const v1$1 = math.vec3();
50802
+ const v2$1 = math.vec3();
50803
+ const v3$1 = math.vec3();
50804
+
50805
+ /**
50806
+ * Calculates the volume of triangle meshes.
50807
+ */
50808
+ class MeshVolume {
50809
+ constructor() {
50810
+ this.vertices = [];
50811
+ this.indices = [];
50812
+ this.reset();
50813
+ }
50814
+
50815
+ /**
50816
+ * Resets, ready to add vertices and indices for a new mesh.
50817
+ */
50818
+ reset() {
50819
+ this.lenVertices = 0;
50820
+ this.lenIndices = 0;
50821
+ this.primitive = null;
50822
+ }
50823
+
50824
+ setPrimitive(primitive) {
50825
+ this.primitive = primitive;
50826
+ }
50827
+
50828
+ /**
50829
+ * Adds a vertex.
50830
+ * @param vertex
50831
+ */
50832
+ addVertex(vertex) {
50833
+ this.vertices[this.lenVertices++] = vertex[0];
50834
+ this.vertices[this.lenVertices++] = vertex[1];
50835
+ this.vertices[this.lenVertices++] = vertex[2];
50836
+ }
50837
+
50838
+ /**
50839
+ * Adds an index.
50840
+ * @param index
50841
+ */
50842
+ addIndex(index) {
50843
+ this.indices[this.lenIndices++] = index;
50844
+ }
50845
+
50846
+ /**
50847
+ * Gets the volume of the mesh.
50848
+ *
50849
+ * The mesh must be a closed solid.
50850
+ *
50851
+ * @returns {number} The volume of the mesh, or -1 if the mesh is not solid, in which case volume cannot be determined.
50852
+ */
50853
+ get volume() {
50854
+
50855
+ const vertices = this.vertices;
50856
+ const indices = this.indices;
50857
+
50858
+ if (this.primitive !== "solid" && this.primitive !== "surface" && this.primitive !== "triangles") {
50859
+ return -1;
50860
+ }
50861
+
50862
+ if (this.primitive !== "solid" && !isTriangleMeshSolid(indices, vertices)) {
50863
+ return -1;
50864
+ }
50865
+
50866
+ let volume = 0;
50867
+
50868
+ for (let i = 0; i < this.lenIndices; i += 3) {
50869
+
50870
+ const index1 = indices[i] * 3;
50871
+ const index2 = indices[i + 1] * 3;
50872
+ const index3 = indices[i + 2] * 3;
50873
+
50874
+ v1$1[0] = vertices[index1];
50875
+ v1$1[1] = vertices[index1 + 1];
50876
+ v1$1[2] = vertices[index1 + 2];
50877
+
50878
+ v2$1[0] = vertices[index2];
50879
+ v2$1[1] = vertices[index2 + 1];
50880
+ v2$1[2] = vertices[index2 + 2];
50881
+
50882
+ v3$1[0] = vertices[index3];
50883
+ v3$1[1] = vertices[index3 + 1];
50884
+ v3$1[2] = vertices[index3 + 2];
50885
+
50886
+ math.cross3Vec3(v1$1, v2$1, v1$1);
50887
+
50888
+ volume += math.dotVec3(v1$1, v3$1);
50889
+ }
50890
+
50891
+ return volume;
50892
+ }
50893
+ }
50894
+
50895
+ /**
50896
+ * Singleton instance of {@link MeshVolume}.
50897
+ * @type {MeshVolume}
50898
+ */
50899
+ const meshVolume = new MeshVolume();
50900
+
50901
+ const v1 = math.vec3();
50902
+ const v2 = math.vec3();
50903
+ const v3 = math.vec3();
50904
+ const v4 = math.vec3();
50905
+ const v5 = math.vec3();
50906
+ const v6 = math.vec3();
50907
+
50908
+ /**
50909
+ * Calculates the surface area of triangle meshes.
50910
+ */
50911
+ class MeshSurfaceArea {
50912
+ constructor() {
50913
+ this.vertices = [];
50914
+ this.indices = [];
50915
+ this.reset();
50916
+ }
50917
+
50918
+ /**
50919
+ * Resets, ready to add vertices and indices for a new mesh.
50920
+ */
50921
+ reset() {
50922
+ this.lenVertices = 0;
50923
+ this.lenIndices = 0;
50924
+ }
50925
+
50926
+ /**
50927
+ * Adds a vertex.
50928
+ * @param vertex
50929
+ */
50930
+ addVertex(vertex) {
50931
+ this.vertices[this.lenVertices++] = vertex[0];
50932
+ this.vertices[this.lenVertices++] = vertex[1];
50933
+ this.vertices[this.lenVertices++] = vertex[2];
50934
+ }
50935
+
50936
+ /**
50937
+ * Adds an index.
50938
+ * @param index
50939
+ */
50940
+ addIndex(index) {
50941
+ this.indices[this.lenIndices++] = index;
50942
+ }
50943
+
50944
+ /**
50945
+ * Gets the surface area of the mesh.
50946
+ *
50947
+ * @returns {number}
50948
+ */
50949
+ get surfaceArea() {
50950
+
50951
+ const vertices = this.vertices;
50952
+ const indices = this.indices;
50953
+
50954
+ let surfaceArea = 0;
50955
+
50956
+ for (let i = 0; i < this.lenIndices; i += 3) {
50957
+
50958
+ const index1 = indices[i] * 3;
50959
+ const index2 = indices[i + 1] * 3;
50960
+ const index3 = indices[i + 2] * 3;
50961
+
50962
+ v1[0] = vertices[index1];
50963
+ v1[1] = vertices[index1 + 1];
50964
+ v1[2] = vertices[index1 + 2];
50965
+
50966
+ v2[0] = vertices[index2];
50967
+ v2[1] = vertices[index2 + 1];
50968
+ v2[2] = vertices[index2 + 2];
50969
+
50970
+ v3[0] = vertices[index3];
50971
+ v3[1] = vertices[index3 + 1];
50972
+ v3[2] = vertices[index3 + 2];
50973
+
50974
+ math.subVec3(v1, v2, v4);
50975
+ math.subVec3(v3, v2, v5);
50976
+
50977
+ surfaceArea += math.lenVec3(math.cross3Vec3(v4, v5, v6)) * 0.5;
50978
+ }
50979
+
50980
+ return surfaceArea;
50981
+ }
50982
+ }
50983
+
50984
+ /**
50985
+ * Singleton instance of {@link MeshSurfaceArea}.
50986
+ * @type {MeshSurfaceArea}
50987
+ */
50988
+ const meshSurfaceArea = new MeshSurfaceArea();
50989
+
50611
50990
  const tempOBB3$1 = math.OBB3();
50612
50991
  const tempOBB3b = math.OBB3();
50613
50992
  const tempOBB3c = math.OBB3();
50614
50993
 
50994
+
50615
50995
  /**
50616
50996
  * A mesh within a {@link SceneModel}.
50617
50997
  *
@@ -50724,6 +51104,9 @@ class SceneModelMesh {
50724
51104
  if (transform) {
50725
51105
  transform._addMesh(this);
50726
51106
  }
51107
+
51108
+ this._volume = null;
51109
+ this._surfaceArea = null;
50727
51110
  }
50728
51111
 
50729
51112
  _sceneModelDirty() {
@@ -50902,7 +51285,75 @@ class SceneModelMesh {
50902
51285
  * @private
50903
51286
  */
50904
51287
  getEachVertex(callback) {
50905
- this.layer.getEachVertex(this.portionId, callback);
51288
+ if (this.layer.getEachVertex) {
51289
+ this.layer.getEachVertex(this.portionId, callback);
51290
+ }
51291
+ }
51292
+
51293
+ /**
51294
+ * @private
51295
+ */
51296
+ getEachIndex(callback) {
51297
+ if (this.layer.getEachIndex ) {
51298
+ this.layer.getEachIndex(this.portionId, callback);
51299
+ }
51300
+ }
51301
+
51302
+ /**
51303
+ * Returns the volume of this SceneModelMesh.
51304
+ * @returns {number}
51305
+ */
51306
+ get volume() {
51307
+ if (this._volume !== null) {
51308
+ return this._volume;
51309
+ }
51310
+ switch (this.layer.primitive) {
51311
+ case "solid":
51312
+ case "surface":
51313
+ case "triangles":
51314
+ meshVolume.reset();
51315
+ meshVolume.setPrimitive(this.layer.primitive);
51316
+ this.getEachVertex((vertex) =>{
51317
+ meshVolume.addVertex(vertex);
51318
+ });
51319
+ this.getEachIndex((index)=>{
51320
+ meshVolume.addIndex(index);
51321
+ });
51322
+ this._volume = meshVolume.volume;
51323
+ break;
51324
+ default:
51325
+ this._volume = 0;
51326
+ break;
51327
+ }
51328
+ return this._volume;
51329
+ }
51330
+
51331
+ /**
51332
+ * Returns the surface area of this SceneModelMesh.
51333
+ * @returns {number}
51334
+ */
51335
+ get surfaceArea() {
51336
+ if (this._surfaceArea !== null) {
51337
+ return this._surfaceArea;
51338
+ }
51339
+ switch (this.layer.primitive) {
51340
+ case "solid":
51341
+ case "surface":
51342
+ case "triangles":
51343
+ meshSurfaceArea.reset();
51344
+ this.getEachVertex((vertex) =>{
51345
+ meshSurfaceArea.addVertex(vertex);
51346
+ });
51347
+ this.getEachIndex((index)=>{
51348
+ meshSurfaceArea.addIndex(index);
51349
+ });
51350
+ this._surfaceArea = meshSurfaceArea.surfaceArea;
51351
+ break;
51352
+ default:
51353
+ this._surfaceArea = 0;
51354
+ break;
51355
+ }
51356
+ return this._surfaceArea;
50906
51357
  }
50907
51358
 
50908
51359
  /**
@@ -55706,7 +56157,7 @@ function octDecodeVec2(oct) { // Decode an oct-encoded normal
55706
56157
 
55707
56158
  const tempMat4$1 = math.mat4();
55708
56159
  const tempMat4b = math.mat4();
55709
- const tempVec4a$7 = math.vec4([0, 0, 0, 1]);
56160
+ const tempVec4a$8 = math.vec4([0, 0, 0, 1]);
55710
56161
 
55711
56162
  const tempVec3a$z = math.vec3();
55712
56163
  const tempVec3b$v = math.vec3();
@@ -55736,7 +56187,7 @@ class VBOBatchingTrianglesLayer {
55736
56187
  */
55737
56188
  constructor(cfg) {
55738
56189
 
55739
- console.info("Creating VBOBatchingTrianglesLayer");
56190
+ // console.info("Creating VBOBatchingTrianglesLayer");
55740
56191
 
55741
56192
  /**
55742
56193
  * Owner model
@@ -55826,6 +56277,11 @@ class VBOBatchingTrianglesLayer {
55826
56277
  * @type {boolean}
55827
56278
  */
55828
56279
  this.solid = !!cfg.solid;
56280
+
56281
+ /**
56282
+ * The type of primitives in this layer.
56283
+ */
56284
+ this.primitive = cfg.primitive;
55829
56285
  }
55830
56286
 
55831
56287
  get aabb() {
@@ -56022,7 +56478,7 @@ class VBOBatchingTrianglesLayer {
56022
56478
  numIndices: indices.length,
56023
56479
  };
56024
56480
 
56025
- if (scene.pickSurfacePrecisionEnabled) {
56481
+ if (scene.readableGeometryEnabled) {
56026
56482
  // Quantized in-memory positions are initialized in finalize()
56027
56483
 
56028
56484
  portion.indices = indices;
@@ -56059,7 +56515,7 @@ class VBOBatchingTrianglesLayer {
56059
56515
  ? new Uint16Array(buffer.positions)
56060
56516
  : quantizePositions(buffer.positions, this._modelAABB, this._state.positionsDecodeMatrix = math.mat4()); // BOTTLENECK
56061
56517
  state.positionsBuf = new ArrayBuf(gl, gl.ARRAY_BUFFER, quantizedPositions, quantizedPositions.length, 3, gl.STATIC_DRAW);
56062
- if (this.model.scene.pickSurfacePrecisionEnabled) {
56518
+ if (this.model.scene.readableGeometryEnabled) {
56063
56519
  for (let i = 0, numPortions = this._portions.length; i < numPortions; i++) {
56064
56520
  const portion = this._portions[i];
56065
56521
  const start = portion.vertsBaseIndex * 3;
@@ -56488,7 +56944,7 @@ class VBOBatchingTrianglesLayer {
56488
56944
  if (this._state.offsetsBuf) {
56489
56945
  this._state.offsetsBuf.setData(tempArray, firstOffset, lenOffsets);
56490
56946
  }
56491
- if (this.model.scene.pickSurfacePrecisionEnabled) {
56947
+ if (this.model.scene.readableGeometryEnabled) {
56492
56948
  portion.offset[0] = offset[0];
56493
56949
  portion.offset[1] = offset[1];
56494
56950
  portion.offset[2] = offset[2];
@@ -56496,7 +56952,7 @@ class VBOBatchingTrianglesLayer {
56496
56952
  }
56497
56953
 
56498
56954
  getEachVertex(portionId, callback) {
56499
- if (!this.model.scene.pickSurfacePrecisionEnabled) {
56955
+ if (!this.model.scene.readableGeometryEnabled) {
56500
56956
  return;
56501
56957
  }
56502
56958
  const state = this._state;
@@ -56507,18 +56963,19 @@ class VBOBatchingTrianglesLayer {
56507
56963
  }
56508
56964
  const positions = portion.quantizedPositions;
56509
56965
  const origin = state.origin;
56510
- const offset = portion.offset;
56511
- const offsetX = origin[0] + offset[0];
56512
- const offsetY = origin[1] + offset[1];
56513
- const offsetZ = origin[2] + offset[2];
56514
- const worldPos = tempVec4a$7;
56966
+ const offsetX = origin[0] ;
56967
+ const offsetY = origin[1] ;
56968
+ const offsetZ = origin[2] ;
56969
+ const worldPos = tempVec4a$8;
56970
+ const sceneModelMatrix = this.model.matrix;
56971
+ const positionsDecodeMatrix = state.positionsDecodeMatrix;
56515
56972
  for (let i = 0, len = positions.length; i < len; i += 3) {
56516
56973
  worldPos[0] = positions[i];
56517
56974
  worldPos[1] = positions[i + 1];
56518
56975
  worldPos[2] = positions[i + 2];
56519
56976
  worldPos[3] = 1.0;
56520
- math.decompressPosition(worldPos, state.positionsDecodeMatrix);
56521
- math.transformPoint4(this.model.worldMatrix, worldPos);
56977
+ math.decompressPosition(worldPos, positionsDecodeMatrix);
56978
+ math.transformPoint4(sceneModelMatrix, worldPos);
56522
56979
  worldPos[0] += offsetX;
56523
56980
  worldPos[1] += offsetY;
56524
56981
  worldPos[2] += offsetZ;
@@ -56526,6 +56983,21 @@ class VBOBatchingTrianglesLayer {
56526
56983
  }
56527
56984
  }
56528
56985
 
56986
+ getEachIndex(portionId, callback) {
56987
+ if (!this.model.scene.readableGeometryEnabled) {
56988
+ return;
56989
+ }
56990
+ const portion = this._portions[portionId];
56991
+ if (!portion) {
56992
+ this.model.error("portion not found: " + portionId);
56993
+ return;
56994
+ }
56995
+ const indices = portion.indices;
56996
+ for (let i = 0, len = indices.length; i < len; i++) {
56997
+ callback(indices[i]);
56998
+ }
56999
+ }
57000
+
56529
57001
  getElementsCountAndOffset(portionId) {
56530
57002
  let count = null;
56531
57003
  let offset = null;
@@ -56813,7 +57285,7 @@ class VBOBatchingTrianglesLayer {
56813
57285
 
56814
57286
  precisionRayPickSurface(portionId, worldRayOrigin, worldRayDir, worldSurfacePos, worldNormal) {
56815
57287
 
56816
- if (!this.model.scene.pickSurfacePrecisionEnabled) {
57288
+ if (!this.model.scene.readableGeometryEnabled) {
56817
57289
  return false;
56818
57290
  }
56819
57291
 
@@ -60793,7 +61265,7 @@ function getRenderers$6(scene) {
60793
61265
 
60794
61266
  const tempUint8Vec4$2 = new Uint8Array(4);
60795
61267
  const tempFloat32$2 = new Float32Array(1);
60796
- const tempVec4a$6 = math.vec4([0, 0, 0, 1]);
61268
+ const tempVec4a$7 = math.vec4([0, 0, 0, 1]);
60797
61269
  const tempVec3fa$2 = new Float32Array(3);
60798
61270
 
60799
61271
  const tempVec3a$w = math.vec3();
@@ -60821,7 +61293,7 @@ class VBOInstancingTrianglesLayer {
60821
61293
  */
60822
61294
  constructor(cfg) {
60823
61295
 
60824
- console.info("Creating VBOInstancingTrianglesLayer");
61296
+ // console.info("Creating VBOInstancingTrianglesLayer");
60825
61297
 
60826
61298
  /**
60827
61299
  * Owner model
@@ -60924,6 +61396,11 @@ class VBOInstancingTrianglesLayer {
60924
61396
  * @type {number|*}
60925
61397
  */
60926
61398
  this.numIndices = cfg.geometry.numIndices;
61399
+
61400
+ /**
61401
+ * The type of primitives in this layer.
61402
+ */
61403
+ this.primitive = cfg.geometry.primitive;
60927
61404
  }
60928
61405
 
60929
61406
  get aabb() {
@@ -61037,7 +61514,7 @@ class VBOInstancingTrianglesLayer {
61037
61514
 
61038
61515
  const portion = {};
61039
61516
 
61040
- if (this.model.scene.pickSurfacePrecisionEnabled) {
61517
+ if (this.model.scene.readableGeometryEnabled) {
61041
61518
  portion.matrix = meshMatrix.slice();
61042
61519
  portion.inverseMatrix = null; // Lazy-computed in precisionRayPickSurface
61043
61520
  portion.normalMatrix = null; // Lazy-computed in precisionRayPickSurface
@@ -61475,7 +61952,7 @@ class VBOInstancingTrianglesLayer {
61475
61952
  }
61476
61953
 
61477
61954
  getEachVertex(portionId, callback) {
61478
- if (!this.model.scene.pickSurfacePrecisionEnabled) {
61955
+ if (!this.model.scene.readableGeometryEnabled) {
61479
61956
  return false;
61480
61957
  }
61481
61958
  const state = this._state;
@@ -61487,13 +61964,12 @@ class VBOInstancingTrianglesLayer {
61487
61964
  }
61488
61965
  const positions = geometry.quantizedPositions;
61489
61966
  const origin = state.origin;
61490
- const offset = portion.offset;
61491
- const offsetX = origin[0] + offset[0];
61492
- const offsetY = origin[1] + offset[1];
61493
- const offsetZ = origin[2] + offset[2];
61494
- const worldPos = tempVec4a$6;
61967
+ const offsetX = origin[0] ;
61968
+ const offsetY = origin[1] ;
61969
+ const offsetZ = origin[2] ;
61970
+ const worldPos = tempVec4a$7;
61495
61971
  const portionMatrix = portion.matrix;
61496
- const sceneModelPatrix = this.model.sceneModelMatrix;
61972
+ const sceneModelMatrix = this.model.matrix;
61497
61973
  const positionsDecodeMatrix = state.positionsDecodeMatrix;
61498
61974
  for (let i = 0, len = positions.length; i < len; i += 3) {
61499
61975
  worldPos[0] = positions[i];
@@ -61501,7 +61977,7 @@ class VBOInstancingTrianglesLayer {
61501
61977
  worldPos[2] = positions[i + 2];
61502
61978
  math.decompressPosition(worldPos, positionsDecodeMatrix);
61503
61979
  math.transformPoint3(portionMatrix, worldPos);
61504
- math.transformPoint3(sceneModelPatrix, worldPos);
61980
+ math.transformPoint3(sceneModelMatrix, worldPos);
61505
61981
  worldPos[0] += offsetX;
61506
61982
  worldPos[1] += offsetY;
61507
61983
  worldPos[2] += offsetZ;
@@ -61509,6 +61985,23 @@ class VBOInstancingTrianglesLayer {
61509
61985
  }
61510
61986
  }
61511
61987
 
61988
+ getEachIndex(portionId, callback) {
61989
+ if (!this.model.scene.readableGeometryEnabled) {
61990
+ return false;
61991
+ }
61992
+ const state = this._state;
61993
+ const geometry = state.geometry;
61994
+ const portion = this._portions[portionId];
61995
+ if (!portion) {
61996
+ this.model.error("portion not found: " + portionId);
61997
+ return;
61998
+ }
61999
+ const indices = geometry.indices;
62000
+ for (let i = 0, len = indices.length; i < len; i++) {
62001
+ callback(indices[i]);
62002
+ }
62003
+ }
62004
+
61512
62005
  setMatrix(portionId, matrix) {
61513
62006
  if (!this._finalized) {
61514
62007
  throw "Not finalized";
@@ -61815,7 +62308,7 @@ class VBOInstancingTrianglesLayer {
61815
62308
 
61816
62309
  precisionRayPickSurface(portionId, worldRayOrigin, worldRayDir, worldSurfacePos, worldNormal) {
61817
62310
 
61818
- if (!this.model.scene.pickSurfacePrecisionEnabled) {
62311
+ if (!this.model.scene.readableGeometryEnabled) {
61819
62312
  return false;
61820
62313
  }
61821
62314
 
@@ -62972,7 +63465,7 @@ class VBOBatchingLinesLayer {
62972
63465
  */
62973
63466
  constructor(cfg) {
62974
63467
 
62975
- console.info("Creating VBOBatchingLinesLayer");
63468
+ // console.info("Creating VBOBatchingLinesLayer");
62976
63469
 
62977
63470
  /**
62978
63471
  * Index of this LinesBatchingLayer in {@link VBOSceneModel#_layerList}.
@@ -63027,6 +63520,11 @@ class VBOBatchingLinesLayer {
63027
63520
  if (cfg.origin) {
63028
63521
  this._state.origin = math.vec3(cfg.origin);
63029
63522
  }
63523
+
63524
+ /**
63525
+ * The type of primitives in this layer.
63526
+ */
63527
+ this.primitive = cfg.primitive;
63030
63528
  }
63031
63529
 
63032
63530
  get aabb() {
@@ -64735,7 +65233,7 @@ class VBOInstancingLinesLayer {
64735
65233
  */
64736
65234
  constructor(cfg) {
64737
65235
 
64738
- console.info("VBOInstancingLinesLayer");
65236
+ // console.info("VBOInstancingLinesLayer");
64739
65237
 
64740
65238
  /**
64741
65239
  * Owner model
@@ -64815,6 +65313,11 @@ class VBOInstancingLinesLayer {
64815
65313
  }
64816
65314
 
64817
65315
  this._finalized = false;
65316
+
65317
+ /**
65318
+ * The type of primitives in this layer.
65319
+ */
65320
+ this.primitive = cfg.primitive;
64818
65321
  }
64819
65322
 
64820
65323
  get aabb() {
@@ -66948,7 +67451,7 @@ class VBOBatchingPointsLayer {
66948
67451
  */
66949
67452
  constructor(cfg) {
66950
67453
 
66951
- console.info("Creating VBOBatchingPointsLayer");
67454
+ // console.info("Creating VBOBatchingPointsLayer");
66952
67455
 
66953
67456
  /**
66954
67457
  * Owner model
@@ -69545,7 +70048,7 @@ class VBOInstancingPointsLayer {
69545
70048
  */
69546
70049
  constructor(cfg) {
69547
70050
 
69548
- console.info("VBOInstancingPointsLayer");
70051
+ // console.info("VBOInstancingPointsLayer");
69549
70052
 
69550
70053
  /**
69551
70054
  * Owner model
@@ -69619,6 +70122,11 @@ class VBOInstancingPointsLayer {
69619
70122
  this.aabbDirty = true;
69620
70123
 
69621
70124
  this._finalized = false;
70125
+
70126
+ /**
70127
+ * The type of primitives in this layer.
70128
+ */
70129
+ this.primitive = cfg.geometry.primitive;
69622
70130
  }
69623
70131
 
69624
70132
  get aabb() {
@@ -71280,7 +71788,7 @@ class DTXLinesLayer {
71280
71788
 
71281
71789
  constructor(model, cfg) {
71282
71790
 
71283
- console.info("Creating DTXLinesLayer");
71791
+ // console.info("Creating DTXLinesLayer");
71284
71792
 
71285
71793
  dataTextureRamStats$1.numberOfLayers++;
71286
71794
 
@@ -71319,6 +71827,12 @@ class DTXLinesLayer {
71319
71827
  this._aabb = math.collapseAABB3();
71320
71828
  this.aabbDirty = true;
71321
71829
  this._numUpdatesInFrame = 0;
71830
+
71831
+ /**
71832
+ * The type of primitives in this layer.
71833
+ */
71834
+ this.primitive = cfg.primitive;
71835
+
71322
71836
  this._finalized = false;
71323
71837
  }
71324
71838
 
@@ -72144,7 +72658,7 @@ const tempVec3b$i = math.vec3();
72144
72658
  const tempVec3c$e = math.vec3();
72145
72659
  math.vec3();
72146
72660
 
72147
- const tempVec4a$5 = math.vec4();
72661
+ const tempVec4a$6 = math.vec4();
72148
72662
 
72149
72663
  const tempMat4a$c = math.mat4();
72150
72664
 
@@ -72423,11 +72937,11 @@ class DTXTrianglesColorRenderer {
72423
72937
  if (saoEnabled) {
72424
72938
  const viewportWidth = gl.drawingBufferWidth;
72425
72939
  const viewportHeight = gl.drawingBufferHeight;
72426
- tempVec4a$5[0] = viewportWidth;
72427
- tempVec4a$5[1] = viewportHeight;
72428
- tempVec4a$5[2] = sao.blendCutoff;
72429
- tempVec4a$5[3] = sao.blendFactor;
72430
- gl.uniform4fv(this._uSAOParams, tempVec4a$5);
72940
+ tempVec4a$6[0] = viewportWidth;
72941
+ tempVec4a$6[1] = viewportHeight;
72942
+ tempVec4a$6[2] = sao.blendCutoff;
72943
+ tempVec4a$6[3] = sao.blendFactor;
72944
+ gl.uniform4fv(this._uSAOParams, tempVec4a$6);
72431
72945
  this._program.bindTexture(this._uOcclusionTexture, frameCtx.occlusionTexture, 10);
72432
72946
  }
72433
72947
  }
@@ -78654,6 +79168,7 @@ const INDICES_EDGE_INDICES_ALIGNEMENT_SIZE = 8;
78654
79168
  */
78655
79169
  const MAX_OBJECT_UPDATES_IN_FRAME_WITHOUT_BATCHED_UPDATE = 10;
78656
79170
 
79171
+ const tempVec4a$5 = math.vec4();
78657
79172
  const tempMat4a = new Float32Array(16);
78658
79173
  const tempUint8Array4 = new Uint8Array(4);
78659
79174
  const tempFloat32Array3 = new Float32Array(3);
@@ -78669,7 +79184,7 @@ class DTXTrianglesLayer {
78669
79184
 
78670
79185
  constructor(model, cfg) {
78671
79186
 
78672
- console.info("Creating DTXTrianglesLayer");
79187
+ //console.info("Creating DTXTrianglesLayer");
78673
79188
 
78674
79189
  dataTextureRamStats.numberOfLayers++;
78675
79190
 
@@ -78709,6 +79224,10 @@ class DTXTrianglesLayer {
78709
79224
 
78710
79225
  this._subPortions = [];
78711
79226
 
79227
+ if (this.model.scene.readableGeometryEnabled) {
79228
+ this._subPortionReadableGeometries = {};
79229
+ }
79230
+
78712
79231
  /**
78713
79232
  * Due to `index rebucketting` process in ```prepareMeshGeometry``` function, it's possible that a single
78714
79233
  * portion is expanded to more than 1 real sub-portion.
@@ -78738,6 +79257,11 @@ class DTXTrianglesLayer {
78738
79257
  */
78739
79258
  this._numUpdatesInFrame = 0;
78740
79259
 
79260
+ /**
79261
+ * The type of primitives in this layer.
79262
+ */
79263
+ this.primitive = cfg.primitive;
79264
+
78741
79265
  this._finalized = false;
78742
79266
  }
78743
79267
 
@@ -79042,6 +79566,15 @@ class DTXTrianglesLayer {
79042
79566
  numVertices: bucketGeometry.numTriangles
79043
79567
  });
79044
79568
 
79569
+ if (this.model.scene.readableGeometryEnabled) {
79570
+ this._subPortionReadableGeometries[subPortionId] = {
79571
+ indices: bucket.indices,
79572
+ positionsCompressed: bucket.positionsCompressed,
79573
+ positionsDecodeMatrix: portionCfg.positionsDecodeMatrix,
79574
+ meshMatrix: portionCfg.meshMatrix
79575
+ };
79576
+ }
79577
+
79045
79578
  this._numPortions++;
79046
79579
 
79047
79580
  dataTextureRamStats.numberOfPortions++;
@@ -79692,6 +80225,63 @@ class DTXTrianglesLayer {
79692
80225
  // gl.bindTexture (gl.TEXTURE_2D, null);
79693
80226
  }
79694
80227
 
80228
+ getEachVertex(portionId, callback) {
80229
+ if (!this.model.scene.readableGeometryEnabled) {
80230
+ return;
80231
+ }
80232
+ const state = this._state;
80233
+ const subPortionIds = this._portionToSubPortionsMap[portionId];
80234
+ if (!subPortionIds) {
80235
+ this.model.error("portion not found: " + portionId);
80236
+ return;
80237
+ }
80238
+ for (let i = 0, len = subPortionIds.length; i < len; i++) {
80239
+ const subPortionId = subPortionIds[i];
80240
+ const subPortionReadableGeometry = this._subPortionReadableGeometries[subPortionId];
80241
+ const positions = subPortionReadableGeometry.positionsCompressed;
80242
+ const positionsDecodeMatrix = subPortionReadableGeometry.positionsDecodeMatrix;
80243
+ subPortionReadableGeometry.meshMatrix;
80244
+ const origin = state.origin;
80245
+ const offsetX = origin[0] ;
80246
+ const offsetY = origin[1] ;
80247
+ const offsetZ = origin[2] ;
80248
+ const worldPos = tempVec4a$5;
80249
+ for (let i = 0, len = positions.length; i < len; i += 3) {
80250
+ worldPos[0] = positions[i];
80251
+ worldPos[1] = positions[i + 1];
80252
+ worldPos[2] = positions[i + 2];
80253
+ worldPos[3] = 1.0;
80254
+ math.decompressPosition(worldPos, positionsDecodeMatrix);
80255
+ math.transformPoint4(this.model.worldMatrix, worldPos);
80256
+ math.transformPoint4(this.model.worldMatrix, worldPos);
80257
+ worldPos[0] += offsetX;
80258
+ worldPos[1] += offsetY;
80259
+ worldPos[2] += offsetZ;
80260
+ callback(worldPos);
80261
+ }
80262
+ }
80263
+ }
80264
+
80265
+ getEachIndex(portionId, callback) {
80266
+ if (!this.model.scene.readableGeometryEnabled) {
80267
+ return;
80268
+ }
80269
+ const subPortionIds = this._portionToSubPortionsMap[portionId];
80270
+ if (!subPortionIds) {
80271
+ this.model.error("portion not found: " + portionId);
80272
+ return;
80273
+ }
80274
+ for (let i = 0, len = subPortionIds.length; i < len; i++) {
80275
+ const subPortionId = subPortionIds[i];
80276
+ const subPortionReadableGeometry = this._subPortionReadableGeometries[subPortionId];
80277
+ const indices = subPortionReadableGeometry.indices;
80278
+ for (let i = 0, len = indices.length; i < len; i++) {
80279
+ callback(indices[i]);
80280
+ }
80281
+ }
80282
+ }
80283
+
80284
+
79695
80285
  // ---------------------- COLOR RENDERING -----------------------------------
79696
80286
 
79697
80287
  drawColorOpaque(renderFlags, frameCtx) {
@@ -83034,7 +83624,10 @@ class SceneModel extends Component {
83034
83624
  this._meshList = [];
83035
83625
 
83036
83626
  this.layerList = []; // For GL state efficiency when drawing, InstancingLayers are in first part, BatchingLayers are in second
83627
+ this._layersToFinalize = [];
83628
+
83037
83629
  this._entityList = [];
83630
+ this._entitiesToFinalize = [];
83038
83631
 
83039
83632
  this._geometries = {};
83040
83633
  this._dtxBuckets = {}; // Geometries with optimizations used for data texture representation
@@ -83110,6 +83703,7 @@ class SceneModel extends Component {
83110
83703
  this._numTriangles = 0;
83111
83704
  this._numLines = 0;
83112
83705
  this._numPoints = 0;
83706
+ this._layersFinalized = false;
83113
83707
 
83114
83708
  this._edgeThreshold = cfg.edgeThreshold || 10;
83115
83709
 
@@ -85051,7 +85645,7 @@ class SceneModel extends Component {
85051
85645
  let dtxLayer = this._dtxLayers[layerId];
85052
85646
  if (dtxLayer) {
85053
85647
  if (!dtxLayer.canCreatePortion(cfg)) {
85054
- dtxLayer.finalize();
85648
+ // dtxLayer.finalize();
85055
85649
  delete this._dtxLayers[layerId];
85056
85650
  dtxLayer = null;
85057
85651
  } else {
@@ -85062,16 +85656,17 @@ class SceneModel extends Component {
85062
85656
  case "triangles":
85063
85657
  case "solid":
85064
85658
  case "surface":
85065
- dtxLayer = new DTXTrianglesLayer(this, {layerIndex: 0, origin}); // layerIndex is set in #finalize()
85659
+ dtxLayer = new DTXTrianglesLayer(this, {layerIndex: 0, origin, primitive}); // layerIndex is set in #finalize()
85066
85660
  break;
85067
85661
  case "lines":
85068
- dtxLayer = new DTXLinesLayer(this, {layerIndex: 0, origin}); // layerIndex is set in #finalize()
85662
+ dtxLayer = new DTXLinesLayer(this, {layerIndex: 0, origin, primitive}); // layerIndex is set in #finalize()
85069
85663
  break;
85070
85664
  default:
85071
85665
  return;
85072
85666
  }
85073
85667
  this._dtxLayers[layerId] = dtxLayer;
85074
85668
  this.layerList.push(dtxLayer);
85669
+ this._layersToFinalize.push(dtxLayer);
85075
85670
  return dtxLayer;
85076
85671
  }
85077
85672
 
@@ -85103,7 +85698,8 @@ class SceneModel extends Component {
85103
85698
  origin,
85104
85699
  maxGeometryBatchSize: this._maxGeometryBatchSize,
85105
85700
  solid: (cfg.primitive === "solid"),
85106
- autoNormals: true
85701
+ autoNormals: true,
85702
+ primitive: cfg.primitive
85107
85703
  });
85108
85704
  break;
85109
85705
  case "solid":
@@ -85118,7 +85714,8 @@ class SceneModel extends Component {
85118
85714
  origin,
85119
85715
  maxGeometryBatchSize: this._maxGeometryBatchSize,
85120
85716
  solid: (cfg.primitive === "solid"),
85121
- autoNormals: true
85717
+ autoNormals: true,
85718
+ primitive: cfg.primitive
85122
85719
  });
85123
85720
  break;
85124
85721
  case "surface":
@@ -85133,7 +85730,8 @@ class SceneModel extends Component {
85133
85730
  origin,
85134
85731
  maxGeometryBatchSize: this._maxGeometryBatchSize,
85135
85732
  solid: (cfg.primitive === "solid"),
85136
- autoNormals: true
85733
+ autoNormals: true,
85734
+ primitive: cfg.primitive
85137
85735
  });
85138
85736
  break;
85139
85737
  case "lines":
@@ -85145,7 +85743,8 @@ class SceneModel extends Component {
85145
85743
  positionsDecodeMatrix: cfg.positionsDecodeMatrix, // Can be undefined
85146
85744
  uvDecodeMatrix: cfg.uvDecodeMatrix, // Can be undefined
85147
85745
  origin,
85148
- maxGeometryBatchSize: this._maxGeometryBatchSize
85746
+ maxGeometryBatchSize: this._maxGeometryBatchSize,
85747
+ primitive: cfg.primitive
85149
85748
  });
85150
85749
  break;
85151
85750
  case "points":
@@ -85157,7 +85756,8 @@ class SceneModel extends Component {
85157
85756
  positionsDecodeMatrix: cfg.positionsDecodeMatrix, // Can be undefined
85158
85757
  uvDecodeMatrix: cfg.uvDecodeMatrix, // Can be undefined
85159
85758
  origin,
85160
- maxGeometryBatchSize: this._maxGeometryBatchSize
85759
+ maxGeometryBatchSize: this._maxGeometryBatchSize,
85760
+ primitive: cfg.primitive
85161
85761
  });
85162
85762
  break;
85163
85763
  }
@@ -85173,6 +85773,7 @@ class SceneModel extends Component {
85173
85773
  }
85174
85774
  this._vboBatchingLayers[layerId] = vboBatchingLayer;
85175
85775
  this.layerList.push(vboBatchingLayer);
85776
+ this._layersToFinalize.push(vboBatchingLayer);
85176
85777
  return vboBatchingLayer;
85177
85778
  }
85178
85779
 
@@ -85265,6 +85866,7 @@ class SceneModel extends Component {
85265
85866
  }
85266
85867
  this._vboInstancingLayers[layerId] = vboInstancingLayer;
85267
85868
  this.layerList.push(vboInstancingLayer);
85869
+ this._layersToFinalize.push(vboInstancingLayer);
85268
85870
  return vboInstancingLayer;
85269
85871
  }
85270
85872
 
@@ -85365,38 +85967,47 @@ class SceneModel extends Component {
85365
85967
  lodCullable); // Internally sets SceneModelEntity#parent to this SceneModel
85366
85968
  this._entityList.push(entity);
85367
85969
  this._entities[cfg.id] = entity;
85970
+ this._entitiesToFinalize.push(entity);
85368
85971
  this.numEntities++;
85369
85972
  }
85370
85973
 
85371
85974
  /**
85372
- * Finalizes this SceneModel.
85373
- *
85374
- * Once finalized, you can't add anything more to this SceneModel.
85975
+ * Pre-renders all meshes that have been added, even if the SceneModel has not bee finalized yet.
85976
+ * This is use for progressively showing the SceneModel while it is being loaded or constructed.
85977
+ * @returns {boolean}
85375
85978
  */
85376
- finalize() {
85979
+ preFinalize() {
85377
85980
  if (this.destroyed) {
85378
- return;
85981
+ return false;
85982
+ }
85983
+ if (this._layersToFinalize.length === 0) {
85984
+ return false;
85379
85985
  }
85380
85986
  this._createDummyEntityForUnusedMeshes();
85381
- for (let i = 0, len = this.layerList.length; i < len; i++) {
85382
- const layer = this.layerList[i];
85987
+ for (let i = 0, len = this._layersToFinalize.length; i < len; i++) {
85988
+ const layer = this._layersToFinalize[i];
85383
85989
  layer.finalize();
85384
85990
  }
85385
- this._geometries = {};
85386
- this._dtxBuckets = {};
85387
- this._textures = {};
85388
- this._textureSets = {};
85389
- this._dtxLayers = {};
85390
- this._vboInstancingLayers = {};
85391
85991
  this._vboBatchingLayers = {};
85392
- for (let i = 0, len = this._entityList.length; i < len; i++) {
85393
- const entity = this._entityList[i];
85992
+ this._vboInstancingLayers = {};
85993
+ this._dtxLayers = {};
85994
+ this._layersToFinalize = [];
85995
+ for (let i = 0, len = this._entitiesToFinalize.length; i < len; i++) {
85996
+ const entity = this._entitiesToFinalize[i];
85394
85997
  entity._finalize();
85395
85998
  }
85396
- for (let i = 0, len = this._entityList.length; i < len; i++) {
85397
- const entity = this._entityList[i];
85999
+ for (let i = 0, len = this._entitiesToFinalize.length; i < len; i++) {
86000
+ const entity = this._entitiesToFinalize[i];
85398
86001
  entity._finalize2();
85399
86002
  }
86003
+ this._entitiesToFinalize = [];
86004
+ this.scene._aabbDirty = true;
86005
+ this._viewMatrixDirty = true;
86006
+ this._matrixDirty = true;
86007
+ this._aabbDirty = true;
86008
+ this._setWorldMatrixDirty();
86009
+ this._sceneModelDirty();
86010
+ this.position = this._position;
85400
86011
  // Sort layers to reduce WebGL shader switching when rendering them
85401
86012
  this.layerList.sort((a, b) => {
85402
86013
  if (a.sortId < b.sortId) {
@@ -85412,15 +86023,23 @@ class SceneModel extends Component {
85412
86023
  layer.layerIndex = i;
85413
86024
  }
85414
86025
  this.glRedraw();
85415
- this.scene._aabbDirty = true;
85416
- this._viewMatrixDirty = true;
85417
- this._matrixDirty = true;
85418
- this._aabbDirty = true;
85419
-
85420
- this._setWorldMatrixDirty();
85421
- this._sceneModelDirty();
86026
+ this._layersFinalized = true;
86027
+ }
85422
86028
 
85423
- this.position = this._position;
86029
+ /**
86030
+ * Finalizes this SceneModel.
86031
+ *
86032
+ * Once finalized, you can't add anything more to this SceneModel.
86033
+ */
86034
+ finalize() {
86035
+ if (this.destroyed) {
86036
+ return;
86037
+ }
86038
+ this.preFinalize();
86039
+ this._geometries = {};
86040
+ this._dtxBuckets = {};
86041
+ this._textures = {};
86042
+ this._textureSets = {};
85424
86043
  }
85425
86044
 
85426
86045
  /** @private */
@@ -85458,7 +86077,7 @@ class SceneModel extends Component {
85458
86077
  _createDummyEntityForUnusedMeshes() {
85459
86078
  const unusedMeshIds = Object.keys(this._unusedMeshes);
85460
86079
  if (unusedMeshIds.length > 0) {
85461
- const entityId = `${this.id}-dummyEntityForUnusedMeshes`;
86080
+ const entityId = `${this.id}-${math.createUUID()}`;
85462
86081
  this.warn(`Creating dummy SceneModelEntity "${entityId}" for unused SceneMeshes: [${unusedMeshIds.join(",")}]`);
85463
86082
  this.createEntity({
85464
86083
  id: entityId,
@@ -85830,6 +86449,7 @@ class SceneModel extends Component {
85830
86449
  for (let i = 0, len = this._entityList.length; i < len; i++) {
85831
86450
  this._entityList[i]._destroy();
85832
86451
  }
86452
+ this._layersToFinalize = {};
85833
86453
  // Object.entries(this._geometries).forEach(([id, geometry]) => {
85834
86454
  // geometry.destroy();
85835
86455
  // });
@@ -88327,12 +88947,6 @@ class DistanceMeasurementsMouseControl extends DistanceMeasurementsControl {
88327
88947
 
88328
88948
  this._initMarkerDiv();
88329
88949
 
88330
- this._onCameraControlHoverSnapOrSurface = null;
88331
- this._onCameraControlHoverSnapOrSurfaceOff = null;
88332
- this._onMouseDown = null;
88333
- this._onMouseUp = null;
88334
- this._onCanvasTouchStart = null;
88335
- this._onCanvasTouchEnd = null;
88336
88950
  this._snapping = cfg.snapping !== false;
88337
88951
  this._mouseState = MOUSE_FIRST_CLICK_EXPECTED;
88338
88952
 
@@ -88396,20 +89010,10 @@ class DistanceMeasurementsMouseControl extends DistanceMeasurementsControl {
88396
89010
  *
88397
89011
  * This is `true` by default.
88398
89012
  *
88399
- * Internally, this deactivates then activates the DistanceMeasurementsMouseControl when changed, which means that
88400
- * it will destroy any DistanceMeasurements currently under construction, and incurs some overhead, since it unbinds
88401
- * and rebinds various input handlers.
88402
- *
88403
89013
  * @param snapping
88404
89014
  */
88405
89015
  set snapping(snapping) {
88406
- if (snapping !== this._snapping) {
88407
- this._snapping = snapping;
88408
- this.deactivate();
88409
- this.activate();
88410
- } else {
88411
- this._snapping = snapping;
88412
- }
89016
+ this._snapping = snapping;
88413
89017
  }
88414
89018
 
88415
89019
  /**
@@ -88421,7 +89025,7 @@ class DistanceMeasurementsMouseControl extends DistanceMeasurementsControl {
88421
89025
  get snapping() {
88422
89026
  return this._snapping;
88423
89027
  }
88424
-
89028
+
88425
89029
  /**
88426
89030
  * Activates this DistanceMeasurementsMouseControl, ready to respond to input.
88427
89031
  */
@@ -88456,11 +89060,8 @@ class DistanceMeasurementsMouseControl extends DistanceMeasurementsControl {
88456
89060
  const getLeft = el => el.offsetLeft + (el.offsetParent && (el.offsetParent !== canvas.parentNode) && getLeft(el.offsetParent));
88457
89061
 
88458
89062
  const pagePos = math.vec2();
88459
-
88460
- this._onCameraControlHoverSnapOrSurface = cameraControl.on(
88461
- this._snapping
88462
- ? "hoverSnapOrSurface"
88463
- : "hoverSurface", event => {
89063
+
89064
+ const hoverOn = event => {
88464
89065
  const canvasPos = event.snappedCanvasPos || event.canvasPos;
88465
89066
  mouseHovering = true;
88466
89067
  pointerWorldPos.set(event.worldPos);
@@ -88513,7 +89114,9 @@ class DistanceMeasurementsMouseControl extends DistanceMeasurementsControl {
88513
89114
  this._markerDiv.style.left = `-10000px`;
88514
89115
  this._markerDiv.style.top = `-10000px`;
88515
89116
  }
88516
- });
89117
+ };
89118
+ this._onHoverSnapOrSurface = cameraControl.on("hoverSnapOrSurface", e => { if (this._snapping) hoverOn(e); });
89119
+ this._onHoverSurface = cameraControl.on("hoverSurface", e => { if (! this._snapping) hoverOn(e); });
88517
89120
 
88518
89121
  canvas.addEventListener('mousedown', this._onMouseDown = (e) => {
88519
89122
  if (e.which !== 1) {
@@ -88574,10 +89177,7 @@ class DistanceMeasurementsMouseControl extends DistanceMeasurementsControl {
88574
89177
  }
88575
89178
  });
88576
89179
 
88577
- this._onCameraControlHoverSnapOrSurfaceOff = cameraControl.on(
88578
- this._snapping
88579
- ? "hoverSnapOrSurfaceOff"
88580
- : "hoverOff", event => {
89180
+ const hoverOff = event => {
88581
89181
  if (this.pointerLens) {
88582
89182
  this.pointerLens.visible = true;
88583
89183
  this.pointerLens.canvasPos = event.canvasPos;
@@ -88592,7 +89192,9 @@ class DistanceMeasurementsMouseControl extends DistanceMeasurementsControl {
88592
89192
  this._currentDistanceMeasurement.axisVisible = false;
88593
89193
  }
88594
89194
  canvas.style.cursor = "default";
88595
- });
89195
+ };
89196
+ this._onHoverSnapOrSurfaceOff = cameraControl.on("hoverSnapOrSurfaceOff", e => { if (this._snapping) hoverOff(e); });
89197
+ this._onHoverOff = cameraControl.on("hoverOff", e => { if (! this._snapping) hoverOff(e); });
88596
89198
 
88597
89199
  this._active = true;
88598
89200
  }
@@ -88606,27 +89208,24 @@ class DistanceMeasurementsMouseControl extends DistanceMeasurementsControl {
88606
89208
  if (!this._active) {
88607
89209
  return;
88608
89210
  }
88609
-
89211
+
88610
89212
  this.fire("activated", false);
88611
89213
 
88612
89214
  if (this.pointerLens) {
88613
89215
  this.pointerLens.visible = false;
88614
89216
  }
88615
- // if (this._markerDiv) {
88616
- // this._destroyMarkerDiv()
88617
- // }
88618
- // this.reset();
89217
+
89218
+ this.reset();
89219
+
88619
89220
  const canvas = this.scene.canvas.canvas;
88620
89221
  canvas.removeEventListener("mousedown", this._onMouseDown);
88621
89222
  canvas.removeEventListener("mouseup", this._onMouseUp);
88622
89223
  const cameraControl = this.distanceMeasurementsPlugin.viewer.cameraControl;
88623
- cameraControl.off(this._onCameraControlHoverSnapOrSurface);
88624
- cameraControl.off(this._onCameraControlHoverSnapOrSurfaceOff);
88625
- // if (this._currentDistanceMeasurement) {
88626
- // this.distanceMeasurementsPlugin.fire("measurementCancel", this._currentDistanceMeasurement);
88627
- // this._currentDistanceMeasurement.destroy();
88628
- // this._currentDistanceMeasurement = null;
88629
- // }
89224
+ cameraControl.off(this._onHoverSnapOrSurface);
89225
+ cameraControl.off(this._onHoverSurface);
89226
+ cameraControl.off(this._onHoverSnapOrSurfaceOff);
89227
+ cameraControl.off(this._onHoverOff);
89228
+
88630
89229
  this._active = false;
88631
89230
  }
88632
89231
 
@@ -89310,11 +89909,8 @@ class DistanceMeasurementsTouchControl extends DistanceMeasurementsControl {
89310
89909
  targetVisible: null,
89311
89910
  };
89312
89911
 
89313
- this._onCanvasTouchStart = null;
89314
- this._onCanvasTouchEnd = null;
89315
89912
  this._longTouchTimeoutMs = 300;
89316
89913
  this._snapping = cfg.snapping !== false;
89317
- this._touchState = WAITING_FOR_ORIGIN_TOUCH_START;
89318
89914
 
89319
89915
  this._attachPlugin(distanceMeasurementsPlugin, cfg);
89320
89916
  }
@@ -89347,20 +89943,10 @@ class DistanceMeasurementsTouchControl extends DistanceMeasurementsControl {
89347
89943
  *
89348
89944
  * This is `true` by default.
89349
89945
  *
89350
- * Internally, this deactivates then activates the DistanceMeasurementsTouchControl when changed, which means that
89351
- * it will destroy any DistanceMeasurements currently under construction, and incurs some overhead, since it unbinds
89352
- * and rebinds various input handlers.
89353
- *
89354
89946
  * @param {boolean} snapping Whether to enable snap-to-vertex and snap-edge for this DistanceMeasurementsTouchControl.
89355
89947
  */
89356
89948
  set snapping(snapping) {
89357
- if (snapping !== this._snapping) {
89358
- this._snapping = snapping;
89359
- this.deactivate();
89360
- this.activate();
89361
- } else {
89362
- this._snapping = snapping;
89363
- }
89949
+ this._snapping = snapping;
89364
89950
  }
89365
89951
 
89366
89952
  /**
@@ -89972,14 +90558,11 @@ class DistanceMeasurementsTouchControl extends DistanceMeasurementsControl {
89972
90558
  this.plugin.pointerLens.visible = false;
89973
90559
  }
89974
90560
  this.reset();
90561
+
89975
90562
  const canvas = this.plugin.viewer.scene.canvas.canvas;
89976
90563
  canvas.removeEventListener("touchstart", this._onCanvasTouchStart);
89977
90564
  canvas.removeEventListener("touchend", this._onCanvasTouchEnd);
89978
- if (this._currentDistanceMeasurement) {
89979
- this.distanceMeasurementsPlugin.fire("measurementCancel", this._currentDistanceMeasurement);
89980
- this._currentDistanceMeasurement.destroy();
89981
- this._currentDistanceMeasurement = null;
89982
- }
90565
+
89983
90566
  this._active = false;
89984
90567
  this.plugin.viewer.cameraControl.active = true;
89985
90568
  }
@@ -89995,12 +90578,12 @@ class DistanceMeasurementsTouchControl extends DistanceMeasurementsControl {
89995
90578
  if (!this._active) {
89996
90579
  return;
89997
90580
  }
90581
+
89998
90582
  if (this._currentDistanceMeasurement) {
89999
90583
  this.distanceMeasurementsPlugin.fire("measurementCancel", this._currentDistanceMeasurement);
90000
90584
  this._currentDistanceMeasurement.destroy();
90001
90585
  this._currentDistanceMeasurement = null;
90002
90586
  }
90003
- this._mouseState = WAITING_FOR_ORIGIN_TOUCH_START;
90004
90587
  }
90005
90588
 
90006
90589
  /**
@@ -97161,7 +97744,7 @@ class MousePickHandler {
97161
97744
 
97162
97745
  this._timeout = setTimeout(() => {
97163
97746
 
97164
- if (firstClickPickResult) {
97747
+ if (firstClickPickResult && firstClickPickResult.worldPos) {
97165
97748
 
97166
97749
  cameraControl.fire("picked", firstClickPickResult, true);
97167
97750
 
@@ -109086,7 +109669,7 @@ class Viewer {
109086
109669
  * @throws {String} Throws an exception when both canvasId or canvasElement are missing or they aren't pointing to a valid HTMLCanvasElement.
109087
109670
  * @param {Boolean} [cfg.alphaDepthMask=true] Whether writing into the depth buffer is enabled or disabled when rendering transparent objects.
109088
109671
  * @param {Boolean} [cfg.entityOffsetsEnabled=false] Whether to enable {@link Entity#offset}. For best performance, only set this ````true```` when you need to use {@link Entity#offset}.
109089
- * @param {Boolean} [cfg.pickSurfacePrecisionEnabled=false] Whether to enable full-precision accuracy when surface picking with {@link Scene#pick}. Note that when ````true````, this configuration will increase the amount of browser memory used by the Viewer. The ````pickSurfacePrecision```` option for ````Scene#pick```` only works if this is set ````true````.
109672
+ * @param {Boolean} [cfg.readableGeometryEnabled=false] Whether to enable full-precision accuracy when surface picking with {@link Scene#pick}. Note that when ````true````, this configuration will increase the amount of browser memory used by the Viewer. The ````pickSurfacePrecision```` option for ````Scene#pick```` only works if this is set ````true````.
109090
109673
  * @param {Boolean} [cfg.logarithmicDepthBufferEnabled=false] Whether to enable logarithmic depth buffer. When this is true,
109091
109674
  * you can set huge values for {@link Perspective#far} and {@link Ortho#far}, to push the far clipping plane back so
109092
109675
  * that it does not clip huge models.
@@ -109156,7 +109739,7 @@ class Viewer {
109156
109739
  saoEnabled: cfg.saoEnabled,
109157
109740
  alphaDepthMask: (cfg.alphaDepthMask !== false),
109158
109741
  entityOffsetsEnabled: (!!cfg.entityOffsetsEnabled),
109159
- pickSurfacePrecisionEnabled: (!!cfg.pickSurfacePrecisionEnabled),
109742
+ readableGeometryEnabled: (!!cfg.readableGeometryEnabled),
109160
109743
  logarithmicDepthBufferEnabled: (!!cfg.logarithmicDepthBufferEnabled),
109161
109744
  pbrEnabled: (!!cfg.pbrEnabled),
109162
109745
  colorTextureEnabled: (cfg.colorTextureEnabled !== false),
@@ -122942,13 +123525,43 @@ class StoreyViewsPlugin extends Plugin {
122942
123525
  getStoreyContainingWorldPos(worldPos) {
122943
123526
  for (var storeyId in this.storeys) {
122944
123527
  const storey = this.storeys[storeyId];
122945
- if (math.point3AABB3Intersect(storey.storeyAABB, worldPos)) {
123528
+ if (math.point3AABB3AbsoluteIntersect(storey.storeyAABB, worldPos)) {
122946
123529
  return storeyId;
122947
123530
  }
122948
123531
  }
122949
123532
  return null;
122950
123533
  }
122951
123534
 
123535
+ /**
123536
+ * Gets the ID of the storey which's bounding box contains the y point of the world position
123537
+ *
123538
+ * @param {Number[]} worldPos 3D World-space position.
123539
+ * @returns {String} ID of the storey containing the position, or null if the position falls outside all the storeys.
123540
+ */
123541
+ getStoreyInVerticalRange(worldPos) {
123542
+ for(let storeyId in this.storeys) {
123543
+ const storey = this.storeys[storeyId];
123544
+ const aabb = [0,0,0,0,0,0], pos = [0,0,0];
123545
+ aabb[1] = storey.storeyAABB[1];
123546
+ aabb[4] = storey.storeyAABB[4];
123547
+ pos[1] = worldPos[1];
123548
+ if (math.point3AABB3AbsoluteIntersect(aabb, pos)) {
123549
+ return storeyId;
123550
+ }
123551
+ }
123552
+ return null;
123553
+ }
123554
+
123555
+ isPositionAboveOrBelowBuilding(worldPos){
123556
+ const keys = Object.keys(this.storeys);
123557
+ const ids = [keys[0], keys[keys.length-1]];
123558
+ if(worldPos[1] < this.storeys[ids[0]].storeyAABB[1])
123559
+ return ids[0];
123560
+ else if (worldPos[1] > this.storeys[ids[1]].storeyAABB[4])
123561
+ return ids[1];
123562
+ return null;
123563
+ }
123564
+
122952
123565
  /**
122953
123566
  * Converts a 3D World-space position to a 2D position within a StoreyMap image.
122954
123567
  *
@@ -131836,6 +132449,9 @@ class XKTLoaderPlugin extends Plugin {
131836
132449
  this.viewer.scene.canvas.spinner.processes++;
131837
132450
 
131838
132451
  const finish = () => {
132452
+ if (sceneModel.destroyed) {
132453
+ return;
132454
+ }
131839
132455
  // this._createDefaultMetaModelIfNeeded(sceneModel, params, options);
131840
132456
  sceneModel.finalize();
131841
132457
  metaModel.finalize();
@@ -131917,7 +132533,9 @@ class XKTLoaderPlugin extends Plugin {
131917
132533
  const loadJSONs = (metaDataFiles, done, error) => {
131918
132534
  let i = 0;
131919
132535
  const loadNext = () => {
131920
- if (i >= metaDataFiles.length) {
132536
+ if (sceneModel.destroyed) {
132537
+ done();
132538
+ } else if (i >= metaDataFiles.length) {
131921
132539
  done();
131922
132540
  } else {
131923
132541
  this._dataSource.getMetaModel(`${baseDir}${metaDataFiles[i]}`, (metaModelData) => {
@@ -131927,7 +132545,7 @@ class XKTLoaderPlugin extends Plugin {
131927
132545
  globalizeObjectIds: options.globalizeObjectIds
131928
132546
  });
131929
132547
  i++;
131930
- this.scheduleTask(loadNext, 100);
132548
+ this.scheduleTask(loadNext, 200);
131931
132549
  }, error);
131932
132550
  }
131933
132551
  };
@@ -131936,13 +132554,16 @@ class XKTLoaderPlugin extends Plugin {
131936
132554
  const loadXKTs_excludeTheirMetaModels = (xktFiles, done, error) => { // Load XKTs, ignore metamodels in the XKT
131937
132555
  let i = 0;
131938
132556
  const loadNext = () => {
131939
- if (i >= xktFiles.length) {
132557
+ if (sceneModel.destroyed) {
132558
+ done();
132559
+ } else if (i >= xktFiles.length) {
131940
132560
  done();
131941
132561
  } else {
131942
132562
  this._dataSource.getXKT(`${baseDir}${xktFiles[i]}`, (arrayBuffer) => {
131943
132563
  this._parseModel(arrayBuffer, params, options, sceneModel, null /* Ignore metamodel in XKT */, manifestCtx);
132564
+ sceneModel.preFinalize();
131944
132565
  i++;
131945
- this.scheduleTask(loadNext, 100);
132566
+ this.scheduleTask(loadNext, 200);
131946
132567
  }, error);
131947
132568
  }
131948
132569
  };
@@ -131951,13 +132572,16 @@ class XKTLoaderPlugin extends Plugin {
131951
132572
  const loadXKTs_includeTheirMetaModels = (xktFiles, done, error) => { // Load XKTs, parse metamodels from the XKT
131952
132573
  let i = 0;
131953
132574
  const loadNext = () => {
131954
- if (i >= xktFiles.length) {
132575
+ if (sceneModel.destroyed) {
132576
+ done();
132577
+ } else if (i >= xktFiles.length) {
131955
132578
  done();
131956
132579
  } else {
131957
132580
  this._dataSource.getXKT(`${baseDir}${xktFiles[i]}`, (arrayBuffer) => {
131958
132581
  this._parseModel(arrayBuffer, params, options, sceneModel, metaModel, manifestCtx);
132582
+ sceneModel.preFinalize();
131959
132583
  i++;
131960
- this.scheduleTask(loadNext, 100);
132584
+ this.scheduleTask(loadNext, 200);
131961
132585
  }, error);
131962
132586
  }
131963
132587
  };
@@ -132007,11 +132631,12 @@ class XKTLoaderPlugin extends Plugin {
132007
132631
  _loadModel(src, params, options, sceneModel, metaModel, manifestCtx, done, error) {
132008
132632
  this._dataSource.getXKT(params.src, (arrayBuffer) => {
132009
132633
  this._parseModel(arrayBuffer, params, options, sceneModel, metaModel, manifestCtx);
132634
+ sceneModel.preFinalize();
132010
132635
  done();
132011
132636
  }, error);
132012
132637
  }
132013
132638
 
132014
- _parseModel(arrayBuffer, params, options, sceneModel, metaModel, manifestCtx) {
132639
+ async _parseModel(arrayBuffer, params, options, sceneModel, metaModel, manifestCtx) {
132015
132640
  if (sceneModel.destroyed) {
132016
132641
  return;
132017
132642
  }
@@ -132023,7 +132648,7 @@ class XKTLoaderPlugin extends Plugin {
132023
132648
  this.error("Unsupported .XKT file version: " + xktVersion + " - this XKTLoaderPlugin supports versions " + Object.keys(parsers));
132024
132649
  return;
132025
132650
  }
132026
- this.log("Loading .xkt V" + xktVersion);
132651
+ // this.log("Loading .xkt V" + xktVersion);
132027
132652
  const numElements = dataView.getUint32(4, true);
132028
132653
  const elements = [];
132029
132654
  let byteOffset = (numElements + 2) * 4;
@@ -138785,7 +139410,7 @@ const triangulateEarClipping = function(planeCoords) {
138785
139410
  next.prev = ear.prev;
138786
139411
  }
138787
139412
 
138788
- return [ planeCoords, baseTriangles ];
139413
+ return [ planeCoords, baseTriangles, isCCW ];
138789
139414
  };
138790
139415
 
138791
139416
  const marker3D = function(scene, color) {
@@ -139307,7 +139932,7 @@ class Zone extends Component {
139307
139932
  const altitude = this._geometry.altitude + (downward ? this._geometry.height : 0);
139308
139933
  const height = this._geometry.height * (downward ? -1 : 1);
139309
139934
 
139310
- const [ baseVertices, baseTriangles ] = triangulateEarClipping(planeCoords); // TODO: prevent crossing edges
139935
+ const [ baseVertices, baseTriangles, isCCW ] = triangulateEarClipping(planeCoords); // TODO: prevent crossing edges
139311
139936
 
139312
139937
  const pos = [ ];
139313
139938
  const ind = [ ];
@@ -139331,7 +139956,7 @@ class Zone extends Component {
139331
139956
  // sides
139332
139957
  for (let i = 0; i < baseVertices.length; ++i) {
139333
139958
  const a = baseVertices[i];
139334
- const b = baseVertices[(i+1) % baseVertices.length];
139959
+ const b = baseVertices[(baseVertices.length + i + (isCCW ? 1 : -1)) % baseVertices.length];
139335
139960
  const f = altitude;
139336
139961
  const c = altitude + height;
139337
139962
 
@@ -139374,6 +139999,28 @@ class Zone extends Component {
139374
139999
 
139375
140000
  this._zoneMesh.zone = this;
139376
140001
 
140002
+ {
140003
+ const u = math.vec2();
140004
+ const v = math.vec2();
140005
+
140006
+ let baseArea = 0;
140007
+
140008
+ for (let t of baseTriangles) {
140009
+ const p0 = baseVertices[t[0]];
140010
+ const p1 = baseVertices[t[1]];
140011
+ const p2 = baseVertices[t[2]];
140012
+
140013
+ math.subVec2(p1, p0, u);
140014
+ math.subVec2(p2, p0, v);
140015
+
140016
+ baseArea += Math.abs(u[0] * v[1] - u[1] * v[0]);
140017
+ }
140018
+
140019
+ this._baseArea = baseArea / 2;
140020
+ }
140021
+
140022
+ this._metrics = null;
140023
+
139377
140024
 
139378
140025
  const min = idx => Math.min(...pos.map(p => p[idx]));
139379
140026
  const max = idx => Math.max(...pos.map(p => p[idx]));
@@ -139388,6 +140035,48 @@ class Zone extends Component {
139388
140035
  this._center = math.vec3([ (xmin + xmax) / 2, (ymin + ymax) / 2, (zmin + zmax) / 2 ]);
139389
140036
  }
139390
140037
 
140038
+ get baseArea() {
140039
+ return this._baseArea;
140040
+ }
140041
+
140042
+ get area() {
140043
+ return this._getMetrics().area;
140044
+ }
140045
+
140046
+ get volume() {
140047
+ return this._getMetrics().volume;
140048
+ }
140049
+
140050
+ _getMetrics() {
140051
+ if (this._metrics === null) {
140052
+ // Sum the volume of tetrahedrons formed by the origin and face triangles
140053
+ let volume = 0;
140054
+ let area = 0;
140055
+ const geo = this._zoneMesh.geometry;
140056
+ const pts = [ math.vec3(), math.vec3(), math.vec3() ];
140057
+ const tmpVec3 = math.vec3();
140058
+ for (let i = 0; i < geo.indices.length; i += 3) {
140059
+ for (let off = 0; off < 3; ++off) {
140060
+ const p = pts[off];
140061
+ const pIdx = 3 * geo.indices[i + off];
140062
+ for (let c = 0; c < 3; ++c) {
140063
+ p[c] = geo.positions[pIdx + c];
140064
+ }
140065
+ }
140066
+ volume += math.dotVec3(pts[0], math.cross3Vec3(pts[1], pts[2], tmpVec3));
140067
+ math.subVec3(pts[1], pts[0], pts[1]);
140068
+ math.subVec3(pts[2], pts[0], pts[2]);
140069
+ area += math.lenVec3(math.cross3Vec3(pts[1], pts[2], tmpVec3));
140070
+ }
140071
+
140072
+ this._metrics = {
140073
+ area: area / 2,
140074
+ volume: volume / 6
140075
+ };
140076
+ }
140077
+ return this._metrics;
140078
+ }
140079
+
139391
140080
  sectionedAverage(sectionPlanes) {
139392
140081
  const planeCoords = this._geometry.planeCoordinates.slice();
139393
140082
 
@@ -140544,6 +141233,7 @@ exports.DefaultLoadingManager = DefaultLoadingManager;
140544
141233
  exports.DepthFormat = DepthFormat;
140545
141234
  exports.DepthStencilFormat = DepthStencilFormat;
140546
141235
  exports.DirLight = DirLight;
141236
+ exports.DistanceMeasurementEditControl = DistanceMeasurementEditControl;
140547
141237
  exports.DistanceMeasurementEditMouseControl = DistanceMeasurementEditMouseControl;
140548
141238
  exports.DistanceMeasurementEditTouchControl = DistanceMeasurementEditTouchControl;
140549
141239
  exports.DistanceMeasurementsControl = DistanceMeasurementsControl;
@@ -140588,6 +141278,8 @@ exports.Marker = Marker;
140588
141278
  exports.MarqueePicker = MarqueePicker;
140589
141279
  exports.MarqueePickerMouseControl = MarqueePickerMouseControl;
140590
141280
  exports.Mesh = Mesh;
141281
+ exports.MeshSurfaceArea = MeshSurfaceArea;
141282
+ exports.MeshVolume = MeshVolume;
140591
141283
  exports.MetallicMaterial = MetallicMaterial;
140592
141284
  exports.MirroredRepeatWrapping = MirroredRepeatWrapping;
140593
141285
  exports.ModelMemento = ModelMemento;
@@ -140706,9 +141398,12 @@ exports.createRTCViewMat = createRTCViewMat;
140706
141398
  exports.frustumIntersectsAABB3 = frustumIntersectsAABB3;
140707
141399
  exports.getKTX2TextureTranscoder = getKTX2TextureTranscoder;
140708
141400
  exports.getPlaneRTCPos = getPlaneRTCPos;
141401
+ exports.isTriangleMeshSolid = isTriangleMeshSolid;
140709
141402
  exports.load3DSGeometry = load3DSGeometry;
140710
141403
  exports.loadOBJGeometry = loadOBJGeometry;
140711
141404
  exports.math = math;
141405
+ exports.meshSurfaceArea = meshSurfaceArea;
141406
+ exports.meshVolume = meshVolume;
140712
141407
  exports.rtcToWorldPos = rtcToWorldPos;
140713
141408
  exports.sRGBEncoding = sRGBEncoding;
140714
141409
  exports.setFrustum = setFrustum;