@thatopen/components 3.4.6 → 3.4.8
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 +386 -98
- 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 +388 -100
- package/package.json +3 -3
package/dist/index.cjs
CHANGED
|
@@ -197,6 +197,15 @@ class BaseRenderer extends BaseWorldItem {
|
|
|
197
197
|
* The list of [clipping planes](https://threejs.org/docs/#api/en/renderers/WebGLRenderer.clippingPlanes) used by this instance of the renderer.
|
|
198
198
|
*/
|
|
199
199
|
__publicField(this, "clippingPlanes", []);
|
|
200
|
+
/**
|
|
201
|
+
* The default `isLocal` value used by {@link setPlane} when the caller
|
|
202
|
+
* doesn't pass one. When `true`, planes added without an explicit
|
|
203
|
+
* `isLocal` stay out of the global `three.clippingPlanes` list and are
|
|
204
|
+
* clipped per-material instead. The {@link Clipper} sets this to mirror
|
|
205
|
+
* its own `localClippingPlanes` flag, so consumers like `Views` that add
|
|
206
|
+
* their own planes automatically inherit the active clipping mode.
|
|
207
|
+
*/
|
|
208
|
+
__publicField(this, "localClippingPlanes", false);
|
|
200
209
|
}
|
|
201
210
|
/**
|
|
202
211
|
* Updates the clipping planes and triggers the `onClippingPlanesUpdated` event.
|
|
@@ -222,7 +231,7 @@ class BaseRenderer extends BaseWorldItem {
|
|
|
222
231
|
* The `three.clippingPlanes` property is then updated to reflect the current state of the `clippingPlanes` array,
|
|
223
232
|
* excluding any planes marked as local.
|
|
224
233
|
*/
|
|
225
|
-
setPlane(active, plane, isLocal) {
|
|
234
|
+
setPlane(active, plane, isLocal = this.localClippingPlanes) {
|
|
226
235
|
plane.isLocal = isLocal;
|
|
227
236
|
const index = this.clippingPlanes.indexOf(plane);
|
|
228
237
|
if (active && index === -1) {
|
|
@@ -233,6 +242,7 @@ class BaseRenderer extends BaseWorldItem {
|
|
|
233
242
|
this.three.clippingPlanes = this.clippingPlanes.filter(
|
|
234
243
|
(plane2) => !plane2.isLocal
|
|
235
244
|
);
|
|
245
|
+
this.updateClippingPlanes();
|
|
236
246
|
}
|
|
237
247
|
}
|
|
238
248
|
const _Disposer = class _Disposer extends Component {
|
|
@@ -9487,9 +9497,11 @@ class VisibilityCuller {
|
|
|
9487
9497
|
const tilesX = Math.ceil(pixelWidth / maxTextureSize);
|
|
9488
9498
|
const tilesY = Math.ceil(pixelHeight / maxTextureSize);
|
|
9489
9499
|
target.setSize(Math.ceil(pixelWidth / tilesX), Math.ceil(pixelHeight / tilesY));
|
|
9500
|
+
const yMargin = Math.max(size.y, 1) * 0.01;
|
|
9490
9501
|
camera.rotation.x = -Math.PI / 2;
|
|
9491
|
-
camera.
|
|
9492
|
-
camera.
|
|
9502
|
+
camera.near = 0;
|
|
9503
|
+
camera.far = size.y + 2 * yMargin;
|
|
9504
|
+
camera.position.y = box.max.y + yMargin;
|
|
9493
9505
|
const idScene = new THREE.Scene();
|
|
9494
9506
|
const originalMaterials = /* @__PURE__ */ new Map();
|
|
9495
9507
|
const originalParents = /* @__PURE__ */ new Map();
|
|
@@ -9523,7 +9535,7 @@ class VisibilityCuller {
|
|
|
9523
9535
|
const tileMaxZ = tileMinZ + stepZ;
|
|
9524
9536
|
const tileCenterX = (tileMinX + tileMaxX) / 2;
|
|
9525
9537
|
const tileCenterZ = (tileMinZ + tileMaxZ) / 2;
|
|
9526
|
-
camera.position.set(tileCenterX, box.max.y, tileCenterZ);
|
|
9538
|
+
camera.position.set(tileCenterX, box.max.y + yMargin, tileCenterZ);
|
|
9527
9539
|
const halfWidth = stepX / 2;
|
|
9528
9540
|
const halfHeight = stepZ / 2;
|
|
9529
9541
|
camera.left = -halfWidth;
|
|
@@ -9572,6 +9584,11 @@ class IDMaterial extends THREE.ShaderMaterial {
|
|
|
9572
9584
|
super({
|
|
9573
9585
|
glslVersion: THREE.GLSL3,
|
|
9574
9586
|
blending: THREE.NoBlending,
|
|
9587
|
+
// A flat item (a slab) seen straight down shows only one face; if its
|
|
9588
|
+
// winding puts the back face toward the camera it wouldn't rasterize and
|
|
9589
|
+
// the item would be culled. The pass only cares about coverage, so render
|
|
9590
|
+
// both sides.
|
|
9591
|
+
side: THREE.DoubleSide,
|
|
9575
9592
|
uniforms: {
|
|
9576
9593
|
objectId: { value: new THREE.Vector4() }
|
|
9577
9594
|
},
|
|
@@ -12562,6 +12579,19 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
12562
12579
|
* restored after.
|
|
12563
12580
|
*/
|
|
12564
12581
|
__publicField(this, "_hiddenLods", []);
|
|
12582
|
+
/**
|
|
12583
|
+
* The meshes each model owns, i.e. excluding those belonging to a
|
|
12584
|
+
* model nested inside it. A delta model's object is parented under
|
|
12585
|
+
* its parent model's object (see the fragments EditHelper), while
|
|
12586
|
+
* both are listed as separate models, so subtree membership alone
|
|
12587
|
+
* does not determine ownership.
|
|
12588
|
+
*
|
|
12589
|
+
* Populated in {@link applyIdMaterial}, consumed by
|
|
12590
|
+
* {@link renderPickPass} to isolate one model per render without
|
|
12591
|
+
* relying on root visibility. A nested model can't be isolated by
|
|
12592
|
+
* its root, since hiding the parent's root culls the child too.
|
|
12593
|
+
*/
|
|
12594
|
+
__publicField(this, "_ownMeshes", /* @__PURE__ */ new Map());
|
|
12565
12595
|
if (!world.renderer) {
|
|
12566
12596
|
throw new Error("A renderer is needed for the FastModelPicker to work!");
|
|
12567
12597
|
}
|
|
@@ -12609,9 +12639,7 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
12609
12639
|
const model = fragments.list.get(result.modelId);
|
|
12610
12640
|
if (!model)
|
|
12611
12641
|
return null;
|
|
12612
|
-
const localIds = await model.getLocalIdsFromItemIds([
|
|
12613
|
-
result.itemId
|
|
12614
|
-
]);
|
|
12642
|
+
const localIds = await model.getLocalIdsFromItemIds([result.itemId]);
|
|
12615
12643
|
const localId = localIds == null ? void 0 : localIds[0];
|
|
12616
12644
|
if (localId === void 0 || localId === null)
|
|
12617
12645
|
return null;
|
|
@@ -12802,14 +12830,14 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
12802
12830
|
applyIdMaterial() {
|
|
12803
12831
|
const fragments = this.components.get(FragmentsManager);
|
|
12804
12832
|
const byteToModel = /* @__PURE__ */ new Map();
|
|
12833
|
+
const modelRoots = this.getModelRoots();
|
|
12834
|
+
this._ownMeshes.clear();
|
|
12805
12835
|
let nextByte = 1;
|
|
12806
12836
|
for (const [modelId, model] of fragments.list) {
|
|
12807
12837
|
if (nextByte > _FastModelPicker.MAX_MODELS)
|
|
12808
12838
|
break;
|
|
12809
|
-
const
|
|
12810
|
-
|
|
12811
|
-
let any = false;
|
|
12812
|
-
model.object.traverse((child) => {
|
|
12839
|
+
const owned = [];
|
|
12840
|
+
this.traverseOwn(model.object, modelRoots, (child) => {
|
|
12813
12841
|
if (!(child instanceof THREE__namespace.Mesh))
|
|
12814
12842
|
return;
|
|
12815
12843
|
const geom = child.geometry;
|
|
@@ -12826,13 +12854,44 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
12826
12854
|
const original = child.material;
|
|
12827
12855
|
const len = Array.isArray(original) ? original.length : 1;
|
|
12828
12856
|
child.material = new Array(len).fill(this._idMaterial);
|
|
12829
|
-
|
|
12857
|
+
owned.push(child);
|
|
12830
12858
|
});
|
|
12831
|
-
if (
|
|
12832
|
-
|
|
12859
|
+
if (!owned.length)
|
|
12860
|
+
continue;
|
|
12861
|
+
this._ownMeshes.set(modelId, owned);
|
|
12862
|
+
byteToModel.set(nextByte, modelId);
|
|
12863
|
+
nextByte += 1;
|
|
12833
12864
|
}
|
|
12834
12865
|
return byteToModel;
|
|
12835
12866
|
}
|
|
12867
|
+
/**
|
|
12868
|
+
* The object roots of every loaded model.
|
|
12869
|
+
*/
|
|
12870
|
+
getModelRoots() {
|
|
12871
|
+
const fragments = this.components.get(FragmentsManager);
|
|
12872
|
+
const roots = /* @__PURE__ */ new Set();
|
|
12873
|
+
for (const [, model] of fragments.list)
|
|
12874
|
+
roots.add(model.object);
|
|
12875
|
+
return roots;
|
|
12876
|
+
}
|
|
12877
|
+
/**
|
|
12878
|
+
* Like `Object3D.traverse`, but prunes the subtree of any nested model
|
|
12879
|
+
* root, so each mesh is visited exactly once, by the model that owns
|
|
12880
|
+
* it. A delta model's object hangs under its parent model's object
|
|
12881
|
+
* while being a model in its own right; a plain `traverse` from the
|
|
12882
|
+
* parent would walk into it.
|
|
12883
|
+
*/
|
|
12884
|
+
traverseOwn(root, modelRoots, callback) {
|
|
12885
|
+
const stack = [root];
|
|
12886
|
+
while (stack.length) {
|
|
12887
|
+
const node = stack.pop();
|
|
12888
|
+
if (node !== root && modelRoots.has(node))
|
|
12889
|
+
continue;
|
|
12890
|
+
callback(node);
|
|
12891
|
+
for (const child of node.children)
|
|
12892
|
+
stack.push(child);
|
|
12893
|
+
}
|
|
12894
|
+
}
|
|
12836
12895
|
/**
|
|
12837
12896
|
* Renders the world scene to the id target one model at a time,
|
|
12838
12897
|
* flipping the `modelByte` uniform between renders. The depth buffer
|
|
@@ -12877,6 +12936,8 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
12877
12936
|
const prevClearAlpha = renderer.getClearAlpha();
|
|
12878
12937
|
const prevScissorTest = renderer.getScissorTest();
|
|
12879
12938
|
const prevScissor = renderer.getScissor(new THREE__namespace.Vector4());
|
|
12939
|
+
const prevBackground = scene.background;
|
|
12940
|
+
scene.background = null;
|
|
12880
12941
|
renderer.setRenderTarget(target);
|
|
12881
12942
|
renderer.setClearColor(0, 0);
|
|
12882
12943
|
renderer.autoClear = false;
|
|
@@ -12923,21 +12984,47 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
12923
12984
|
nonBimVisibility.set(child, child.visible);
|
|
12924
12985
|
child.visible = false;
|
|
12925
12986
|
});
|
|
12926
|
-
const
|
|
12987
|
+
const wasOnScreen = /* @__PURE__ */ new Map();
|
|
12988
|
+
for (const [modelId, obj] of objectsByModel) {
|
|
12989
|
+
let visible = true;
|
|
12990
|
+
let node = obj;
|
|
12991
|
+
while (node) {
|
|
12992
|
+
if (!node.visible) {
|
|
12993
|
+
visible = false;
|
|
12994
|
+
break;
|
|
12995
|
+
}
|
|
12996
|
+
node = node.parent;
|
|
12997
|
+
}
|
|
12998
|
+
wasOnScreen.set(modelId, visible);
|
|
12999
|
+
}
|
|
13000
|
+
const rootVisibilityBefore = /* @__PURE__ */ new Map();
|
|
12927
13001
|
for (const obj of objectsByModel.values()) {
|
|
12928
|
-
|
|
12929
|
-
obj.visible =
|
|
13002
|
+
rootVisibilityBefore.set(obj, obj.visible);
|
|
13003
|
+
obj.visible = true;
|
|
13004
|
+
}
|
|
13005
|
+
const meshVisibilityBefore = /* @__PURE__ */ new Map();
|
|
13006
|
+
for (const meshes of this._ownMeshes.values()) {
|
|
13007
|
+
for (const mesh of meshes) {
|
|
13008
|
+
meshVisibilityBefore.set(mesh, mesh.visible);
|
|
13009
|
+
mesh.visible = false;
|
|
13010
|
+
}
|
|
12930
13011
|
}
|
|
12931
13012
|
for (const [byte, modelId] of byteToModel) {
|
|
12932
|
-
|
|
12933
|
-
if (!obj)
|
|
13013
|
+
if (!wasOnScreen.get(modelId))
|
|
12934
13014
|
continue;
|
|
12935
|
-
|
|
13015
|
+
const meshes = this._ownMeshes.get(modelId);
|
|
13016
|
+
if (!meshes)
|
|
13017
|
+
continue;
|
|
13018
|
+
for (const mesh of meshes)
|
|
13019
|
+
mesh.visible = meshVisibilityBefore.get(mesh);
|
|
12936
13020
|
material.uniforms.modelByte.value = byte;
|
|
12937
13021
|
renderer.render(scene, camera);
|
|
12938
|
-
|
|
13022
|
+
for (const mesh of meshes)
|
|
13023
|
+
mesh.visible = false;
|
|
12939
13024
|
}
|
|
12940
|
-
for (const [
|
|
13025
|
+
for (const [mesh, was] of meshVisibilityBefore)
|
|
13026
|
+
mesh.visible = was;
|
|
13027
|
+
for (const [obj, was] of rootVisibilityBefore)
|
|
12941
13028
|
obj.visible = was;
|
|
12942
13029
|
for (const [obj, was] of nonBimVisibility)
|
|
12943
13030
|
obj.visible = was;
|
|
@@ -12946,6 +13033,7 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
12946
13033
|
renderer.setRenderTarget(prevTarget);
|
|
12947
13034
|
renderer.autoClear = prevAutoClear;
|
|
12948
13035
|
renderer.setClearColor(prevClearColor, prevClearAlpha);
|
|
13036
|
+
scene.background = prevBackground;
|
|
12949
13037
|
}
|
|
12950
13038
|
/**
|
|
12951
13039
|
* Renders the picker's color target with the BIM tile shells using
|
|
@@ -12976,10 +13064,13 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
12976
13064
|
const prevAutoClear = renderer.autoClear;
|
|
12977
13065
|
const prevClearColor = renderer.getClearColor(new THREE__namespace.Color());
|
|
12978
13066
|
const prevClearAlpha = renderer.getClearAlpha();
|
|
13067
|
+
const prevBackground = scene.background;
|
|
13068
|
+
scene.background = null;
|
|
12979
13069
|
const matSwap = /* @__PURE__ */ new Map();
|
|
12980
13070
|
const hiddenLines = [];
|
|
13071
|
+
const modelRoots = this.getModelRoots();
|
|
12981
13072
|
for (const [, model] of fragments.list) {
|
|
12982
|
-
model.object
|
|
13073
|
+
this.traverseOwn(model.object, modelRoots, (child) => {
|
|
12983
13074
|
if (!(child instanceof THREE__namespace.Mesh))
|
|
12984
13075
|
return;
|
|
12985
13076
|
const geom = child.geometry;
|
|
@@ -13037,6 +13128,7 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
13037
13128
|
renderer.setRenderTarget(prevTarget);
|
|
13038
13129
|
renderer.autoClear = prevAutoClear;
|
|
13039
13130
|
renderer.setClearColor(prevClearColor, prevClearAlpha);
|
|
13131
|
+
scene.background = prevBackground;
|
|
13040
13132
|
}
|
|
13041
13133
|
renderDepthPass() {
|
|
13042
13134
|
this.renderWithTileMaterial(this._depthMaterial);
|
|
@@ -13049,6 +13141,7 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
13049
13141
|
mesh.material = mat;
|
|
13050
13142
|
}
|
|
13051
13143
|
this._originalMaterials.clear();
|
|
13144
|
+
this._ownMeshes.clear();
|
|
13052
13145
|
for (const obj of this._hiddenLods)
|
|
13053
13146
|
obj.visible = true;
|
|
13054
13147
|
this._hiddenLods.length = 0;
|
|
@@ -13425,12 +13518,32 @@ class SnapResolver {
|
|
|
13425
13518
|
*/
|
|
13426
13519
|
__publicField(this, "maxCacheSize", 1e3);
|
|
13427
13520
|
__publicField(this, "components");
|
|
13521
|
+
__publicField(this, "_precision", "half");
|
|
13428
13522
|
// Map insertion order is recency order (LRU). On every read we
|
|
13429
13523
|
// delete + re-set the entry to bump it to most-recent; on every
|
|
13430
13524
|
// write we drop oldest entries until size <= maxCacheSize.
|
|
13431
13525
|
__publicField(this, "cache", /* @__PURE__ */ new Map());
|
|
13432
13526
|
this.components = components;
|
|
13433
13527
|
}
|
|
13528
|
+
/**
|
|
13529
|
+
* Numeric precision for cached face/edge/vertex buffers.
|
|
13530
|
+
*
|
|
13531
|
+
* `"half"` uses Float32Array for lower memory footprint.
|
|
13532
|
+
* `"full"` uses Float64Array for higher numeric precision.
|
|
13533
|
+
* Use `"full"` for workflows that require higher geometric fidelity.
|
|
13534
|
+
*
|
|
13535
|
+
* Changing this value clears the snap cache so subsequent requests
|
|
13536
|
+
* are rebuilt with the new precision.
|
|
13537
|
+
*/
|
|
13538
|
+
get precision() {
|
|
13539
|
+
return this._precision;
|
|
13540
|
+
}
|
|
13541
|
+
set precision(value) {
|
|
13542
|
+
if (value === this._precision)
|
|
13543
|
+
return;
|
|
13544
|
+
this._precision = value;
|
|
13545
|
+
this.clear();
|
|
13546
|
+
}
|
|
13434
13547
|
/** {@link Disposable.dispose} */
|
|
13435
13548
|
dispose() {
|
|
13436
13549
|
this.cache.clear();
|
|
@@ -13570,8 +13683,8 @@ class SnapResolver {
|
|
|
13570
13683
|
}
|
|
13571
13684
|
if (polygons.length === 0)
|
|
13572
13685
|
return null;
|
|
13573
|
-
const edges = deriveUniqueEdges(polygons);
|
|
13574
|
-
const vertices = deriveUniqueVertices(polygons);
|
|
13686
|
+
const edges = deriveUniqueEdges(polygons, this._precision);
|
|
13687
|
+
const vertices = deriveUniqueVertices(polygons, this._precision);
|
|
13575
13688
|
return { faces: polygons, edges, vertices };
|
|
13576
13689
|
}
|
|
13577
13690
|
collectPolygonsFromShell(shell, worldMatrix, out) {
|
|
@@ -13582,7 +13695,8 @@ class SnapResolver {
|
|
|
13582
13695
|
const collect = (indices) => {
|
|
13583
13696
|
if (indices.length < 3)
|
|
13584
13697
|
return;
|
|
13585
|
-
const
|
|
13698
|
+
const Ctor = this._precision === "full" ? Float64Array : Float32Array;
|
|
13699
|
+
const flat = new Ctor(indices.length * 3);
|
|
13586
13700
|
for (let i = 0; i < indices.length; i++) {
|
|
13587
13701
|
const p = points[indices[i]];
|
|
13588
13702
|
tmp.set(p[0], p[1], p[2]).applyMatrix4(worldMatrix);
|
|
@@ -13691,19 +13805,33 @@ class SnapResolver {
|
|
|
13691
13805
|
return null;
|
|
13692
13806
|
let best = null;
|
|
13693
13807
|
let bestAbs = Infinity;
|
|
13808
|
+
let bestContains = false;
|
|
13694
13809
|
for (const f of faces) {
|
|
13695
|
-
const signed =
|
|
13810
|
+
const signed = this.signedDistance(f, point);
|
|
13696
13811
|
const abs = Math.abs(signed);
|
|
13697
|
-
if (abs
|
|
13812
|
+
if (abs > this.maxDistance)
|
|
13813
|
+
continue;
|
|
13814
|
+
const contains = this.containsPoint(f, this.projectOntoPlane(point, f, signed));
|
|
13815
|
+
if (bestContains && !contains)
|
|
13816
|
+
continue;
|
|
13817
|
+
if (contains && !bestContains) {
|
|
13818
|
+
bestContains = true;
|
|
13819
|
+
bestAbs = abs;
|
|
13820
|
+
best = f;
|
|
13821
|
+
continue;
|
|
13822
|
+
}
|
|
13823
|
+
if (abs < bestAbs) {
|
|
13698
13824
|
bestAbs = abs;
|
|
13699
13825
|
best = f;
|
|
13700
13826
|
}
|
|
13701
13827
|
}
|
|
13702
13828
|
if (!best)
|
|
13703
13829
|
return null;
|
|
13704
|
-
const projected =
|
|
13705
|
-
|
|
13706
|
-
|
|
13830
|
+
const projected = this.projectOntoPlane(
|
|
13831
|
+
point,
|
|
13832
|
+
best,
|
|
13833
|
+
this.signedDistance(best, point)
|
|
13834
|
+
);
|
|
13707
13835
|
return {
|
|
13708
13836
|
result: {
|
|
13709
13837
|
point: projected,
|
|
@@ -13714,6 +13842,50 @@ class SnapResolver {
|
|
|
13714
13842
|
}
|
|
13715
13843
|
};
|
|
13716
13844
|
}
|
|
13845
|
+
signedDistance(face, point) {
|
|
13846
|
+
return face.normal.x * point.x + face.normal.y * point.y + face.normal.z * point.z - face.d;
|
|
13847
|
+
}
|
|
13848
|
+
projectOntoPlane(point, face, signed) {
|
|
13849
|
+
return point.clone().sub(face.normal.clone().multiplyScalar(signed));
|
|
13850
|
+
}
|
|
13851
|
+
/**
|
|
13852
|
+
* Even-odd point-in-polygon test, run on the polygon projected onto its
|
|
13853
|
+
* dominant plane. `point` is assumed to already lie on the face's plane.
|
|
13854
|
+
*/
|
|
13855
|
+
containsPoint(face, point) {
|
|
13856
|
+
const { points, normal } = face;
|
|
13857
|
+
const count = points.length / 3;
|
|
13858
|
+
if (count < 3)
|
|
13859
|
+
return false;
|
|
13860
|
+
const ax = Math.abs(normal.x);
|
|
13861
|
+
const ay = Math.abs(normal.y);
|
|
13862
|
+
const az = Math.abs(normal.z);
|
|
13863
|
+
let a = 0;
|
|
13864
|
+
let b = 1;
|
|
13865
|
+
if (ax >= ay && ax >= az) {
|
|
13866
|
+
a = 1;
|
|
13867
|
+
b = 2;
|
|
13868
|
+
} else if (ay >= az) {
|
|
13869
|
+
a = 0;
|
|
13870
|
+
b = 2;
|
|
13871
|
+
}
|
|
13872
|
+
const px = point.getComponent(a);
|
|
13873
|
+
const py = point.getComponent(b);
|
|
13874
|
+
let inside = false;
|
|
13875
|
+
for (let i = 0, j = count - 1; i < count; j = i, i += 1) {
|
|
13876
|
+
const xi = points[i * 3 + a];
|
|
13877
|
+
const yi = points[i * 3 + b];
|
|
13878
|
+
const xj = points[j * 3 + a];
|
|
13879
|
+
const yj = points[j * 3 + b];
|
|
13880
|
+
const straddles = yi > py !== yj > py;
|
|
13881
|
+
if (!straddles)
|
|
13882
|
+
continue;
|
|
13883
|
+
const x = (xj - xi) * (py - yi) / (yj - yi) + xi;
|
|
13884
|
+
if (px < x)
|
|
13885
|
+
inside = !inside;
|
|
13886
|
+
}
|
|
13887
|
+
return inside;
|
|
13888
|
+
}
|
|
13717
13889
|
}
|
|
13718
13890
|
const _tmpMatrix = new THREE__namespace.Matrix4();
|
|
13719
13891
|
const _tmpX = new THREE__namespace.Vector3();
|
|
@@ -13781,7 +13953,7 @@ function fanTriangulation(vertexCount) {
|
|
|
13781
13953
|
}
|
|
13782
13954
|
return out;
|
|
13783
13955
|
}
|
|
13784
|
-
function deriveUniqueEdges(faces) {
|
|
13956
|
+
function deriveUniqueEdges(faces, precision) {
|
|
13785
13957
|
const seen = /* @__PURE__ */ new Set();
|
|
13786
13958
|
const collected = [];
|
|
13787
13959
|
for (const f of faces) {
|
|
@@ -13798,9 +13970,10 @@ function deriveUniqueEdges(faces) {
|
|
|
13798
13970
|
collected.push(ax, ay, az, bx, by, bz);
|
|
13799
13971
|
}
|
|
13800
13972
|
}
|
|
13801
|
-
|
|
13973
|
+
const Ctor = precision === "full" ? Float64Array : Float32Array;
|
|
13974
|
+
return new Ctor(collected);
|
|
13802
13975
|
}
|
|
13803
|
-
function deriveUniqueVertices(faces) {
|
|
13976
|
+
function deriveUniqueVertices(faces, precision) {
|
|
13804
13977
|
const seen = /* @__PURE__ */ new Set();
|
|
13805
13978
|
const collected = [];
|
|
13806
13979
|
for (const f of faces) {
|
|
@@ -13815,7 +13988,8 @@ function deriveUniqueVertices(faces) {
|
|
|
13815
13988
|
collected.push(x, y, z);
|
|
13816
13989
|
}
|
|
13817
13990
|
}
|
|
13818
|
-
|
|
13991
|
+
const Ctor = precision === "full" ? Float64Array : Float32Array;
|
|
13992
|
+
return new Ctor(collected);
|
|
13819
13993
|
}
|
|
13820
13994
|
function quantKey(x, y, z) {
|
|
13821
13995
|
return `${Math.round(x * VERTEX_QUANT)},${Math.round(y * VERTEX_QUANT)},${Math.round(z * VERTEX_QUANT)}`;
|
|
@@ -14111,6 +14285,9 @@ class SimpleWorld extends Base {
|
|
|
14111
14285
|
*/
|
|
14112
14286
|
__publicField(this, "enabled", true);
|
|
14113
14287
|
__publicField(this, "_dynamicAnchor", false);
|
|
14288
|
+
// Bumped on every anchor press so a slow geometry pick that resolves after a
|
|
14289
|
+
// newer press is ignored (see onPointerDown).
|
|
14290
|
+
__publicField(this, "_anchorRequestId", 0);
|
|
14114
14291
|
/**
|
|
14115
14292
|
* A unique identifier for the world. Is not meant to be changed at any moment.
|
|
14116
14293
|
*/
|
|
@@ -14122,21 +14299,36 @@ class SimpleWorld extends Base {
|
|
|
14122
14299
|
__publicField(this, "_scene");
|
|
14123
14300
|
__publicField(this, "_camera");
|
|
14124
14301
|
__publicField(this, "_renderer", null);
|
|
14125
|
-
__publicField(this, "onPointerDown",
|
|
14302
|
+
__publicField(this, "onPointerDown", (event) => {
|
|
14126
14303
|
if (!this.camera.hasCameraControls()) {
|
|
14127
14304
|
throw new Error(
|
|
14128
14305
|
"World: can't set dynamic anchor if the camera doesn't have controls."
|
|
14129
14306
|
);
|
|
14130
14307
|
}
|
|
14308
|
+
if (event.button !== 0)
|
|
14309
|
+
return;
|
|
14310
|
+
const position = this.getPointerPosition(event);
|
|
14311
|
+
if (!position)
|
|
14312
|
+
return;
|
|
14131
14313
|
const caster = this.components.get(Raycasters).get(this);
|
|
14132
|
-
const
|
|
14133
|
-
if (
|
|
14314
|
+
const planePoint = this.getPlaneAnchor(caster, position);
|
|
14315
|
+
if (planePoint) {
|
|
14134
14316
|
this.camera.controls.setOrbitPoint(
|
|
14135
|
-
|
|
14136
|
-
|
|
14137
|
-
|
|
14317
|
+
planePoint.x,
|
|
14318
|
+
planePoint.y,
|
|
14319
|
+
planePoint.z
|
|
14138
14320
|
);
|
|
14139
14321
|
}
|
|
14322
|
+
const requestId = ++this._anchorRequestId;
|
|
14323
|
+
caster.castRay({ position }).then((result) => {
|
|
14324
|
+
const isStale = requestId !== this._anchorRequestId;
|
|
14325
|
+
if (isStale || this.isDisposing || !this._dynamicAnchor)
|
|
14326
|
+
return;
|
|
14327
|
+
if (!(result == null ? void 0 : result.point) || !this.camera.hasCameraControls())
|
|
14328
|
+
return;
|
|
14329
|
+
const { x, y, z } = result.point;
|
|
14330
|
+
this.camera.controls.setOrbitPoint(x, y, z);
|
|
14331
|
+
});
|
|
14140
14332
|
});
|
|
14141
14333
|
__publicField(this, "_defaultCamera");
|
|
14142
14334
|
}
|
|
@@ -14155,10 +14347,46 @@ class SimpleWorld extends Base {
|
|
|
14155
14347
|
} else {
|
|
14156
14348
|
container.removeEventListener("pointerdown", this.onPointerDown);
|
|
14157
14349
|
}
|
|
14350
|
+
this._dynamicAnchor = value;
|
|
14158
14351
|
}
|
|
14159
14352
|
get dynamicAnchor() {
|
|
14160
14353
|
return this._dynamicAnchor;
|
|
14161
14354
|
}
|
|
14355
|
+
/**
|
|
14356
|
+
* The pointer position in normalized device coordinates, derived from the
|
|
14357
|
+
* event rather than the raycaster's mouse: that one only tracks pointermove
|
|
14358
|
+
* and touchstart, so on a bare pointerdown it would still report the center of
|
|
14359
|
+
* the viewport.
|
|
14360
|
+
*/
|
|
14361
|
+
getPointerPosition(event) {
|
|
14362
|
+
var _a;
|
|
14363
|
+
const dom = (_a = this.renderer) == null ? void 0 : _a.three.domElement;
|
|
14364
|
+
if (!dom)
|
|
14365
|
+
return null;
|
|
14366
|
+
const bounds = dom.getBoundingClientRect();
|
|
14367
|
+
return new THREE__namespace.Vector2(
|
|
14368
|
+
(event.clientX - bounds.left) / (bounds.right - bounds.left) * 2 - 1,
|
|
14369
|
+
-((event.clientY - bounds.top) / (bounds.bottom - bounds.top)) * 2 + 1
|
|
14370
|
+
);
|
|
14371
|
+
}
|
|
14372
|
+
/**
|
|
14373
|
+
* The point where the pointer ray crosses the plane that contains the current
|
|
14374
|
+
* orbit target and faces the camera. Used as the anchor when the pointer
|
|
14375
|
+
* doesn't land on any geometry.
|
|
14376
|
+
*/
|
|
14377
|
+
getPlaneAnchor(caster, position) {
|
|
14378
|
+
if (!this.camera.hasCameraControls())
|
|
14379
|
+
return null;
|
|
14380
|
+
const camera = this.camera.three;
|
|
14381
|
+
caster.three.setFromCamera(position, camera);
|
|
14382
|
+
const target = this.camera.controls.getTarget(new THREE__namespace.Vector3());
|
|
14383
|
+
const normal = camera.getWorldDirection(new THREE__namespace.Vector3());
|
|
14384
|
+
const plane = new THREE__namespace.Plane().setFromNormalAndCoplanarPoint(
|
|
14385
|
+
normal,
|
|
14386
|
+
target
|
|
14387
|
+
);
|
|
14388
|
+
return caster.three.ray.intersectPlane(plane, new THREE__namespace.Vector3());
|
|
14389
|
+
}
|
|
14162
14390
|
get defaultCamera() {
|
|
14163
14391
|
if (!this._defaultCamera) {
|
|
14164
14392
|
throw new Error("World: there is no default camera defined.");
|
|
@@ -14261,8 +14489,16 @@ class SimpleWorld extends Base {
|
|
|
14261
14489
|
}
|
|
14262
14490
|
/** {@link Disposable.dispose} */
|
|
14263
14491
|
dispose(disposeResources = true) {
|
|
14492
|
+
var _a;
|
|
14493
|
+
if (this.isDisposing)
|
|
14494
|
+
return;
|
|
14264
14495
|
this.enabled = false;
|
|
14265
14496
|
this.isDisposing = true;
|
|
14497
|
+
const container = (_a = this.renderer) == null ? void 0 : _a.three.domElement.parentElement;
|
|
14498
|
+
if (container) {
|
|
14499
|
+
container.removeEventListener("pointerdown", this.onPointerDown);
|
|
14500
|
+
}
|
|
14501
|
+
this._dynamicAnchor = false;
|
|
14266
14502
|
this.scene.onWorldChanged.trigger({ world: this, action: "removed" });
|
|
14267
14503
|
this.camera.onWorldChanged.trigger({ world: this, action: "removed" });
|
|
14268
14504
|
if (this.renderer) {
|
|
@@ -15509,16 +15745,23 @@ const _Components = class _Components {
|
|
|
15509
15745
|
dispose() {
|
|
15510
15746
|
this.enabled = false;
|
|
15511
15747
|
let fragments;
|
|
15748
|
+
let worlds;
|
|
15512
15749
|
for (const [_id, component] of this.list) {
|
|
15513
15750
|
component.enabled = false;
|
|
15514
15751
|
if (_id === FragmentsManager.uuid) {
|
|
15515
15752
|
fragments = component;
|
|
15516
15753
|
continue;
|
|
15517
15754
|
}
|
|
15755
|
+
if (_id === Worlds.uuid) {
|
|
15756
|
+
worlds = component;
|
|
15757
|
+
continue;
|
|
15758
|
+
}
|
|
15518
15759
|
if (component.isDisposeable()) {
|
|
15519
15760
|
component.dispose();
|
|
15520
15761
|
}
|
|
15521
15762
|
}
|
|
15763
|
+
if (worlds == null ? void 0 : worlds.isDisposeable())
|
|
15764
|
+
worlds.dispose();
|
|
15522
15765
|
fragments == null ? void 0 : fragments.dispose();
|
|
15523
15766
|
this._timer.dispose();
|
|
15524
15767
|
this.onDisposed.trigger();
|
|
@@ -15995,7 +16238,7 @@ Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/js
|
|
|
15995
16238
|
JSZip uses the library pako released under the MIT license :
|
|
15996
16239
|
https://github.com/nodeca/pako/blob/main/LICENSE
|
|
15997
16240
|
*/
|
|
15998
|
-
(function(module2,
|
|
16241
|
+
(function(module2, exports$1) {
|
|
15999
16242
|
!function(e) {
|
|
16000
16243
|
module2.exports = e();
|
|
16001
16244
|
}(function() {
|
|
@@ -19053,33 +19296,31 @@ const _Topic = class _Topic {
|
|
|
19053
19296
|
serialize() {
|
|
19054
19297
|
var _a, _b;
|
|
19055
19298
|
const version = this._managerVersion;
|
|
19299
|
+
const isV3 = version === "3";
|
|
19056
19300
|
const topic = {
|
|
19057
19301
|
$Guid: this.guid,
|
|
19058
19302
|
$TopicType: this.type,
|
|
19059
19303
|
$TopicStatus: this.status,
|
|
19060
19304
|
$ServerAssignedId: this.serverAssignedId,
|
|
19061
19305
|
Title: this.title,
|
|
19062
|
-
CreationAuthor: this.creationAuthor,
|
|
19063
|
-
CreationDate: this.creationDate.toISOString(),
|
|
19064
19306
|
Priority: this.priority,
|
|
19065
19307
|
Index: version === "2.1" ? this.index : void 0,
|
|
19308
|
+
Labels: isV3 ? { Label: this.createLabelTags() } : this.createLabelTags(),
|
|
19309
|
+
CreationDate: this.creationDate.toISOString(),
|
|
19310
|
+
CreationAuthor: this.creationAuthor,
|
|
19066
19311
|
ModifiedDate: (_a = this.modifiedDate) == null ? void 0 : _a.toISOString(),
|
|
19067
19312
|
ModifiedAuthor: this.modifiedAuthor,
|
|
19068
19313
|
DueDate: (_b = this.dueDate) == null ? void 0 : _b.toISOString(),
|
|
19069
19314
|
AssignedTo: this.assignedTo,
|
|
19070
|
-
Description: this.description,
|
|
19071
19315
|
Stage: this.stage,
|
|
19072
|
-
|
|
19073
|
-
|
|
19074
|
-
|
|
19075
|
-
|
|
19076
|
-
|
|
19077
|
-
Comments:
|
|
19316
|
+
Description: this.description,
|
|
19317
|
+
DocumentReferences: isV3 ? { DocumentReference: this.createDocumentReferencesTag(version) } : void 0,
|
|
19318
|
+
DocumentReference: isV3 ? void 0 : this.createDocumentReferencesTag(version),
|
|
19319
|
+
RelatedTopics: isV3 ? { RelatedTopic: this.createRelatedTopicTags() } : void 0,
|
|
19320
|
+
RelatedTopic: isV3 ? void 0 : this.createRelatedTopicTags(),
|
|
19321
|
+
Comments: isV3 ? { Comment: this.createCommentTags() } : void 0,
|
|
19322
|
+
Viewpoints: isV3 ? { ViewPoint: this.createViewpointTags() } : void 0
|
|
19078
19323
|
};
|
|
19079
|
-
if (version === "2.1") {
|
|
19080
|
-
topic.Labels = this.createLabelTags();
|
|
19081
|
-
topic.DocumentReference = this.createDocumentReferencesTag(version);
|
|
19082
|
-
}
|
|
19083
19324
|
const markup = {
|
|
19084
19325
|
Markup: { Topic: topic }
|
|
19085
19326
|
};
|
|
@@ -19506,10 +19747,13 @@ const _BCFTopics = class _BCFTopics extends Component {
|
|
|
19506
19747
|
*/
|
|
19507
19748
|
async export(topics = this.list.values()) {
|
|
19508
19749
|
const zip = new JSZip();
|
|
19750
|
+
const isV3 = this.config.version === "3";
|
|
19751
|
+
const versionId = isV3 ? "3.0" : this.config.version;
|
|
19752
|
+
const schemaRelease = isV3 ? "release_3_0" : "release_2_1";
|
|
19509
19753
|
zip.file(
|
|
19510
19754
|
"bcf.version",
|
|
19511
19755
|
`<?xml version="1.0" encoding="UTF-8"?>
|
|
19512
|
-
<Version VersionId="${
|
|
19756
|
+
<Version VersionId="${versionId}" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/buildingSMART/BCF-XML/${schemaRelease}/Schemas/version.xsd"
|
|
19513
19757
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
19514
19758
|
</Version>`
|
|
19515
19759
|
);
|
|
@@ -19544,7 +19788,7 @@ const _BCFTopics = class _BCFTopics extends Component {
|
|
|
19544
19788
|
);
|
|
19545
19789
|
}
|
|
19546
19790
|
}
|
|
19547
|
-
zip.file("
|
|
19791
|
+
zip.file("extensions.xml", this.serializeExtensions());
|
|
19548
19792
|
const viewpoints = this.components.get(Viewpoints);
|
|
19549
19793
|
for (const topic of topics) {
|
|
19550
19794
|
const topicFolder = zip.folder(topic.guid);
|
|
@@ -19616,7 +19860,7 @@ ${users}
|
|
|
19616
19860
|
Comment: CommentText,
|
|
19617
19861
|
Viewpoint: Viewpoint2
|
|
19618
19862
|
} = markupComment;
|
|
19619
|
-
if (!(Guid && CommentDate && Author && Comment))
|
|
19863
|
+
if (!(Guid && CommentDate && Author && (Comment || Viewpoint2)))
|
|
19620
19864
|
return null;
|
|
19621
19865
|
const comment = new Comment(this.components, CommentText ?? "");
|
|
19622
19866
|
comment.guid = Guid;
|
|
@@ -19713,14 +19957,16 @@ ${users}
|
|
|
19713
19957
|
const versionFile = files.find((file) => file.name.endsWith(".version"));
|
|
19714
19958
|
if (versionFile) {
|
|
19715
19959
|
const versionXML = await versionFile.async("string");
|
|
19716
|
-
const bcfVersion =
|
|
19717
|
-
|
|
19960
|
+
const bcfVersion = String(
|
|
19961
|
+
_BCFTopics.xmlParser.parse(versionXML).Version.VersionId
|
|
19962
|
+
);
|
|
19963
|
+
version = bcfVersion === "3.0" ? "3" : bcfVersion;
|
|
19718
19964
|
}
|
|
19719
19965
|
if (!(version && (version === "2.1" || version === "3"))) {
|
|
19720
19966
|
throw new Error(`BCFTopics: ${version} is not supported.`);
|
|
19721
19967
|
}
|
|
19722
19968
|
const extensionsFile = files.find(
|
|
19723
|
-
(file) => file.name.endsWith(".extensions")
|
|
19969
|
+
(file) => file.name.endsWith("extensions.xml") || file.name.endsWith(".extensions")
|
|
19724
19970
|
);
|
|
19725
19971
|
if (updateExtensionsOnImport && extensionsFile) {
|
|
19726
19972
|
const extensionsXML = await extensionsFile.async("string");
|
|
@@ -20263,7 +20509,7 @@ class SimplePlane {
|
|
|
20263
20509
|
dispose() {
|
|
20264
20510
|
var _a;
|
|
20265
20511
|
this._enabled = false;
|
|
20266
|
-
if ((_a = this.world.camera) == null ? void 0 : _a.controls) {
|
|
20512
|
+
if (!this.world.isDisposing && ((_a = this.world.camera) == null ? void 0 : _a.controls)) {
|
|
20267
20513
|
this.world.camera.controls.removeEventListener(
|
|
20268
20514
|
"update",
|
|
20269
20515
|
this.updateScale
|
|
@@ -20504,8 +20750,13 @@ const _Clipper = class _Clipper extends Component {
|
|
|
20504
20750
|
* Default `false` to preserve existing behavior. Set this once
|
|
20505
20751
|
* before creating planes; toggling at runtime won't reclassify
|
|
20506
20752
|
* planes already on the renderer.
|
|
20753
|
+
*
|
|
20754
|
+
* Setting this also mirrors the value onto every world's
|
|
20755
|
+
* `renderer.localClippingPlanes`, so planes added by other
|
|
20756
|
+
* components (e.g. the {@link Views} cut planes) default to the
|
|
20757
|
+
* same mode without each call site having to pass `isLocal`.
|
|
20507
20758
|
*/
|
|
20508
|
-
__publicField(this, "
|
|
20759
|
+
__publicField(this, "_localClippingPlanes", false);
|
|
20509
20760
|
/**
|
|
20510
20761
|
* The type of clipping plane to be created.
|
|
20511
20762
|
* Default is {@link SimplePlane}.
|
|
@@ -20541,6 +20792,17 @@ const _Clipper = class _Clipper extends Component {
|
|
|
20541
20792
|
this.components.add(_Clipper.uuid, this);
|
|
20542
20793
|
this.setEvents();
|
|
20543
20794
|
}
|
|
20795
|
+
get localClippingPlanes() {
|
|
20796
|
+
return this._localClippingPlanes;
|
|
20797
|
+
}
|
|
20798
|
+
set localClippingPlanes(value) {
|
|
20799
|
+
this._localClippingPlanes = value;
|
|
20800
|
+
const worlds = this.components.get(Worlds);
|
|
20801
|
+
for (const [, world] of worlds.list) {
|
|
20802
|
+
if (world.renderer)
|
|
20803
|
+
world.renderer.localClippingPlanes = value;
|
|
20804
|
+
}
|
|
20805
|
+
}
|
|
20544
20806
|
/** {@link Component.enabled} */
|
|
20545
20807
|
get enabled() {
|
|
20546
20808
|
return this._enabled;
|
|
@@ -23468,19 +23730,24 @@ class IDSProperty extends IDSFacet {
|
|
|
23468
23730
|
);
|
|
23469
23731
|
}
|
|
23470
23732
|
getTypePsets(item) {
|
|
23471
|
-
|
|
23472
|
-
|
|
23473
|
-
|
|
23474
|
-
|
|
23475
|
-
|
|
23733
|
+
const definitions = [
|
|
23734
|
+
...Array.isArray(item.IsTypedBy) ? item.IsTypedBy : [],
|
|
23735
|
+
...Array.isArray(item.IsDefinedBy) ? item.IsDefinedBy : []
|
|
23736
|
+
];
|
|
23737
|
+
const psets = [];
|
|
23738
|
+
for (const definition of definitions) {
|
|
23739
|
+
if (Array.isArray(definition == null ? void 0 : definition.HasPropertySets)) {
|
|
23740
|
+
psets.push(...definition.HasPropertySets);
|
|
23741
|
+
}
|
|
23476
23742
|
}
|
|
23477
|
-
return
|
|
23743
|
+
return psets;
|
|
23478
23744
|
}
|
|
23479
23745
|
async getPsets(item) {
|
|
23480
23746
|
const typeSets = this.getTypePsets(item);
|
|
23481
23747
|
if (!Array.isArray(item.IsDefinedBy))
|
|
23482
23748
|
return typeSets;
|
|
23483
23749
|
const sets = [];
|
|
23750
|
+
const mergedTypeSets = /* @__PURE__ */ new Set();
|
|
23484
23751
|
for (const definition of item.IsDefinedBy) {
|
|
23485
23752
|
if (!("value" in definition.Name))
|
|
23486
23753
|
continue;
|
|
@@ -23493,22 +23760,29 @@ class IDSProperty extends IDSFacet {
|
|
|
23493
23760
|
return false;
|
|
23494
23761
|
return set.Name.value === definitionName;
|
|
23495
23762
|
});
|
|
23496
|
-
if (typeSet
|
|
23497
|
-
|
|
23498
|
-
|
|
23499
|
-
|
|
23500
|
-
|
|
23501
|
-
|
|
23502
|
-
|
|
23503
|
-
|
|
23504
|
-
|
|
23505
|
-
|
|
23506
|
-
|
|
23507
|
-
|
|
23763
|
+
if (typeSet) {
|
|
23764
|
+
mergedTypeSets.add(typeSet);
|
|
23765
|
+
if (Array.isArray(typeSet.HasProperties) && Array.isArray(definition.HasProperties)) {
|
|
23766
|
+
for (const prop of typeSet.HasProperties) {
|
|
23767
|
+
if (!("value" in prop.Name))
|
|
23768
|
+
continue;
|
|
23769
|
+
const name = prop.Name.value;
|
|
23770
|
+
const existingProp = definition.HasProperties.find((p) => {
|
|
23771
|
+
if (!("value" in p.Name))
|
|
23772
|
+
return false;
|
|
23773
|
+
return p.Name.value === name;
|
|
23774
|
+
});
|
|
23775
|
+
if (!existingProp)
|
|
23776
|
+
definition.HasProperties.push(prop);
|
|
23777
|
+
}
|
|
23508
23778
|
}
|
|
23509
23779
|
}
|
|
23510
23780
|
sets.push(definition);
|
|
23511
23781
|
}
|
|
23782
|
+
for (const typeSet of typeSets) {
|
|
23783
|
+
if (!mergedTypeSets.has(typeSet))
|
|
23784
|
+
sets.push(typeSet);
|
|
23785
|
+
}
|
|
23512
23786
|
return sets;
|
|
23513
23787
|
}
|
|
23514
23788
|
// IFCPROPERTYBOUNDEDVALUE are not supported yet
|
|
@@ -23530,7 +23804,7 @@ class IDSProperty extends IDSFacet {
|
|
|
23530
23804
|
return false;
|
|
23531
23805
|
}
|
|
23532
23806
|
const facetValue = structuredClone(this.value);
|
|
23533
|
-
if (valueAttr.
|
|
23807
|
+
if (typeof valueAttr.value === "string" && facetValue.type === "simple") {
|
|
23534
23808
|
facetValue.parameter = String(facetValue.parameter);
|
|
23535
23809
|
}
|
|
23536
23810
|
const result = this.evalRequirement(
|
|
@@ -23586,12 +23860,38 @@ class IDSProperty extends IDSFacet {
|
|
|
23586
23860
|
class IDSMaterial extends IDSFacet {
|
|
23587
23861
|
constructor() {
|
|
23588
23862
|
super(...arguments);
|
|
23863
|
+
// Every type IfcRelAssociatesMaterial.RelatingMaterial (IfcMaterialSelect)
|
|
23864
|
+
// can point at. Missing any of them silently drops every element that
|
|
23865
|
+
// associates its material through it: an element can reference a layer set
|
|
23866
|
+
// directly instead of through a layer set usage, and both spellings are
|
|
23867
|
+
// valid IFC.
|
|
23589
23868
|
__publicField(this, "_ifcMaterialEntities", [
|
|
23590
23869
|
/^IFCMATERIALLAYERSETUSAGE$/,
|
|
23870
|
+
/^IFCMATERIALLAYERSET$/,
|
|
23871
|
+
/^IFCMATERIALPROFILESETUSAGE$/,
|
|
23872
|
+
/^IFCMATERIALPROFILESET$/,
|
|
23591
23873
|
/^IFCMATERIALCONSTITUENTSET$/,
|
|
23592
23874
|
/^IFCMATERIAL$/,
|
|
23593
23875
|
/^IFCMATERIALLIST$/
|
|
23594
23876
|
]);
|
|
23877
|
+
// Attributes that lead from a material set / usage down to its IfcMaterial.
|
|
23878
|
+
__publicField(this, "_materialParentAttributes", [
|
|
23879
|
+
"ForLayerSet",
|
|
23880
|
+
"MaterialLayers",
|
|
23881
|
+
"ForProfileSet",
|
|
23882
|
+
"MaterialProfiles",
|
|
23883
|
+
"Material",
|
|
23884
|
+
"MaterialConstituents",
|
|
23885
|
+
"Materials"
|
|
23886
|
+
]);
|
|
23887
|
+
__publicField(this, "_materialRelations", {
|
|
23888
|
+
MaterialConstituents: { attributes: true, relations: true },
|
|
23889
|
+
ForLayerSet: { attributes: true, relations: true },
|
|
23890
|
+
MaterialLayers: { attributes: true, relations: true },
|
|
23891
|
+
ForProfileSet: { attributes: true, relations: true },
|
|
23892
|
+
MaterialProfiles: { attributes: true, relations: true },
|
|
23893
|
+
Materials: { attributes: true, relations: false }
|
|
23894
|
+
});
|
|
23595
23895
|
__publicField(this, "facetType", "Material");
|
|
23596
23896
|
__publicField(this, "value");
|
|
23597
23897
|
__publicField(this, "uri");
|
|
@@ -23623,10 +23923,7 @@ class IDSMaterial extends IDSFacet {
|
|
|
23623
23923
|
const data = await model.getItemsData(localIds, {
|
|
23624
23924
|
relations: {
|
|
23625
23925
|
AssociatedTo: { attributes: true, relations: false },
|
|
23626
|
-
|
|
23627
|
-
ForLayerSet: { attributes: true, relations: true },
|
|
23628
|
-
MaterialLayers: { attributes: true, relations: true },
|
|
23629
|
-
Materials: { attributes: true, relations: false }
|
|
23926
|
+
...this._materialRelations
|
|
23630
23927
|
}
|
|
23631
23928
|
});
|
|
23632
23929
|
for (const item of data) {
|
|
@@ -23655,10 +23952,7 @@ class IDSMaterial extends IDSFacet {
|
|
|
23655
23952
|
relations: {
|
|
23656
23953
|
AssociatedTo: { attributes: false, relations: false },
|
|
23657
23954
|
HasAssociations: { attributes: true, relations: true },
|
|
23658
|
-
|
|
23659
|
-
ForLayerSet: { attributes: true, relations: true },
|
|
23660
|
-
MaterialLayers: { attributes: true, relations: true },
|
|
23661
|
-
Materials: { attributes: true, relations: false }
|
|
23955
|
+
...this._materialRelations
|
|
23662
23956
|
}
|
|
23663
23957
|
});
|
|
23664
23958
|
for (const item of data) {
|
|
@@ -23702,13 +23996,7 @@ class IDSMaterial extends IDSFacet {
|
|
|
23702
23996
|
isValid = true;
|
|
23703
23997
|
} else {
|
|
23704
23998
|
for (const [name, attribute] of Object.entries(item)) {
|
|
23705
|
-
if (!
|
|
23706
|
-
"ForLayerSet",
|
|
23707
|
-
"MaterialLayers",
|
|
23708
|
-
"Material",
|
|
23709
|
-
"MaterialConstituents",
|
|
23710
|
-
"Materials"
|
|
23711
|
-
].includes(name))
|
|
23999
|
+
if (!this._materialParentAttributes.includes(name))
|
|
23712
24000
|
continue;
|
|
23713
24001
|
if (!Array.isArray(attribute))
|
|
23714
24002
|
continue;
|
|
@@ -26715,7 +27003,7 @@ function buildPreviewPositions(kind, points, cursor, style) {
|
|
|
26715
27003
|
for (let i = 0; i < points.length - 1; i++) {
|
|
26716
27004
|
positions.push(
|
|
26717
27005
|
...buildDimensionPositions(
|
|
26718
|
-
{
|
|
27006
|
+
{ pointA: points[i], pointB: points[i + 1], offset },
|
|
26719
27007
|
style
|
|
26720
27008
|
)
|
|
26721
27009
|
);
|