diff --git a/packages/clay/src/elements/Walls/SimpleWall/example.ts b/packages/clay/src/elements/Walls/SimpleWall/example.ts index e2f2a91..53febea 100644 --- a/packages/clay/src/elements/Walls/SimpleWall/example.ts +++ b/packages/clay/src/elements/Walls/SimpleWall/example.ts @@ -33,6 +33,9 @@ const model = new CLAY.Model(); model.wasm = { path: "https://unpkg.com/web-ifc@0.0.59/", absolute: true }; await model.init(); +const project = new CLAY.Project(model); +const site = new CLAY.Site(model, project); + const simpleWallType = new CLAY.SimpleWallType(model); const wall1 = simpleWallType.addInstance(); @@ -48,6 +51,9 @@ wall2.startPoint = new THREE.Vector2(0, -2); wall2.endPoint = new THREE.Vector2(0, 3); wall2.update(true); +site.children.add(wall1.attributes.expressID); +site.children.add(wall2.attributes.expressID); + simpleWallType.addCorner({ wall1, wall2, @@ -198,23 +204,21 @@ const button = BUI.Component.create(() => { document.body.append(button); -// window.addEventListener("keydown", async (e) => { -// if (e.code === "KeyP") { -// simpleWallType.attributes = {}; -// console.log("hey"); -// if (model._modelID === undefined) { -// throw new Error("Malformed model!"); -// } -// // TODO: Fix memory leak -// const asdf = model._ifcAPI.SaveModel(model._modelID); -// -// model._ifcAPI.Dispose(); -// model._ifcAPI = null as any; -// model._ifcAPI = new WEBIFC.IfcAPI(); -// -// await model.init(); -// model._modelID = model._ifcAPI.OpenModel(asdf, { -// TAPE_SIZE: 5000000, // 5MB -// }); -// } -// }); +window.addEventListener("keydown", async (e) => { + if (e.code === "KeyP") { + simpleWallType.attributes = {}; + console.log("hey"); + if (model._modelID === undefined) { + throw new Error("Malformed model!"); + } + // TODO: Fix memory leak + const asdf = model._ifcAPI.SaveModel(model._modelID); + + const a = document.createElement("a"); + const name = "example.ifc"; + a.href = URL.createObjectURL(new File([asdf], name)); + a.download = name; + a.click(); + a.remove(); + } +}); diff --git a/packages/clay/src/general/ElementChildren/index.ts b/packages/clay/src/general/ElementChildren/index.ts new file mode 100644 index 0000000..85b077f --- /dev/null +++ b/packages/clay/src/general/ElementChildren/index.ts @@ -0,0 +1,51 @@ +import { IFC4X3 as IFC, Handle } from "web-ifc"; +import { v4 as uuidv4 } from "uuid"; +import { ClayObject, Model } from "../../core"; + +export class ElementChildren extends ClayObject { + attributes: IFC.IfcRelContainedInSpatialStructure; + ids = new Set(); + + constructor( + model: Model, + ownerHistory: IFC.IfcOwnerHistory, + element: IFC.IfcSpatialElement, + ) { + super(model); + this.attributes = new IFC.IfcRelContainedInSpatialStructure( + new IFC.IfcGloballyUniqueId(uuidv4()), + ownerHistory, + null, + null, + [], + element, + ); + + this.update(); + } + + add(itemID: number) { + if (this.ids.has(itemID)) { + return; + } + this.attributes.RelatedElements.push(new Handle(itemID)); + this.ids.add(itemID); + this.update(); + } + + remove(itemID: number) { + if (!this.ids.has(itemID)) { + return; + } + const children = this.attributes.RelatedElements as Handle[]; + this.attributes.RelatedElements = children.filter( + (item) => item.value !== itemID, + ); + this.ids.delete(itemID); + this.update(); + } + + update() { + this.model.set(this.attributes); + } +} diff --git a/packages/clay/src/general/Project/index.ts b/packages/clay/src/general/Project/index.ts new file mode 100644 index 0000000..bf336a7 --- /dev/null +++ b/packages/clay/src/general/Project/index.ts @@ -0,0 +1,123 @@ +import { IFC4X3 as IFC } from "web-ifc"; +import { v4 as uuidv4 } from "uuid"; +import * as THREE from "three"; +import { ClayObject, Model } from "../../core"; +import { ClippingPlaneType } from "../../elements"; +import { IfcUtils } from "../../utils/ifc-utils"; +import { SpatialChildren } from "../SpatialChildren"; + +export class Project extends ClayObject { + attributes: IFC.IfcProject; + + ownerHistory: IFC.IfcOwnerHistory; + + spatialChildren: SpatialChildren; + + constructor(model: Model) { + super(model); + + if (!this.model.types.has("clipping-planes")) { + this.model.types.set("clipping-planes", new ClippingPlaneType(model)); + } + + const organization = new IFC.IfcOrganization( + null, + new IFC.IfcLabel("That Open Company"), + null, + null, + null, + ); + + const person = new IFC.IfcPerson( + null, + null, + null, + null, + null, + null, + null, + null, + ); + + const personAndOrganization = new IFC.IfcPersonAndOrganization( + person, + organization, + null, + ); + + const application = new IFC.IfcApplication( + organization, + new IFC.IfcLabel("2.4.0"), + new IFC.IfcLabel("CLAY"), + new IFC.IfcLabel("CLAY"), + ); + + this.ownerHistory = new IFC.IfcOwnerHistory( + personAndOrganization, + application, + null, + IFC.IfcChangeActionEnum.NOTDEFINED, + null, + null, + null, + new IFC.IfcTimeStamp(new Date().getTime()), + ); + + const context = new IFC.IfcGeometricRepresentationContext( + null, + null, + new IFC.IfcDimensionCount(3), + new IFC.IfcReal(1.0e-5), + new IFC.IfcAxis2Placement3D( + IfcUtils.point(new THREE.Vector3()), + null, + null, + ), + null, + ); + + const lengthUnit = new IFC.IfcSIUnit( + IFC.IfcUnitEnum.LENGTHUNIT, + null, + IFC.IfcSIUnitName.METRE, + ); + + const areaUnit = new IFC.IfcSIUnit( + IFC.IfcUnitEnum.AREAUNIT, + null, + IFC.IfcSIUnitName.SQUARE_METRE, + ); + + const volumeUnit = new IFC.IfcSIUnit( + IFC.IfcUnitEnum.AREAUNIT, + null, + IFC.IfcSIUnitName.SQUARE_METRE, + ); + + const units = new IFC.IfcUnitAssignment([lengthUnit, areaUnit, volumeUnit]); + + this.attributes = new IFC.IfcProject( + new IFC.IfcGloballyUniqueId(uuidv4()), + this.ownerHistory, + null, + null, + null, + null, + null, + [context], + units, + ); + + this.model.set(this.attributes); + + this.spatialChildren = new SpatialChildren( + model, + this.ownerHistory, + this.attributes, + ); + } + + update(): void { + this.model.set(this.attributes); + } +} diff --git a/packages/clay/src/general/Site/index.ts b/packages/clay/src/general/Site/index.ts new file mode 100644 index 0000000..622fb01 --- /dev/null +++ b/packages/clay/src/general/Site/index.ts @@ -0,0 +1,56 @@ +import { IFC4X3 as IFC } from "web-ifc"; +import { v4 as uuidv4 } from "uuid"; +import { ClayObject, Model } from "../../core"; +import { SpatialChildren } from "../SpatialChildren"; +import { ElementChildren } from "../ElementChildren"; +import { Project } from "../Project"; +import { IfcUtils } from "../../utils/ifc-utils"; + +export class Site extends ClayObject { + attributes: IFC.IfcSite; + + spatialChildren: SpatialChildren; + + children: ElementChildren; + + constructor(model: Model, project: Project) { + super(model); + + this.attributes = new IFC.IfcSite( + new IFC.IfcGloballyUniqueId(uuidv4()), + project.ownerHistory, + null, + null, + null, + IfcUtils.localPlacement(), + null, + null, + IFC.IfcElementCompositionEnum.ELEMENT, + null, + null, + null, + null, + null, + ); + + this.model.set(this.attributes); + + project.spatialChildren.add(this.attributes.expressID); + + this.spatialChildren = new SpatialChildren( + model, + project.ownerHistory, + this.attributes, + ); + + this.children = new ElementChildren( + model, + project.ownerHistory, + this.attributes, + ); + } + + update(): void { + this.model.set(this.attributes); + } +} diff --git a/packages/clay/src/general/SpatialChildren/index.ts b/packages/clay/src/general/SpatialChildren/index.ts new file mode 100644 index 0000000..b44970c --- /dev/null +++ b/packages/clay/src/general/SpatialChildren/index.ts @@ -0,0 +1,51 @@ +import { IFC4X3 as IFC, Handle } from "web-ifc"; +import { v4 as uuidv4 } from "uuid"; +import { ClayObject, Model } from "../../core"; + +export class SpatialChildren extends ClayObject { + attributes: IFC.IfcRelAggregates; + ids = new Set(); + + constructor( + model: Model, + ownerHistory: IFC.IfcOwnerHistory, + element: IFC.IfcObjectDefinition, + ) { + super(model); + this.attributes = new IFC.IfcRelAggregates( + new IFC.IfcGloballyUniqueId(uuidv4()), + ownerHistory, + null, + null, + element, + [], + ); + + this.update(); + } + + add(itemID: number) { + if (this.ids.has(itemID)) { + return; + } + this.attributes.RelatedObjects.push(new Handle(itemID)); + this.ids.add(itemID); + this.update(); + } + + remove(itemID: number) { + if (!this.ids.has(itemID)) { + return; + } + const children = this.attributes.RelatedObjects as Handle[]; + this.attributes.RelatedObjects = children.filter( + (item) => item.value !== itemID, + ); + this.ids.delete(itemID); + this.update(); + } + + update() { + this.model.set(this.attributes); + } +} diff --git a/packages/clay/src/general/index.ts b/packages/clay/src/general/index.ts new file mode 100644 index 0000000..03136a8 --- /dev/null +++ b/packages/clay/src/general/index.ts @@ -0,0 +1,4 @@ +export * from "./Project"; +export * from "./Site"; +export * from "./SpatialChildren"; +export * from "./ElementChildren"; diff --git a/packages/clay/src/index.ts b/packages/clay/src/index.ts index 642eda1..b8ccab6 100644 --- a/packages/clay/src/index.ts +++ b/packages/clay/src/index.ts @@ -1,5 +1,6 @@ export * from "./primitives"; export * from "./elements"; +export * from "./general"; export * from "./utils"; export * from "./elements"; export * from "./geometries";