Last active
May 16, 2025 09:29
-
-
Save arcs-/9e98886f56385cfa78d09f8c35e8edde to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { IFC4, IfcAPI, IfcLineObject, Schemas } from 'web-ifc' | |
const ID_CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_$' | |
/** | |
* This library creates an object and context to work with web-ifc | |
* as web-ifc is provides simply types and a way to write to files | |
*/ | |
export class EasyIfc { | |
public ctx: IfcAPI | |
public modelID: number | |
public unit: IFC4.IfcUnitAssignment | |
public wcs: IFC4.IfcAxis2Placement3D | |
/** | |
* Creates a new EasyIfc Object, used for creating IFC files. | |
* Used internally by the EasyIfc class. Use EasyIfc.create() to create a new EasyIfc Object. | |
* @param _ctx an IfcAPI object | |
* @param name the name of the model | |
*/ | |
private constructor(_ctx: IfcAPI, name: string) { | |
this.ctx = _ctx | |
this.modelID = this.ctx.CreateModel({ | |
schema: Schemas.IFC4, | |
name, | |
authors: ['Patrick Stillhart'], | |
}) | |
const metric = this.setupMetric() | |
this.unit = metric[0] | |
this.wcs = metric[1] | |
} | |
/** | |
* Creates a new ifc object builder | |
* @param name the name of the model | |
* @returns a new EasyIfc Object | |
*/ | |
static async create(name: string) { | |
const ctx = new IfcAPI() | |
await ctx.Init() | |
return new EasyIfc(ctx, name) | |
} | |
/** | |
* Generates IFC compliant ids | |
* specification: https://standards.buildingsmart.org/IFC/RELEASE/IFC2x3/TC1/HTML/ifcutilityresource/lexical/ifcgloballyuniqueid.htm | |
* implemenation based on: https://github.com/IfcOpenShell/IfcOpenShell/blob/master/src/ifcopenshell-python/ifcopenshell/guid.py | |
* @returns an IFCGloballyUniqueId | |
*/ | |
static guid() { | |
const g = crypto.randomUUID().replace(/-/g, '') | |
const bs: number[] = [] | |
for (let i = 0; i < g.length; i += 2) { | |
bs.push(parseInt(g.slice(i, i + 2), 16)) | |
} | |
const b64 = (v: number, l = 4) => (Array.from({ length: l }) | |
.map((_, i) => ID_CHARS[Math.floor(v / (64 ** i)) % 64]) | |
.reverse() | |
.join("") | |
) | |
const newId = [ | |
b64(bs[0], 2), | |
...Array | |
.from({ length: Math.floor((bs.length - 1) / 3) }) | |
.map((_, i) => b64((bs[i * 3 + 1] << 16) + (bs[i * 3 + 2] << 8) + bs[i * 3 + 3])) | |
].join("") | |
return new IFC4.IfcGloballyUniqueId(newId) | |
} | |
/** | |
* Sets the context up for the metric unit system | |
* @returns a tuple of the unit assignment and the axis2placement3d | |
*/ | |
setupMetric(): [IFC4.IfcUnitAssignment, IFC4.IfcAxis2Placement3D] { | |
const unit = this.add(new IFC4.IfcUnitAssignment([ | |
new IFC4.IfcSIUnit(IFC4.IfcUnitEnum.LENGTHUNIT, IFC4.IfcSIPrefix.MILLI, IFC4.IfcSIUnitName.METRE), | |
new IFC4.IfcSIUnit(IFC4.IfcUnitEnum.AREAUNIT, null, IFC4.IfcSIUnitName.SQUARE_METRE), | |
new IFC4.IfcSIUnit(IFC4.IfcUnitEnum.VOLUMEUNIT, null, IFC4.IfcSIUnitName.CUBIC_METRE) | |
])) | |
const cartPoint = this.add(new IFC4.IfcCartesianPoint([ | |
new IFC4.IfcLengthMeasure(0), | |
new IFC4.IfcLengthMeasure(0), | |
new IFC4.IfcLengthMeasure(0), | |
])) | |
const axis = this.add(new IFC4.IfcDirection([ | |
new IFC4.IfcLengthMeasure(0), | |
new IFC4.IfcLengthMeasure(0), | |
])) | |
const dir = this.add(new IFC4.IfcDirection([ | |
new IFC4.IfcLengthMeasure(1), | |
new IFC4.IfcLengthMeasure(0), | |
])) | |
const wcs = this.add(new IFC4.IfcAxis2Placement3D( | |
cartPoint, | |
axis, | |
dir | |
)) | |
return [unit, wcs] | |
} | |
/** | |
* Adds an object to the context | |
* @param object the object to add | |
* @returns the object | |
*/ | |
add<T extends IfcLineObject>(object: T) { | |
this.ctx.WriteLine(this.modelID, object) | |
return object | |
} | |
/** | |
* Compiles the context | |
* @returns the compiled context | |
*/ | |
compile() { | |
return this.ctx.SaveModel(this.modelID) | |
} | |
/** | |
* Adds a 3D context | |
* @returns the 3D context | |
*/ | |
add3dContext() { | |
return this.add(new IFC4.IfcGeometricRepresentationContext( | |
new IFC4.IfcLabel('3D'), | |
new IFC4.IfcLabel('Model'), | |
new IFC4.IfcDimensionCount(3), | |
new IFC4.IfcReal(1.E-05), | |
this.wcs, | |
null, | |
)) | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
export function createWorldScaffolding(easyIfc: EasyIfc, visualContext: IFC4.IfcGeometricRepresentationContext) { | |
const project = easyIfc.add(new IFC4.IfcProject( | |
EasyIfc.guid(), | |
null, | |
new IFC4.IfcLabel('Kabelschacht'), | |
null, | |
null, | |
null, | |
null, | |
[visualContext], | |
easyIfc.unit | |
)) | |
// ifc structure | |
const site = easyIfc.add(new IFC4.IfcSite( | |
EasyIfc.guid(), | |
null, | |
new IFC4.IfcLabel('Baustelle'), | |
new IFC4.IfcText(''), | |
null, | |
null, | |
null, | |
null, | |
null, | |
null, | |
null, | |
null, | |
null, | |
null | |
)) | |
easyIfc.add(new IFC4.IfcRelAggregates( | |
EasyIfc.guid(), | |
null, | |
null, | |
null, | |
project, | |
[site] | |
)) | |
// in most examples i've seen there is also a building and a building storey | |
// however, it doesn't seem to be necessary for a kabelschacht | |
/* | |
const building = easyIfc.add(new IFC4.IfcBuilding( | |
EasyIfc.guid(), | |
null, | |
new IFC4.IfcLabel('Gebaeude'), | |
new IFC4.IfcText(''), | |
null, | |
null, null, null, null, null, null, null | |
)) | |
easyIfc.add(new IFC4.IfcRelAggregates( | |
EasyIfc.guid(), | |
null, | |
null, | |
null, | |
site, | |
[building] | |
)) | |
const buildingStorey = easyIfc.add(new IFC4.IfcBuildingStorey( | |
EasyIfc.guid(), | |
null, | |
new IFC4.IfcLabel('Erdgeschoss'), | |
new IFC4.IfcText('Datum'), | |
null, | |
null, null, null, null, | |
new IFC4.IfcPositiveLengthMeasure(0) | |
)) | |
easyIfc.add(new IFC4.IfcRelAggregates( | |
EasyIfc.guid(), | |
null, | |
null, | |
null, | |
building, | |
[buildingStorey] | |
)) | |
*/ | |
return { | |
project, | |
site, | |
// building, | |
// buildingStorey | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment