-
Notifications
You must be signed in to change notification settings - Fork 1
Tutorials
Step-by-step walkthroughs for common tasks with Ifc-Factory.
Goal: Read an IFC file and extract a summary of all building elements with their properties.
import { IfcModel, getPropertySets } from '@ifc-factory/core';
import { readFileSync, writeFileSync } from 'node:fs';
const source = readFileSync('building.ifc', 'utf-8');
const model = IfcModel.fromStep(source);
// Define the element types we're interested in
const elementTypes = [
'IfcWall', 'IfcDoor', 'IfcWindow', 'IfcSlab',
'IfcColumn', 'IfcBeam', 'IfcStair', 'IfcRoof',
];
const report: string[] = [];
report.push('# Building Element Report');
report.push(`Project: ${model.project?.Name ?? 'Unknown'}`);
report.push(`Total entities: ${model.size}`);
report.push('');
for (const typeName of elementTypes) {
const elements = model.getAllOfType(typeName);
if (elements.length === 0) continue;
report.push(`## ${typeName} (${elements.length})`);
report.push('');
for (const element of elements) {
report.push(`### ${element.Name ?? '(unnamed)'} [#${element.expressID}]`);
report.push(`- GlobalId: ${element.GlobalId}`);
report.push(`- Description: ${element.Description ?? '—'}`);
// Get property sets
const psets = getPropertySets(model, element.expressID);
if (psets.length > 0) {
report.push('- Property Sets:');
for (const pset of psets) {
report.push(` - **${pset.Name}**`);
const propIds = pset.HasProperties as number[] | undefined;
if (propIds) {
for (const propId of propIds) {
const prop = model.get(propId);
if (prop) {
report.push(` - ${prop.Name}: ${prop.NominalValue ?? '—'}`);
}
}
}
}
}
report.push('');
}
}
writeFileSync('report.md', report.join('\n'));
console.log('Report written to report.md');Goal: Create a model from scratch with spatial structure, elements, and rich property data.
import {
IfcModel,
createSpatialStructure,
createPropertySet,
createQuantitySet,
assignPropertySet,
generateIfcGuid,
} from '@ifc-factory/core';
import { writeFileSync } from 'node:fs';
const model = new IfcModel();
// Step 1: Create spatial hierarchy
const { project, site, building, storeys } = createSpatialStructure(model, {
projectName: 'Kantoorgebouw De Toren',
siteName: 'Locatie Zuidas',
buildingName: 'Toren A',
storeyNames: ['Kelder', 'Begane grond', 'Verdieping 1', 'Verdieping 2'],
});
// Step 2: Create walls for the ground floor
const wallConfigs = [
{ name: 'Buitenwand Noord', external: true, bearing: true },
{ name: 'Buitenwand Zuid', external: true, bearing: true },
{ name: 'Buitenwand Oost', external: true, bearing: false },
{ name: 'Buitenwand West', external: true, bearing: false },
{ name: 'Binnenwand 1', external: false, bearing: false },
{ name: 'Binnenwand 2', external: false, bearing: false },
];
const wallIds: number[] = [];
for (const config of wallConfigs) {
const wall = model.create('IfcWall', {
GlobalId: generateIfcGuid(),
Name: config.name,
PredefinedType: config.external ? 'SOLIDWALL' : 'PARTITIONING',
});
wallIds.push(wall.expressID);
// Place in ground floor
model.containInSpatialStructure(storeys[1].expressID, wall.expressID);
// Add common properties
const pset = createPropertySet(model, 'Pset_WallCommon', [
{ name: 'IsExternal', value: config.external },
{ name: 'LoadBearing', value: config.bearing },
{ name: 'FireRating', value: config.external ? 'REI90' : 'EI30' },
{ name: 'ThermalTransmittance', value: config.external ? 0.18 : 0.0, type: 'IFCREAL' },
]);
assignPropertySet(model, pset.expressID, [wall.expressID]);
}
// Step 3: Create doors
const door = model.create('IfcDoor', {
GlobalId: generateIfcGuid(),
Name: 'Hoofdingang',
OverallHeight: 2.4,
OverallWidth: 1.2,
PredefinedType: 'DOOR',
});
model.containInSpatialStructure(storeys[1].expressID, door.expressID);
const doorPset = createPropertySet(model, 'Pset_DoorCommon', [
{ name: 'IsExternal', value: true },
{ name: 'FireRating', value: 'EI30' },
{ name: 'SecurityRating', value: 'RC3' },
{ name: 'AcousticRating', value: '42 dB' },
]);
assignPropertySet(model, doorPset.expressID, [door.expressID]);
// Step 4: Create windows
const window = model.create('IfcWindow', {
GlobalId: generateIfcGuid(),
Name: 'Panoraamraam Zuid',
OverallHeight: 1.8,
OverallWidth: 2.4,
PredefinedType: 'WINDOW',
});
model.containInSpatialStructure(storeys[1].expressID, window.expressID);
// Step 5: Add quantity sets
const qset = createQuantitySet(model, 'Qto_WallBaseQuantities', [
{ name: 'Length', value: 12.0, quantityType: 'LENGTH' },
{ name: 'Height', value: 3.0, quantityType: 'LENGTH' },
{ name: 'Width', value: 0.3, quantityType: 'LENGTH' },
{ name: 'GrossArea', value: 36.0, quantityType: 'AREA' },
{ name: 'NetArea', value: 32.4, quantityType: 'AREA' },
{ name: 'GrossVolume', value: 10.8, quantityType: 'VOLUME' },
{ name: 'NetVolume', value: 9.72, quantityType: 'VOLUME' },
]);
assignPropertySet(model, qset.expressID, [wallIds[0]]);
// Step 6: Write the model
const output = model.toStep();
writeFileSync('kantoorgebouw.ifc', output);
console.log(`Model created with ${model.size} entities`);Goal: Load two versions of a model and find what changed.
import { IfcModel } from '@ifc-factory/core';
import { diffModels } from '@ifc-factory/ifc-utils';
import { readFileSync } from 'node:fs';
const sourceA = readFileSync('model_v1.ifc', 'utf-8');
const sourceB = readFileSync('model_v2.ifc', 'utf-8');
const modelA = IfcModel.fromStep(sourceA);
const modelB = IfcModel.fromStep(sourceB);
const diff = diffModels(modelA, modelB);
console.log('=== Model Comparison ===');
console.log(`Model A: ${modelA.size} entities`);
console.log(`Model B: ${modelB.size} entities`);
console.log('');
// Added entities
if (diff.added.length > 0) {
console.log(`Added (${diff.added.length}):`);
for (const id of diff.added) {
const entity = modelB.get(id);
console.log(` + #${id} ${entity?.type} "${entity?.Name ?? ''}"`)
}
}
// Removed entities
if (diff.removed.length > 0) {
console.log(`\nRemoved (${diff.removed.length}):`);
for (const id of diff.removed) {
const entity = modelA.get(id);
console.log(` - #${id} ${entity?.type} "${entity?.Name ?? ''}"`)
}
}
// Modified entities
if (diff.modified.length > 0) {
console.log(`\nModified (${diff.modified.length}):`);
for (const mod of diff.modified) {
const entity = modelA.get(mod.id);
console.log(` ~ #${mod.id} ${entity?.type} "${entity?.Name ?? ''}":`);
for (const change of mod.changes) {
console.log(` ${change}`);
}
}
}Goal: Assign property sets to many elements at once.
import { IfcModel } from '@ifc-factory/core';
import { batchAssignProperties } from '@ifc-factory/ifc-utils';
import { readFileSync, writeFileSync } from 'node:fs';
const model = IfcModel.fromStep(readFileSync('model.ifc', 'utf-8'));
// Get IDs by type
const wallIds = model.getAllOfType('IfcWall').map(e => e.expressID);
const doorIds = model.getAllOfType('IfcDoor').map(e => e.expressID);
const windowIds = model.getAllOfType('IfcWindow').map(e => e.expressID);
const slabIds = model.getAllOfType('IfcSlab').map(e => e.expressID);
// Batch assign different property sets to different element groups
batchAssignProperties(model, [
{
elementIds: wallIds,
psetName: 'Pset_WallCommon',
properties: [
{ name: 'IsExternal', value: true },
{ name: 'ThermalTransmittance', value: 0.22, type: 'IFCREAL' },
{ name: 'FireRating', value: 'REI60' },
],
},
{
elementIds: doorIds,
psetName: 'Pset_DoorCommon',
properties: [
{ name: 'IsExternal', value: false },
{ name: 'FireRating', value: 'EI30' },
],
},
{
elementIds: windowIds,
psetName: 'Pset_WindowCommon',
properties: [
{ name: 'IsExternal', value: true },
{ name: 'ThermalTransmittance', value: 1.1, type: 'IFCREAL' },
{ name: 'GlazingAreaFraction', value: 0.8, type: 'IFCREAL' },
],
},
{
elementIds: slabIds,
psetName: 'Pset_SlabCommon',
properties: [
{ name: 'IsExternal', value: false },
{ name: 'LoadBearing', value: true },
{ name: 'FireRating', value: 'REI120' },
],
},
]);
writeFileSync('output.ifc', model.toStep());
console.log('Properties assigned to all elements');Goal: Create a model with full Dutch regulatory compliance data.
See the Dutch Compliance page for a complete walkthrough.
Goal: Attach documents, library references, and classifications to elements.
import {
IfcModel,
createSpatialStructure,
createDocumentInformation,
associateDocument,
createLibraryInformation,
createLibraryReference,
associateLibrary,
createClassification,
createClassificationReference,
associateClassification,
generateIfcGuid,
} from '@ifc-factory/core';
const model = new IfcModel();
const { project, building, storeys } = createSpatialStructure(model, {
projectName: 'Test Project',
siteName: 'Test Site',
buildingName: 'Building A',
storeyNames: ['Ground Floor'],
});
// Create some elements
const wall = model.create('IfcWall', {
GlobalId: generateIfcGuid(),
Name: 'Main Wall',
});
model.containInSpatialStructure(storeys[0].expressID, wall.expressID);
// --- Documents ---
const doc = createDocumentInformation(model, {
name: 'Constructietekening Detail A',
description: 'Detailtekening wandaansluiting',
location: 'https://docs.example.com/detail-a.pdf',
});
associateDocument(model, doc.expressID, [wall.expressID]);
// --- Classifications ---
const nlsfb = createClassification(model, {
name: 'NL-SfB',
edition: '2005',
source: 'BIM Loket',
});
const classRef = createClassificationReference(model, {
identification: '21.22',
name: 'Buitenwanden; niet-dragende wanden',
classificationId: nlsfb.expressID,
});
associateClassification(model, classRef.expressID, [wall.expressID]);
// --- Libraries ---
const lib = createLibraryInformation(model, {
name: 'STABU Besteksystematiek',
version: '2024',
description: 'Nederlandse bestekssystematiek voor de bouw',
});
const libRef = createLibraryReference(model, {
name: 'Metselwerk baksteen',
identification: '22.21.10',
libraryId: lib.expressID,
});
associateLibrary(model, libRef.expressID, [wall.expressID]);
console.log(`Model: ${model.size} entities`);Goal: Work directly with the STEP file format without IFC schema awareness.
import { readStepFile, writeStepFile } from '@ifc-factory/step-serializer';
import { readFileSync, writeFileSync } from 'node:fs';
const source = readFileSync('model.ifc', 'utf-8');
const stepFile = readStepFile(source);
// Inspect header
console.log('File Description:', stepFile.header.fileDescription.description);
console.log('File Name:', stepFile.header.fileName.name);
console.log('Schema:', stepFile.header.fileSchema.schemas);
// Count entity types
const typeCounts = new Map<string, number>();
for (const [, entity] of stepFile.entities) {
typeCounts.set(entity.typeName, (typeCounts.get(entity.typeName) ?? 0) + 1);
}
// Sort by count
const sorted = [...typeCounts.entries()].sort((a, b) => b[1] - a[1]);
console.log('\nTop 20 entity types:');
for (const [type, count] of sorted.slice(0, 20)) {
console.log(` ${type}: ${count}`);
}
// Modify an entity's raw attributes
const entity42 = stepFile.entities.get(42);
if (entity42) {
console.log(`\n#42 = ${entity42.typeName}(${entity42.attributes.length} attributes)`);
// Attributes are StepValue[] — raw STEP values
for (let i = 0; i < entity42.attributes.length; i++) {
console.log(` [${i}] = ${JSON.stringify(entity42.attributes[i])}`);
}
}
// Write back
const output = writeStepFile(stepFile);
writeFileSync('output.ifc', output);Goal: Parse the IFC EXPRESS schema and analyze its structure.
import { parseExpress } from '@ifc-factory/express-parser';
import { readFileSync } from 'node:fs';
const source = readFileSync('schemas/IFC4X3_ADD2.exp', 'utf-8');
const schema = parseExpress(source);
console.log(`Schema: ${schema.name}`);
console.log(`Total declarations: ${schema.declarations.length}`);
// Count by kind
const kinds = { entity: 0, type: 0, function: 0, rule: 0 };
for (const decl of schema.declarations) {
kinds[decl.kind]++;
}
console.log(`Entities: ${kinds.entity}`);
console.log(`Types: ${kinds.type}`);
console.log(`Functions: ${kinds.function}`);
console.log(`Rules: ${kinds.rule}`);
// Find all abstract entities
const abstractEntities = schema.declarations
.filter(d => d.kind === 'entity' && d.abstract)
.map(d => d.name);
console.log(`\nAbstract entities (${abstractEntities.length}):`);
for (const name of abstractEntities.slice(0, 10)) {
console.log(` ${name}`);
}
// Find entity inheritance tree for IfcWall
function getInheritanceChain(entityName: string): string[] {
const chain = [entityName];
let current = schema.declarations.find(d => d.kind === 'entity' && d.name === entityName);
while (current?.kind === 'entity' && current.subtypeOf) {
chain.push(current.subtypeOf);
current = schema.declarations.find(d => d.kind === 'entity' && d.name === current!.subtypeOf);
}
return chain.reverse();
}
console.log('\nIfcWall inheritance:');
console.log(getInheritanceChain('IfcWall').join(' → '));
// IfcRoot → IfcObjectDefinition → IfcObject → IfcProduct → IfcElement → IfcBuildingElement → IfcWallIfc-Factory
Getting Started
Concepts
Packages
API & Reference
Development