Skip to content

Commit

Permalink
feat: define boolean operations at the element level
Browse files Browse the repository at this point in the history
  • Loading branch information
agviegas committed Mar 3, 2024
1 parent 4d23558 commit b9f3d56
Show file tree
Hide file tree
Showing 16 changed files with 473 additions and 429 deletions.
316 changes: 160 additions & 156 deletions resources/openbim-clay.js

Large diffs are not rendered by default.

59 changes: 59 additions & 0 deletions src/base/clay-object.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import * as WEBIFC from "web-ifc";
import * as THREE from "three";
import { Model } from "./model";

export abstract class ClayObject {
Expand All @@ -11,4 +12,62 @@ export abstract class ClayObject {
protected constructor(model: Model) {
this.model = model;
}

setMesh(id: number, mesh: THREE.Mesh) {
const modelID = this.model.modelID;
this.model.ifcAPI.StreamMeshes(modelID, [id], (ifcMesh) => {
mesh.geometry.dispose();
const { geometryExpressID, flatTransformation } =
ifcMesh.geometries.get(0);
const data = this.model.ifcAPI.GetGeometry(modelID, geometryExpressID);
mesh.geometry = this.ifcToThreeGeometry(data);
const matrix = new THREE.Matrix4().fromArray(flatTransformation);
mesh.position.set(0, 0, 0);
mesh.rotation.set(0, 0, 0);
mesh.scale.set(1, 1, 1);
mesh.updateMatrix();
mesh.applyMatrix4(matrix);
});
}

newThreeMesh() {
const geometry = new THREE.BufferGeometry();
const mesh = new THREE.InstancedMesh(geometry, this.model.material, 1);
mesh.frustumCulled = false;
const identity = new THREE.Matrix4().identity();
mesh.setMatrixAt(0, identity);
mesh.instanceMatrix.needsUpdate = true;
return mesh;
}

private ifcToThreeGeometry(data: WEBIFC.IfcGeometry) {
const index = this.model.ifcAPI.GetIndexArray(
data.GetIndexData(),
data.GetIndexDataSize()
);

const vertexData = this.model.ifcAPI.GetVertexArray(
data.GetVertexData(),
data.GetVertexDataSize()
);

const position = new Float32Array(vertexData.length / 2);
const normal = new Float32Array(vertexData.length / 2);

for (let i = 0; i < vertexData.length; i += 6) {
position[i / 2] = vertexData[i];
position[i / 2 + 1] = vertexData[i + 1];
position[i / 2 + 2] = vertexData[i + 2];

normal[i / 2] = vertexData[i + 3];
normal[i / 2 + 1] = vertexData[i + 4];
normal[i / 2 + 2] = vertexData[i + 5];
}

const geometry = new THREE.BufferGeometry();
geometry.setAttribute("position", new THREE.BufferAttribute(position, 3));
geometry.setAttribute("normal", new THREE.BufferAttribute(normal, 3));
geometry.setIndex(Array.from(index));
return geometry;
}
}
45 changes: 0 additions & 45 deletions src/base/ifc-getter.ts

This file was deleted.

10 changes: 10 additions & 0 deletions src/base/model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,14 @@ export class Model {
}
return item;
}

update() {
if (this._modelID === undefined) {
throw new Error("Malformed model!");
}
const model = this.ifcAPI.SaveModel(this._modelID);
this.ifcAPI.CloseModel(this._modelID);
this._modelID++;
this.ifcAPI.OpenModel(model);
}
}
66 changes: 64 additions & 2 deletions src/families/Family/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,70 @@
import * as THREE from "three";
import { ClayObject } from "../../base";
import { v4 as uuidv4 } from "uuid";
import { IFC4X3 as IFC } from "web-ifc";
import { ClayObject, Model } from "../../base";
import { Opening } from "../Opening";
import { IfcUtils } from "../../utils/ifc-utils";

export abstract class Family extends ClayObject {
abstract ifcData: IFC.IfcElement;
abstract geometries: { [name: string]: ClayObject };

abstract get mesh(): THREE.InstancedMesh;
mesh: THREE.InstancedMesh;

position = new THREE.Vector3();

rotation = new THREE.Euler();

openings = new Map<number, IFC.IfcRelVoidsElement>();

constructor(model: Model) {
super(model);
this.mesh = this.newThreeMesh();
}

addOpening(opening: Opening) {
const voids = new IFC.IfcRelVoidsElement(
new IFC.IfcGloballyUniqueId(uuidv4()),
null,
null,
null,
this.ifcData,
opening.ifcData
);

this.model.set(voids);

const id = opening.ifcData.expressID;
this.openings.set(id, voids);

this.model.update();
}

removeOpening(opening: Opening) {
const id = opening.ifcData.expressID;
const found = this.openings.get(id);
if (!found) return;
this.model.delete(found);
this.model.update();
}

updateElement() {
const placement = this.model.get(
this.ifcData.ObjectPlacement
) as IFC.IfcLocalPlacement;

const relPlacement = this.model.get(
placement.RelativePlacement
) as IFC.IfcAxis2Placement3D;

IfcUtils.setAxis2Placement(
this.model,
relPlacement,
this.position,
this.rotation
);

this.model.set(this.ifcData);
this.setMesh(this.ifcData.expressID, this.mesh);
}
}
12 changes: 4 additions & 8 deletions src/families/Furniture/SimpleFurniture/index.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,26 @@
import { IFC4X3 as IFC } from "web-ifc";
import * as THREE from "three";
import { v4 as uuidv4 } from "uuid";
import { InstancedMesh } from "three";
import { Model } from "../../../base";
import { Family } from "../../Family";
import { Brep } from "../../../geometries";
import { IfcGetter } from "../../../base/ifc-getter";
import { IfcUtils } from "../../../utils/ifc-utils";

