@thatopen/components 3.4.5 → 3.4.7
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.
- package/README.md +1 -0
- package/dist/index.cjs +385 -97
- package/dist/index.d.ts +85 -2
- package/dist/index.min.cjs +2 -2
- package/dist/index.min.mjs +2 -2
- package/dist/index.mjs +387 -99
- package/package.json +1 -1
package/dist/index.mjs
CHANGED
|
@@ -7,9 +7,9 @@ var __publicField = (obj, key, value) => {
|
|
|
7
7
|
import * as FRAGS from "@thatopen/fragments";
|
|
8
8
|
import { DataMap as DataMap$1, FragmentsModels, DataSet as DataSet$1 } from "@thatopen/fragments";
|
|
9
9
|
import * as THREE from "three";
|
|
10
|
-
import { Box3, Matrix4, BufferAttribute, Vector3,
|
|
10
|
+
import { Box3, Matrix4, BufferAttribute, Vector3, Line3, Plane, Vector2, Triangle, BackSide, DoubleSide, REVISION, Ray, FrontSide, Mesh, LineSegments, LineLoop, Line, Points, Sphere, BatchedMesh, OrthographicCamera, WebGLRenderTarget, Scene, Color, ShaderMaterial, Vector4, NoBlending, GLSL3, MathUtils, BufferGeometry } from "three";
|
|
11
11
|
import * as THREEWEBGPU from "three/webgpu";
|
|
12
|
-
import { instancedArray, Fn, mat4, Loop, int, vec3, vec4, float, cross, If, Continue, max, min, normalize, select, abs, mix, uint, atomicAdd
|
|
12
|
+
import { instancedArray, Fn, instanceIndex, mat4, Loop, int, vec3, vec4, float, cross, If, Continue, max, min, normalize, select, abs, mix, uint, atomicAdd } from "three/tsl";
|
|
13
13
|
import * as WEBIFC from "web-ifc";
|
|
14
14
|
import CameraControls from "camera-controls";
|
|
15
15
|
import { TransformControls } from "three/examples/jsm/controls/TransformControls.js";
|
|
@@ -177,6 +177,15 @@ class BaseRenderer extends BaseWorldItem {
|
|
|
177
177
|
* The list of [clipping planes](https://threejs.org/docs/#api/en/renderers/WebGLRenderer.clippingPlanes) used by this instance of the renderer.
|
|
178
178
|
*/
|
|
179
179
|
__publicField(this, "clippingPlanes", []);
|
|
180
|
+
/**
|
|
181
|
+
* The default `isLocal` value used by {@link setPlane} when the caller
|
|
182
|
+
* doesn't pass one. When `true`, planes added without an explicit
|
|
183
|
+
* `isLocal` stay out of the global `three.clippingPlanes` list and are
|
|
184
|
+
* clipped per-material instead. The {@link Clipper} sets this to mirror
|
|
185
|
+
* its own `localClippingPlanes` flag, so consumers like `Views` that add
|
|
186
|
+
* their own planes automatically inherit the active clipping mode.
|
|
187
|
+
*/
|
|
188
|
+
__publicField(this, "localClippingPlanes", false);
|
|
180
189
|
}
|
|
181
190
|
/**
|
|
182
191
|
* Updates the clipping planes and triggers the `onClippingPlanesUpdated` event.
|
|
@@ -202,7 +211,7 @@ class BaseRenderer extends BaseWorldItem {
|
|
|
202
211
|
* The `three.clippingPlanes` property is then updated to reflect the current state of the `clippingPlanes` array,
|
|
203
212
|
* excluding any planes marked as local.
|
|
204
213
|
*/
|
|
205
|
-
setPlane(active, plane, isLocal) {
|
|
214
|
+
setPlane(active, plane, isLocal = this.localClippingPlanes) {
|
|
206
215
|
plane.isLocal = isLocal;
|
|
207
216
|
const index = this.clippingPlanes.indexOf(plane);
|
|
208
217
|
if (active && index === -1) {
|
|
@@ -213,6 +222,7 @@ class BaseRenderer extends BaseWorldItem {
|
|
|
213
222
|
this.three.clippingPlanes = this.clippingPlanes.filter(
|
|
214
223
|
(plane2) => !plane2.isLocal
|
|
215
224
|
);
|
|
225
|
+
this.updateClippingPlanes();
|
|
216
226
|
}
|
|
217
227
|
}
|
|
218
228
|
const _Disposer = class _Disposer extends Component {
|
|
@@ -9467,9 +9477,11 @@ class VisibilityCuller {
|
|
|
9467
9477
|
const tilesX = Math.ceil(pixelWidth / maxTextureSize);
|
|
9468
9478
|
const tilesY = Math.ceil(pixelHeight / maxTextureSize);
|
|
9469
9479
|
target.setSize(Math.ceil(pixelWidth / tilesX), Math.ceil(pixelHeight / tilesY));
|
|
9480
|
+
const yMargin = Math.max(size.y, 1) * 0.01;
|
|
9470
9481
|
camera.rotation.x = -Math.PI / 2;
|
|
9471
|
-
camera.
|
|
9472
|
-
camera.
|
|
9482
|
+
camera.near = 0;
|
|
9483
|
+
camera.far = size.y + 2 * yMargin;
|
|
9484
|
+
camera.position.y = box.max.y + yMargin;
|
|
9473
9485
|
const idScene = new Scene();
|
|
9474
9486
|
const originalMaterials = /* @__PURE__ */ new Map();
|
|
9475
9487
|
const originalParents = /* @__PURE__ */ new Map();
|
|
@@ -9503,7 +9515,7 @@ class VisibilityCuller {
|
|
|
9503
9515
|
const tileMaxZ = tileMinZ + stepZ;
|
|
9504
9516
|
const tileCenterX = (tileMinX + tileMaxX) / 2;
|
|
9505
9517
|
const tileCenterZ = (tileMinZ + tileMaxZ) / 2;
|
|
9506
|
-
camera.position.set(tileCenterX, box.max.y, tileCenterZ);
|
|
9518
|
+
camera.position.set(tileCenterX, box.max.y + yMargin, tileCenterZ);
|
|
9507
9519
|
const halfWidth = stepX / 2;
|
|
9508
9520
|
const halfHeight = stepZ / 2;
|
|
9509
9521
|
camera.left = -halfWidth;
|
|
@@ -9552,6 +9564,11 @@ class IDMaterial extends ShaderMaterial {
|
|
|
9552
9564
|
super({
|
|
9553
9565
|
glslVersion: GLSL3,
|
|
9554
9566
|
blending: NoBlending,
|
|
9567
|
+
// A flat item (a slab) seen straight down shows only one face; if its
|
|
9568
|
+
// winding puts the back face toward the camera it wouldn't rasterize and
|
|
9569
|
+
// the item would be culled. The pass only cares about coverage, so render
|
|
9570
|
+
// both sides.
|
|
9571
|
+
side: DoubleSide,
|
|
9555
9572
|
uniforms: {
|
|
9556
9573
|
objectId: { value: new Vector4() }
|
|
9557
9574
|
},
|
|
@@ -12542,6 +12559,19 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
12542
12559
|
* restored after.
|
|
12543
12560
|
*/
|
|
12544
12561
|
__publicField(this, "_hiddenLods", []);
|
|
12562
|
+
/**
|
|
12563
|
+
* The meshes each model owns, i.e. excluding those belonging to a
|
|
12564
|
+
* model nested inside it. A delta model's object is parented under
|
|
12565
|
+
* its parent model's object (see the fragments EditHelper), while
|
|
12566
|
+
* both are listed as separate models, so subtree membership alone
|
|
12567
|
+
* does not determine ownership.
|
|
12568
|
+
*
|
|
12569
|
+
* Populated in {@link applyIdMaterial}, consumed by
|
|
12570
|
+
* {@link renderPickPass} to isolate one model per render without
|
|
12571
|
+
* relying on root visibility. A nested model can't be isolated by
|
|
12572
|
+
* its root, since hiding the parent's root culls the child too.
|
|
12573
|
+
*/
|
|
12574
|
+
__publicField(this, "_ownMeshes", /* @__PURE__ */ new Map());
|
|
12545
12575
|
if (!world.renderer) {
|
|
12546
12576
|
throw new Error("A renderer is needed for the FastModelPicker to work!");
|
|
12547
12577
|
}
|
|
@@ -12782,14 +12812,14 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
12782
12812
|
applyIdMaterial() {
|
|
12783
12813
|
const fragments = this.components.get(FragmentsManager);
|
|
12784
12814
|
const byteToModel = /* @__PURE__ */ new Map();
|
|
12815
|
+
const modelRoots = this.getModelRoots();
|
|
12816
|
+
this._ownMeshes.clear();
|
|
12785
12817
|
let nextByte = 1;
|
|
12786
12818
|
for (const [modelId, model] of fragments.list) {
|
|
12787
12819
|
if (nextByte > _FastModelPicker.MAX_MODELS)
|
|
12788
12820
|
break;
|
|
12789
|
-
const
|
|
12790
|
-
|
|
12791
|
-
let any = false;
|
|
12792
|
-
model.object.traverse((child) => {
|
|
12821
|
+
const owned = [];
|
|
12822
|
+
this.traverseOwn(model.object, modelRoots, (child) => {
|
|
12793
12823
|
if (!(child instanceof THREE.Mesh))
|
|
12794
12824
|
return;
|
|
12795
12825
|
const geom = child.geometry;
|
|
@@ -12803,14 +12833,47 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
12803
12833
|
return;
|
|
12804
12834
|
}
|
|
12805
12835
|
this._originalMaterials.set(child, child.material);
|
|
12806
|
-
|
|
12807
|
-
|
|
12836
|
+
const original = child.material;
|
|
12837
|
+
const len = Array.isArray(original) ? original.length : 1;
|
|
12838
|
+
child.material = new Array(len).fill(this._idMaterial);
|
|
12839
|
+
owned.push(child);
|
|
12808
12840
|
});
|
|
12809
|
-
if (
|
|
12810
|
-
|
|
12841
|
+
if (!owned.length)
|
|
12842
|
+
continue;
|
|
12843
|
+
this._ownMeshes.set(modelId, owned);
|
|
12844
|
+
byteToModel.set(nextByte, modelId);
|
|
12845
|
+
nextByte += 1;
|
|
12811
12846
|
}
|
|
12812
12847
|
return byteToModel;
|
|
12813
12848
|
}
|
|
12849
|
+
/**
|
|
12850
|
+
* The object roots of every loaded model.
|
|
12851
|
+
*/
|
|
12852
|
+
getModelRoots() {
|
|
12853
|
+
const fragments = this.components.get(FragmentsManager);
|
|
12854
|
+
const roots = /* @__PURE__ */ new Set();
|
|
12855
|
+
for (const [, model] of fragments.list)
|
|
12856
|
+
roots.add(model.object);
|
|
12857
|
+
return roots;
|
|
12858
|
+
}
|
|
12859
|
+
/**
|
|
12860
|
+
* Like `Object3D.traverse`, but prunes the subtree of any nested model
|
|
12861
|
+
* root, so each mesh is visited exactly once, by the model that owns
|
|
12862
|
+
* it. A delta model's object hangs under its parent model's object
|
|
12863
|
+
* while being a model in its own right; a plain `traverse` from the
|
|
12864
|
+
* parent would walk into it.
|
|
12865
|
+
*/
|
|
12866
|
+
traverseOwn(root, modelRoots, callback) {
|
|
12867
|
+
const stack = [root];
|
|
12868
|
+
while (stack.length) {
|
|
12869
|
+
const node = stack.pop();
|
|
12870
|
+
if (node !== root && modelRoots.has(node))
|
|
12871
|
+
continue;
|
|
12872
|
+
callback(node);
|
|
12873
|
+
for (const child of node.children)
|
|
12874
|
+
stack.push(child);
|
|
12875
|
+
}
|
|
12876
|
+
}
|
|
12814
12877
|
/**
|
|
12815
12878
|
* Renders the world scene to the id target one model at a time,
|
|
12816
12879
|
* flipping the `modelByte` uniform between renders. The depth buffer
|
|
@@ -12901,21 +12964,47 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
12901
12964
|
nonBimVisibility.set(child, child.visible);
|
|
12902
12965
|
child.visible = false;
|
|
12903
12966
|
});
|
|
12904
|
-
const
|
|
12967
|
+
const wasOnScreen = /* @__PURE__ */ new Map();
|
|
12968
|
+
for (const [modelId, obj] of objectsByModel) {
|
|
12969
|
+
let visible = true;
|
|
12970
|
+
let node = obj;
|
|
12971
|
+
while (node) {
|
|
12972
|
+
if (!node.visible) {
|
|
12973
|
+
visible = false;
|
|
12974
|
+
break;
|
|
12975
|
+
}
|
|
12976
|
+
node = node.parent;
|
|
12977
|
+
}
|
|
12978
|
+
wasOnScreen.set(modelId, visible);
|
|
12979
|
+
}
|
|
12980
|
+
const rootVisibilityBefore = /* @__PURE__ */ new Map();
|
|
12905
12981
|
for (const obj of objectsByModel.values()) {
|
|
12906
|
-
|
|
12907
|
-
obj.visible =
|
|
12982
|
+
rootVisibilityBefore.set(obj, obj.visible);
|
|
12983
|
+
obj.visible = true;
|
|
12984
|
+
}
|
|
12985
|
+
const meshVisibilityBefore = /* @__PURE__ */ new Map();
|
|
12986
|
+
for (const meshes of this._ownMeshes.values()) {
|
|
12987
|
+
for (const mesh of meshes) {
|
|
12988
|
+
meshVisibilityBefore.set(mesh, mesh.visible);
|
|
12989
|
+
mesh.visible = false;
|
|
12990
|
+
}
|
|
12908
12991
|
}
|
|
12909
12992
|
for (const [byte, modelId] of byteToModel) {
|
|
12910
|
-
|
|
12911
|
-
if (!obj)
|
|
12993
|
+
if (!wasOnScreen.get(modelId))
|
|
12912
12994
|
continue;
|
|
12913
|
-
|
|
12995
|
+
const meshes = this._ownMeshes.get(modelId);
|
|
12996
|
+
if (!meshes)
|
|
12997
|
+
continue;
|
|
12998
|
+
for (const mesh of meshes)
|
|
12999
|
+
mesh.visible = meshVisibilityBefore.get(mesh);
|
|
12914
13000
|
material.uniforms.modelByte.value = byte;
|
|
12915
13001
|
renderer.render(scene, camera);
|
|
12916
|
-
|
|
13002
|
+
for (const mesh of meshes)
|
|
13003
|
+
mesh.visible = false;
|
|
12917
13004
|
}
|
|
12918
|
-
for (const [
|
|
13005
|
+
for (const [mesh, was] of meshVisibilityBefore)
|
|
13006
|
+
mesh.visible = was;
|
|
13007
|
+
for (const [obj, was] of rootVisibilityBefore)
|
|
12919
13008
|
obj.visible = was;
|
|
12920
13009
|
for (const [obj, was] of nonBimVisibility)
|
|
12921
13010
|
obj.visible = was;
|
|
@@ -12956,8 +13045,9 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
12956
13045
|
const prevClearAlpha = renderer.getClearAlpha();
|
|
12957
13046
|
const matSwap = /* @__PURE__ */ new Map();
|
|
12958
13047
|
const hiddenLines = [];
|
|
13048
|
+
const modelRoots = this.getModelRoots();
|
|
12959
13049
|
for (const [, model] of fragments.list) {
|
|
12960
|
-
model.object
|
|
13050
|
+
this.traverseOwn(model.object, modelRoots, (child) => {
|
|
12961
13051
|
if (!(child instanceof THREE.Mesh))
|
|
12962
13052
|
return;
|
|
12963
13053
|
const geom = child.geometry;
|
|
@@ -12973,7 +13063,9 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
12973
13063
|
if (!child.visible)
|
|
12974
13064
|
return;
|
|
12975
13065
|
matSwap.set(child, child.material);
|
|
12976
|
-
|
|
13066
|
+
const original = child.material;
|
|
13067
|
+
const len = Array.isArray(original) ? original.length : 1;
|
|
13068
|
+
child.material = new Array(len).fill(material);
|
|
12977
13069
|
});
|
|
12978
13070
|
}
|
|
12979
13071
|
const bimRoots = /* @__PURE__ */ new Set();
|
|
@@ -13025,6 +13117,7 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
13025
13117
|
mesh.material = mat;
|
|
13026
13118
|
}
|
|
13027
13119
|
this._originalMaterials.clear();
|
|
13120
|
+
this._ownMeshes.clear();
|
|
13028
13121
|
for (const obj of this._hiddenLods)
|
|
13029
13122
|
obj.visible = true;
|
|
13030
13123
|
this._hiddenLods.length = 0;
|
|
@@ -13401,12 +13494,32 @@ class SnapResolver {
|
|
|
13401
13494
|
*/
|
|
13402
13495
|
__publicField(this, "maxCacheSize", 1e3);
|
|
13403
13496
|
__publicField(this, "components");
|
|
13497
|
+
__publicField(this, "_precision", "half");
|
|
13404
13498
|
// Map insertion order is recency order (LRU). On every read we
|
|
13405
13499
|
// delete + re-set the entry to bump it to most-recent; on every
|
|
13406
13500
|
// write we drop oldest entries until size <= maxCacheSize.
|
|
13407
13501
|
__publicField(this, "cache", /* @__PURE__ */ new Map());
|
|
13408
13502
|
this.components = components;
|
|
13409
13503
|
}
|
|
13504
|
+
/**
|
|
13505
|
+
* Numeric precision for cached face/edge/vertex buffers.
|
|
13506
|
+
*
|
|
13507
|
+
* `"half"` uses Float32Array for lower memory footprint.
|
|
13508
|
+
* `"full"` uses Float64Array for higher numeric precision.
|
|
13509
|
+
* Use `"full"` for workflows that require higher geometric fidelity.
|
|
13510
|
+
*
|
|
13511
|
+
* Changing this value clears the snap cache so subsequent requests
|
|
13512
|
+
* are rebuilt with the new precision.
|
|
13513
|
+
*/
|
|
13514
|
+
get precision() {
|
|
13515
|
+
return this._precision;
|
|
13516
|
+
}
|
|
13517
|
+
set precision(value) {
|
|
13518
|
+
if (value === this._precision)
|
|
13519
|
+
return;
|
|
13520
|
+
this._precision = value;
|
|
13521
|
+
this.clear();
|
|
13522
|
+
}
|
|
13410
13523
|
/** {@link Disposable.dispose} */
|
|
13411
13524
|
dispose() {
|
|
13412
13525
|
this.cache.clear();
|
|
@@ -13546,8 +13659,8 @@ class SnapResolver {
|
|
|
13546
13659
|
}
|
|
13547
13660
|
if (polygons.length === 0)
|
|
13548
13661
|
return null;
|
|
13549
|
-
const edges = deriveUniqueEdges(polygons);
|
|
13550
|
-
const vertices = deriveUniqueVertices(polygons);
|
|
13662
|
+
const edges = deriveUniqueEdges(polygons, this._precision);
|
|
13663
|
+
const vertices = deriveUniqueVertices(polygons, this._precision);
|
|
13551
13664
|
return { faces: polygons, edges, vertices };
|
|
13552
13665
|
}
|
|
13553
13666
|
collectPolygonsFromShell(shell, worldMatrix, out) {
|
|
@@ -13558,7 +13671,8 @@ class SnapResolver {
|
|
|
13558
13671
|
const collect = (indices) => {
|
|
13559
13672
|
if (indices.length < 3)
|
|
13560
13673
|
return;
|
|
13561
|
-
const
|
|
13674
|
+
const Ctor = this._precision === "full" ? Float64Array : Float32Array;
|
|
13675
|
+
const flat = new Ctor(indices.length * 3);
|
|
13562
13676
|
for (let i = 0; i < indices.length; i++) {
|
|
13563
13677
|
const p = points[indices[i]];
|
|
13564
13678
|
tmp.set(p[0], p[1], p[2]).applyMatrix4(worldMatrix);
|
|
@@ -13667,19 +13781,33 @@ class SnapResolver {
|
|
|
13667
13781
|
return null;
|
|
13668
13782
|
let best = null;
|
|
13669
13783
|
let bestAbs = Infinity;
|
|
13784
|
+
let bestContains = false;
|
|
13670
13785
|
for (const f of faces) {
|
|
13671
|
-
const signed =
|
|
13786
|
+
const signed = this.signedDistance(f, point);
|
|
13672
13787
|
const abs2 = Math.abs(signed);
|
|
13673
|
-
if (abs2
|
|
13788
|
+
if (abs2 > this.maxDistance)
|
|
13789
|
+
continue;
|
|
13790
|
+
const contains = this.containsPoint(f, this.projectOntoPlane(point, f, signed));
|
|
13791
|
+
if (bestContains && !contains)
|
|
13792
|
+
continue;
|
|
13793
|
+
if (contains && !bestContains) {
|
|
13794
|
+
bestContains = true;
|
|
13795
|
+
bestAbs = abs2;
|
|
13796
|
+
best = f;
|
|
13797
|
+
continue;
|
|
13798
|
+
}
|
|
13799
|
+
if (abs2 < bestAbs) {
|
|
13674
13800
|
bestAbs = abs2;
|
|
13675
13801
|
best = f;
|
|
13676
13802
|
}
|
|
13677
13803
|
}
|
|
13678
13804
|
if (!best)
|
|
13679
13805
|
return null;
|
|
13680
|
-
const projected =
|
|
13681
|
-
|
|
13682
|
-
|
|
13806
|
+
const projected = this.projectOntoPlane(
|
|
13807
|
+
point,
|
|
13808
|
+
best,
|
|
13809
|
+
this.signedDistance(best, point)
|
|
13810
|
+
);
|
|
13683
13811
|
return {
|
|
13684
13812
|
result: {
|
|
13685
13813
|
point: projected,
|
|
@@ -13690,6 +13818,50 @@ class SnapResolver {
|
|
|
13690
13818
|
}
|
|
13691
13819
|
};
|
|
13692
13820
|
}
|
|
13821
|
+
signedDistance(face, point) {
|
|
13822
|
+
return face.normal.x * point.x + face.normal.y * point.y + face.normal.z * point.z - face.d;
|
|
13823
|
+
}
|
|
13824
|
+
projectOntoPlane(point, face, signed) {
|
|
13825
|
+
return point.clone().sub(face.normal.clone().multiplyScalar(signed));
|
|
13826
|
+
}
|
|
13827
|
+
/**
|
|
13828
|
+
* Even-odd point-in-polygon test, run on the polygon projected onto its
|
|
13829
|
+
* dominant plane. `point` is assumed to already lie on the face's plane.
|
|
13830
|
+
*/
|
|
13831
|
+
containsPoint(face, point) {
|
|
13832
|
+
const { points, normal } = face;
|
|
13833
|
+
const count = points.length / 3;
|
|
13834
|
+
if (count < 3)
|
|
13835
|
+
return false;
|
|
13836
|
+
const ax = Math.abs(normal.x);
|
|
13837
|
+
const ay = Math.abs(normal.y);
|
|
13838
|
+
const az = Math.abs(normal.z);
|
|
13839
|
+
let a = 0;
|
|
13840
|
+
let b = 1;
|
|
13841
|
+
if (ax >= ay && ax >= az) {
|
|
13842
|
+
a = 1;
|
|
13843
|
+
b = 2;
|
|
13844
|
+
} else if (ay >= az) {
|
|
13845
|
+
a = 0;
|
|
13846
|
+
b = 2;
|
|
13847
|
+
}
|
|
13848
|
+
const px = point.getComponent(a);
|
|
13849
|
+
const py = point.getComponent(b);
|
|
13850
|
+
let inside = false;
|
|
13851
|
+
for (let i = 0, j = count - 1; i < count; j = i, i += 1) {
|
|
13852
|
+
const xi = points[i * 3 + a];
|
|
13853
|
+
const yi = points[i * 3 + b];
|
|
13854
|
+
const xj = points[j * 3 + a];
|
|
13855
|
+
const yj = points[j * 3 + b];
|
|
13856
|
+
const straddles = yi > py !== yj > py;
|
|
13857
|
+
if (!straddles)
|
|
13858
|
+
continue;
|
|
13859
|
+
const x = (xj - xi) * (py - yi) / (yj - yi) + xi;
|
|
13860
|
+
if (px < x)
|
|
13861
|
+
inside = !inside;
|
|
13862
|
+
}
|
|
13863
|
+
return inside;
|
|
13864
|
+
}
|
|
13693
13865
|
}
|
|
13694
13866
|
const _tmpMatrix = new THREE.Matrix4();
|
|
13695
13867
|
const _tmpX = new THREE.Vector3();
|
|
@@ -13757,7 +13929,7 @@ function fanTriangulation(vertexCount) {
|
|
|
13757
13929
|
}
|
|
13758
13930
|
return out;
|
|
13759
13931
|
}
|
|
13760
|
-
function deriveUniqueEdges(faces) {
|
|
13932
|
+
function deriveUniqueEdges(faces, precision) {
|
|
13761
13933
|
const seen = /* @__PURE__ */ new Set();
|
|
13762
13934
|
const collected = [];
|
|
13763
13935
|
for (const f of faces) {
|
|
@@ -13774,9 +13946,10 @@ function deriveUniqueEdges(faces) {
|
|
|
13774
13946
|
collected.push(ax, ay, az, bx, by, bz);
|
|
13775
13947
|
}
|
|
13776
13948
|
}
|
|
13777
|
-
|
|
13949
|
+
const Ctor = precision === "full" ? Float64Array : Float32Array;
|
|
13950
|
+
return new Ctor(collected);
|
|
13778
13951
|
}
|
|
13779
|
-
function deriveUniqueVertices(faces) {
|
|
13952
|
+
function deriveUniqueVertices(faces, precision) {
|
|
13780
13953
|
const seen = /* @__PURE__ */ new Set();
|
|
13781
13954
|
const collected = [];
|
|
13782
13955
|
for (const f of faces) {
|
|
@@ -13791,7 +13964,8 @@ function deriveUniqueVertices(faces) {
|
|
|
13791
13964
|
collected.push(x, y, z);
|
|
13792
13965
|
}
|
|
13793
13966
|
}
|
|
13794
|
-
|
|
13967
|
+
const Ctor = precision === "full" ? Float64Array : Float32Array;
|
|
13968
|
+
return new Ctor(collected);
|
|
13795
13969
|
}
|
|
13796
13970
|
function quantKey(x, y, z) {
|
|
13797
13971
|
return `${Math.round(x * VERTEX_QUANT)},${Math.round(y * VERTEX_QUANT)},${Math.round(z * VERTEX_QUANT)}`;
|
|
@@ -14087,6 +14261,9 @@ class SimpleWorld extends Base {
|
|
|
14087
14261
|
*/
|
|
14088
14262
|
__publicField(this, "enabled", true);
|
|
14089
14263
|
__publicField(this, "_dynamicAnchor", false);
|
|
14264
|
+
// Bumped on every anchor press so a slow geometry pick that resolves after a
|
|
14265
|
+
// newer press is ignored (see onPointerDown).
|
|
14266
|
+
__publicField(this, "_anchorRequestId", 0);
|
|
14090
14267
|
/**
|
|
14091
14268
|
* A unique identifier for the world. Is not meant to be changed at any moment.
|
|
14092
14269
|
*/
|
|
@@ -14098,21 +14275,36 @@ class SimpleWorld extends Base {
|
|
|
14098
14275
|
__publicField(this, "_scene");
|
|
14099
14276
|
__publicField(this, "_camera");
|
|
14100
14277
|
__publicField(this, "_renderer", null);
|
|
14101
|
-
__publicField(this, "onPointerDown",
|
|
14278
|
+
__publicField(this, "onPointerDown", (event) => {
|
|
14102
14279
|
if (!this.camera.hasCameraControls()) {
|
|
14103
14280
|
throw new Error(
|
|
14104
14281
|
"World: can't set dynamic anchor if the camera doesn't have controls."
|
|
14105
14282
|
);
|
|
14106
14283
|
}
|
|
14284
|
+
if (event.button !== 0)
|
|
14285
|
+
return;
|
|
14286
|
+
const position = this.getPointerPosition(event);
|
|
14287
|
+
if (!position)
|
|
14288
|
+
return;
|
|
14107
14289
|
const caster = this.components.get(Raycasters).get(this);
|
|
14108
|
-
const
|
|
14109
|
-
if (
|
|
14290
|
+
const planePoint = this.getPlaneAnchor(caster, position);
|
|
14291
|
+
if (planePoint) {
|
|
14110
14292
|
this.camera.controls.setOrbitPoint(
|
|
14111
|
-
|
|
14112
|
-
|
|
14113
|
-
|
|
14293
|
+
planePoint.x,
|
|
14294
|
+
planePoint.y,
|
|
14295
|
+
planePoint.z
|
|
14114
14296
|
);
|
|
14115
14297
|
}
|
|
14298
|
+
const requestId = ++this._anchorRequestId;
|
|
14299
|
+
caster.castRay({ position }).then((result) => {
|
|
14300
|
+
const isStale = requestId !== this._anchorRequestId;
|
|
14301
|
+
if (isStale || this.isDisposing || !this._dynamicAnchor)
|
|
14302
|
+
return;
|
|
14303
|
+
if (!(result == null ? void 0 : result.point) || !this.camera.hasCameraControls())
|
|
14304
|
+
return;
|
|
14305
|
+
const { x, y, z } = result.point;
|
|
14306
|
+
this.camera.controls.setOrbitPoint(x, y, z);
|
|
14307
|
+
});
|
|
14116
14308
|
});
|
|
14117
14309
|
__publicField(this, "_defaultCamera");
|
|
14118
14310
|
}
|
|
@@ -14131,10 +14323,46 @@ class SimpleWorld extends Base {
|
|
|
14131
14323
|
} else {
|
|
14132
14324
|
container.removeEventListener("pointerdown", this.onPointerDown);
|
|
14133
14325
|
}
|
|
14326
|
+
this._dynamicAnchor = value;
|
|
14134
14327
|
}
|
|
14135
14328
|
get dynamicAnchor() {
|
|
14136
14329
|
return this._dynamicAnchor;
|
|
14137
14330
|
}
|
|
14331
|
+
/**
|
|
14332
|
+
* The pointer position in normalized device coordinates, derived from the
|
|
14333
|
+
* event rather than the raycaster's mouse: that one only tracks pointermove
|
|
14334
|
+
* and touchstart, so on a bare pointerdown it would still report the center of
|
|
14335
|
+
* the viewport.
|
|
14336
|
+
*/
|
|
14337
|
+
getPointerPosition(event) {
|
|
14338
|
+
var _a;
|
|
14339
|
+
const dom = (_a = this.renderer) == null ? void 0 : _a.three.domElement;
|
|
14340
|
+
if (!dom)
|
|
14341
|
+
return null;
|
|
14342
|
+
const bounds = dom.getBoundingClientRect();
|
|
14343
|
+
return new THREE.Vector2(
|
|
14344
|
+
(event.clientX - bounds.left) / (bounds.right - bounds.left) * 2 - 1,
|
|
14345
|
+
-((event.clientY - bounds.top) / (bounds.bottom - bounds.top)) * 2 + 1
|
|
14346
|
+
);
|
|
14347
|
+
}
|
|
14348
|
+
/**
|
|
14349
|
+
* The point where the pointer ray crosses the plane that contains the current
|
|
14350
|
+
* orbit target and faces the camera. Used as the anchor when the pointer
|
|
14351
|
+
* doesn't land on any geometry.
|
|
14352
|
+
*/
|
|
14353
|
+
getPlaneAnchor(caster, position) {
|
|
14354
|
+
if (!this.camera.hasCameraControls())
|
|
14355
|
+
return null;
|
|
14356
|
+
const camera = this.camera.three;
|
|
14357
|
+
caster.three.setFromCamera(position, camera);
|
|
14358
|
+
const target = this.camera.controls.getTarget(new THREE.Vector3());
|
|
14359
|
+
const normal = camera.getWorldDirection(new THREE.Vector3());
|
|
14360
|
+
const plane = new THREE.Plane().setFromNormalAndCoplanarPoint(
|
|
14361
|
+
normal,
|
|
14362
|
+
target
|
|
14363
|
+
);
|
|
14364
|
+
return caster.three.ray.intersectPlane(plane, new THREE.Vector3());
|
|
14365
|
+
}
|
|
14138
14366
|
get defaultCamera() {
|
|
14139
14367
|
if (!this._defaultCamera) {
|
|
14140
14368
|
throw new Error("World: there is no default camera defined.");
|
|
@@ -14237,8 +14465,16 @@ class SimpleWorld extends Base {
|
|
|
14237
14465
|
}
|
|
14238
14466
|
/** {@link Disposable.dispose} */
|
|
14239
14467
|
dispose(disposeResources = true) {
|
|
14468
|
+
var _a;
|
|
14469
|
+
if (this.isDisposing)
|
|
14470
|
+
return;
|
|
14240
14471
|
this.enabled = false;
|
|
14241
14472
|
this.isDisposing = true;
|
|
14473
|
+
const container = (_a = this.renderer) == null ? void 0 : _a.three.domElement.parentElement;
|
|
14474
|
+
if (container) {
|
|
14475
|
+
container.removeEventListener("pointerdown", this.onPointerDown);
|
|
14476
|
+
}
|
|
14477
|
+
this._dynamicAnchor = false;
|
|
14242
14478
|
this.scene.onWorldChanged.trigger({ world: this, action: "removed" });
|
|
14243
14479
|
this.camera.onWorldChanged.trigger({ world: this, action: "removed" });
|
|
14244
14480
|
if (this.renderer) {
|
|
@@ -15485,16 +15721,23 @@ const _Components = class _Components {
|
|
|
15485
15721
|
dispose() {
|
|
15486
15722
|
this.enabled = false;
|
|
15487
15723
|
let fragments;
|
|
15724
|
+
let worlds;
|
|
15488
15725
|
for (const [_id, component] of this.list) {
|
|
15489
15726
|
component.enabled = false;
|
|
15490
15727
|
if (_id === FragmentsManager.uuid) {
|
|
15491
15728
|
fragments = component;
|
|
15492
15729
|
continue;
|
|
15493
15730
|
}
|
|
15731
|
+
if (_id === Worlds.uuid) {
|
|
15732
|
+
worlds = component;
|
|
15733
|
+
continue;
|
|
15734
|
+
}
|
|
15494
15735
|
if (component.isDisposeable()) {
|
|
15495
15736
|
component.dispose();
|
|
15496
15737
|
}
|
|
15497
15738
|
}
|
|
15739
|
+
if (worlds == null ? void 0 : worlds.isDisposeable())
|
|
15740
|
+
worlds.dispose();
|
|
15498
15741
|
fragments == null ? void 0 : fragments.dispose();
|
|
15499
15742
|
this._timer.dispose();
|
|
15500
15743
|
this.onDisposed.trigger();
|
|
@@ -15971,7 +16214,7 @@ Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/js
|
|
|
15971
16214
|
JSZip uses the library pako released under the MIT license :
|
|
15972
16215
|
https://github.com/nodeca/pako/blob/main/LICENSE
|
|
15973
16216
|
*/
|
|
15974
|
-
(function(module, exports) {
|
|
16217
|
+
(function(module, exports$1) {
|
|
15975
16218
|
!function(e) {
|
|
15976
16219
|
module.exports = e();
|
|
15977
16220
|
}(function() {
|
|
@@ -19029,33 +19272,31 @@ const _Topic = class _Topic {
|
|
|
19029
19272
|
serialize() {
|
|
19030
19273
|
var _a, _b;
|
|
19031
19274
|
const version = this._managerVersion;
|
|
19275
|
+
const isV3 = version === "3";
|
|
19032
19276
|
const topic = {
|
|
19033
19277
|
$Guid: this.guid,
|
|
19034
19278
|
$TopicType: this.type,
|
|
19035
19279
|
$TopicStatus: this.status,
|
|
19036
19280
|
$ServerAssignedId: this.serverAssignedId,
|
|
19037
19281
|
Title: this.title,
|
|
19038
|
-
CreationAuthor: this.creationAuthor,
|
|
19039
|
-
CreationDate: this.creationDate.toISOString(),
|
|
19040
19282
|
Priority: this.priority,
|
|
19041
19283
|
Index: version === "2.1" ? this.index : void 0,
|
|
19284
|
+
Labels: isV3 ? { Label: this.createLabelTags() } : this.createLabelTags(),
|
|
19285
|
+
CreationDate: this.creationDate.toISOString(),
|
|
19286
|
+
CreationAuthor: this.creationAuthor,
|
|
19042
19287
|
ModifiedDate: (_a = this.modifiedDate) == null ? void 0 : _a.toISOString(),
|
|
19043
19288
|
ModifiedAuthor: this.modifiedAuthor,
|
|
19044
19289
|
DueDate: (_b = this.dueDate) == null ? void 0 : _b.toISOString(),
|
|
19045
19290
|
AssignedTo: this.assignedTo,
|
|
19046
|
-
Description: this.description,
|
|
19047
19291
|
Stage: this.stage,
|
|
19048
|
-
|
|
19049
|
-
|
|
19050
|
-
|
|
19051
|
-
|
|
19052
|
-
|
|
19053
|
-
Comments:
|
|
19292
|
+
Description: this.description,
|
|
19293
|
+
DocumentReferences: isV3 ? { DocumentReference: this.createDocumentReferencesTag(version) } : void 0,
|
|
19294
|
+
DocumentReference: isV3 ? void 0 : this.createDocumentReferencesTag(version),
|
|
19295
|
+
RelatedTopics: isV3 ? { RelatedTopic: this.createRelatedTopicTags() } : void 0,
|
|
19296
|
+
RelatedTopic: isV3 ? void 0 : this.createRelatedTopicTags(),
|
|
19297
|
+
Comments: isV3 ? { Comment: this.createCommentTags() } : void 0,
|
|
19298
|
+
Viewpoints: isV3 ? { ViewPoint: this.createViewpointTags() } : void 0
|
|
19054
19299
|
};
|
|
19055
|
-
if (version === "2.1") {
|
|
19056
|
-
topic.Labels = this.createLabelTags();
|
|
19057
|
-
topic.DocumentReference = this.createDocumentReferencesTag(version);
|
|
19058
|
-
}
|
|
19059
19300
|
const markup = {
|
|
19060
19301
|
Markup: { Topic: topic }
|
|
19061
19302
|
};
|
|
@@ -19482,10 +19723,13 @@ const _BCFTopics = class _BCFTopics extends Component {
|
|
|
19482
19723
|
*/
|
|
19483
19724
|
async export(topics = this.list.values()) {
|
|
19484
19725
|
const zip = new JSZip();
|
|
19726
|
+
const isV3 = this.config.version === "3";
|
|
19727
|
+
const versionId = isV3 ? "3.0" : this.config.version;
|
|
19728
|
+
const schemaRelease = isV3 ? "release_3_0" : "release_2_1";
|
|
19485
19729
|
zip.file(
|
|
19486
19730
|
"bcf.version",
|
|
19487
19731
|
`<?xml version="1.0" encoding="UTF-8"?>
|
|
19488
|
-
<Version VersionId="${
|
|
19732
|
+
<Version VersionId="${versionId}" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/buildingSMART/BCF-XML/${schemaRelease}/Schemas/version.xsd"
|
|
19489
19733
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
19490
19734
|
</Version>`
|
|
19491
19735
|
);
|
|
@@ -19520,7 +19764,7 @@ const _BCFTopics = class _BCFTopics extends Component {
|
|
|
19520
19764
|
);
|
|
19521
19765
|
}
|
|
19522
19766
|
}
|
|
19523
|
-
zip.file("
|
|
19767
|
+
zip.file("extensions.xml", this.serializeExtensions());
|
|
19524
19768
|
const viewpoints = this.components.get(Viewpoints);
|
|
19525
19769
|
for (const topic of topics) {
|
|
19526
19770
|
const topicFolder = zip.folder(topic.guid);
|
|
@@ -19592,7 +19836,7 @@ ${users}
|
|
|
19592
19836
|
Comment: CommentText,
|
|
19593
19837
|
Viewpoint: Viewpoint2
|
|
19594
19838
|
} = markupComment;
|
|
19595
|
-
if (!(Guid && CommentDate && Author && Comment))
|
|
19839
|
+
if (!(Guid && CommentDate && Author && (Comment || Viewpoint2)))
|
|
19596
19840
|
return null;
|
|
19597
19841
|
const comment = new Comment(this.components, CommentText ?? "");
|
|
19598
19842
|
comment.guid = Guid;
|
|
@@ -19689,14 +19933,16 @@ ${users}
|
|
|
19689
19933
|
const versionFile = files.find((file) => file.name.endsWith(".version"));
|
|
19690
19934
|
if (versionFile) {
|
|
19691
19935
|
const versionXML = await versionFile.async("string");
|
|
19692
|
-
const bcfVersion =
|
|
19693
|
-
|
|
19936
|
+
const bcfVersion = String(
|
|
19937
|
+
_BCFTopics.xmlParser.parse(versionXML).Version.VersionId
|
|
19938
|
+
);
|
|
19939
|
+
version = bcfVersion === "3.0" ? "3" : bcfVersion;
|
|
19694
19940
|
}
|
|
19695
19941
|
if (!(version && (version === "2.1" || version === "3"))) {
|
|
19696
19942
|
throw new Error(`BCFTopics: ${version} is not supported.`);
|
|
19697
19943
|
}
|
|
19698
19944
|
const extensionsFile = files.find(
|
|
19699
|
-
(file) => file.name.endsWith(".extensions")
|
|
19945
|
+
(file) => file.name.endsWith("extensions.xml") || file.name.endsWith(".extensions")
|
|
19700
19946
|
);
|
|
19701
19947
|
if (updateExtensionsOnImport && extensionsFile) {
|
|
19702
19948
|
const extensionsXML = await extensionsFile.async("string");
|
|
@@ -20239,7 +20485,7 @@ class SimplePlane {
|
|
|
20239
20485
|
dispose() {
|
|
20240
20486
|
var _a;
|
|
20241
20487
|
this._enabled = false;
|
|
20242
|
-
if ((_a = this.world.camera) == null ? void 0 : _a.controls) {
|
|
20488
|
+
if (!this.world.isDisposing && ((_a = this.world.camera) == null ? void 0 : _a.controls)) {
|
|
20243
20489
|
this.world.camera.controls.removeEventListener(
|
|
20244
20490
|
"update",
|
|
20245
20491
|
this.updateScale
|
|
@@ -20480,8 +20726,13 @@ const _Clipper = class _Clipper extends Component {
|
|
|
20480
20726
|
* Default `false` to preserve existing behavior. Set this once
|
|
20481
20727
|
* before creating planes; toggling at runtime won't reclassify
|
|
20482
20728
|
* planes already on the renderer.
|
|
20729
|
+
*
|
|
20730
|
+
* Setting this also mirrors the value onto every world's
|
|
20731
|
+
* `renderer.localClippingPlanes`, so planes added by other
|
|
20732
|
+
* components (e.g. the {@link Views} cut planes) default to the
|
|
20733
|
+
* same mode without each call site having to pass `isLocal`.
|
|
20483
20734
|
*/
|
|
20484
|
-
__publicField(this, "
|
|
20735
|
+
__publicField(this, "_localClippingPlanes", false);
|
|
20485
20736
|
/**
|
|
20486
20737
|
* The type of clipping plane to be created.
|
|
20487
20738
|
* Default is {@link SimplePlane}.
|
|
@@ -20517,6 +20768,17 @@ const _Clipper = class _Clipper extends Component {
|
|
|
20517
20768
|
this.components.add(_Clipper.uuid, this);
|
|
20518
20769
|
this.setEvents();
|
|
20519
20770
|
}
|
|
20771
|
+
get localClippingPlanes() {
|
|
20772
|
+
return this._localClippingPlanes;
|
|
20773
|
+
}
|
|
20774
|
+
set localClippingPlanes(value) {
|
|
20775
|
+
this._localClippingPlanes = value;
|
|
20776
|
+
const worlds = this.components.get(Worlds);
|
|
20777
|
+
for (const [, world] of worlds.list) {
|
|
20778
|
+
if (world.renderer)
|
|
20779
|
+
world.renderer.localClippingPlanes = value;
|
|
20780
|
+
}
|
|
20781
|
+
}
|
|
20520
20782
|
/** {@link Component.enabled} */
|
|
20521
20783
|
get enabled() {
|
|
20522
20784
|
return this._enabled;
|
|
@@ -23444,19 +23706,24 @@ class IDSProperty extends IDSFacet {
|
|
|
23444
23706
|
);
|
|
23445
23707
|
}
|
|
23446
23708
|
getTypePsets(item) {
|
|
23447
|
-
|
|
23448
|
-
|
|
23449
|
-
|
|
23450
|
-
|
|
23451
|
-
|
|
23709
|
+
const definitions = [
|
|
23710
|
+
...Array.isArray(item.IsTypedBy) ? item.IsTypedBy : [],
|
|
23711
|
+
...Array.isArray(item.IsDefinedBy) ? item.IsDefinedBy : []
|
|
23712
|
+
];
|
|
23713
|
+
const psets = [];
|
|
23714
|
+
for (const definition of definitions) {
|
|
23715
|
+
if (Array.isArray(definition == null ? void 0 : definition.HasPropertySets)) {
|
|
23716
|
+
psets.push(...definition.HasPropertySets);
|
|
23717
|
+
}
|
|
23452
23718
|
}
|
|
23453
|
-
return
|
|
23719
|
+
return psets;
|
|
23454
23720
|
}
|
|
23455
23721
|
async getPsets(item) {
|
|
23456
23722
|
const typeSets = this.getTypePsets(item);
|
|
23457
23723
|
if (!Array.isArray(item.IsDefinedBy))
|
|
23458
23724
|
return typeSets;
|
|
23459
23725
|
const sets = [];
|
|
23726
|
+
const mergedTypeSets = /* @__PURE__ */ new Set();
|
|
23460
23727
|
for (const definition of item.IsDefinedBy) {
|
|
23461
23728
|
if (!("value" in definition.Name))
|
|
23462
23729
|
continue;
|
|
@@ -23469,22 +23736,29 @@ class IDSProperty extends IDSFacet {
|
|
|
23469
23736
|
return false;
|
|
23470
23737
|
return set.Name.value === definitionName;
|
|
23471
23738
|
});
|
|
23472
|
-
if (typeSet
|
|
23473
|
-
|
|
23474
|
-
|
|
23475
|
-
|
|
23476
|
-
|
|
23477
|
-
|
|
23478
|
-
|
|
23479
|
-
|
|
23480
|
-
|
|
23481
|
-
|
|
23482
|
-
|
|
23483
|
-
|
|
23739
|
+
if (typeSet) {
|
|
23740
|
+
mergedTypeSets.add(typeSet);
|
|
23741
|
+
if (Array.isArray(typeSet.HasProperties) && Array.isArray(definition.HasProperties)) {
|
|
23742
|
+
for (const prop of typeSet.HasProperties) {
|
|
23743
|
+
if (!("value" in prop.Name))
|
|
23744
|
+
continue;
|
|
23745
|
+
const name = prop.Name.value;
|
|
23746
|
+
const existingProp = definition.HasProperties.find((p) => {
|
|
23747
|
+
if (!("value" in p.Name))
|
|
23748
|
+
return false;
|
|
23749
|
+
return p.Name.value === name;
|
|
23750
|
+
});
|
|
23751
|
+
if (!existingProp)
|
|
23752
|
+
definition.HasProperties.push(prop);
|
|
23753
|
+
}
|
|
23484
23754
|
}
|
|
23485
23755
|
}
|
|
23486
23756
|
sets.push(definition);
|
|
23487
23757
|
}
|
|
23758
|
+
for (const typeSet of typeSets) {
|
|
23759
|
+
if (!mergedTypeSets.has(typeSet))
|
|
23760
|
+
sets.push(typeSet);
|
|
23761
|
+
}
|
|
23488
23762
|
return sets;
|
|
23489
23763
|
}
|
|
23490
23764
|
// IFCPROPERTYBOUNDEDVALUE are not supported yet
|
|
@@ -23506,7 +23780,7 @@ class IDSProperty extends IDSFacet {
|
|
|
23506
23780
|
return false;
|
|
23507
23781
|
}
|
|
23508
23782
|
const facetValue = structuredClone(this.value);
|
|
23509
|
-
if (valueAttr.
|
|
23783
|
+
if (typeof valueAttr.value === "string" && facetValue.type === "simple") {
|
|
23510
23784
|
facetValue.parameter = String(facetValue.parameter);
|
|
23511
23785
|
}
|
|
23512
23786
|
const result = this.evalRequirement(
|
|
@@ -23562,12 +23836,38 @@ class IDSProperty extends IDSFacet {
|
|
|
23562
23836
|
class IDSMaterial extends IDSFacet {
|
|
23563
23837
|
constructor() {
|
|
23564
23838
|
super(...arguments);
|
|
23839
|
+
// Every type IfcRelAssociatesMaterial.RelatingMaterial (IfcMaterialSelect)
|
|
23840
|
+
// can point at. Missing any of them silently drops every element that
|
|
23841
|
+
// associates its material through it: an element can reference a layer set
|
|
23842
|
+
// directly instead of through a layer set usage, and both spellings are
|
|
23843
|
+
// valid IFC.
|
|
23565
23844
|
__publicField(this, "_ifcMaterialEntities", [
|
|
23566
23845
|
/^IFCMATERIALLAYERSETUSAGE$/,
|
|
23846
|
+
/^IFCMATERIALLAYERSET$/,
|
|
23847
|
+
/^IFCMATERIALPROFILESETUSAGE$/,
|
|
23848
|
+
/^IFCMATERIALPROFILESET$/,
|
|
23567
23849
|
/^IFCMATERIALCONSTITUENTSET$/,
|
|
23568
23850
|
/^IFCMATERIAL$/,
|
|
23569
23851
|
/^IFCMATERIALLIST$/
|
|
23570
23852
|
]);
|
|
23853
|
+
// Attributes that lead from a material set / usage down to its IfcMaterial.
|
|
23854
|
+
__publicField(this, "_materialParentAttributes", [
|
|
23855
|
+
"ForLayerSet",
|
|
23856
|
+
"MaterialLayers",
|
|
23857
|
+
"ForProfileSet",
|
|
23858
|
+
"MaterialProfiles",
|
|
23859
|
+
"Material",
|
|
23860
|
+
"MaterialConstituents",
|
|
23861
|
+
"Materials"
|
|
23862
|
+
]);
|
|
23863
|
+
__publicField(this, "_materialRelations", {
|
|
23864
|
+
MaterialConstituents: { attributes: true, relations: true },
|
|
23865
|
+
ForLayerSet: { attributes: true, relations: true },
|
|
23866
|
+
MaterialLayers: { attributes: true, relations: true },
|
|
23867
|
+
ForProfileSet: { attributes: true, relations: true },
|
|
23868
|
+
MaterialProfiles: { attributes: true, relations: true },
|
|
23869
|
+
Materials: { attributes: true, relations: false }
|
|
23870
|
+
});
|
|
23571
23871
|
__publicField(this, "facetType", "Material");
|
|
23572
23872
|
__publicField(this, "value");
|
|
23573
23873
|
__publicField(this, "uri");
|
|
@@ -23599,10 +23899,7 @@ class IDSMaterial extends IDSFacet {
|
|
|
23599
23899
|
const data = await model.getItemsData(localIds, {
|
|
23600
23900
|
relations: {
|
|
23601
23901
|
AssociatedTo: { attributes: true, relations: false },
|
|
23602
|
-
|
|
23603
|
-
ForLayerSet: { attributes: true, relations: true },
|
|
23604
|
-
MaterialLayers: { attributes: true, relations: true },
|
|
23605
|
-
Materials: { attributes: true, relations: false }
|
|
23902
|
+
...this._materialRelations
|
|
23606
23903
|
}
|
|
23607
23904
|
});
|
|
23608
23905
|
for (const item of data) {
|
|
@@ -23631,10 +23928,7 @@ class IDSMaterial extends IDSFacet {
|
|
|
23631
23928
|
relations: {
|
|
23632
23929
|
AssociatedTo: { attributes: false, relations: false },
|
|
23633
23930
|
HasAssociations: { attributes: true, relations: true },
|
|
23634
|
-
|
|
23635
|
-
ForLayerSet: { attributes: true, relations: true },
|
|
23636
|
-
MaterialLayers: { attributes: true, relations: true },
|
|
23637
|
-
Materials: { attributes: true, relations: false }
|
|
23931
|
+
...this._materialRelations
|
|
23638
23932
|
}
|
|
23639
23933
|
});
|
|
23640
23934
|
for (const item of data) {
|
|
@@ -23678,13 +23972,7 @@ class IDSMaterial extends IDSFacet {
|
|
|
23678
23972
|
isValid = true;
|
|
23679
23973
|
} else {
|
|
23680
23974
|
for (const [name, attribute] of Object.entries(item)) {
|
|
23681
|
-
if (!
|
|
23682
|
-
"ForLayerSet",
|
|
23683
|
-
"MaterialLayers",
|
|
23684
|
-
"Material",
|
|
23685
|
-
"MaterialConstituents",
|
|
23686
|
-
"Materials"
|
|
23687
|
-
].includes(name))
|
|
23975
|
+
if (!this._materialParentAttributes.includes(name))
|
|
23688
23976
|
continue;
|
|
23689
23977
|
if (!Array.isArray(attribute))
|
|
23690
23978
|
continue;
|
|
@@ -26691,7 +26979,7 @@ function buildPreviewPositions(kind, points, cursor, style) {
|
|
|
26691
26979
|
for (let i = 0; i < points.length - 1; i++) {
|
|
26692
26980
|
positions.push(
|
|
26693
26981
|
...buildDimensionPositions(
|
|
26694
|
-
{
|
|
26982
|
+
{ pointA: points[i], pointB: points[i + 1], offset },
|
|
26695
26983
|
style
|
|
26696
26984
|
)
|
|
26697
26985
|
);
|