Skip to content

Multi-Model Federation

IFClite supports loading multiple IFC files simultaneously with unified selection, visibility, and spatial hierarchy. This is essential for real-world BIM workflows where architectural, structural, and MEP models are maintained as separate files.

How It Works

Each loaded model is assigned a unique ID offset so that entity IDs never collide across models. The FederationRegistry manages these offsets automatically.

Model A: expressIds 1-5000    -> globalIds 1-5000       (offset: 0)
Model B: expressIds 1-3000    -> globalIds 5001-8000    (offset: 5000)
Model C: expressIds 1-2000    -> globalIds 8001-10000   (offset: 8000)

Global vs Local IDs

  • Local expressId: The original ID within a single IFC file (e.g., #42)
  • Global ID: expressId + model.idOffset - unique across all loaded models
  • EntityRef: { modelId: string, expressId: number } - unambiguous reference to any entity
// Convert local to global
const globalId = expressId + model.idOffset;

// Convert global to local
const lookup = resolveGlobalIdFromModels(globalId);
// { modelId: 'arch-model', expressId: 42 }

Loading Multiple Models

In the viewer, drop multiple IFC files or load them sequentially. Each model appears as a collapsible group in the hierarchy panel.

Programmatic Usage

import { IfcParser } from '@ifc-lite/parser';
import { federationRegistry } from '@ifc-lite/renderer';

const parser = new IfcParser();

// Load first model
const archStore = await parser.parseColumnar(archBuffer);
// Compute maxExpressId from entity index
const archMaxId = Math.max(...archStore.entityIndex.byId.keys());
const archOffset = federationRegistry.registerModel('arch', archMaxId);

// Load second model - IDs start after the first model's range
const structStore = await parser.parseColumnar(structBuffer);
const structMaxId = Math.max(...structStore.entityIndex.byId.keys());
const structOffset = federationRegistry.registerModel('struct', structMaxId);

// Convert IDs
const globalId = federationRegistry.toGlobalId('struct', 42);
const lookup = federationRegistry.fromGlobalId(globalId);
if (lookup) {
  console.log(`Model: ${lookup.modelId}, Express ID: ${lookup.expressId}`);
}

Unified Interactions

When multiple models are loaded:

  • Selection works across all models - clicking any entity in any model selects it
  • Visibility can be toggled per-model or per-entity across models
  • Spatial hierarchy shows all models as top-level groups, expandable to their internal structure
  • Properties panel shows properties for the selected entity regardless of which model it belongs to
  • Section planes cut through all visible models simultaneously
  • Measurements can span across models

Model Management

The viewer provides controls for each loaded model:

Action Description
Visibility toggle Show/hide an entire model
Collapse/Expand Collapse a model's hierarchy tree
Rename Give a model a descriptive name
Remove Unload a model and free its ID range
Set Active Focus the properties panel on a specific model

FederatedModel Type

Each loaded model is tracked as a FederatedModel:

interface FederatedModel {
  id: string;            // Unique model identifier
  name: string;          // Display name
  idOffset: number;      // Global ID offset
  maxExpressId: number;  // Highest expressId in this model
  visible: boolean;      // Visibility state
  collapsed: boolean;    // Hierarchy tree state
}

Performance Considerations

  • Each model adds its entities to the shared spatial index and renderer
  • Memory usage scales linearly with total entity count across all models
  • The FederationRegistry uses O(1) lookups for ID resolution
  • Visibility toggling per-model is O(1) (GPU-level filtering)
  • Loading 5+ large models (100MB+ each) may require the server paradigm for best performance

IFC5 Federated Layers

For IFC5 (IFCX) files, federation works differently - files can be loaded as overlay layers where later files override properties from earlier ones:

import { parseFederatedIfcx } from '@ifc-lite/ifcx';

const result = await parseFederatedIfcx([
  { buffer: baseBuffer, name: 'base-model.ifcx' },
  { buffer: overlayBuffer, name: 'add-fire-rating.ifcx' },
]);

// Properties from the overlay take precedence
// Wall now has FireRating property from the overlay file

See the IFC5 Parsing Guide for more details on IFCX format support.