Skip to content

Commit 88cd07b

Browse files
committed
feat: implement fragment cloning
1 parent 88be54b commit 88cd07b

File tree

4 files changed

+132
-1
lines changed

4 files changed

+132
-1
lines changed

packages/fragments/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "@thatopen/fragments",
33
"description": "Simple geometric system built on top of Three.js to display 3D BIM data efficiently.",
4-
"version": "2.1.5",
4+
"version": "2.1.6",
55
"author": "That Open Company",
66
"contributors": [
77
"Antonio Gonzalez Viegas (https://github.com/agviegas)",

packages/fragments/src/fragment-mesh.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,10 @@ export class FragmentMesh extends THREE.InstancedMesh {
118118
colors,
119119
};
120120
}
121+
122+
clone(_recursive?: boolean): any {
123+
throw new Error(
124+
"Fragment meshes can't be cloned directly. Use mesh.fragment.clone instead!",
125+
);
126+
}
121127
}

packages/fragments/src/fragment.ts

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,51 @@ export class Fragment {
546546
return { ...geometry, ids, id };
547547
}
548548

549+
/**
550+
* Creates a copy of the whole fragment or a part of it. It shares the geometry with the original fragment, but has its own InstancedMesh data, so it also needs to be disposed.
551+
*
552+
* @param itemIDs - An iterable of item IDs to be included in the clone.
553+
*
554+
*/
555+
clone(itemIDs: Iterable<number> = this.ids) {
556+
const newFragment = new Fragment(
557+
this.mesh.geometry,
558+
this.mesh.material,
559+
this.capacity,
560+
);
561+
562+
const items: Item[] = [];
563+
564+
for (const id of itemIDs) {
565+
const instancesIDs = this.getInstancesIDs(id);
566+
if (instancesIDs === null) {
567+
continue;
568+
}
569+
570+
const transforms: THREE.Matrix4[] = [];
571+
const colors: THREE.Color[] = [];
572+
573+
for (const instanceID of instancesIDs) {
574+
const newMatrix = new THREE.Matrix4();
575+
const newColor = new THREE.Color();
576+
this.mesh.getMatrixAt(instanceID, newMatrix);
577+
this.mesh.getColorAt(instanceID, newColor);
578+
transforms.push(newMatrix);
579+
colors.push(newColor);
580+
}
581+
582+
items.push({
583+
id,
584+
transforms,
585+
colors,
586+
});
587+
}
588+
589+
newFragment.add(items);
590+
591+
return newFragment;
592+
}
593+
549594
private putLast(instanceID1: number) {
550595
if (this.mesh.count === 0) return;
551596

packages/fragments/src/fragments-group.ts

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -404,6 +404,86 @@ export class FragmentsGroup extends THREE.Group {
404404
return result;
405405
}
406406

407+
clone(_recursive?: boolean): any {
408+
throw new Error("Use FragmentsGroup.cloneGroup instead!");
409+
}
410+
411+
/**
412+
* Creates a copy of the whole group or a part of it. Each fragment clone shares the geometry of with its respective original fragment, but has its own InstancedMesh data, so it also needs to be disposed.
413+
*
414+
* @param items - Optional - The part of the group to be cloned. If not given, the whole group is cloned.
415+
*
416+
*/
417+
cloneGroup(items?: FragmentIdMap) {
418+
const newGroup = new FragmentsGroup();
419+
420+
newGroup.coordinationMatrix = this.coordinationMatrix;
421+
newGroup.position.copy(this.position);
422+
newGroup.rotation.copy(this.rotation);
423+
newGroup.scale.copy(this.scale);
424+
newGroup.updateMatrix();
425+
426+
newGroup.ifcMetadata = { ...this.ifcMetadata };
427+
428+
if (!items) {
429+
items = this.getFragmentMap(this.data.keys());
430+
}
431+
432+
const allIDs = new Set<number>();
433+
434+
const fragmentIDConversion = new Map<string, string>();
435+
436+
for (const fragment of this.items) {
437+
if (!items[fragment.id]) {
438+
continue;
439+
}
440+
441+
const ids = items[fragment.id];
442+
const newFragment = fragment.clone(ids);
443+
444+
fragmentIDConversion.set(fragment.id, newFragment.id);
445+
446+
newGroup.items.push(newFragment);
447+
newGroup.add(newFragment.mesh);
448+
449+
for (const expressID of ids) {
450+
allIDs.add(expressID);
451+
}
452+
}
453+
454+
for (const id of allIDs) {
455+
const data = this.data.get(id);
456+
if (data) {
457+
newGroup.data.set(id, data);
458+
}
459+
}
460+
461+
for (const [fragKey, fragID] of this.keyFragments) {
462+
if (fragmentIDConversion.has(fragID)) {
463+
const newID = fragmentIDConversion.get(fragID);
464+
if (newID === undefined) {
465+
throw new Error("Malformed fragment ID map during clone!");
466+
}
467+
newGroup.keyFragments.set(fragKey, newID);
468+
}
469+
}
470+
471+
for (const [globalID, expressID] of this.globalToExpressIDs) {
472+
if (allIDs.has(expressID)) {
473+
newGroup.globalToExpressIDs.set(globalID, expressID);
474+
}
475+
}
476+
477+
if (this.civilData) {
478+
newGroup.civilData = {
479+
coordinationMatrix: this.coordinationMatrix,
480+
alignments: new Map(),
481+
};
482+
}
483+
484+
return newGroup as this;
485+
}
486+
407487
private getPropsURL(id: number) {
408488
const { ids } = this.streamSettings;
409489
const fileID = ids.get(id);

0 commit comments

Comments
 (0)