Skip to content

Commit

Permalink
feat: implement fragment cloning
Browse files Browse the repository at this point in the history
  • Loading branch information
agviegas committed Jul 31, 2024
1 parent 88be54b commit 88cd07b
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 1 deletion.
2 changes: 1 addition & 1 deletion packages/fragments/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@thatopen/fragments",
"description": "Simple geometric system built on top of Three.js to display 3D BIM data efficiently.",
"version": "2.1.5",
"version": "2.1.6",
"author": "That Open Company",
"contributors": [
"Antonio Gonzalez Viegas (https://github.com/agviegas)",
Expand Down
6 changes: 6 additions & 0 deletions packages/fragments/src/fragment-mesh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,4 +118,10 @@ export class FragmentMesh extends THREE.InstancedMesh {
colors,
};
}

clone(_recursive?: boolean): any {
throw new Error(
"Fragment meshes can't be cloned directly. Use mesh.fragment.clone instead!",
);
}
}
45 changes: 45 additions & 0 deletions packages/fragments/src/fragment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -546,6 +546,51 @@ export class Fragment {
return { ...geometry, ids, id };
}

/**
* 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.
*
* @param itemIDs - An iterable of item IDs to be included in the clone.
*
*/
clone(itemIDs: Iterable<number> = this.ids) {
const newFragment = new Fragment(
this.mesh.geometry,
this.mesh.material,
this.capacity,
);

const items: Item[] = [];

for (const id of itemIDs) {
const instancesIDs = this.getInstancesIDs(id);
if (instancesIDs === null) {
continue;
}

const transforms: THREE.Matrix4[] = [];
const colors: THREE.Color[] = [];

for (const instanceID of instancesIDs) {
const newMatrix = new THREE.Matrix4();
const newColor = new THREE.Color();
this.mesh.getMatrixAt(instanceID, newMatrix);
this.mesh.getColorAt(instanceID, newColor);
transforms.push(newMatrix);
colors.push(newColor);
}

items.push({
id,
transforms,
colors,
});
}

newFragment.add(items);

return newFragment;
}

private putLast(instanceID1: number) {
if (this.mesh.count === 0) return;

Expand Down
80 changes: 80 additions & 0 deletions packages/fragments/src/fragments-group.ts
Original file line number Diff line number Diff line change
Expand Up @@ -404,6 +404,86 @@ export class FragmentsGroup extends THREE.Group {
return result;
}

clone(_recursive?: boolean): any {
throw new Error("Use FragmentsGroup.cloneGroup instead!");
}

/**
* 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.
*
* @param items - Optional - The part of the group to be cloned. If not given, the whole group is cloned.
*
*/
cloneGroup(items?: FragmentIdMap) {
const newGroup = new FragmentsGroup();

newGroup.coordinationMatrix = this.coordinationMatrix;
newGroup.position.copy(this.position);
newGroup.rotation.copy(this.rotation);
newGroup.scale.copy(this.scale);
newGroup.updateMatrix();

newGroup.ifcMetadata = { ...this.ifcMetadata };

if (!items) {
items = this.getFragmentMap(this.data.keys());
}

const allIDs = new Set<number>();

const fragmentIDConversion = new Map<string, string>();

for (const fragment of this.items) {
if (!items[fragment.id]) {
continue;
}

const ids = items[fragment.id];
const newFragment = fragment.clone(ids);

fragmentIDConversion.set(fragment.id, newFragment.id);

newGroup.items.push(newFragment);
newGroup.add(newFragment.mesh);

for (const expressID of ids) {
allIDs.add(expressID);
}
}

for (const id of allIDs) {
const data = this.data.get(id);
if (data) {
newGroup.data.set(id, data);
}
}

for (const [fragKey, fragID] of this.keyFragments) {
if (fragmentIDConversion.has(fragID)) {
const newID = fragmentIDConversion.get(fragID);
if (newID === undefined) {
throw new Error("Malformed fragment ID map during clone!");
}
newGroup.keyFragments.set(fragKey, newID);
}
}

for (const [globalID, expressID] of this.globalToExpressIDs) {
if (allIDs.has(expressID)) {
newGroup.globalToExpressIDs.set(globalID, expressID);
}
}

if (this.civilData) {
newGroup.civilData = {
coordinationMatrix: this.coordinationMatrix,
alignments: new Map(),
};
}

return newGroup as this;
}

private getPropsURL(id: number) {
const { ids } = this.streamSettings;
const fileID = ids.get(id);
Expand Down

0 comments on commit 88cd07b

Please sign in to comment.