@xeokit/xeokit-sdk 2.6.95 → 2.6.96

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.
@@ -1,11 +1,11 @@
1
1
  /**
2
- * xeokit-sdk v2.6.95
3
- * Commit: ff66e348fc6786a85f8ff8732f9876d63e3782d6
4
- * Built: 2025-11-18T12:58:25.225Z
2
+ * xeokit-sdk v2.6.96
3
+ * Commit: c76eb4c08555d55fdd54313f5fb25481d28d1150
4
+ * Built: 2025-12-02T12:22:54.826Z
5
5
  */
6
6
 
7
7
  if (typeof window !== 'undefined') {
8
- window.__XEOKIT__ = { version: '2.6.95', commit: 'ff66e348fc6786a85f8ff8732f9876d63e3782d6', built: '2025-11-18T12:58:25.225Z' };
8
+ window.__XEOKIT__ = { version: '2.6.96', commit: 'c76eb4c08555d55fdd54313f5fb25481d28d1150', built: '2025-12-02T12:22:54.826Z' };
9
9
  }
10
10
 
11
11
  /** @private */
@@ -7433,9 +7433,12 @@ math.makeSectionPlaneSlicer = (function() {
7433
7433
  math.vec3();
7434
7434
 
7435
7435
  const triangle = [ math.vec3(), math.vec3(), math.vec3() ];
7436
+ const tmpIntersections = [ null, null, null ];
7437
+ const tmpPositions = [ null, null, null ];
7438
+ const tmpReferences = [ null, null, null ];
7436
7439
 
7437
- const worldUp = [0, 1, 0];
7438
7440
  const worldRight = [1, 0, 0];
7441
+ const worldUp = [0, 1, 0];
7439
7442
  const worldForward = [0, 0, 1];
7440
7443
 
7441
7444
  const sqDistVec3 = (function() {
@@ -7450,84 +7453,113 @@ math.makeSectionPlaneSlicer = (function() {
7450
7453
  return ret;
7451
7454
  };
7452
7455
 
7453
- const setCoord2D = (p, dst) => { dst[0] = p.coord2Dx; dst[1] = p.coord2Dy; return dst; };
7454
-
7455
7456
  const ccw = (a, b, c) => ((c[1] - a[1]) * (b[0] - a[0])) > ((b[1] - a[1]) * (c[0] - a[0]));
7456
7457
 
7457
- const isLoopInside = (inner, outer) => {
7458
- const bbI = inner.boundingBox;
7459
- const bbO = outer.boundingBox;
7460
- if ((bbI[0] < bbO[0]) || (bbI[1] < bbO[1]) || (bbI[2] > bbO[2]) || (bbI[3] > bbO[3])) {
7461
- return false;
7462
- }
7458
+ return function(plane) {
7459
+ const planeU = math.vec3ApplyQuaternion(plane.quaternion, worldRight, math.vec3());
7460
+ const planeV = math.vec3ApplyQuaternion(plane.quaternion, worldUp, math.vec3());
7461
+ const planeN = math.vec3ApplyQuaternion(plane.quaternion, worldForward, math.vec3());
7463
7462
 
7464
- const innerEndpoints = inner.endPoints;
7465
- const outerEndpoints = outer.endPoints;
7466
- for (let ii = 0, ij = innerEndpoints.length - 1; ii < innerEndpoints.length; ij = ii++) {
7467
- const i0 = setCoord2D(innerEndpoints[ii], tempVec2a);
7468
- const [i0x, i0y] = i0;
7469
- const i1 = setCoord2D(innerEndpoints[ij], tempVec2b);
7463
+ return function(mesh, cfg = { }) {
7464
+ const planeToMesh = math.subVec3(mesh.origin, plane.pos, math.vec3());
7465
+ const planeDist = math.dotVec3(planeN, planeToMesh);
7466
+
7467
+ const unsortedSegment = [ ];
7468
+ const indexedPositions = [ null ]; // to never return 0 from addPosition, so its result can be used as a predicate
7469
+ const addPosition = (p, addUV) => {
7470
+ const idx = indexedPositions.length;
7471
+ const P = new Float64Array(5);
7472
+ P.set(p);
7473
+ if (addUV) {
7474
+ math.addVec3(planeToMesh, p, tempVec3a);
7475
+ P[3] = -math.dotVec3(planeU, tempVec3a);
7476
+ P[4] = math.dotVec3(planeV, tempVec3a);
7477
+ }
7478
+ indexedPositions.push(P);
7479
+ return idx;
7480
+ };
7470
7481
 
7471
- let inside = false;
7472
- for (let i = 0, j = outerEndpoints.length - 1; i < outerEndpoints.length; j = i++) {
7473
- const o0 = setCoord2D(outerEndpoints[i], tempVec2c);
7474
- const o1 = setCoord2D(outerEndpoints[j], tempVec2d);
7482
+ const getCoord2D = (idx, dst) => { const P = indexedPositions[idx]; dst[0] = P[3]; dst[1] = P[4]; return dst; };
7475
7483
 
7476
- if ((ccw(i0, o0, o1) !== ccw(i1, o0, o1)) && (ccw(i0, i1, o0) !== ccw(i0, i1, o1))) {
7477
- return false; // segments intersect
7484
+ const isLoopInside = (inner, outer) => {
7485
+ const bbI = inner.boundingBox;
7486
+ const bbO = outer.boundingBox;
7487
+ if ((bbI[0] < bbO[0]) || (bbI[1] < bbO[1]) || (bbI[2] > bbO[2]) || (bbI[3] > bbO[3])) {
7488
+ return false;
7478
7489
  }
7479
7490
 
7480
- const [o0x, o0y] = o0;
7481
- const [o1x, o1y] = o1;
7491
+ const innerEndpoints = inner.endPoints;
7492
+ const outerEndpoints = outer.endPoints;
7493
+ for (let ii = 0, ij = innerEndpoints.length - 1; ii < innerEndpoints.length; ij = ii++) {
7494
+ const i0 = getCoord2D(innerEndpoints[ii], tempVec2a);
7495
+ const [i0x, i0y] = i0;
7496
+ const i1 = getCoord2D(innerEndpoints[ij], tempVec2b);
7482
7497
 
7483
- const dx = i0x - o0x;
7484
- const dy = i0y - o0y;
7498
+ let inside = false;
7499
+ for (let i = 0, j = outerEndpoints.length - 1; i < outerEndpoints.length; j = i++) {
7500
+ const o0 = getCoord2D(outerEndpoints[i], tempVec2c);
7501
+ const o1 = getCoord2D(outerEndpoints[j], tempVec2d);
7485
7502
 
7486
- const oDx = o1x - o0x;
7487
- const oDy = o1y - o0y;
7503
+ if ((ccw(i0, o0, o1) !== ccw(i1, o0, o1)) && (ccw(i0, i1, o0) !== ccw(i0, i1, o1))) {
7504
+ return false; // segments intersect
7505
+ }
7488
7506
 
7489
- const dot = (((oDx !== 0) || (oDy !== 0)) && (Math.abs(oDx * dy - oDy * dx) < 1e-10)) ? (dx * oDx + dy * oDy) : -1;
7490
- if ((dot >= 0) && (dot <= (Math.pow(oDx, 2) + Math.pow(oDy, 2)))) {
7491
- return false; // on edge
7492
- }
7507
+ const [o0x, o0y] = o0;
7508
+ const [o1x, o1y] = o1;
7509
+
7510
+ const dx = i0x - o0x;
7511
+ const dy = i0y - o0y;
7493
7512
 
7494
- if (((o0y > i0y) !== (o1y > i0y)) && (dx < (dy * oDx / oDy))) {
7495
- inside = !inside;
7513
+ const oDx = o1x - o0x;
7514
+ const oDy = o1y - o0y;
7515
+
7516
+ const dot = (((oDx !== 0) || (oDy !== 0)) && (Math.abs(oDx * dy - oDy * dx) < 1e-10)) ? (dx * oDx + dy * oDy) : -1;
7517
+ if ((dot >= 0) && (dot <= (Math.pow(oDx, 2) + Math.pow(oDy, 2)))) {
7518
+ return false; // on edge
7519
+ }
7520
+
7521
+ if (((o0y > i0y) !== (o1y > i0y)) && (dx < (dy * oDx / oDy))) {
7522
+ inside = !inside;
7523
+ }
7524
+ }
7525
+ if (! inside) {
7526
+ return false;
7527
+ }
7496
7528
  }
7497
- }
7498
- if (! inside) {
7499
- return false;
7500
- }
7501
- }
7502
7529
 
7503
- return true;
7504
- };
7530
+ return true;
7531
+ };
7505
7532
 
7506
- return function(planePos, planeRot) {
7507
- const planeU = math.vec3ApplyQuaternion(planeRot, worldRight, math.vec3());
7508
- const planeV = math.vec3ApplyQuaternion(planeRot, worldUp, math.vec3());
7509
- const planeN = math.vec3ApplyQuaternion(planeRot, worldForward, math.vec3());
7533
+ const pos = { indices: [ ], normals: [ ] };
7534
+ const neg = (! cfg.onlyPosSliceWithUV) && { indices: [ ], normals: [ ] };
7510
7535
 
7511
- return function(meshCenter, meshIndices, meshPositions) {
7512
- const planeToMesh = math.subVec3(meshCenter, planePos, math.vec3());
7513
- const planeDist = math.dotVec3(planeN, planeToMesh);
7536
+ const appendOnSide = (dst, indices, normal) => {
7537
+ if (dst) {
7538
+ const p0 = indexedPositions[indices[0]];
7539
+ normal ||= math.normalizeVec3(math.cross3Vec3(math.subVec3(indexedPositions[indices[1]], p0, tempVec3a),
7540
+ math.subVec3(indexedPositions[indices[2]], p0, tempVec3b),
7541
+ tempVec3a),
7542
+ tempVec3a);
7514
7543
 
7515
- const unsortedSegment = [ ];
7516
- const indexedPositions = [ null ]; // to never return 0 from addPosition, so its result can be used as a predicate
7517
- const addPosition = p => { const idx = indexedPositions.length; indexedPositions.push(math.vec3(p)); return idx; };
7544
+ for (let i = 0; i < 3; ++i) {
7545
+ dst.indices.push(indices[i]);
7546
+ dst.normals.push(normal[0], normal[1], normal[2]);
7547
+ }
7548
+ }
7549
+ };
7518
7550
 
7519
7551
  const setVertex = (i, dst) => {
7520
- const idx = meshIndices[i] * 3;
7521
- dst[0] = meshPositions[idx + 0];
7522
- dst[1] = meshPositions[idx + 1];
7523
- dst[2] = meshPositions[idx + 2];
7552
+ const idx = mesh.indices[i] * 3;
7553
+ dst[0] = mesh.positions[idx + 0];
7554
+ dst[1] = mesh.positions[idx + 1];
7555
+ dst[2] = mesh.positions[idx + 2];
7524
7556
  return dst;
7525
7557
  };
7526
7558
 
7527
- for (let meshIdx = 0; meshIdx < meshIndices.length; meshIdx += 3) {
7528
- const p0 = setVertex(meshIdx + 0, triangle[0]);
7529
- const p1 = setVertex(meshIdx + 1, triangle[1]);
7530
- const p2 = setVertex(meshIdx + 2, triangle[2]);
7559
+ for (let faceIdx = 0; faceIdx < mesh.indices.length; faceIdx += 3) {
7560
+ const p0 = setVertex(faceIdx + 0, triangle[0]);
7561
+ const p1 = setVertex(faceIdx + 1, triangle[1]);
7562
+ const p2 = setVertex(faceIdx + 2, triangle[2]);
7531
7563
 
7532
7564
  if (math.compareVec3(p0, p1) || math.compareVec3(p1, p2) || math.compareVec3(p2, p0)) {
7533
7565
  continue; // skip degenerate triangle
@@ -7538,12 +7570,60 @@ math.makeSectionPlaneSlicer = (function() {
7538
7570
  const d2 = planeDist + math.dotVec3(planeN, p2);
7539
7571
 
7540
7572
  if ((d0 !== 0) || (d1 !== 0) || (d2 !== 0)) {
7541
- const i0 = (d0 * d1 <= 0) && addPosition(math.lerpVec3(d0 / (d0 - d1), 0, 1, p0, p1, tempVec3a));
7542
- const i1 = (d1 * d2 <= 0) && addPosition(math.lerpVec3(d1 / (d1 - d2), 0, 1, p1, p2, tempVec3a));
7543
- const i2 = (d2 * d0 <= 0) && addPosition(math.lerpVec3(d2 / (d2 - d0), 0, 1, p2, p0, tempVec3a));
7573
+ const i0 = (d0 * d1 <= 0) && addPosition(math.lerpVec3(d0 / (d0 - d1), 0, 1, p0, p1, tempVec3a), true);
7574
+ const i1 = (d1 * d2 <= 0) && addPosition(math.lerpVec3(d1 / (d1 - d2), 0, 1, p1, p2, tempVec3a), true);
7575
+ const i2 = (d2 * d0 <= 0) && addPosition(math.lerpVec3(d2 / (d2 - d0), 0, 1, p2, p0, tempVec3a), true);
7576
+
7577
+ const p = (! cfg.onlyPosSliceWithUV) && tmpPositions;
7578
+ if (p) {
7579
+ p[0] = addPosition(p0);
7580
+ p[1] = addPosition(p1);
7581
+ p[2] = addPosition(p2);
7582
+ }
7544
7583
 
7545
7584
  if (i0 ? (i1 || i2) : (i1 && i2)) { // triangle intersected by the section plane
7546
7585
  unsortedSegment.push(i0 ? [ i0, i1 || i2 ] : [ i1, i2 ]);
7586
+
7587
+ if (p) {
7588
+ if ((d0 === 0) && (d1 === 0)) {
7589
+ appendOnSide((d2 > 0) ? pos : neg, p);
7590
+ } else if ((d0 === 0) && (d2 === 0)) {
7591
+ appendOnSide((d1 > 0) ? pos : neg, p);
7592
+ } else if ((d1 === 0) && (d2 === 0)) {
7593
+ appendOnSide((d0 > 0) ? pos : neg, p);
7594
+ } else {
7595
+ const isPos = (i0 ? d0 : d1) > 0;
7596
+ const dst0 = isPos ? pos : neg;
7597
+ const dst1 = isPos ? neg : pos;
7598
+ const i = tmpIntersections;
7599
+ i[0] = i0;
7600
+ i[1] = i1;
7601
+ i[2] = i2;
7602
+ const ref = tmpReferences;
7603
+ if (i0) {
7604
+ ref[0] = 0; ref[1] = 1; ref[2] = 2;
7605
+ } else {
7606
+ ref[0] = 1; ref[1] = 2; ref[2] = 0;
7607
+ }
7608
+ if (i[ref[1]]) {
7609
+ appendOnSide(dst0, [ p[ref[0]], i[ref[0]], p[ref[2]] ]);
7610
+ appendOnSide(dst0, [ i[ref[0]], i[ref[1]], p[ref[2]] ]);
7611
+ appendOnSide(dst1, [ i[ref[0]], p[ref[1]], i[ref[1]] ]);
7612
+ } else {
7613
+ appendOnSide(dst0, [ p[ref[0]], i[ref[0]], i[ref[2]] ]);
7614
+ appendOnSide(dst1, [ i[ref[0]], p[ref[1]], p[ref[2]] ]);
7615
+ appendOnSide(dst1, [ i[ref[0]], p[ref[2]], i[ref[2]] ]);
7616
+ }
7617
+ }
7618
+ }
7619
+ } else if (p) {
7620
+ if ((d0 >= 0) && (d1 >= 0) && (d2 >= 0)) {
7621
+ appendOnSide(pos, p);
7622
+ } else if ((d0 <= 0) && (d1 <= 0) && (d2 <= 0)) {
7623
+ appendOnSide(neg, p);
7624
+ } else {
7625
+ debugger;
7626
+ }
7547
7627
  }
7548
7628
  }
7549
7629
  }
@@ -7589,37 +7669,30 @@ math.makeSectionPlaneSlicer = (function() {
7589
7669
  }
7590
7670
 
7591
7671
  const loops = endpointLoops.filter(endPoints => endPoints.length > 2).map((endPoints, idx) => {
7592
- const planeEndpoints = endPoints.map(posIdx => {
7593
- const P = math.addVec3(planeToMesh, indexedPositions[posIdx], tempVec3a);
7594
- return { posIdx: posIdx, coord2Dx: math.dotVec3(planeU, P), coord2Dy: math.dotVec3(planeV, P) };
7595
- });
7596
7672
  let doubleArea = 0;
7597
7673
  const aabb = math.collapseAABB2(math.AABB2());
7598
- for (let i = 0; i < planeEndpoints.length; i++) {
7599
- const p0 = planeEndpoints[i];
7600
- tempVec2a[0] = p0.coord2Dx;
7601
- tempVec2a[1] = p0.coord2Dy;
7674
+ for (let i = 0; i < endPoints.length; i++) {
7675
+ getCoord2D(endPoints[i], tempVec2a);
7602
7676
  math.expandAABB2Point2(aabb, tempVec2a);
7603
- const p1 = planeEndpoints[(i + 1) % planeEndpoints.length];
7604
- doubleArea += (p0.coord2Dx * p1.coord2Dy - p1.coord2Dx * p0.coord2Dy);
7677
+ getCoord2D(endPoints[(i + 1) % endPoints.length], tempVec2b);
7678
+ doubleArea += (tempVec2a[0] * tempVec2b[1] - tempVec2b[0] * tempVec2a[1]);
7605
7679
  }
7606
7680
  return {
7607
7681
  boundingBox: aabb,
7608
7682
  doubleArea: Math.abs(doubleArea),
7609
- endPoints: planeEndpoints
7683
+ endPoints: endPoints
7610
7684
  };
7611
7685
  }).sort((a, b) => b.doubleArea - a.doubleArea);
7612
7686
 
7613
- const sliceGeometries = [ ];
7614
-
7615
7687
  while (loops.length > 0) {
7616
7688
  const vertices2D = [ ];
7617
7689
  const vertices3D = [ ];
7618
7690
 
7619
7691
  const appendLoopVertices = loop => loop.endPoints.forEach(endpoint2D => {
7620
- vertices2D.push(endpoint2D.coord2Dx, endpoint2D.coord2Dy);
7621
- vertices3D.push(endpoint2D.posIdx);
7622
- });
7692
+ getCoord2D(endpoint2D, tempVec2a);
7693
+ vertices2D.push(tempVec2a[0], tempVec2a[1]);
7694
+ vertices3D.push(endpoint2D);
7695
+ });
7623
7696
 
7624
7697
  const outerLoop = loops.shift();
7625
7698
  appendLoopVertices(outerLoop);
@@ -7641,41 +7714,33 @@ math.makeSectionPlaneSlicer = (function() {
7641
7714
  // Triangulate
7642
7715
  const triangles = earcut(vertices2D, innerLoops.map(loop => loop.index));
7643
7716
 
7644
- const positions = [ ];
7645
- const normals = [ ];
7646
- const uv = [ ];
7647
7717
  for (let i = 0; i < triangles.length; i += 3) {
7648
- const v0 = indexedPositions[vertices3D[triangles[i + 0]]];
7649
- const v1 = indexedPositions[vertices3D[triangles[i + 1]]];
7650
- const v2 = indexedPositions[vertices3D[triangles[i + 2]]];
7651
- math.subVec3(v1, v0, tempVec3b);
7652
- math.subVec3(v2, v0, tempVec3c);
7718
+ const ti = tmpIntersections;
7719
+ ti[0] = vertices3D[triangles[i + 0]];
7720
+ ti[1] = vertices3D[triangles[i + 1]];
7721
+ ti[2] = vertices3D[triangles[i + 2]];
7722
+ const v0 = indexedPositions[ti[0]];
7723
+ math.subVec3(indexedPositions[ti[1]], v0, tempVec3b);
7724
+ math.subVec3(indexedPositions[ti[2]], v0, tempVec3c);
7653
7725
  math.normalizeVec3(math.cross3Vec3(tempVec3b, tempVec3c, tempVec3c), tempVec3c);
7654
7726
  const facedPositively = math.dotVec3(tempVec3c, planeN) <= 0;
7655
- if (! facedPositively) {
7656
- math.negateVec3(tempVec3c, tempVec3c);
7657
- }
7658
- for (let j = 0; j < 3; ++j) {
7659
- const vIdx = triangles[i + (facedPositively ? j : (2 - j))];
7660
- const v = indexedPositions[vertices3D[vIdx]];
7661
- positions.push(v[0], v[1], v[2]);
7662
- normals.push(tempVec3c[0], tempVec3c[1], tempVec3c[2]);
7663
- const uvOff = 2 * vIdx;
7664
- uv.push(-vertices2D[uvOff], vertices2D[uvOff + 1]);
7665
- }
7666
- }
7667
-
7668
- if (positions.length > 0) {
7669
- sliceGeometries.push({
7670
- indices: iota(positions.length / 3),
7671
- positions: positions,
7672
- normals: normals,
7673
- uv: uv
7674
- });
7727
+ appendOnSide(facedPositively ? pos : neg, ti, tempVec3c);
7728
+ const tmp = ti[0]; ti[0] = ti[2]; ti[2] = tmp;
7729
+ appendOnSide(facedPositively ? neg : pos, ti, math.negateVec3(tempVec3c, tempVec3c));
7675
7730
  }
7676
7731
  }
7677
7732
 
7678
- return sliceGeometries;
7733
+ const side = src => src && (src.indices.length > 0) && (function() {
7734
+ const positions = [ ];
7735
+ const uv = cfg.onlyPosSliceWithUV && [ ];
7736
+ src.indices.forEach(idx => {
7737
+ const P = indexedPositions[idx];
7738
+ positions.push(P[0], P[1], P[2]);
7739
+ uv && uv.push(P[3], P[4]);
7740
+ });
7741
+ return { indices: iota(src.indices.length), positions: positions, normals: src.normals, uv: uv };
7742
+ })();
7743
+ return { pos: side(pos), neg: side(neg) };
7679
7744
  };
7680
7745
  };
7681
7746
  })();
@@ -31327,6 +31392,8 @@ class SceneModelMesh {
31327
31392
  */
31328
31393
  _destroy() {
31329
31394
  this.model.scene._renderer.putPickID(this.pickId);
31395
+
31396
+ this.layer = null;
31330
31397
  }
31331
31398
  }
31332
31399
 
@@ -31939,10 +32006,7 @@ const getRenderers = (function() {
31939
32006
  appendFragmentOutputs: programSetup.appendFragmentOutputs,
31940
32007
  cleanerEdges: programSetup.cleanerEdges,
31941
32008
  clipPos: clipPos,
31942
- clippableTest: (function() {
31943
- const vClippable = programVariables.createVarying("float", "vClippable", () => `${attributes.clippable} ? 1.0 : 0.0`, "flat");
31944
- return () => `${vClippable} > 0.0`;
31945
- })(),
32009
+ clippableTest: renderingAttributes.clippableTest,
31946
32010
  clippingCaps: programSetup.clippingCaps,
31947
32011
  crossSections: scene.crossSections,
31948
32012
  discardPoints: setupPoints && pointsMaterial.roundPoints,
@@ -33499,9 +33563,13 @@ const makeDTXRenderingAttributes = function(programVariables, isTriangle) {
33499
33563
  const colorsAndFlags = (offset) => perObjColsFlags(`ivec2(objectIndexCoords.x*8+${offset}, objectIndexCoords.y)`);
33500
33564
 
33501
33565
  return {
33566
+ clippableTest: (function() {
33567
+ const vClippable = programVariables.createVarying("uint", "vClippable", () => "flags2.r", "flat");
33568
+ return () => `${vClippable} > 0u`;
33569
+ })(),
33570
+
33502
33571
  geometryParameters: {
33503
33572
  attributes: {
33504
- clippable: "(flags2.r > 0u)",
33505
33573
  color: colorA,
33506
33574
  flags: iota$2(4).map(i => `int(flags[${i}])`),
33507
33575
  metallicRoughness: null,
@@ -33638,9 +33706,9 @@ function quantizePositions(positions, aabb, positionsDecodeMatrix) { // http://c
33638
33706
  const xmin = aabb[0];
33639
33707
  const ymin = aabb[1];
33640
33708
  const zmin = aabb[2];
33641
- const xwid = aabb[3] - xmin;
33642
- const ywid = aabb[4] - ymin;
33643
- const zwid = aabb[5] - zmin;
33709
+ const xwid = (aabb[3] - xmin) || 1;
33710
+ const ywid = (aabb[4] - ymin) || 1;
33711
+ const zwid = (aabb[5] - zmin) || 1;
33644
33712
  const maxInt = 65525;
33645
33713
  const xMultiplier = maxInt / xwid;
33646
33714
  const yMultiplier = maxInt / ywid;
@@ -33669,9 +33737,9 @@ function createPositionsDecodeMatrix(aabb, positionsDecodeMatrix) { // http://cg
33669
33737
  const xmin = aabb[0];
33670
33738
  const ymin = aabb[1];
33671
33739
  const zmin = aabb[2];
33672
- const xwid = aabb[3] - xmin;
33673
- const ywid = aabb[4] - ymin;
33674
- const zwid = aabb[5] - zmin;
33740
+ const xwid = (aabb[3] - xmin) || 1;
33741
+ const ywid = (aabb[4] - ymin) || 1;
33742
+ const zwid = (aabb[5] - zmin) || 1;
33675
33743
  const maxInt = 65525;
33676
33744
  math.identityMat4(translate$1);
33677
33745
  math.translationMat4v(aabb, translate$1);
@@ -34659,8 +34727,8 @@ class VBOLayer extends Layer {
34659
34727
  } else { // triangles
34660
34728
  if (subGeometry && subGeometry.vertices) {
34661
34729
  return drawPoints;
34662
- } else if (subGeometry && edgeIndicesBuf) {
34663
- return elementsDrawer(gl.LINES, edgeIndicesBuf);
34730
+ } else if (subGeometry) {
34731
+ return edgeIndicesBuf ? elementsDrawer(gl.LINES, edgeIndicesBuf) : (() => { });
34664
34732
  } else {
34665
34733
  return elementsDrawer(gl.TRIANGLES, indicesBuf);
34666
34734
  }
@@ -34742,9 +34810,13 @@ const makeVBORenderingAttributes = function(programVariables, instancing, entity
34742
34810
  return {
34743
34811
  dontCullOnAlphaZero: true,
34744
34812
 
34813
+ clippableTest: (function() {
34814
+ const vClippable = programVariables.createVarying("float", "vClippable", () => `${`((int(${attributes.flags}) >> 16 & 0xF) == 1)`} ? 1.0 : 0.0`); // Using `flat uint` for vClippable causes an instability - see XEOK-385
34815
+ return () => `${vClippable} != 0.0`;
34816
+ })(),
34817
+
34745
34818
  geometryParameters: {
34746
34819
  attributes: {
34747
- clippable: `((int(${attributes.flags}) >> 16 & 0xF) == 1)`,
34748
34820
  color: attributes.color,
34749
34821
  flags: iota$1(4).map(i => ({ toString: () => `(int(${attributes.flags}) >> ${i * 4} & 0xF)` })),
34750
34822
  metallicRoughness: attributes.metallicRoughness,
@@ -54010,7 +54082,7 @@ class SectionCaps {
54010
54082
  const visibleSceneModels = Object.values(scene.models).filter(sceneModel => (sceneModel.id in modelCaches) && sceneModel.visible);
54011
54083
  sectionPlanes.forEach((plane) => {
54012
54084
  if (plane.active) {
54013
- const sliceMesh = math.makeSectionPlaneSlicer(plane.pos, plane.quaternion);
54085
+ const sliceMesh = math.makeSectionPlaneSlicer(plane);
54014
54086
  visibleSceneModels.forEach(sceneModel => {
54015
54087
  const modelAABB = sceneModel.aabb;
54016
54088
  if (math.planeIntersectsAABB3(plane, modelAABB)) {
@@ -54030,10 +54102,11 @@ class SectionCaps {
54030
54102
  });
54031
54103
 
54032
54104
  entityCache.meshCaches.filter(meshCache => math.planeIntersectsAABB3(plane, meshCache.mesh.aabb)).forEach((meshCache, meshIdx) => {
54033
- sliceMesh(modelCenter, meshCache.meshIndices, meshCache.meshVertices).forEach((geo, geoIdx) => {
54105
+ const geo = sliceMesh({ origin: modelCenter, indices: meshCache.meshIndices, positions: meshCache.meshVertices }, { onlyPosSliceWithUV: true }).pos;
54106
+ if (geo) {
54034
54107
  entityCache.capMeshes.push(new Mesh(scene, {
54035
54108
  isObject: true,
54036
- id: `${plane.id}-${entityId}-${meshIdx}-${geoIdx}`,
54109
+ id: `${plane.id}-${entityId}-${meshIdx}`,
54037
54110
  material: entity.capMaterial,
54038
54111
  origin: math.addVec3(modelCenter, math.mulVec3Scalar(plane.dir, 0.001, tempVec3a$a), tempVec3a$a),
54039
54112
  geometry: new ReadableGeometry(scene, {
@@ -54044,7 +54117,7 @@ class SectionCaps {
54044
54117
  uv: geo.uv
54045
54118
  })
54046
54119
  }));
54047
- });
54120
+ }
54048
54121
  });
54049
54122
  }
54050
54123
  });
@@ -60456,7 +60529,7 @@ class CameraControl extends Component {
60456
60529
  *
60457
60530
  * See class docs for usage.
60458
60531
  *
60459
- * @param {{Number:Number}|String} value Either a set of new key mappings, or a string to select a keyboard layout,
60532
+ * @param {{Number:(Number | Number[])[]} | String} value Either a set of new key mappings, or a string to select a keyboard layout,
60460
60533
  * which causes ````CameraControl```` to use the default key mappings for that layout.
60461
60534
  */
60462
60535
  set keyMap(value) {
@@ -60535,7 +60608,7 @@ class CameraControl extends Component {
60535
60608
  /**
60536
60609
  * Gets custom mappings of keys to {@link CameraControl} actions.
60537
60610
  *
60538
- * @returns {{Number:Number}} Current key mappings.
60611
+ * @returns {{Number:(Number | Number[])[]}} Current key mappings.
60539
60612
  */
60540
60613
  get keyMap() {
60541
60614
  return this._keyMap;
@@ -131072,6 +131145,974 @@ class CxConverterIFCLoaderPlugin extends Plugin {
131072
131145
  }
131073
131146
  }
131074
131147
 
131148
+ /**
131149
+ * Default data access strategy for {@link IFCOpenShellLoaderPlugin}.
131150
+ *
131151
+ * This just loads assets using XMLHttpRequest.
131152
+ */
131153
+ class IFCOpenShellDefaultDataSource {
131154
+
131155
+ constructor(cfg = {}) {
131156
+ this.cacheBuster = (cfg.cacheBuster !== false);
131157
+ }
131158
+
131159
+ _cacheBusterURL(url) {
131160
+ if (!this.cacheBuster) {
131161
+ return url;
131162
+ }
131163
+ const timestamp = new Date().getTime();
131164
+ if (url.indexOf('?') > -1) {
131165
+ return url + '&_=' + timestamp;
131166
+ } else {
131167
+ return url + '?_=' + timestamp;
131168
+ }
131169
+ }
131170
+
131171
+ /**
131172
+ * Gets the contents of the given IFC file in an arraybuffer.
131173
+ *
131174
+ * @param {String|Number} src Path or ID of an IFC file.
131175
+ * @param {Function} ok Callback fired on success, argument is the IFC file in an arraybuffer.
131176
+ * @param {Function} error Callback fired on error.
131177
+ */
131178
+ getIFC(src, ok, error) {
131179
+ src = this._cacheBusterURL(src);
131180
+
131181
+ var defaultCallback = () => {
131182
+ };
131183
+ ok = ok || defaultCallback;
131184
+ error = error || defaultCallback;
131185
+ const dataUriRegex = /^data:(.*?)(;base64)?,(.*)$/;
131186
+ const dataUriRegexResult = src.match(dataUriRegex);
131187
+ if (dataUriRegexResult) { // Safari can't handle data URIs through XMLHttpRequest
131188
+ const isBase64 = !!dataUriRegexResult[2];
131189
+ var data = dataUriRegexResult[3];
131190
+ data = window.decodeURIComponent(data);
131191
+ if (isBase64) {
131192
+ data = window.atob(data);
131193
+ }
131194
+ try {
131195
+ const buffer = new ArrayBuffer(data.length);
131196
+ const view = new Uint8Array(buffer);
131197
+ for (var i = 0; i < data.length; i++) {
131198
+ view[i] = data.charCodeAt(i);
131199
+ }
131200
+ ok(buffer);
131201
+ } catch (errMsg) {
131202
+ error(errMsg);
131203
+ }
131204
+ } else {
131205
+ const request = new XMLHttpRequest();
131206
+ request.open('GET', src, true);
131207
+ request.responseType = 'text';
131208
+ request.onreadystatechange = function () {
131209
+ if (request.readyState === 4) {
131210
+ if (request.status === 200) {
131211
+ ok(request.response);
131212
+ } else {
131213
+ error('getIFC error : ' + request.response);
131214
+ }
131215
+ }
131216
+ };
131217
+ request.send(null);
131218
+ }
131219
+ }
131220
+ }
131221
+
131222
+ /**
131223
+ * {@link Viewer} plugin that uses [IfcOpenShell](https://ifcopenshell.org/) to load BIM models directly from IFC files.
131224
+ *
131225
+ * <a href="https://xeokit.github.io/xeokit-sdk/examples/index.html#BIMOffline_IFCOpenShellLoaderPlugin_Duplex"><img src="https://xeokit.io/img/docs/IFCOpenShellLoaderPlugin/IFCOpenShellLoaderPlugin.png"></a>
131226
+ *
131227
+ * [[Run this example](https://xeokit.github.io/xeokit-sdk/examples/index.html#BIMOffline_IFCOpenShellLoaderPlugin_Duplex)]
131228
+ *
131229
+ * ## Overview
131230
+ *
131231
+ * * Loads small-to-medium sized BIM models directly from IFC files.
131232
+ * * Uses [IfcOpenShell API](https://ifcopenshell.org/) to parse IFC files in the browser.
131233
+ * * Loads IFC geometry, element structure metadata, and property sets.
131234
+ * * Not for large models. For best performance with large models, we recommend using {@link XKTLoaderPlugin}.
131235
+ * * Loads double-precision coordinates, enabling models to be viewed at global coordinates without accuracy loss.
131236
+ * * Filter which IFC types don't get loaded.
131237
+ * * Configure initial appearances of specified IFC types.
131238
+ * * Set a custom data source for IFC files.
131239
+ *
131240
+ * ## Limitations
131241
+ *
131242
+ * Loading and parsing huge IFC STEP files can be slow, and can overwhelm the browser, however. To view your
131243
+ * largest IFC models, we recommend instead pre-converting those to xeokit's compressed native .XKT format, then
131244
+ * loading them with {@link XKTLoaderPlugin} instead.</p>
131245
+ *
131246
+ * ## Scene representation
131247
+ *
131248
+ * When loading a model, IFCOpenShellLoaderPlugin creates an {@link Entity} that represents the model, which
131249
+ * will have {@link Entity#isModel} set ````true```` and will be registered by {@link Entity#id}
131250
+ * in {@link Scene#models}. The IFCOpenShellLoaderPlugin also creates an {@link Entity} for each object within the
131251
+ * model. Those Entities will have {@link Entity#isObject} set ````true```` and will be registered
131252
+ * by {@link Entity#id} in {@link Scene#objects}.
131253
+ *
131254
+ * ## Metadata
131255
+ *
131256
+ * When loading a model, IFCOpenShellLoaderPlugin also creates a {@link MetaModel} that represents the model, which contains
131257
+ * a {@link MetaObject} for each IFC element, plus a {@link PropertySet} for each IFC property set. Loading metadata
131258
+ * can be very slow, so we can also optionally disable it if we don't need it.
131259
+ *
131260
+ * ## Usage
131261
+ *
131262
+ * In the example below we'll load the Duplex BIM model from
131263
+ * an [IFC file](https://github.com/xeokit/xeokit-sdk/tree/master/assets/models/ifc). Within our {@link Viewer}, this
131264
+ * will create a bunch of {@link Entity}s that represents the model and its objects, along with a {@link MetaModel},
131265
+ * {@link MetaObject}s and {@link PropertySet}s that hold their metadata.
131266
+ *
131267
+ * ````javascript
131268
+ * import {Viewer, IFCOpenShellLoaderPlugin, NavCubePlugin, TreeViewPlugin} from "../../dist/xeokit-sdk.es.js";
131269
+ *
131270
+ * //------------------------------------------------------------------------------------------------------------------
131271
+ * // 1. Create a Viewer,
131272
+ * // 2. Arrange the camera
131273
+ * //------------------------------------------------------------------------------------------------------------------
131274
+ *
131275
+ * // 1
131276
+ * const viewer = new Viewer({
131277
+ * canvasId: "myCanvas",
131278
+ * transparent: true
131279
+ * });
131280
+ *
131281
+ * // 2
131282
+ * viewer.camera.eye = [-3.933, 2.855, 27.018];
131283
+ * viewer.camera.look = [4.400, 3.724, 8.899];
131284
+ * viewer.camera.up = [-0.018, 0.999, 0.039];
131285
+ *
131286
+ * //------------------------------------------------------------------------------------------------------------------
131287
+ * // 1. Create the IFCOpenShellLoaderPlugin,
131288
+ * // 2. Load an IFC model
131289
+ * //------------------------------------------------------------------------------------------------------------------
131290
+ *
131291
+ * // 1
131292
+ *
131293
+ * const ifcLoader = new IFCOpenShellLoaderPlugin(viewer, {
131294
+ * workerSrc: "./my/directory/IFCOpenShellWorker.js",
131295
+ * ifcOpenShellURL: "./my/directory/ifcopenshell-0.8.3+34a1bc6-cp313-cp313-emscripten_4_0_9_wasm32.whl"
131296
+ * });
131297
+ *
131298
+ * // 2
131299
+ * const model = ifcLoader.load({ // Returns an Entity that represents the model
131300
+ * id: "myModel",
131301
+ * src: "../assets/models/ifc/Duplex.ifc",
131302
+ * excludeTypes: ["IfcSpace"],
131303
+ * edges: true
131304
+ * });
131305
+ *
131306
+ * model.on("loaded", () => {
131307
+ *
131308
+ * //----------------------------------------------------------------------------------------------------------
131309
+ * // 1. Find metadata on the bottom storey
131310
+ * // 2. X-ray all the objects except for the bottom storey
131311
+ * // 3. Fit the bottom storey in view
131312
+ * //----------------------------------------------------------------------------------------------------------
131313
+ *
131314
+ * // 1
131315
+ * const metaModel = viewer.metaScene.metaModels["myModel"]; // MetaModel with ID "myModel"
131316
+ * const metaObject
131317
+ * = viewer.metaScene.metaObjects["1xS3BCk291UvhgP2dvNsgp"]; // MetaObject with ID "1xS3BCk291UvhgP2dvNsgp"
131318
+ *
131319
+ * const name = metaObject.name; // "01 eerste verdieping"
131320
+ * const type = metaObject.type; // "IfcBuildingStorey"
131321
+ * const parent = metaObject.parent; // MetaObject with type "IfcBuilding"
131322
+ * const children = metaObject.children; // Array of child MetaObjects
131323
+ * const objectId = metaObject.id; // "1xS3BCk291UvhgP2dvNsgp"
131324
+ * const objectIds = viewer.metaScene.getObjectIDsInSubtree(objectId); // IDs of leaf sub-objects
131325
+ * const aabb = viewer.scene.getAABB(objectIds); // Axis-aligned boundary of the leaf sub-objects
131326
+ *
131327
+ * // 2
131328
+ * viewer.scene.setObjectsXRayed(viewer.scene.objectIds, true);
131329
+ * viewer.scene.setObjectsXRayed(objectIds, false);
131330
+ *
131331
+ * // 3
131332
+ * viewer.cameraFlight.flyTo(aabb);
131333
+ *
131334
+ * // Find the model Entity by ID
131335
+ * model = viewer.scene.models["myModel"];
131336
+ *
131337
+ * // Destroy the model
131338
+ * model.destroy();
131339
+ * });
131340
+ * ````
131341
+ *
131342
+ * ## Configuring a custom data source
131343
+ *
131344
+ * By default, IFCOpenShellLoaderPlugin will load IFC files over HTTP.
131345
+ *
131346
+ * In the example below, we'll customize the way IFCOpenShellLoaderPlugin loads the files by configuring it with our own data source
131347
+ * object. For simplicity, our custom data source example also uses HTTP, using a couple of xeokit utility functions.
131348
+ *
131349
+ * ````javascript
131350
+ * import {utils} from "xeokit-sdk.es.js";
131351
+ *
131352
+ * class MyDataSource {
131353
+ *
131354
+ * constructor() {
131355
+ * }
131356
+ *
131357
+ * // Gets the contents of the given IFC file in an arraybuffer
131358
+ * getIFC(src, ok, error) {
131359
+ * console.log("MyDataSource#getIFC(" + IFCSrc + ", ... )");
131360
+ * utils.loadArraybuffer(src,
131361
+ * (arraybuffer) => {
131362
+ * ok(arraybuffer);
131363
+ * },
131364
+ * function (errMsg) {
131365
+ * error(errMsg);
131366
+ * });
131367
+ * }
131368
+ * }
131369
+ *
131370
+ * const ifcLoader2 = new IFCOpenShellLoaderPlugin(viewer, {
131371
+ * dataSource: new MyDataSource()
131372
+ * });
131373
+ *
131374
+ * const model5 = ifcLoader2.load({
131375
+ * id: "myModel5",
131376
+ * src: "../assets/models/ifc/Duplex.ifc"
131377
+ * });
131378
+ * ````
131379
+ *
131380
+ * ## Loading multiple copies of a model, without object ID clashes
131381
+ *
131382
+ * Sometimes we need to load two or more instances of the same model, without having clashes
131383
+ * between the IDs of the equivalent objects in the model instances.
131384
+ *
131385
+ * As shown in the example below, we do this by setting {@link IFCOpenShellLoaderPlugin#globalizeObjectIds} ````true```` before we load our models.
131386
+ *
131387
+ * ````javascript
131388
+ * ifcLoader.globalizeObjectIds = true;
131389
+ *
131390
+ * const model = ifcLoader.load({
131391
+ * id: "model1",
131392
+ * src: "../assets/models/ifc/Duplex.ifc"
131393
+ * });
131394
+ *
131395
+ * const model2 = ifcLoader.load({
131396
+ * id: "model2",
131397
+ * src: "../assets/models/ifc/Duplex.ifc"
131398
+ * });
131399
+ * ````
131400
+ *
131401
+ * For each {@link Entity} loaded by these two calls, {@link Entity#id} and {@link MetaObject#id} will get prefixed by
131402
+ * the ID of their model, in order to avoid ID clashes between the two models.
131403
+ *
131404
+ * An Entity belonging to the first model will get an ID like this:
131405
+ *
131406
+ * ````
131407
+ * myModel1#0BTBFw6f90Nfh9rP1dlXrb
131408
+ * ````
131409
+ *
131410
+ * The equivalent Entity in the second model will get an ID like this:
131411
+ *
131412
+ * ````
131413
+ * myModel2#0BTBFw6f90Nfh9rP1dlXrb
131414
+ * ````
131415
+ *
131416
+ * Now, to update the visibility of both of those Entities collectively, using {@link Scene#setObjectsVisible}, we can
131417
+ * supply just the IFC product ID part to that method:
131418
+ *
131419
+ * ````javascript
131420
+ * myViewer.scene.setObjectVisibilities("0BTBFw6f90Nfh9rP1dlXrb", true);
131421
+ * ````
131422
+ *
131423
+ * The method, along with {@link Scene#setObjectsXRayed}, {@link Scene#setObjectsHighlighted} etc, will internally expand
131424
+ * the given ID to refer to the instances of that Entity in both models.
131425
+ *
131426
+ * We can also, of course, reference each Entity directly, using its globalized ID:
131427
+ *
131428
+ * ````javascript
131429
+ * myViewer.scene.setObjectVisibilities("myModel1#0BTBFw6f90Nfh9rP1dlXrb", true);
131430
+ *````
131431
+ *
131432
+ * @class IFCOpenShellLoaderPlugin
131433
+ * @since 2.6.90
131434
+ */
131435
+ class IFCOpenShellLoaderPlugin extends Plugin {
131436
+
131437
+ /**
131438
+ * @param {Viewer} viewer The {@link Viewer} that will own this plugin.
131439
+ * @param {Object} cfg Plugin configuration.
131440
+ * @param {String} [cfg.id="IFCOpenShellLoader"] Optional ID for this plugin instance.
131441
+ * @param {Object} [cfg.dataSource] Custom data source (defaults to {@link IFCOpenShellDefaultDataSource}).
131442
+ * @param {Object} cfg.ifcopenshell IfcOpenShell API object.
131443
+ * @param {Object} cfg.ifcopenshell_geom IfcOpenShell geometry API object.
131444
+ */
131445
+ constructor(viewer, cfg) {
131446
+
131447
+ super("IFCOpenShellLoader", viewer, cfg);
131448
+
131449
+ if (!cfg) {
131450
+ throw new Error("IFCOpenShellLoaderPlugin: No configuration given");
131451
+ }
131452
+
131453
+ if (!cfg.ifcopenshell) {
131454
+ throw new Error("IFCOpenShellLoaderPlugin: No ifcopenshell given");
131455
+ }
131456
+
131457
+ if (!cfg.ifcopenshell_geom) {
131458
+ throw new Error("IFCOpenShellLoaderPlugin: No ifcopenshell_geom given");
131459
+ }
131460
+
131461
+ this.ifcopenshell = cfg.ifcopenshell;
131462
+ this.ifcopenshell_geom = cfg.ifcopenshell_geom;
131463
+
131464
+ this.dataSource = cfg.dataSource;
131465
+ }
131466
+
131467
+ /**
131468
+ * Sets a custom data source for IFC files.
131469
+ * @param value
131470
+ */
131471
+ set dataSource(value) {
131472
+ this._dataSource = value || new IFCOpenShellDefaultDataSource();
131473
+ }
131474
+
131475
+ /**
131476
+ * Gets the data source for IFC files.
131477
+ * @returns {*|IFCOpenShellDefaultDataSource}
131478
+ */
131479
+ get dataSource() {
131480
+ return this._dataSource;
131481
+ }
131482
+
131483
+ /**
131484
+ * Gets whether IFCOpenShellLoaderPlugin globalizes each {@link Entity#id} and {@link MetaObject#id} as it loads a model.
131485
+ *
131486
+ * Default value is ````false````.
131487
+ *
131488
+ * @type {Boolean}
131489
+ */
131490
+ get globalizeObjectIds() {
131491
+ return this._globalizeObjectIds;
131492
+ }
131493
+
131494
+ /**
131495
+ * Sets whether IFCOpenShellLoaderPlugin globalizes each {@link Entity#id} and {@link MetaObject#id} as it loads a model.
131496
+ *
131497
+ * Set this ````true```` when you need to load multiple instances of the same model, to avoid ID clashes
131498
+ * between the objects in the different instances.
131499
+ *
131500
+ * When we load a model with this set ````true````, then each {@link Entity#id} and {@link MetaObject#id} will be
131501
+ * prefixed by the ID of the model, ie. ````<modelId>#<objectId>````.
131502
+ *
131503
+ * {@link Entity#originalSystemId} and {@link MetaObject#originalSystemId} will always hold the original, un-prefixed, ID values.
131504
+ *
131505
+ * Default value is ````false````.
131506
+ *
131507
+ * See the main {@link IFCOpenShellLoaderPlugin} class documentation for usage info.
131508
+ *
131509
+ * @type {Boolean}
131510
+ */
131511
+ set globalizeObjectIds(value) {
131512
+ this._globalizeObjectIds = !!value;
131513
+ }
131514
+
131515
+ /**
131516
+ * Loads an IFC model from a file or text into the {@link Viewer}.
131517
+ *
131518
+ * @param {Object} params
131519
+ * @param {String} [params.id] Optional root Entity ID.
131520
+ * @param {String} [params.src] IFC file path (alternative to `text`).
131521
+ * @param {String} [params.text] IFC text (alternative to `src`).
131522
+ * @param {{String:Object}} [params.objectDefaults]
131523
+ * @param {String[]} [params.excludeTypes] Array of IFC types to exclude.
131524
+ * @param {Number[]} [params.origin=[0,0,0]] Optional World-coordinate origin to apply to the model.
131525
+ * @param {Number[]} [params.position=[0,0,0]] Optional position offset to apply to the model.
131526
+ * @param {Number[]} [params.rotation=[0,0,0]] Optional XYZ Euler rotation (degrees) to apply to the model.
131527
+ * @param {Boolean} [params.backfaces=true] Whether to render backfaces.
131528
+ * @param {Boolean} [params.dtxEnabled=true] Whether to enable data texture storage for geometry buffers.
131529
+ * @param {Boolean} [params.loadMetadata=true] Whether to load metadata.
131530
+ * @param {Boolean} [params.loadMetadataPropertySets=true] Whether to load property sets within the metadata. Only works when `loadMetadata` is true.
131531
+ * @param {Boolean} [params.edges=false] Whether to generate edge lines for the model.
131532
+ * @param {Boolean} [params.saoEnabled=false] Whether to enable SAO for the model.
131533
+ * @param {Boolean} [params.globalizeObjectIds=false] Whether to globalize each {@link Entity#id} and {@link MetaObject#id} as it loads the model.
131534
+ * @returns {Entity}
131535
+ */
131536
+ async load(params = {}) {
131537
+
131538
+ let {
131539
+ id,
131540
+ backfaces = true,
131541
+ dtxEnabled = true,
131542
+ position,
131543
+ rotation,
131544
+ origin,
131545
+ loadMetadata,
131546
+ loadMetadataPropertySets,
131547
+ edges,
131548
+ saoEnabled,
131549
+ globalizeObjectIds,
131550
+ excludeTypes
131551
+ } = params;
131552
+
131553
+ if (id && this.viewer.scene.components[id]) {
131554
+ this.error(`Component with this ID already exists: ${id} - autogenerating SceneModel ID`);
131555
+ id = null;
131556
+ }
131557
+
131558
+ const sceneModel = new SceneModel(this.viewer.scene, {
131559
+ id,
131560
+ isModel: true,
131561
+ globalizeObjectIds,
131562
+ backfaces,
131563
+ dtxEnabled,
131564
+ position,
131565
+ rotation,
131566
+ origin,
131567
+ edges,
131568
+ saoEnabled
131569
+ });
131570
+
131571
+ const modelId = sceneModel.id;
131572
+
131573
+ if (!params.src && !params.text) {
131574
+ this.error("load() expected 'src' or 'text'");
131575
+ return sceneModel; // Return empty model
131576
+ }
131577
+
131578
+ const spinner = this.viewer.scene.canvas.spinner;
131579
+ spinner.processes++;
131580
+
131581
+ const loadIFC = (fileData) => {
131582
+ const ifc = this.ifcopenshell.file.from_string(fileData);
131583
+ const ctx = {
131584
+ loadMetadataPropertySets: (loadMetadataPropertySets !== false),
131585
+ globalizeObjectIds: globalizeObjectIds || this._globalizeObjectIds,
131586
+ geometryCache: new Map(),
131587
+ ifc,
131588
+ sceneModel
131589
+ };
131590
+ if (excludeTypes) {
131591
+ ctx.excludeTypes = excludeTypes;
131592
+ }
131593
+ this._loadIFCGeometry(ctx);
131594
+ if (loadMetadata !== false) {
131595
+ const metaModelData = this._loadIFCMetaModel(ctx, ifc);
131596
+ this.viewer.metaScene.createMetaModel(modelId, metaModelData);
131597
+ }
131598
+ this.viewer.scene.canvas.spinner.processes--;
131599
+ };
131600
+
131601
+ if (params.src) {
131602
+ this.viewer.scene.canvas.spinner.processes++;
131603
+ this._dataSource.getIFC(
131604
+ params.src,
131605
+ (fileData) => {
131606
+ loadIFC(fileData);
131607
+ this.viewer.scene.canvas.spinner.processes--;
131608
+ },
131609
+ (err) => {
131610
+ this.viewer.scene.canvas.spinner.processes--;
131611
+ this.error(err);
131612
+ }
131613
+ );
131614
+ } else {
131615
+ loadIFC(params.text);
131616
+ }
131617
+
131618
+ sceneModel.once("destroyed", () => {
131619
+ this.viewer.metaScene.destroyMetaModel(modelId);
131620
+ });
131621
+
131622
+ return sceneModel;
131623
+ }
131624
+
131625
+ _loadIFCGeometry(ctx) {
131626
+ const {ifc, sceneModel} = ctx;
131627
+ const {ifcopenshell_geom} = this;
131628
+
131629
+ const settings = ifcopenshell_geom.settings();
131630
+ settings.set(settings.WELD_VERTICES, false);
131631
+
131632
+ const iterator = ifcopenshell_geom.iterator.callKwargs({
131633
+ settings,
131634
+ file_or_filename: ifc,
131635
+ exclude: ctx.excludeTypes,
131636
+ geometry_library: "hybrid-cgal-simple-opencascade"
131637
+ });
131638
+
131639
+ if (iterator.initialize()) {
131640
+ do {
131641
+ const obj = iterator.get();
131642
+ if (obj) {
131643
+ const entity = ifc.by_id(obj.id);
131644
+ this._parseIFCEntity(ctx, obj, entity);
131645
+ }
131646
+ } while (iterator.next());
131647
+ }
131648
+
131649
+ sceneModel.finalize();
131650
+
131651
+ sceneModel.scene.once("tick", () => {
131652
+ if (!sceneModel.destroyed) {
131653
+ sceneModel.scene.fire("modelLoaded", sceneModel.id);
131654
+ sceneModel.fire("loaded", true, false);
131655
+ }
131656
+ });
131657
+ }
131658
+
131659
+ _parseIFCEntity(ctx, obj, ifcEntity) {
131660
+ const {sceneModel, geometryCache} = ctx;
131661
+ const geometry_id = obj.geometry.id;
131662
+
131663
+ const M = obj.transformation.data().components.toJs();
131664
+ const {origin, matrix} = extractRTCTransform(M);
131665
+
131666
+ if (!geometryCache.get(geometry_id)) {
131667
+
131668
+ const srcMaterials = obj.geometry.materials.toJs();
131669
+ const materials = srcMaterials.map((m) => ({
131670
+ diffuse: m.diffuse.components.toJs(),
131671
+ transparency: (m.transparency
131672
+ && !isNaN(m.transparency)) ? m.transparency : 0.0,
131673
+ }));
131674
+
131675
+ const materialIds = new Int32Array(obj.geometry.material_ids.toJs());
131676
+
131677
+ // Build mapping: materialIndex -> [faceIdx...]
131678
+ const mapping = buildMaterialMapping(materialIds);
131679
+
131680
+ // Create sub-geometry per materialIndex, once
131681
+ const subGeoms = new Map();
131682
+
131683
+ for (const [matIndexStr, faceList] of Object.entries(mapping)) {
131684
+
131685
+ if (!faceList || faceList.length === 0) {
131686
+ continue;
131687
+ }
131688
+
131689
+ // xeokit auto-generates normals on the GPU side
131690
+
131691
+ const positions = new Float32Array(obj.geometry.verts.toJs());
131692
+ const edgeIndices = new Uint32Array(obj.geometry.edges.toJs());
131693
+ const faces = new Uint32Array(obj.geometry.faces.toJs());
131694
+ const matIndex = Number(matIndexStr);
131695
+ const indices = buildIndicesForFaces(faceList, faces);
131696
+ const sceneGeometryId = makeSubGeometryId(geometry_id, matIndex); // deterministic
131697
+
131698
+ sceneModel.createGeometry({
131699
+ id: sceneGeometryId,
131700
+ primitive: "triangles",
131701
+ positions,
131702
+ indices,
131703
+ edgeIndices
131704
+ });
131705
+
131706
+ subGeoms.set(matIndex, sceneGeometryId);
131707
+ }
131708
+
131709
+ geometryCache.set(geometry_id, {
131710
+ subGeoms,
131711
+ materials,
131712
+ // store mapping as Map<number, Uint32Array> to avoid recomputing
131713
+ mapping: new Map(Object.entries(mapping).map(
131714
+ ([k, v]) => [Number(k), new Uint32Array(v)]
131715
+ ))
131716
+ });
131717
+ }
131718
+
131719
+ // Reuse cached sub-geometries to create per-object meshes
131720
+
131721
+ const cached = geometryCache.get(geometry_id);
131722
+ const meshIds = [];
131723
+
131724
+ for (const [matIndex, sceneGeometryId] of cached.subGeoms.entries()) {
131725
+ const material = cached.materials[matIndex] || {diffuse: [0.6, 0.6, 0.6], transparency: 0.0};
131726
+ const meshId = generateUUID();
131727
+ const diffuse = material.diffuse;
131728
+ sceneModel.createMesh({
131729
+ id: meshId,
131730
+ geometryId: sceneGeometryId,
131731
+ origin,
131732
+ matrix,
131733
+ color: [diffuse[0], diffuse[1], diffuse[2]],
131734
+ opacity: 1.0 - material.transparency
131735
+ });
131736
+ meshIds.push(meshId);
131737
+ }
131738
+
131739
+ sceneModel.createEntity({
131740
+ id: ctx.globalizeObjectIds ? math.globalizeObjectId(ctx.sceneModel.id, ifcEntity.GlobalId) : ifcEntity.GlobalId,
131741
+ isObject: true,
131742
+ meshIds
131743
+ });
131744
+ }
131745
+
131746
+ _loadIFCMetaModel(ctx, ifc) {
131747
+
131748
+ const visited = new Set();
131749
+ const metaObjects = [];
131750
+ const propertySets = [];
131751
+
131752
+ // ---- helpers -----------------------------------------------------------
131753
+ const toStr = (v) => (v === undefined || v === null) ? "" : String(v);
131754
+
131755
+ function getGlobalId(entity) {
131756
+ try {
131757
+ return String(entity.GlobalId);
131758
+ } catch {
131759
+ return null;
131760
+ }
131761
+ }
131762
+
131763
+ function addNode(entity, parent) {
131764
+ const id = getGlobalId(entity);
131765
+ if (!id || visited.has(id)) return false;
131766
+ visited.add(id);
131767
+ const globalizeObjectIds = ctx.globalizeObjectIds;
131768
+ const modelId = ctx.sceneModel.id;
131769
+ const propertySetIds = [];
131770
+ if (ctx.loadMetadataPropertySets) {
131771
+ // Try all possible association fields
131772
+ const associationFields = ["HasAssociations", "IsDefinedBy", "IsDecomposedBy", "ContainsElements"];
131773
+ for (const field of associationFields) {
131774
+ const associations = entity[field];
131775
+ if (associations && associations.length > 0) {
131776
+ for (let j = 0; j < associations.length; j++) {
131777
+ const rel = associations.get(j);
131778
+ if (rel.is_a && rel.is_a() === "IfcRelDefinesByProperties") {
131779
+ const propSet = rel.RelatingPropertyDefinition;
131780
+ if (propSet && propSet.is_a) {
131781
+ // Accept both IfcPropertySet and IfcElementQuantity
131782
+ if (["IfcPropertySet", "IfcElementQuantity"].includes(propSet.is_a())) {
131783
+ const propSetId = propSet.GlobalId ? String(propSet.GlobalId) : null;
131784
+ const propSetName = propSet.Name ? String(propSet.Name) : "";
131785
+ const propSetType = propSet.is_a ? String(propSet.is_a()) : "";
131786
+ const properties = [];
131787
+ const props = propSet.HasProperties || propSet.Quantities;
131788
+ if (props && props.length > 0) {
131789
+ for (let k = 0; k < props.length; k++) {
131790
+ const p = props.get(k);
131791
+ const propName = p.Name ? String(p.Name) : "";
131792
+ let propValue = "";
131793
+ let propType = p.is_a ? String(p.is_a()) : "";
131794
+ if (p.is_a && p.is_a() === "IfcPropertySingleValue") {
131795
+ try {
131796
+ propValue = p.NominalValue ? String(p.NominalValue.wrappedValue) : "";
131797
+ } catch {
131798
+ propValue = "";
131799
+ }
131800
+ } else if (p.is_a && p.is_a() === "IfcPropertyEnumeratedValue") {
131801
+ try {
131802
+ const values = p.EnumerationValues;
131803
+ if (values && values.length > 0) {
131804
+ const arr = [];
131805
+ for (let vi = 0; vi < values.length; vi++) {
131806
+ arr.push(String(values.get(vi).wrappedValue));
131807
+ }
131808
+ propValue = arr.join(", ");
131809
+ }
131810
+ } catch {
131811
+ propValue = "";
131812
+ }
131813
+ } else if (p.is_a && p.is_a() === "IfcQuantityArea") {
131814
+ propValue = p.AreaValue ? String(p.AreaValue) : "";
131815
+ } else if (p.is_a && p.is_a() === "IfcQuantityLength") {
131816
+ propValue = p.LengthValue ? String(p.LengthValue) : "";
131817
+ } else if (p.is_a && p.is_a() === "IfcQuantityVolume") {
131818
+ propValue = p.VolumeValue ? String(p.VolumeValue) : "";
131819
+ } else {
131820
+ try {
131821
+ propValue = p.NominalValue ? String(p.NominalValue) : "";
131822
+ } catch {
131823
+ propValue = "";
131824
+ }
131825
+ }
131826
+ properties.push({
131827
+ name: propName,
131828
+ value: propValue,
131829
+ type: propType
131830
+ });
131831
+ p.destroy?.();
131832
+ }
131833
+ props.destroy?.();
131834
+ }
131835
+ propertySets.push({
131836
+ id: propSetId,
131837
+ // objectId: ctx.globalizeObjectIds ? math.globalizeObjectId(ctx.sceneModel.id, objectId) : objectId,
131838
+ name: propSetName,
131839
+ type: propSetType,
131840
+ properties
131841
+ });
131842
+ propertySetIds.push(propSetId);
131843
+ propSet.destroy?.();
131844
+ }
131845
+ }
131846
+ rel.destroy?.();
131847
+ }
131848
+ }
131849
+ associations.destroy?.();
131850
+ }
131851
+ }
131852
+ }
131853
+ metaObjects.push({
131854
+ id: globalizeObjectIds ? math.globalizeObjectId(modelId, id) : id,
131855
+ type: String(entity.is_a()),
131856
+ parent: parent
131857
+ ? (globalizeObjectIds
131858
+ ? math.globalizeObjectId(modelId, getGlobalId(parent))
131859
+ : getGlobalId(parent))
131860
+ : null,
131861
+ propertySetIds
131862
+ });
131863
+ return true;
131864
+ }
131865
+
131866
+ function walk(entity, parent = null) {
131867
+ if (!entity) return;
131868
+
131869
+ // add current node (skip children if already visited)
131870
+ if (!addNode(entity, parent)) {
131871
+ entity.destroy?.();
131872
+ return;
131873
+ }
131874
+
131875
+ // 1) Decomposition (IfcRelAggregates / IfcRelNests)
131876
+ const decos = entity.IsDecomposedBy;
131877
+ if (decos) {
131878
+ for (let i = 0; i < decos.length; i++) {
131879
+ const rel = decos.get(i);
131880
+ const children = rel.RelatedObjects;
131881
+ if (children) {
131882
+ for (let j = 0; j < children.length; j++) {
131883
+ const child = children.get(j);
131884
+ walk(child, entity);
131885
+ child.destroy?.();
131886
+ }
131887
+ children.destroy?.();
131888
+ }
131889
+ rel.destroy?.();
131890
+ }
131891
+ }
131892
+
131893
+ // 2) Spatial containment (IfcRelContainedInSpatialStructure)
131894
+ const contains = entity.ContainsElements;
131895
+ if (contains) {
131896
+ for (let i = 0; i < contains.length; i++) {
131897
+ const rel = contains.get(i);
131898
+ const elems = rel.RelatedElements;
131899
+ if (elems) {
131900
+ for (let j = 0; j < elems.length; j++) {
131901
+ const elem = elems.get(j);
131902
+ walk(elem, entity);
131903
+ elem.destroy?.();
131904
+ }
131905
+ elems.destroy?.();
131906
+ }
131907
+ rel.destroy?.();
131908
+ }
131909
+ }
131910
+
131911
+ entity.destroy?.();
131912
+ }
131913
+
131914
+ // ---- metadata extraction ----------------------------------------------
131915
+ let projectId = "";
131916
+ let author = "";
131917
+ let createdAt = ""; // ISO string
131918
+ let schema = "";
131919
+ let creatingApplication = "";
131920
+
131921
+ // Schema (primary)
131922
+ try {
131923
+ // ifcopenshell.file usually exposes a `schema` string property
131924
+ schema = toStr(ifc.schema);
131925
+ } catch {
131926
+ }
131927
+ if (!schema) {
131928
+ // Fallback to STEP header
131929
+ try {
131930
+ const ids = ifc.wrapped_data.header.file_schema.schema_identifiers;
131931
+ if (ids && ids.length > 0) schema = toStr(ids.get(0));
131932
+ } catch {
131933
+ }
131934
+ }
131935
+
131936
+ // Project (also gives us OwnerHistory on many files)
131937
+ const projects = ifc.by_type("IfcProject");
131938
+ if (projects && projects.length > 0) {
131939
+ const project = projects.get(0);
131940
+ projectId = toStr(project.GlobalId);
131941
+
131942
+ // OwnerHistory path (preferred when present)
131943
+ try {
131944
+ const oh = project.OwnerHistory; // deprecated in newer IFC4.x, but present in many files
131945
+ if (oh) {
131946
+ // Author: IfcPersonAndOrganization → ThePerson (GivenName/FamilyName) and TheOrganization.Name
131947
+ try {
131948
+ const user = oh.OwningUser;
131949
+ const person = user?.ThePerson;
131950
+ const org = user?.TheOrganization;
131951
+ const gn = person?.GivenName ? toStr(person.GivenName) : "";
131952
+ const fn = person?.FamilyName ? toStr(person.FamilyName) : "";
131953
+ const personName = (gn || fn) ? [gn, fn].filter(Boolean).join(" ") : "";
131954
+ const orgName = org?.Name ? toStr(org.Name) : "";
131955
+ author = [personName, orgName].filter(Boolean).join(" / ");
131956
+ } catch {
131957
+ }
131958
+
131959
+ // Creation time (UNIX seconds)
131960
+ try {
131961
+ const ts = oh?.CreationDate;
131962
+ if (typeof ts === "number" && isFinite(ts) && ts > 0) {
131963
+ createdAt = new Date(ts * 1000).toISOString();
131964
+ }
131965
+ } catch {
131966
+ }
131967
+
131968
+ // Creating application
131969
+ try {
131970
+ const app = oh?.OwningApplication;
131971
+ const appName =
131972
+ app?.ApplicationFullName ? toStr(app.ApplicationFullName) :
131973
+ app?.ApplicationIdentifier ? toStr(app.ApplicationIdentifier) : "";
131974
+ const appVer = app?.Version ? toStr(app.Version) : "";
131975
+ creatingApplication = [appName, appVer].filter(Boolean).join(" ");
131976
+ } catch {
131977
+ }
131978
+ }
131979
+ } catch {
131980
+ }
131981
+
131982
+ // Clean first project (we’ll traverse below with a fresh pointer anyway)
131983
+ project.destroy?.();
131984
+ }
131985
+
131986
+ // Fallbacks via STEP header if OwnerHistory wasn’t there / incomplete
131987
+ try {
131988
+ const fileName = ifc.wrapped_data.header.file_name;
131989
+ if (!author) {
131990
+ try {
131991
+ const authors = fileName.author;
131992
+ if (authors && authors.length > 0) {
131993
+ // `author` is a LIST in the STEP header; join if multiple
131994
+ const parts = [];
131995
+ for (let i = 0; i < authors.length; i++) parts.push(toStr(authors.get(i)));
131996
+ author = parts.filter(Boolean).join(", ");
131997
+ }
131998
+ } catch {
131999
+ }
132000
+ }
132001
+ if (!createdAt) {
132002
+ const ts = toStr(fileName.time_stamp); // already a string like "2023-08-10T12:34:56"
132003
+ if (ts) {
132004
+ // normalize to ISO if possible
132005
+ const maybe = new Date(ts);
132006
+ if (!isNaN(maybe.getTime())) createdAt = maybe.toISOString();
132007
+ }
132008
+ }
132009
+ if (!creatingApplication) {
132010
+ // STEP header carries "originating_system" and "preprocessor_version"
132011
+ const orig = toStr(fileName.originating_system);
132012
+ const prep = toStr(fileName.preprocessor_version);
132013
+ creatingApplication = [orig, prep].filter(Boolean).join(" / ");
132014
+ }
132015
+ } catch {
132016
+ }
132017
+
132018
+ // If createdAt still missing, sweep for earliest OwnerHistory timestamp across roots
132019
+ if (!createdAt) {
132020
+ try {
132021
+ let minTs = Infinity;
132022
+ const roots = ifc.by_type("IfcRoot");
132023
+ for (let i = 0; i < roots.length; i++) {
132024
+ const r = roots.get(i);
132025
+ const oh = r?.OwnerHistory;
132026
+ const ts = oh?.CreationDate;
132027
+ if (typeof ts === "number" && isFinite(ts) && ts > 0 && ts < minTs) {
132028
+ minTs = ts;
132029
+ }
132030
+ r.destroy?.();
132031
+ }
132032
+ roots.destroy?.();
132033
+ if (isFinite(minTs)) createdAt = new Date(minTs * 1000).toISOString();
132034
+ } catch {
132035
+ }
132036
+ }
132037
+
132038
+ // ---- hierarchy walk ----------------------------------------------------
132039
+ // Re-query projects since we destroyed the first pointer above
132040
+ const projects2 = ifc.by_type("IfcProject");
132041
+ for (let i = 0; i < projects2.length; i++) {
132042
+ const project = projects2.get(i);
132043
+ walk(project, null);
132044
+ project.destroy?.();
132045
+ }
132046
+ projects2.destroy?.();
132047
+
132048
+ return {
132049
+ id: "",
132050
+ projectId,
132051
+ author,
132052
+ createdAt,
132053
+ schema,
132054
+ creatingApplication,
132055
+ metaObjects,
132056
+ propertySets
132057
+ };
132058
+ }
132059
+
132060
+ /**
132061
+ * Destroys this IFCOpenShellLoaderPlugin instance.
132062
+ */
132063
+ destroy() {
132064
+ super.destroy();
132065
+ }
132066
+ }
132067
+
132068
+ function makeSubGeometryId(geometry_id, matIndex) {
132069
+ return `${geometry_id}:${matIndex}#geom`;
132070
+ }
132071
+
132072
+ function buildMaterialMapping(materialIds) {
132073
+ const mapping = {};
132074
+ for (let faceIdx = 0; faceIdx < materialIds.length; faceIdx++) {
132075
+ const materialId = materialIds[faceIdx];
132076
+ if (materialId == null || materialId < 0) continue; // skip invalid / missing
132077
+ (mapping[materialId] ||= []).push(faceIdx);
132078
+ }
132079
+ return mapping;
132080
+ }
132081
+
132082
+ function buildIndicesForFaces(faceList, faceIndices) {
132083
+ const indices = new Uint32Array(faceList.length * 3);
132084
+ let k = 0;
132085
+ for (const faceIdx of faceList) {
132086
+ const base = faceIdx * 3;
132087
+ indices[k++] = faceIndices[base + 0];
132088
+ indices[k++] = faceIndices[base + 1];
132089
+ indices[k++] = faceIndices[base + 2];
132090
+ }
132091
+ return indices;
132092
+ }
132093
+
132094
+ function generateUUID() {
132095
+ return Math.random().toString(36).substr(2, 9);
132096
+ }
132097
+
132098
+ function extractRTCTransform(transform) {
132099
+ const matrix = flattenMatrixArray(transform);
132100
+ const origin = [];
132101
+ const worldOrigin = matrix.slice(12, 15); // translation xyz
132102
+ worldToRTCPositions(worldOrigin, worldOrigin, origin);
132103
+ matrix.set(worldOrigin, 12);
132104
+ return {origin, matrix};
132105
+ }
132106
+
132107
+ function flattenMatrixArray(m) {
132108
+ return new Float64Array([
132109
+ m[0][0], m[2][0], -m[1][0], m[3][0],
132110
+ m[0][1], m[2][1], -m[1][1], m[3][1],
132111
+ m[0][2], m[2][2], -m[1][2], m[3][2],
132112
+ m[0][3], m[2][3], -m[1][3], m[3][3]
132113
+ ]);
132114
+ }
132115
+
131075
132116
  /**
131076
132117
  * Default data access strategy for {@link LASLoaderPlugin}.
131077
132118
  */
@@ -135111,4 +136152,4 @@ class ZoneTranslateTouchControl extends ZoneTranslateControl {
135111
136152
  }
135112
136153
  }
135113
136154
 
135114
- export { AlphaFormat, AmbientLight, AngleMeasurementEditMouseControl, AngleMeasurementEditTouchControl, AngleMeasurementsControl, AngleMeasurementsMouseControl, AngleMeasurementsPlugin, AngleMeasurementsTouchControl, AnnotationsPlugin, AxisGizmoPlugin, BCFViewpointsPlugin, Bitmap, ByteType, CameraMemento, CameraPath, CameraPathAnimation, CityJSONLoaderPlugin, ClampToEdgeWrapping, Component, CompressedMediaType, Configs, ContextMenu, CubicBezierCurve, Curve, CxConverterIFCLoaderPlugin, DefaultLoadingManager, DepthFormat, DepthStencilFormat, DirLight, DistanceMeasurementEditControl, DistanceMeasurementEditMouseControl, DistanceMeasurementEditTouchControl, DistanceMeasurementsControl, DistanceMeasurementsMouseControl, DistanceMeasurementsPlugin, DistanceMeasurementsTouchControl, Dot3D, DotBIMDefaultDataSource, DotBIMLoaderPlugin, EdgeMaterial, EmphasisMaterial, FaceAlignedSectionPlanesPlugin, FastNavPlugin, FloatType, Fresnel, Frustum$1 as Frustum, FrustumPlane, GIFMediaType, GLTFDefaultDataSource, GLTFLoaderPlugin, HalfFloatType, ImagePlane, IntType, JPEGMediaType, KTX2TextureTranscoder, LASLoaderPlugin, Label3D, LambertMaterial, LightMap, LineSet, LinearEncoding, LinearFilter, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, Loader, LoadingManager, LocaleService, LuminanceAlphaFormat, LuminanceFormat, Map$1 as Map, Marker, MarqueePicker, MarqueePickerMouseControl, Mesh, MeshSurfaceArea, MeshVolume, MetallicMaterial, MirroredRepeatWrapping, ModelMemento, NavCubePlugin, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, Node$1 as Node, OBJLoaderPlugin, ObjectsKdTree3, ObjectsMemento, PNGMediaType, Path, PerformanceModel, PhongMaterial, PickResult, Plugin, PointLight, PointerCircle, PointerLens, QuadraticBezierCurve, Queue, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBFormat, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, ReadableGeometry, RedFormat, RedIntegerFormat, ReflectionMap, RepeatWrapping, STLDefaultDataSource, STLLoaderPlugin, SceneModel, SceneModelMesh, SceneModelTransform, SectionPlane, SectionPlanesPlugin, ShortType, SpecularMaterial, SplineCurve, SpriteMarker, StoreyViewsPlugin, Texture, TextureTranscoder, TransformControl, TreeViewPlugin, UnsignedByteType, UnsignedInt248Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VBOGeometry, ViewCullPlugin, Viewer, WebIFCLoaderPlugin, Wire3D, WorkerPool$1 as WorkerPool, XKTDefaultDataSource, XKTLoaderPlugin, XML3DLoaderPlugin, ZoneEditControl, ZoneEditMouseControl, ZoneEditTouchControl, ZoneTranslateControl, ZoneTranslateMouseControl, ZoneTranslateTouchControl, ZonesMouseControl, ZonesPlugin, ZonesPolysurfaceMouseControl, ZonesPolysurfaceTouchControl, ZonesTouchControl, activateDraggableDot, activateDraggableDots, addMousePressListener, addTouchPressListener, buildBoxGeometry, buildBoxLinesGeometry, buildBoxLinesGeometryFromAABB, buildCylinderGeometry, buildGridGeometry, buildLineGeometry, buildPlaneGeometry, buildPolylineGeometry, buildPolylineGeometryFromCurve, buildSphereGeometry, buildTorusGeometry, buildVectorTextGeometry, createCombinedTexture, createRTCViewMat, createSkyboxMesh, createSphereMapMesh, frustumIntersectsAABB3, getKTX2TextureTranscoder, isTriangleMeshSolid, load3DSGeometry, loadOBJGeometry, marker3D, math, meshSurfaceArea, meshVolume, os, sRGBEncoding, setFrustum, startPolygonCreate, stats, touchPointSelector, transformToNode, triangulateEarClipping, utils, wire3D, worldToRTCPos, worldToRTCPositions };
136155
+ export { AlphaFormat, AmbientLight, AngleMeasurementEditMouseControl, AngleMeasurementEditTouchControl, AngleMeasurementsControl, AngleMeasurementsMouseControl, AngleMeasurementsPlugin, AngleMeasurementsTouchControl, AnnotationsPlugin, AxisGizmoPlugin, BCFViewpointsPlugin, Bitmap, ByteType, CameraMemento, CameraPath, CameraPathAnimation, CityJSONLoaderPlugin, ClampToEdgeWrapping, Component, CompressedMediaType, Configs, ContextMenu, CubicBezierCurve, Curve, CxConverterIFCLoaderPlugin, DefaultLoadingManager, DepthFormat, DepthStencilFormat, DirLight, DistanceMeasurementEditControl, DistanceMeasurementEditMouseControl, DistanceMeasurementEditTouchControl, DistanceMeasurementsControl, DistanceMeasurementsMouseControl, DistanceMeasurementsPlugin, DistanceMeasurementsTouchControl, Dot3D, DotBIMDefaultDataSource, DotBIMLoaderPlugin, EdgeMaterial, EmphasisMaterial, FaceAlignedSectionPlanesPlugin, FastNavPlugin, FloatType, Fresnel, Frustum$1 as Frustum, FrustumPlane, GIFMediaType, GLTFDefaultDataSource, GLTFLoaderPlugin, HalfFloatType, IFCOpenShellDefaultDataSource, IFCOpenShellLoaderPlugin, ImagePlane, IntType, JPEGMediaType, KTX2TextureTranscoder, LASLoaderPlugin, Label3D, LambertMaterial, LightMap, LineSet, LinearEncoding, LinearFilter, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, Loader, LoadingManager, LocaleService, LuminanceAlphaFormat, LuminanceFormat, Map$1 as Map, Marker, MarqueePicker, MarqueePickerMouseControl, Mesh, MeshSurfaceArea, MeshVolume, MetallicMaterial, MirroredRepeatWrapping, ModelMemento, NavCubePlugin, NearestFilter, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, Node$1 as Node, OBJLoaderPlugin, ObjectsKdTree3, ObjectsMemento, PNGMediaType, Path, PerformanceModel, PhongMaterial, PickResult, Plugin, PointLight, PointerCircle, PointerLens, QuadraticBezierCurve, Queue, RGBAFormat, RGBAIntegerFormat, RGBA_ASTC_10x10_Format, RGBA_ASTC_10x5_Format, RGBA_ASTC_10x6_Format, RGBA_ASTC_10x8_Format, RGBA_ASTC_12x10_Format, RGBA_ASTC_12x12_Format, RGBA_ASTC_4x4_Format, RGBA_ASTC_5x4_Format, RGBA_ASTC_5x5_Format, RGBA_ASTC_6x5_Format, RGBA_ASTC_6x6_Format, RGBA_ASTC_8x5_Format, RGBA_ASTC_8x6_Format, RGBA_ASTC_8x8_Format, RGBA_BPTC_Format, RGBA_ETC2_EAC_Format, RGBA_PVRTC_2BPPV1_Format, RGBA_PVRTC_4BPPV1_Format, RGBA_S3TC_DXT1_Format, RGBA_S3TC_DXT3_Format, RGBA_S3TC_DXT5_Format, RGBFormat, RGB_ETC1_Format, RGB_ETC2_Format, RGB_PVRTC_2BPPV1_Format, RGB_PVRTC_4BPPV1_Format, RGB_S3TC_DXT1_Format, RGFormat, RGIntegerFormat, ReadableGeometry, RedFormat, RedIntegerFormat, ReflectionMap, RepeatWrapping, STLDefaultDataSource, STLLoaderPlugin, SceneModel, SceneModelMesh, SceneModelTransform, SectionPlane, SectionPlanesPlugin, ShortType, SpecularMaterial, SplineCurve, SpriteMarker, StoreyViewsPlugin, Texture, TextureTranscoder, TransformControl, TreeViewPlugin, UnsignedByteType, UnsignedInt248Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VBOGeometry, ViewCullPlugin, Viewer, WebIFCLoaderPlugin, Wire3D, WorkerPool$1 as WorkerPool, XKTDefaultDataSource, XKTLoaderPlugin, XML3DLoaderPlugin, ZoneEditControl, ZoneEditMouseControl, ZoneEditTouchControl, ZoneTranslateControl, ZoneTranslateMouseControl, ZoneTranslateTouchControl, ZonesMouseControl, ZonesPlugin, ZonesPolysurfaceMouseControl, ZonesPolysurfaceTouchControl, ZonesTouchControl, activateDraggableDot, activateDraggableDots, addMousePressListener, addTouchPressListener, buildBoxGeometry, buildBoxLinesGeometry, buildBoxLinesGeometryFromAABB, buildCylinderGeometry, buildGridGeometry, buildLineGeometry, buildPlaneGeometry, buildPolylineGeometry, buildPolylineGeometryFromCurve, buildSphereGeometry, buildTorusGeometry, buildVectorTextGeometry, createCombinedTexture, createRTCViewMat, createSkyboxMesh, createSphereMapMesh, frustumIntersectsAABB3, getKTX2TextureTranscoder, isTriangleMeshSolid, load3DSGeometry, loadOBJGeometry, marker3D, math, meshSurfaceArea, meshVolume, os, sRGBEncoding, setFrustum, startPolygonCreate, stats, touchPointSelector, transformToNode, triangulateEarClipping, utils, wire3D, worldToRTCPos, worldToRTCPositions };