export class Furniture extends Family {
ifcData: IFC.IfcFurnishingElement;

geometries: { body: Brep };

get mesh(): InstancedMesh {
return this.geometries.body.mesh;
}

constructor(model: Model, geometry: THREE.BufferGeometry) {
super(model);

this.geometries = { body: new Brep(model, geometry) };

const { body } = this.geometries;

const representation = IfcGetter.shapeRepresentation(this.model);
const representation = IfcUtils.shapeRepresentation(this.model);
representation.Items = [body.ifcData];
const placement = IfcGetter.localPlacement();
const placement = IfcUtils.localPlacement();
const shape = new IFC.IfcProductDefinitionShape(null, null, [
representation,
]);
Expand All @@ -49,5 +44,6 @@ export class Furniture extends Family {
update(): void {
const { body } = this.geometries;
body.update();
this.updateElement();
}
}
45 changes: 5 additions & 40 deletions src/families/Opening/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,13 @@ import { v4 as uuidv4 } from "uuid";
import { Model } from "../../base";
import { Extrusion, RectangleProfile } from "../../geometries";
import { Family } from "../Family";
import { IfcGetter } from "../../base/ifc-getter";
import { IfcUtils } from "../../utils/ifc-utils";

export class Opening extends Family {
ifcData: IFC.IfcOpeningElement;

geometries: { body: Extrusion<RectangleProfile> };

get mesh() {
return this.geometries.body.mesh;
}

get position() {
return this.geometries.body.position;
}

set position(value: THREE.Vector3) {
this.geometries.body.position = value;
}

get baseDimension() {
return this.geometries.body.profile.dimension;
}
Expand All @@ -31,30 +19,6 @@ export class Opening extends Family {
this.geometries.body.profile.dimension = value;
}

get xDirection() {
return this.geometries.body.xDirection;
}

set xDirection(value: THREE.Vector3) {
this.geometries.body.xDirection = value;
}

get zDirection() {
return this.geometries.body.zDirection;
}

set zDirection(value: THREE.Vector3) {
this.geometries.body.zDirection = value;
}

get zRotation() {
return this.geometries.body.zRotation;
}

set zRotation(value: number) {
this.geometries.body.zRotation = value;
}

get direction() {
return this.geometries.body.direction;
}
Expand All @@ -78,11 +42,11 @@ export class Opening extends Family {
this.geometries = { body: new Extrusion(model, profile) };

const { body } = this.geometries;
body.mesh.material = model.materialT;
this.mesh.material = model.materialT;

const representation = IfcGetter.shapeRepresentation(this.model);
const representation = IfcUtils.shapeRepresentation(this.model);
representation.Items = [body.ifcData];
const placement = IfcGetter.localPlacement();
const placement = IfcUtils.localPlacement();
const shape = new IFC.IfcProductDefinitionShape(null, null, [
representation,
]);
Expand All @@ -108,5 +72,6 @@ export class Opening extends Family {
const { body } = this.geometries;
body.profile.update();
body.update();
this.updateElement();
}
}
11 changes: 4 additions & 7 deletions src/families/Slabs/SimpleSlab/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { IFC4X3 as IFC } from "web-ifc";
import { Model } from "../../../base";
import { Family } from "../../Family";
import { Extrusion, RectangleProfile } from "../../../geometries";
import { IfcGetter } from "../../../base/ifc-getter";
import { IfcUtils } from "../../../utils/ifc-utils";

export class SimpleSlab extends Family {
ifcData: IFC.IfcSlab;
Expand All @@ -18,10 +18,6 @@ export class SimpleSlab extends Family {
this.geometries.body.depth = value;
}

get mesh() {
return this.geometries.body.mesh;
}

constructor(model: Model) {
super(model);

Expand All @@ -33,9 +29,9 @@ export class SimpleSlab extends Family {
body.profile.dimension.x = 5;
body.profile.dimension.y = 10;

const representation = IfcGetter.shapeRepresentation(this.model);
const representation = IfcUtils.shapeRepresentation(this.model);
representation.Items = [body.ifcData];
const placement = IfcGetter.localPlacement();
const placement = IfcUtils.localPlacement();
const shape = new IFC.IfcProductDefinitionShape(null, null, [
representation,
]);
Expand All @@ -61,5 +57,6 @@ export class SimpleSlab extends Family {
const { body } = this.geometries;
body.profile.update();
body.update();
this.updateElement();
}
}
Loading

0 comments on commit b9f3d56

Please sign in to comment.