@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.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
|
}
|
|
@@ -12589,9 +12619,7 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
12589
12619
|
const model = fragments.list.get(result.modelId);
|
|
12590
12620
|
if (!model)
|
|
12591
12621
|
return null;
|
|
12592
|
-
const localIds = await model.getLocalIdsFromItemIds([
|
|
12593
|
-
result.itemId
|
|
12594
|
-
]);
|
|
12622
|
+
const localIds = await model.getLocalIdsFromItemIds([result.itemId]);
|
|
12595
12623
|
const localId = localIds == null ? void 0 : localIds[0];
|
|
12596
12624
|
if (localId === void 0 || localId === null)
|
|
12597
12625
|
return null;
|
|
@@ -12782,14 +12810,14 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
12782
12810
|
applyIdMaterial() {
|
|
12783
12811
|
const fragments = this.components.get(FragmentsManager);
|
|
12784
12812
|
const byteToModel = /* @__PURE__ */ new Map();
|
|
12813
|
+
const modelRoots = this.getModelRoots();
|
|
12814
|
+
this._ownMeshes.clear();
|
|
12785
12815
|
let nextByte = 1;
|
|
12786
12816
|
for (const [modelId, model] of fragments.list) {
|
|
12787
12817
|
if (nextByte > _FastModelPicker.MAX_MODELS)
|
|
12788
12818
|
break;
|
|
12789
|
-
const
|
|
12790
|
-
|
|
12791
|
-
let any = false;
|
|
12792
|
-
model.object.traverse((child) => {
|
|
12819
|
+
const owned = [];
|
|
12820
|
+
this.traverseOwn(model.object, modelRoots, (child) => {
|
|
12793
12821
|
if (!(child instanceof THREE.Mesh))
|
|
12794
12822
|
return;
|
|
12795
12823
|
const geom = child.geometry;
|
|
@@ -12806,13 +12834,44 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
12806
12834
|
const original = child.material;
|
|
12807
12835
|
const len = Array.isArray(original) ? original.length : 1;
|
|
12808
12836
|
child.material = new Array(len).fill(this._idMaterial);
|
|
12809
|
-
|
|
12837
|
+
owned.push(child);
|
|
12810
12838
|
});
|
|
12811
|
-
if (
|
|
12812
|
-
|
|
12839
|
+
if (!owned.length)
|
|
12840
|
+
continue;
|
|
12841
|
+
this._ownMeshes.set(modelId, owned);
|
|
12842
|
+
byteToModel.set(nextByte, modelId);
|
|
12843
|
+
nextByte += 1;
|
|
12813
12844
|
}
|
|
12814
12845
|
return byteToModel;
|
|
12815
12846
|
}
|
|
12847
|
+
/**
|
|
12848
|
+
* The object roots of every loaded model.
|
|
12849
|
+
*/
|
|
12850
|
+
getModelRoots() {
|
|
12851
|
+
const fragments = this.components.get(FragmentsManager);
|
|
12852
|
+
const roots = /* @__PURE__ */ new Set();
|
|
12853
|
+
for (const [, model] of fragments.list)
|
|
12854
|
+
roots.add(model.object);
|
|
12855
|
+
return roots;
|
|
12856
|
+
}
|
|
12857
|
+
/**
|
|
12858
|
+
* Like `Object3D.traverse`, but prunes the subtree of any nested model
|
|
12859
|
+
* root, so each mesh is visited exactly once, by the model that owns
|
|
12860
|
+
* it. A delta model's object hangs under its parent model's object
|
|
12861
|
+
* while being a model in its own right; a plain `traverse` from the
|
|
12862
|
+
* parent would walk into it.
|
|
12863
|
+
*/
|
|
12864
|
+
traverseOwn(root, modelRoots, callback) {
|
|
12865
|
+
const stack = [root];
|
|
12866
|
+
while (stack.length) {
|
|
12867
|
+
const node = stack.pop();
|
|
12868
|
+
if (node !== root && modelRoots.has(node))
|
|
12869
|
+
continue;
|
|
12870
|
+
callback(node);
|
|
12871
|
+
for (const child of node.children)
|
|
12872
|
+
stack.push(child);
|
|
12873
|
+
}
|
|
12874
|
+
}
|
|
12816
12875
|
/**
|
|
12817
12876
|
* Renders the world scene to the id target one model at a time,
|
|
12818
12877
|
* flipping the `modelByte` uniform between renders. The depth buffer
|
|
@@ -12857,6 +12916,8 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
12857
12916
|
const prevClearAlpha = renderer.getClearAlpha();
|
|
12858
12917
|
const prevScissorTest = renderer.getScissorTest();
|
|
12859
12918
|
const prevScissor = renderer.getScissor(new THREE.Vector4());
|
|
12919
|
+
const prevBackground = scene.background;
|
|
12920
|
+
scene.background = null;
|
|
12860
12921
|
renderer.setRenderTarget(target);
|
|
12861
12922
|
renderer.setClearColor(0, 0);
|
|
12862
12923
|
renderer.autoClear = false;
|
|
@@ -12903,21 +12964,47 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
12903
12964
|
nonBimVisibility.set(child, child.visible);
|
|
12904
12965
|
child.visible = false;
|
|
12905
12966
|
});
|
|
12906
|
-
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();
|
|
12907
12981
|
for (const obj of objectsByModel.values()) {
|
|
12908
|
-
|
|
12909
|
-
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
|
+
}
|
|
12910
12991
|
}
|
|
12911
12992
|
for (const [byte, modelId] of byteToModel) {
|
|
12912
|
-
|
|
12913
|
-
if (!obj)
|
|
12993
|
+
if (!wasOnScreen.get(modelId))
|
|
12914
12994
|
continue;
|
|
12915
|
-
|
|
12995
|
+
const meshes = this._ownMeshes.get(modelId);
|
|
12996
|
+
if (!meshes)
|
|
12997
|
+
continue;
|
|
12998
|
+
for (const mesh of meshes)
|
|
12999
|
+
mesh.visible = meshVisibilityBefore.get(mesh);
|
|
12916
13000
|
material.uniforms.modelByte.value = byte;
|
|
12917
13001
|
renderer.render(scene, camera);
|
|
12918
|
-
|
|
13002
|
+
for (const mesh of meshes)
|
|
13003
|
+
mesh.visible = false;
|
|
12919
13004
|
}
|
|
12920
|
-
for (const [
|
|
13005
|
+
for (const [mesh, was] of meshVisibilityBefore)
|
|
13006
|
+
mesh.visible = was;
|
|
13007
|
+
for (const [obj, was] of rootVisibilityBefore)
|
|
12921
13008
|
obj.visible = was;
|
|
12922
13009
|
for (const [obj, was] of nonBimVisibility)
|
|
12923
13010
|
obj.visible = was;
|
|
@@ -12926,6 +13013,7 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
12926
13013
|
renderer.setRenderTarget(prevTarget);
|
|
12927
13014
|
renderer.autoClear = prevAutoClear;
|
|
12928
13015
|
renderer.setClearColor(prevClearColor, prevClearAlpha);
|
|
13016
|
+
scene.background = prevBackground;
|
|
12929
13017
|
}
|
|
12930
13018
|
/**
|
|
12931
13019
|
* Renders the picker's color target with the BIM tile shells using
|
|
@@ -12956,10 +13044,13 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
12956
13044
|
const prevAutoClear = renderer.autoClear;
|
|
12957
13045
|
const prevClearColor = renderer.getClearColor(new THREE.Color());
|
|
12958
13046
|
const prevClearAlpha = renderer.getClearAlpha();
|
|
13047
|
+
const prevBackground = scene.background;
|
|
13048
|
+
scene.background = null;
|
|
12959
13049
|
const matSwap = /* @__PURE__ */ new Map();
|
|
12960
13050
|
const hiddenLines = [];
|
|
13051
|
+
const modelRoots = this.getModelRoots();
|
|
12961
13052
|
for (const [, model] of fragments.list) {
|
|
12962
|
-
model.object
|
|
13053
|
+
this.traverseOwn(model.object, modelRoots, (child) => {
|
|
12963
13054
|
if (!(child instanceof THREE.Mesh))
|
|
12964
13055
|
return;
|
|
12965
13056
|
const geom = child.geometry;
|
|
@@ -13017,6 +13108,7 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
13017
13108
|
renderer.setRenderTarget(prevTarget);
|
|
13018
13109
|
renderer.autoClear = prevAutoClear;
|
|
13019
13110
|
renderer.setClearColor(prevClearColor, prevClearAlpha);
|
|
13111
|
+
scene.background = prevBackground;
|
|
13020
13112
|
}
|
|
13021
13113
|
renderDepthPass() {
|
|
13022
13114
|
this.renderWithTileMaterial(this._depthMaterial);
|
|
@@ -13029,6 +13121,7 @@ const _FastModelPicker = class _FastModelPicker {
|
|
|
13029
13121
|
mesh.material = mat;
|
|
13030
13122
|
}
|
|
13031
13123
|
this._originalMaterials.clear();
|
|
13124
|
+
this._ownMeshes.clear();
|
|
13032
13125
|
for (const obj of this._hiddenLods)
|
|
13033
13126
|
obj.visible = true;
|
|
13034
13127
|
this._hiddenLods.length = 0;
|
|
@@ -13405,12 +13498,32 @@ class SnapResolver {
|
|
|
13405
13498
|
*/
|
|
13406
13499
|
__publicField(this, "maxCacheSize", 1e3);
|
|
13407
13500
|
__publicField(this, "components");
|
|
13501
|
+
__publicField(this, "_precision", "half");
|
|
13408
13502
|
// Map insertion order is recency order (LRU). On every read we
|
|
13409
13503
|
// delete + re-set the entry to bump it to most-recent; on every
|
|
13410
13504
|
// write we drop oldest entries until size <= maxCacheSize.
|
|
13411
13505
|
__publicField(this, "cache", /* @__PURE__ */ new Map());
|
|
13412
13506
|
this.components = components;
|
|
13413
13507
|
}
|
|
13508
|
+
/**
|
|
13509
|
+
* Numeric precision for cached face/edge/vertex buffers.
|
|
13510
|
+
*
|
|
13511
|
+
* `"half"` uses Float32Array for lower memory footprint.
|
|
13512
|
+
* `"full"` uses Float64Array for higher numeric precision.
|
|
13513
|
+
* Use `"full"` for workflows that require higher geometric fidelity.
|
|
13514
|
+
*
|
|
13515
|
+
* Changing this value clears the snap cache so subsequent requests
|
|
13516
|
+
* are rebuilt with the new precision.
|
|
13517
|
+
*/
|
|
13518
|
+
get precision() {
|
|
13519
|
+
return this._precision;
|
|
13520
|
+
}
|
|
13521
|
+
set precision(value) {
|
|
13522
|
+
if (value === this._precision)
|
|
13523
|
+
return;
|
|
13524
|
+
this._precision = value;
|
|
13525
|
+
this.clear();
|
|
13526
|
+
}
|
|
13414
13527
|
/** {@link Disposable.dispose} */
|
|
13415
13528
|
dispose() {
|
|
13416
13529
|
this.cache.clear();
|
|
@@ -13550,8 +13663,8 @@ class SnapResolver {
|
|
|
13550
13663
|
}
|
|
13551
13664
|
if (polygons.length === 0)
|
|
13552
13665
|
return null;
|
|
13553
|
-
const edges = deriveUniqueEdges(polygons);
|
|
13554
|
-
const vertices = deriveUniqueVertices(polygons);
|
|
13666
|
+
const edges = deriveUniqueEdges(polygons, this._precision);
|
|
13667
|
+
const vertices = deriveUniqueVertices(polygons, this._precision);
|
|
13555
13668
|
return { faces: polygons, edges, vertices };
|
|
13556
13669
|
}
|
|
13557
13670
|
collectPolygonsFromShell(shell, worldMatrix, out) {
|
|
@@ -13562,7 +13675,8 @@ class SnapResolver {
|
|
|
13562
13675
|
const collect = (indices) => {
|
|
13563
13676
|
if (indices.length < 3)
|
|
13564
13677
|
return;
|
|
13565
|
-
const
|
|
13678
|
+
const Ctor = this._precision === "full" ? Float64Array : Float32Array;
|
|
13679
|
+
const flat = new Ctor(indices.length * 3);
|
|
13566
13680
|
for (let i = 0; i < indices.length; i++) {
|
|
13567
13681
|
const p = points[indices[i]];
|
|
13568
13682
|
tmp.set(p[0], p[1], p[2]).applyMatrix4(worldMatrix);
|
|
@@ -13671,19 +13785,33 @@ class SnapResolver {
|
|
|
13671
13785
|
return null;
|
|
13672
13786
|
let best = null;
|
|
13673
13787
|
let bestAbs = Infinity;
|
|
13788
|
+
let bestContains = false;
|
|
13674
13789
|
for (const f of faces) {
|
|
13675
|
-
const signed =
|
|
13790
|
+
const signed = this.signedDistance(f, point);
|
|
13676
13791
|
const abs2 = Math.abs(signed);
|
|
13677
|
-
if (abs2
|
|
13792
|
+
if (abs2 > this.maxDistance)
|
|
13793
|
+
continue;
|
|
13794
|
+
const contains = this.containsPoint(f, this.projectOntoPlane(point, f, signed));
|
|
13795
|
+
if (bestContains && !contains)
|
|
13796
|
+
continue;
|
|
13797
|
+
if (contains && !bestContains) {
|
|
13798
|
+
bestContains = true;
|
|
13799
|
+
bestAbs = abs2;
|
|
13800
|
+
best = f;
|
|
13801
|
+
continue;
|
|
13802
|
+
}
|
|
13803
|
+
if (abs2 < bestAbs) {
|
|
13678
13804
|
bestAbs = abs2;
|
|
13679
13805
|
best = f;
|
|
13680
13806
|
}
|
|
13681
13807
|
}
|
|
13682
13808
|
if (!best)
|
|
13683
13809
|
return null;
|
|
13684
|
-
const projected =
|
|
13685
|
-
|
|
13686
|
-
|
|
13810
|
+
const projected = this.projectOntoPlane(
|
|
13811
|
+
point,
|
|
13812
|
+
best,
|
|
13813
|
+
this.signedDistance(best, point)
|
|
13814
|
+
);
|
|
13687
13815
|
return {
|
|
13688
13816
|
result: {
|
|
13689
13817
|
point: projected,
|
|
@@ -13694,6 +13822,50 @@ class SnapResolver {
|
|
|
13694
13822
|
}
|
|
13695
13823
|
};
|
|
13696
13824
|
}
|
|
13825
|
+
signedDistance(face, point) {
|
|
13826
|
+
return face.normal.x * point.x + face.normal.y * point.y + face.normal.z * point.z - face.d;
|
|
13827
|
+
}
|
|
13828
|
+
projectOntoPlane(point, face, signed) {
|
|
13829
|
+
return point.clone().sub(face.normal.clone().multiplyScalar(signed));
|
|
13830
|
+
}
|
|
13831
|
+
/**
|
|
13832
|
+
* Even-odd point-in-polygon test, run on the polygon projected onto its
|
|
13833
|
+
* dominant plane. `point` is assumed to already lie on the face's plane.
|
|
13834
|
+
*/
|
|
13835
|
+
containsPoint(face, point) {
|
|
13836
|
+
const { points, normal } = face;
|
|
13837
|
+
const count = points.length / 3;
|
|
13838
|
+
if (count < 3)
|
|
13839
|
+
return false;
|
|
13840
|
+
const ax = Math.abs(normal.x);
|
|
13841
|
+
const ay = Math.abs(normal.y);
|
|
13842
|
+
const az = Math.abs(normal.z);
|
|
13843
|
+
let a = 0;
|
|
13844
|
+
let b = 1;
|
|
13845
|
+
if (ax >= ay && ax >= az) {
|
|
13846
|
+
a = 1;
|
|
13847
|
+
b = 2;
|
|
13848
|
+
} else if (ay >= az) {
|
|
13849
|
+
a = 0;
|
|
13850
|
+
b = 2;
|
|
13851
|
+
}
|
|
13852
|
+
const px = point.getComponent(a);
|
|
13853
|
+
const py = point.getComponent(b);
|
|
13854
|
+
let inside = false;
|
|
13855
|
+
for (let i = 0, j = count - 1; i < count; j = i, i += 1) {
|
|
13856
|
+
const xi = points[i * 3 + a];
|
|
13857
|
+
const yi = points[i * 3 + b];
|
|
13858
|
+
const xj = points[j * 3 + a];
|
|
13859
|
+
const yj = points[j * 3 + b];
|
|
13860
|
+
const straddles = yi > py !== yj > py;
|
|
13861
|
+
if (!straddles)
|
|
13862
|
+
continue;
|
|
13863
|
+
const x = (xj - xi) * (py - yi) / (yj - yi) + xi;
|
|
13864
|
+
if (px < x)
|
|
13865
|
+
inside = !inside;
|
|
13866
|
+
}
|
|
13867
|
+
return inside;
|
|
13868
|
+
}
|
|
13697
13869
|
}
|
|
13698
13870
|
const _tmpMatrix = new THREE.Matrix4();
|
|
13699
13871
|
const _tmpX = new THREE.Vector3();
|
|
@@ -13761,7 +13933,7 @@ function fanTriangulation(vertexCount) {
|
|
|
13761
13933
|
}
|
|
13762
13934
|
return out;
|
|
13763
13935
|
}
|
|
13764
|
-
function deriveUniqueEdges(faces) {
|
|
13936
|
+
function deriveUniqueEdges(faces, precision) {
|
|
13765
13937
|
const seen = /* @__PURE__ */ new Set();
|
|
13766
13938
|
const collected = [];
|
|
13767
13939
|
for (const f of faces) {
|
|
@@ -13778,9 +13950,10 @@ function deriveUniqueEdges(faces) {
|
|
|
13778
13950
|
collected.push(ax, ay, az, bx, by, bz);
|
|
13779
13951
|
}
|
|
13780
13952
|
}
|
|
13781
|
-
|
|
13953
|
+
const Ctor = precision === "full" ? Float64Array : Float32Array;
|
|
13954
|
+
return new Ctor(collected);
|
|
13782
13955
|
}
|
|
13783
|
-
function deriveUniqueVertices(faces) {
|
|
13956
|
+
function deriveUniqueVertices(faces, precision) {
|
|
13784
13957
|
const seen = /* @__PURE__ */ new Set();
|
|
13785
13958
|
const collected = [];
|
|
13786
13959
|
for (const f of faces) {
|
|
@@ -13795,7 +13968,8 @@ function deriveUniqueVertices(faces) {
|
|
|
13795
13968
|
collected.push(x, y, z);
|
|
13796
13969
|
}
|
|
13797
13970
|
}
|
|
13798
|
-
|
|
13971
|
+
const Ctor = precision === "full" ? Float64Array : Float32Array;
|
|
13972
|
+
return new Ctor(collected);
|
|
13799
13973
|
}
|
|
13800
13974
|
function quantKey(x, y, z) {
|
|
13801
13975
|
return `${Math.round(x * VERTEX_QUANT)},${Math.round(y * VERTEX_QUANT)},${Math.round(z * VERTEX_QUANT)}`;
|
|
@@ -14091,6 +14265,9 @@ class SimpleWorld extends Base {
|
|
|
14091
14265
|
*/
|
|
14092
14266
|
__publicField(this, "enabled", true);
|
|
14093
14267
|
__publicField(this, "_dynamicAnchor", false);
|
|
14268
|
+
// Bumped on every anchor press so a slow geometry pick that resolves after a
|
|
14269
|
+
// newer press is ignored (see onPointerDown).
|
|
14270
|
+
__publicField(this, "_anchorRequestId", 0);
|
|
14094
14271
|
/**
|
|
14095
14272
|
* A unique identifier for the world. Is not meant to be changed at any moment.
|
|
14096
14273
|
*/
|
|
@@ -14102,21 +14279,36 @@ class SimpleWorld extends Base {
|
|
|
14102
14279
|
__publicField(this, "_scene");
|
|
14103
14280
|
__publicField(this, "_camera");
|
|
14104
14281
|
__publicField(this, "_renderer", null);
|
|
14105
|
-
__publicField(this, "onPointerDown",
|
|
14282
|
+
__publicField(this, "onPointerDown", (event) => {
|
|
14106
14283
|
if (!this.camera.hasCameraControls()) {
|
|
14107
14284
|
throw new Error(
|
|
14108
14285
|
"World: can't set dynamic anchor if the camera doesn't have controls."
|
|
14109
14286
|
);
|
|
14110
14287
|
}
|
|
14288
|
+
if (event.button !== 0)
|
|
14289
|
+
return;
|
|
14290
|
+
const position = this.getPointerPosition(event);
|
|
14291
|
+
if (!position)
|
|
14292
|
+
return;
|
|
14111
14293
|
const caster = this.components.get(Raycasters).get(this);
|
|
14112
|
-
const
|
|
14113
|
-
if (
|
|
14294
|
+
const planePoint = this.getPlaneAnchor(caster, position);
|
|
14295
|
+
if (planePoint) {
|
|
14114
14296
|
this.camera.controls.setOrbitPoint(
|
|
14115
|
-
|
|
14116
|
-
|
|
14117
|
-
|
|
14297
|
+
planePoint.x,
|
|
14298
|
+
planePoint.y,
|
|
14299
|
+
planePoint.z
|
|
14118
14300
|
);
|
|
14119
14301
|
}
|
|
14302
|
+
const requestId = ++this._anchorRequestId;
|
|
14303
|
+
caster.castRay({ position }).then((result) => {
|
|
14304
|
+
const isStale = requestId !== this._anchorRequestId;
|
|
14305
|
+
if (isStale || this.isDisposing || !this._dynamicAnchor)
|
|
14306
|
+
return;
|
|
14307
|
+
if (!(result == null ? void 0 : result.point) || !this.camera.hasCameraControls())
|
|
14308
|
+
return;
|
|
14309
|
+
const { x, y, z } = result.point;
|
|
14310
|
+
this.camera.controls.setOrbitPoint(x, y, z);
|
|
14311
|
+
});
|
|
14120
14312
|
});
|
|
14121
14313
|
__publicField(this, "_defaultCamera");
|
|
14122
14314
|
}
|
|
@@ -14135,10 +14327,46 @@ class SimpleWorld extends Base {
|
|
|
14135
14327
|
} else {
|
|
14136
14328
|
container.removeEventListener("pointerdown", this.onPointerDown);
|
|
14137
14329
|
}
|
|
14330
|
+
this._dynamicAnchor = value;
|
|
14138
14331
|
}
|
|
14139
14332
|
get dynamicAnchor() {
|
|
14140
14333
|
return this._dynamicAnchor;
|
|
14141
14334
|
}
|
|
14335
|
+
/**
|
|
14336
|
+
* The pointer position in normalized device coordinates, derived from the
|
|
14337
|
+
* event rather than the raycaster's mouse: that one only tracks pointermove
|
|
14338
|
+
* and touchstart, so on a bare pointerdown it would still report the center of
|
|
14339
|
+
* the viewport.
|
|
14340
|
+
*/
|
|
14341
|
+
getPointerPosition(event) {
|
|
14342
|
+
var _a;
|
|
14343
|
+
const dom = (_a = this.renderer) == null ? void 0 : _a.three.domElement;
|
|
14344
|
+
if (!dom)
|
|
14345
|
+
return null;
|
|
14346
|
+
const bounds = dom.getBoundingClientRect();
|
|
14347
|
+
return new THREE.Vector2(
|
|
14348
|
+
(event.clientX - bounds.left) / (bounds.right - bounds.left) * 2 - 1,
|
|
14349
|
+
-((event.clientY - bounds.top) / (bounds.bottom - bounds.top)) * 2 + 1
|
|
14350
|
+
);
|
|
14351
|
+
}
|
|
14352
|
+
/**
|
|
14353
|
+
* The point where the pointer ray crosses the plane that contains the current
|
|
14354
|
+
* orbit target and faces the camera. Used as the anchor when the pointer
|
|
14355
|
+
* doesn't land on any geometry.
|
|
14356
|
+
*/
|
|
14357
|
+
getPlaneAnchor(caster, position) {
|
|
14358
|
+
if (!this.camera.hasCameraControls())
|
|
14359
|
+
return null;
|
|
14360
|
+
const camera = this.camera.three;
|
|
14361
|
+
caster.three.setFromCamera(position, camera);
|
|
14362
|
+
const target = this.camera.controls.getTarget(new THREE.Vector3());
|
|
14363
|
+
const normal = camera.getWorldDirection(new THREE.Vector3());
|
|
14364
|
+
const plane = new THREE.Plane().setFromNormalAndCoplanarPoint(
|
|
14365
|
+
normal,
|
|
14366
|
+
target
|
|
14367
|
+
);
|
|
14368
|
+
return caster.three.ray.intersectPlane(plane, new THREE.Vector3());
|
|
14369
|
+
}
|
|
14142
14370
|
get defaultCamera() {
|
|
14143
14371
|
if (!this._defaultCamera) {
|
|
14144
14372
|
throw new Error("World: there is no default camera defined.");
|
|
@@ -14241,8 +14469,16 @@ class SimpleWorld extends Base {
|
|
|
14241
14469
|
}
|
|
14242
14470
|
/** {@link Disposable.dispose} */
|
|
14243
14471
|
dispose(disposeResources = true) {
|
|
14472
|
+
var _a;
|
|
14473
|
+
if (this.isDisposing)
|
|
14474
|
+
return;
|
|
14244
14475
|
this.enabled = false;
|
|
14245
14476
|
this.isDisposing = true;
|
|
14477
|
+
const container = (_a = this.renderer) == null ? void 0 : _a.three.domElement.parentElement;
|
|
14478
|
+
if (container) {
|
|
14479
|
+
container.removeEventListener("pointerdown", this.onPointerDown);
|
|
14480
|
+
}
|
|
14481
|
+
this._dynamicAnchor = false;
|
|
14246
14482
|
this.scene.onWorldChanged.trigger({ world: this, action: "removed" });
|
|
14247
14483
|
this.camera.onWorldChanged.trigger({ world: this, action: "removed" });
|
|
14248
14484
|
if (this.renderer) {
|
|
@@ -15489,16 +15725,23 @@ const _Components = class _Components {
|
|
|
15489
15725
|
dispose() {
|
|
15490
15726
|
this.enabled = false;
|
|
15491
15727
|
let fragments;
|
|
15728
|
+
let worlds;
|
|
15492
15729
|
for (const [_id, component] of this.list) {
|
|
15493
15730
|
component.enabled = false;
|
|
15494
15731
|
if (_id === FragmentsManager.uuid) {
|
|
15495
15732
|
fragments = component;
|
|
15496
15733
|
continue;
|
|
15497
15734
|
}
|
|
15735
|
+
if (_id === Worlds.uuid) {
|
|
15736
|
+
worlds = component;
|
|
15737
|
+
continue;
|
|
15738
|
+
}
|
|
15498
15739
|
if (component.isDisposeable()) {
|
|
15499
15740
|
component.dispose();
|
|
15500
15741
|
}
|
|
15501
15742
|
}
|
|
15743
|
+
if (worlds == null ? void 0 : worlds.isDisposeable())
|
|
15744
|
+
worlds.dispose();
|
|
15502
15745
|
fragments == null ? void 0 : fragments.dispose();
|
|
15503
15746
|
this._timer.dispose();
|
|
15504
15747
|
this.onDisposed.trigger();
|
|
@@ -15975,7 +16218,7 @@ Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/js
|
|
|
15975
16218
|
JSZip uses the library pako released under the MIT license :
|
|
15976
16219
|
https://github.com/nodeca/pako/blob/main/LICENSE
|
|
15977
16220
|
*/
|
|
15978
|
-
(function(module, exports) {
|
|
16221
|
+
(function(module, exports$1) {
|
|
15979
16222
|
!function(e) {
|
|
15980
16223
|
module.exports = e();
|
|
15981
16224
|
}(function() {
|
|
@@ -19033,33 +19276,31 @@ const _Topic = class _Topic {
|
|
|
19033
19276
|
serialize() {
|
|
19034
19277
|
var _a, _b;
|
|
19035
19278
|
const version = this._managerVersion;
|
|
19279
|
+
const isV3 = version === "3";
|
|
19036
19280
|
const topic = {
|
|
19037
19281
|
$Guid: this.guid,
|
|
19038
19282
|
$TopicType: this.type,
|
|
19039
19283
|
$TopicStatus: this.status,
|
|
19040
19284
|
$ServerAssignedId: this.serverAssignedId,
|
|
19041
19285
|
Title: this.title,
|
|
19042
|
-
CreationAuthor: this.creationAuthor,
|
|
19043
|
-
CreationDate: this.creationDate.toISOString(),
|
|
19044
19286
|
Priority: this.priority,
|
|
19045
19287
|
Index: version === "2.1" ? this.index : void 0,
|
|
19288
|
+
Labels: isV3 ? { Label: this.createLabelTags() } : this.createLabelTags(),
|
|
19289
|
+
CreationDate: this.creationDate.toISOString(),
|
|
19290
|
+
CreationAuthor: this.creationAuthor,
|
|
19046
19291
|
ModifiedDate: (_a = this.modifiedDate) == null ? void 0 : _a.toISOString(),
|
|
19047
19292
|
ModifiedAuthor: this.modifiedAuthor,
|
|
19048
19293
|
DueDate: (_b = this.dueDate) == null ? void 0 : _b.toISOString(),
|
|
19049
19294
|
AssignedTo: this.assignedTo,
|
|
19050
|
-
Description: this.description,
|
|
19051
19295
|
Stage: this.stage,
|
|
19052
|
-
|
|
19053
|
-
|
|
19054
|
-
|
|
19055
|
-
|
|
19056
|
-
|
|
19057
|
-
Comments:
|
|
19296
|
+
Description: this.description,
|
|
19297
|
+
DocumentReferences: isV3 ? { DocumentReference: this.createDocumentReferencesTag(version) } : void 0,
|
|
19298
|
+
DocumentReference: isV3 ? void 0 : this.createDocumentReferencesTag(version),
|
|
19299
|
+
RelatedTopics: isV3 ? { RelatedTopic: this.createRelatedTopicTags() } : void 0,
|
|
19300
|
+
RelatedTopic: isV3 ? void 0 : this.createRelatedTopicTags(),
|
|
19301
|
+
Comments: isV3 ? { Comment: this.createCommentTags() } : void 0,
|
|
19302
|
+
Viewpoints: isV3 ? { ViewPoint: this.createViewpointTags() } : void 0
|
|
19058
19303
|
};
|
|
19059
|
-
if (version === "2.1") {
|
|
19060
|
-
topic.Labels = this.createLabelTags();
|
|
19061
|
-
topic.DocumentReference = this.createDocumentReferencesTag(version);
|
|
19062
|
-
}
|
|
19063
19304
|
const markup = {
|
|
19064
19305
|
Markup: { Topic: topic }
|
|
19065
19306
|
};
|
|
@@ -19486,10 +19727,13 @@ const _BCFTopics = class _BCFTopics extends Component {
|
|
|
19486
19727
|
*/
|
|
19487
19728
|
async export(topics = this.list.values()) {
|
|
19488
19729
|
const zip = new JSZip();
|
|
19730
|
+
const isV3 = this.config.version === "3";
|
|
19731
|
+
const versionId = isV3 ? "3.0" : this.config.version;
|
|
19732
|
+
const schemaRelease = isV3 ? "release_3_0" : "release_2_1";
|
|
19489
19733
|
zip.file(
|
|
19490
19734
|
"bcf.version",
|
|
19491
19735
|
`<?xml version="1.0" encoding="UTF-8"?>
|
|
19492
|
-
<Version VersionId="${
|
|
19736
|
+
<Version VersionId="${versionId}" xsi:noNamespaceSchemaLocation="https://raw.githubusercontent.com/buildingSMART/BCF-XML/${schemaRelease}/Schemas/version.xsd"
|
|
19493
19737
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
|
|
19494
19738
|
</Version>`
|
|
19495
19739
|
);
|
|
@@ -19524,7 +19768,7 @@ const _BCFTopics = class _BCFTopics extends Component {
|
|
|
19524
19768
|
);
|
|
19525
19769
|
}
|
|
19526
19770
|
}
|
|
19527
|
-
zip.file("
|
|
19771
|
+
zip.file("extensions.xml", this.serializeExtensions());
|
|
19528
19772
|
const viewpoints = this.components.get(Viewpoints);
|
|
19529
19773
|
for (const topic of topics) {
|
|
19530
19774
|
const topicFolder = zip.folder(topic.guid);
|
|
@@ -19596,7 +19840,7 @@ ${users}
|
|
|
19596
19840
|
Comment: CommentText,
|
|
19597
19841
|
Viewpoint: Viewpoint2
|
|
19598
19842
|
} = markupComment;
|
|
19599
|
-
if (!(Guid && CommentDate && Author && Comment))
|
|
19843
|
+
if (!(Guid && CommentDate && Author && (Comment || Viewpoint2)))
|
|
19600
19844
|
return null;
|
|
19601
19845
|
const comment = new Comment(this.components, CommentText ?? "");
|
|
19602
19846
|
comment.guid = Guid;
|
|
@@ -19693,14 +19937,16 @@ ${users}
|
|
|
19693
19937
|
const versionFile = files.find((file) => file.name.endsWith(".version"));
|
|
19694
19938
|
if (versionFile) {
|
|
19695
19939
|
const versionXML = await versionFile.async("string");
|
|
19696
|
-
const bcfVersion =
|
|
19697
|
-
|
|
19940
|
+
const bcfVersion = String(
|
|
19941
|
+
_BCFTopics.xmlParser.parse(versionXML).Version.VersionId
|
|
19942
|
+
);
|
|
19943
|
+
version = bcfVersion === "3.0" ? "3" : bcfVersion;
|
|
19698
19944
|
}
|
|
19699
19945
|
if (!(version && (version === "2.1" || version === "3"))) {
|
|
19700
19946
|
throw new Error(`BCFTopics: ${version} is not supported.`);
|
|
19701
19947
|
}
|
|
19702
19948
|
const extensionsFile = files.find(
|
|
19703
|
-
(file) => file.name.endsWith(".extensions")
|
|
19949
|
+
(file) => file.name.endsWith("extensions.xml") || file.name.endsWith(".extensions")
|
|
19704
19950
|
);
|
|
19705
19951
|
if (updateExtensionsOnImport && extensionsFile) {
|
|
19706
19952
|
const extensionsXML = await extensionsFile.async("string");
|
|
@@ -20243,7 +20489,7 @@ class SimplePlane {
|
|
|
20243
20489
|
dispose() {
|
|
20244
20490
|
var _a;
|
|
20245
20491
|
this._enabled = false;
|
|
20246
|
-
if ((_a = this.world.camera) == null ? void 0 : _a.controls) {
|
|
20492
|
+
if (!this.world.isDisposing && ((_a = this.world.camera) == null ? void 0 : _a.controls)) {
|
|
20247
20493
|
this.world.camera.controls.removeEventListener(
|
|
20248
20494
|
"update",
|
|
20249
20495
|
this.updateScale
|
|
@@ -20484,8 +20730,13 @@ const _Clipper = class _Clipper extends Component {
|
|
|
20484
20730
|
* Default `false` to preserve existing behavior. Set this once
|
|
20485
20731
|
* before creating planes; toggling at runtime won't reclassify
|
|
20486
20732
|
* planes already on the renderer.
|
|
20733
|
+
*
|
|
20734
|
+
* Setting this also mirrors the value onto every world's
|
|
20735
|
+
* `renderer.localClippingPlanes`, so planes added by other
|
|
20736
|
+
* components (e.g. the {@link Views} cut planes) default to the
|
|
20737
|
+
* same mode without each call site having to pass `isLocal`.
|
|
20487
20738
|
*/
|
|
20488
|
-
__publicField(this, "
|
|
20739
|
+
__publicField(this, "_localClippingPlanes", false);
|
|
20489
20740
|
/**
|
|
20490
20741
|
* The type of clipping plane to be created.
|
|
20491
20742
|
* Default is {@link SimplePlane}.
|
|
@@ -20521,6 +20772,17 @@ const _Clipper = class _Clipper extends Component {
|
|
|
20521
20772
|
this.components.add(_Clipper.uuid, this);
|
|
20522
20773
|
this.setEvents();
|
|
20523
20774
|
}
|
|
20775
|
+
get localClippingPlanes() {
|
|
20776
|
+
return this._localClippingPlanes;
|
|
20777
|
+
}
|
|
20778
|
+
set localClippingPlanes(value) {
|
|
20779
|
+
this._localClippingPlanes = value;
|
|
20780
|
+
const worlds = this.components.get(Worlds);
|
|
20781
|
+
for (const [, world] of worlds.list) {
|
|
20782
|
+
if (world.renderer)
|
|
20783
|
+
world.renderer.localClippingPlanes = value;
|
|
20784
|
+
}
|
|
20785
|
+
}
|
|
20524
20786
|
/** {@link Component.enabled} */
|
|
20525
20787
|
get enabled() {
|
|
20526
20788
|
return this._enabled;
|
|
@@ -23448,19 +23710,24 @@ class IDSProperty extends IDSFacet {
|
|
|
23448
23710
|
);
|
|
23449
23711
|
}
|
|
23450
23712
|
getTypePsets(item) {
|
|
23451
|
-
|
|
23452
|
-
|
|
23453
|
-
|
|
23454
|
-
|
|
23455
|
-
|
|
23713
|
+
const definitions = [
|
|
23714
|
+
...Array.isArray(item.IsTypedBy) ? item.IsTypedBy : [],
|
|
23715
|
+
...Array.isArray(item.IsDefinedBy) ? item.IsDefinedBy : []
|
|
23716
|
+
];
|
|
23717
|
+
const psets = [];
|
|
23718
|
+
for (const definition of definitions) {
|
|
23719
|
+
if (Array.isArray(definition == null ? void 0 : definition.HasPropertySets)) {
|
|
23720
|
+
psets.push(...definition.HasPropertySets);
|
|
23721
|
+
}
|
|
23456
23722
|
}
|
|
23457
|
-
return
|
|
23723
|
+
return psets;
|
|
23458
23724
|
}
|
|
23459
23725
|
async getPsets(item) {
|
|
23460
23726
|
const typeSets = this.getTypePsets(item);
|
|
23461
23727
|
if (!Array.isArray(item.IsDefinedBy))
|
|
23462
23728
|
return typeSets;
|
|
23463
23729
|
const sets = [];
|
|
23730
|
+
const mergedTypeSets = /* @__PURE__ */ new Set();
|
|
23464
23731
|
for (const definition of item.IsDefinedBy) {
|
|
23465
23732
|
if (!("value" in definition.Name))
|
|
23466
23733
|
continue;
|
|
@@ -23473,22 +23740,29 @@ class IDSProperty extends IDSFacet {
|
|
|
23473
23740
|
return false;
|
|
23474
23741
|
return set.Name.value === definitionName;
|
|
23475
23742
|
});
|
|
23476
|
-
if (typeSet
|
|
23477
|
-
|
|
23478
|
-
|
|
23479
|
-
|
|
23480
|
-
|
|
23481
|
-
|
|
23482
|
-
|
|
23483
|
-
|
|
23484
|
-
|
|
23485
|
-
|
|
23486
|
-
|
|
23487
|
-
|
|
23743
|
+
if (typeSet) {
|
|
23744
|
+
mergedTypeSets.add(typeSet);
|
|
23745
|
+
if (Array.isArray(typeSet.HasProperties) && Array.isArray(definition.HasProperties)) {
|
|
23746
|
+
for (const prop of typeSet.HasProperties) {
|
|
23747
|
+
if (!("value" in prop.Name))
|
|
23748
|
+
continue;
|
|
23749
|
+
const name = prop.Name.value;
|
|
23750
|
+
const existingProp = definition.HasProperties.find((p) => {
|
|
23751
|
+
if (!("value" in p.Name))
|
|
23752
|
+
return false;
|
|
23753
|
+
return p.Name.value === name;
|
|
23754
|
+
});
|
|
23755
|
+
if (!existingProp)
|
|
23756
|
+
definition.HasProperties.push(prop);
|
|
23757
|
+
}
|
|
23488
23758
|
}
|
|
23489
23759
|
}
|
|
23490
23760
|
sets.push(definition);
|
|
23491
23761
|
}
|
|
23762
|
+
for (const typeSet of typeSets) {
|
|
23763
|
+
if (!mergedTypeSets.has(typeSet))
|
|
23764
|
+
sets.push(typeSet);
|
|
23765
|
+
}
|
|
23492
23766
|
return sets;
|
|
23493
23767
|
}
|
|
23494
23768
|
// IFCPROPERTYBOUNDEDVALUE are not supported yet
|
|
@@ -23510,7 +23784,7 @@ class IDSProperty extends IDSFacet {
|
|
|
23510
23784
|
return false;
|
|
23511
23785
|
}
|
|
23512
23786
|
const facetValue = structuredClone(this.value);
|
|
23513
|
-
if (valueAttr.
|
|
23787
|
+
if (typeof valueAttr.value === "string" && facetValue.type === "simple") {
|
|
23514
23788
|
facetValue.parameter = String(facetValue.parameter);
|
|
23515
23789
|
}
|
|
23516
23790
|
const result = this.evalRequirement(
|
|
@@ -23566,12 +23840,38 @@ class IDSProperty extends IDSFacet {
|
|
|
23566
23840
|
class IDSMaterial extends IDSFacet {
|
|
23567
23841
|
constructor() {
|
|
23568
23842
|
super(...arguments);
|
|
23843
|
+
// Every type IfcRelAssociatesMaterial.RelatingMaterial (IfcMaterialSelect)
|
|
23844
|
+
// can point at. Missing any of them silently drops every element that
|
|
23845
|
+
// associates its material through it: an element can reference a layer set
|
|
23846
|
+
// directly instead of through a layer set usage, and both spellings are
|
|
23847
|
+
// valid IFC.
|
|
23569
23848
|
__publicField(this, "_ifcMaterialEntities", [
|
|
23570
23849
|
/^IFCMATERIALLAYERSETUSAGE$/,
|
|
23850
|
+
/^IFCMATERIALLAYERSET$/,
|
|
23851
|
+
/^IFCMATERIALPROFILESETUSAGE$/,
|
|
23852
|
+
/^IFCMATERIALPROFILESET$/,
|
|
23571
23853
|
/^IFCMATERIALCONSTITUENTSET$/,
|
|
23572
23854
|
/^IFCMATERIAL$/,
|
|
23573
23855
|
/^IFCMATERIALLIST$/
|
|
23574
23856
|
]);
|
|
23857
|
+
// Attributes that lead from a material set / usage down to its IfcMaterial.
|
|
23858
|
+
__publicField(this, "_materialParentAttributes", [
|
|
23859
|
+
"ForLayerSet",
|
|
23860
|
+
"MaterialLayers",
|
|
23861
|
+
"ForProfileSet",
|
|
23862
|
+
"MaterialProfiles",
|
|
23863
|
+
"Material",
|
|
23864
|
+
"MaterialConstituents",
|
|
23865
|
+
"Materials"
|
|
23866
|
+
]);
|
|
23867
|
+
__publicField(this, "_materialRelations", {
|
|
23868
|
+
MaterialConstituents: { attributes: true, relations: true },
|
|
23869
|
+
ForLayerSet: { attributes: true, relations: true },
|
|
23870
|
+
MaterialLayers: { attributes: true, relations: true },
|
|
23871
|
+
ForProfileSet: { attributes: true, relations: true },
|
|
23872
|
+
MaterialProfiles: { attributes: true, relations: true },
|
|
23873
|
+
Materials: { attributes: true, relations: false }
|
|
23874
|
+
});
|
|
23575
23875
|
__publicField(this, "facetType", "Material");
|
|
23576
23876
|
__publicField(this, "value");
|
|
23577
23877
|
__publicField(this, "uri");
|
|
@@ -23603,10 +23903,7 @@ class IDSMaterial extends IDSFacet {
|
|
|
23603
23903
|
const data = await model.getItemsData(localIds, {
|
|
23604
23904
|
relations: {
|
|
23605
23905
|
AssociatedTo: { attributes: true, relations: false },
|
|
23606
|
-
|
|
23607
|
-
ForLayerSet: { attributes: true, relations: true },
|
|
23608
|
-
MaterialLayers: { attributes: true, relations: true },
|
|
23609
|
-
Materials: { attributes: true, relations: false }
|
|
23906
|
+
...this._materialRelations
|
|
23610
23907
|
}
|
|
23611
23908
|
});
|
|
23612
23909
|
for (const item of data) {
|
|
@@ -23635,10 +23932,7 @@ class IDSMaterial extends IDSFacet {
|
|
|
23635
23932
|
relations: {
|
|
23636
23933
|
AssociatedTo: { attributes: false, relations: false },
|
|
23637
23934
|
HasAssociations: { attributes: true, relations: true },
|
|
23638
|
-
|
|
23639
|
-
ForLayerSet: { attributes: true, relations: true },
|
|
23640
|
-
MaterialLayers: { attributes: true, relations: true },
|
|
23641
|
-
Materials: { attributes: true, relations: false }
|
|
23935
|
+
...this._materialRelations
|
|
23642
23936
|
}
|
|
23643
23937
|
});
|
|
23644
23938
|
for (const item of data) {
|
|
@@ -23682,13 +23976,7 @@ class IDSMaterial extends IDSFacet {
|
|
|
23682
23976
|
isValid = true;
|
|
23683
23977
|
} else {
|
|
23684
23978
|
for (const [name, attribute] of Object.entries(item)) {
|
|
23685
|
-
if (!
|
|
23686
|
-
"ForLayerSet",
|
|
23687
|
-
"MaterialLayers",
|
|
23688
|
-
"Material",
|
|
23689
|
-
"MaterialConstituents",
|
|
23690
|
-
"Materials"
|
|
23691
|
-
].includes(name))
|
|
23979
|
+
if (!this._materialParentAttributes.includes(name))
|
|
23692
23980
|
continue;
|
|
23693
23981
|
if (!Array.isArray(attribute))
|
|
23694
23982
|
continue;
|
|
@@ -26695,7 +26983,7 @@ function buildPreviewPositions(kind, points, cursor, style) {
|
|
|
26695
26983
|
for (let i = 0; i < points.length - 1; i++) {
|
|
26696
26984
|
positions.push(
|
|
26697
26985
|
...buildDimensionPositions(
|
|
26698
|
-
{
|
|
26986
|
+
{ pointA: points[i], pointB: points[i + 1], offset },
|
|
26699
26987
|
style
|
|
26700
26988
|
)
|
|
26701
26989
|
);
|