Skip to content

Commit 20c1916

Browse files
authored
Fix(rebar): use shell geometry if rebars are not exported as SweptDiskSolids (#156)
* docs: document ItemDataConfig and full-property examples * fix(rebar): use shell geometry if rebars are not exported as SweptDiskSolids * chore: clean up debug logs * fix: reset attributesToExclude to ensure all attributes are processed * revert: remove attributesToExclude clearing from active PR
1 parent 381eb46 commit 20c1916

File tree

5 files changed

+59
-9
lines changed

5 files changed

+59
-9
lines changed

packages/fragments/src/FragmentsModels/src/multithreading/connection-handlers.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export class ConnectionHandlers {
1313
this._list.set(id, handler);
1414
}
1515

16+
// It resolves the awaited model.threads.fetch(...)
1617
run(data: any) {
1718
const handler = this._list.get(data.requestId) as ThreadHandler;
1819
this._list.delete(data.requestId);

packages/fragments/src/FragmentsModels/src/multithreading/fragments-connection.ts

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,22 @@ export class FragmentsConnection extends Connection {
2929
return response.result;
3030
}
3131

32-
protected override async fetchConnection(input: any) {
32+
protected override async fetchConnection(input: any): Promise<MessagePort> {
3333
const thread = this._data.getAndCheckThread(input.modelId);
3434
if (thread) {
3535
return this._data.getPort(thread);
3636
}
3737
return this.setupNewThread(input);
3838
}
3939

40-
private setupNewThread(input: any) {
40+
/**
41+
* This method either:
42+
* - creates a new worker thread (if CPU cores are available)
43+
* - assigns the task to an existing worker with the lowest load.
44+
* @param input
45+
* @returns
46+
*/
47+
private setupNewThread(input: any): MessagePort {
4148
const helper = MultithreadingHelper;
4249
this._data.usePlaceholder(input.modelId);
4350
const currentThreads = this._data.getThreadAmount();
@@ -47,7 +54,13 @@ export class FragmentsConnection extends Connection {
4754
}
4855
return this._data.balanceThreadLoad(input);
4956
}
50-
57+
/**
58+
* Creates a `MessageChannel` to establish a bidirectional
59+
* communication link between the main thread and the worker.
60+
* - `port1` is kept on the main thread
61+
* - `port2` is transferred to the worker via `postMessage`
62+
* @param newThread
63+
*/
5164
private setupThread(newThread: Thread) {
5265
const threadChannel = new MessageChannel();
5366
const p1 = threadChannel.port1;

packages/fragments/src/FragmentsModels/src/multithreading/fragments-thread.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import { ThreadControllerManager } from "./thread-controllers/thread-controller-
55
export class FragmentsThread {
66
readonly actions: { [index: number]: any } = {};
77
readonly list = new Map<string, VirtualFragmentsModel>();
8+
9+
// It registers all actions from multithreadingRequestClass
810
readonly controllerManager = new ThreadControllerManager(this);
911

1012
private _connection?: Connection;

packages/fragments/src/Importers/IfcImporter/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,7 @@ export class IfcImporter {
9797
...ifcClasses.base,
9898
...ifcClasses.materials,
9999
...ifcClasses.properties,
100-
...ifcClasses.units
100+
...ifcClasses.units,
101101
]),
102102
};
103103

packages/fragments/src/Importers/IfcImporter/src/geometry/ifc-file-reader.ts

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -209,22 +209,30 @@ export class IfcFileReader {
209209
}
210210

211211
for (let i = 0; i < geometryCount; i++) {
212+
let geometryMode: "Shell" | "CircleExtrusion" = "Shell";
213+
212214
if (element.type === WEBIFC.IFCREINFORCINGBAR) {
213-
this.loadCircleExtrusionGeometry(
215+
// Rebars can be SweptDiskSolid, FacetedBrep, Tessellated, ...
216+
// if it doesn't have a directrix, it's not a SweptDiskSolid shape representation
217+
if (this.hasSweptDiskDirectrix(modelID, mesh, i))
218+
geometryMode = "CircleExtrusion";
219+
}
220+
if (geometryMode === "Shell") {
221+
this.loadShellGeometry(
214222
modelID,
215223
element,
216224
mesh,
217225
i,
218226
transformWithoutScale.elements,
227+
currentCategory,
219228
);
220-
} else {
221-
this.loadShellGeometry(
229+
} else if (geometryMode === "CircleExtrusion") {
230+
this.loadCircleExtrusionGeometry(
222231
modelID,
223232
element,
224233
mesh,
225234
i,
226235
transformWithoutScale.elements,
227-
currentCategory,
228236
);
229237
}
230238
}
@@ -314,6 +322,7 @@ export class IfcFileReader {
314322
this._problematicGeometriesHashes.clear();
315323
}
316324

325+
// @ts-ignore
317326
private loadCircleExtrusionGeometry(
318327
modelID: number,
319328
element: IfcElement,
@@ -370,7 +379,6 @@ export class IfcFileReader {
370379

371380
// @ts-ignore
372381
const circleExtrusion = geometry.GetSweptDiskSolid();
373-
374382
const circleCurves: number[][] = [];
375383
const axisPoints: any[][] = [];
376384

@@ -1068,4 +1076,30 @@ export class IfcFileReader {
10681076
angle: (angle * 180) / Math.PI, // Convert to degrees
10691077
};
10701078
}
1079+
1080+
private hasSweptDiskDirectrix(
1081+
modelID: number,
1082+
mesh: any,
1083+
geometryIndex: number,
1084+
): boolean {
1085+
try {
1086+
if (!this._ifcAPI) return false;
1087+
1088+
const geometryRef = mesh.geometries.get(geometryIndex);
1089+
if (!geometryRef) return false;
1090+
1091+
const geometry = this._ifcAPI.GetGeometry(
1092+
modelID,
1093+
geometryRef.geometryExpressID,
1094+
);
1095+
1096+
if (!geometry?.GetSweptDiskSolid) return false;
1097+
1098+
const swept = geometry.GetSweptDiskSolid();
1099+
// @ts-ignore
1100+
return !!swept?.axis && swept.axis.size() > 0;
1101+
} catch {
1102+
return false;
1103+
}
1104+
}
10711105
}

0 commit comments

Comments
 (0)