Skip to content

Lenses

Lenses are rule-based 3D filters: they colorize, hide, or ghost entities based on what the model data says about them. The @ifc-lite/lens package evaluates a lens against model data and produces a color map you can apply to any renderer, plus counts and legends for UI.

How It Works

A lens is a named set of rules. Each rule has:

  • Criteria - A single condition on one axis (IFC class, property, material, attribute, quantity, classification, model, or group)
  • Action - colorize, hide, or transparent
  • Color - A hex color used by colorize and transparent

evaluateLens checks every entity against the enabled rules in order; the first matching rule wins. Entities that match no rule are ghosted (a faint neutral color) so the matches stand out.

Alternatively, a lens can use auto-color: instead of hand-written rules, it groups entities by the distinct values of one data source (IFC class, a property, a material, ...) and assigns each group a color automatically, producing a legend.

Quick Start

import { evaluateLens, BUILTIN_LENSES } from '@ifc-lite/lens';

// BUILTIN_LENSES includes a "Structural" preset:
// columns red, beams blue, slabs yellow, footings green
const structural = BUILTIN_LENSES.find((l) => l.id === 'lens-structural')!;

declare const selectedByRule: ReadonlyMap<string, ReadonlySet<number>>;
const result = evaluateLens(structural, provider, selectedByRule);

result.colorMap;      // Map<expressId (number), [r, g, b, a]> (0-1 range)
result.hiddenIds;     // Set<expressId (number)> from 'hide' rules
result.ruleCounts;    // Map<ruleId, matchCount>
result.executionTime; // ms

The provider is a LensDataProvider, an adapter interface over your parsed model data (entity types, property values, materials, and so on), so the package is renderer- and parser-agnostic.

A saved Lens.capturedScope pins exact selected or visible members at capture time. It applies to manual rules, their unassigned context, and automatic color buckets; later selection and visibility changes do not change the captured population. For automatic color, pass the same metadata as the optional third argument to evaluateAutoColorLens(spec, provider, capturedScope). A provider serving a captured lens must implement resolveCapturedScope(scope) and return its validated native global IDs. A provider without that capability refuses the run.

The shared Rules resolveCapturedEntityScope validates the full source identity and every member before evaluation. Missing or ambiguous files, replaced source bytes, deleted members, and reused authored IDs refuse rather than becoming an unscoped lens. Authored members also need their original authored record creation identity; reconstructing a view without that identity requires a new capture. Normal authored edits and delete undo retain membership.

Built-in Lenses

BUILTIN_LENSES ships seven presets:

Id Name What it does
lens-by-class By IFC Class Auto-colors every entity by its IFC class
lens-structural Structural Columns, beams, slabs, footings in distinct colors
lens-envelope Building Envelope Roofs, curtain walls, windows, doors, walls
lens-openings Openings & Circulation Doors, windows, stairs, ramps, railings
lens-auto-material By Material Auto-colors by material name
lens-by-stage By Stage Auto-colors vendor CESIUM.Stage property values
lens-by-model By Model Auto-colors by source model (federation)
lens-by-zone By Zone Auto-colors by IfcZone/IfcGroup membership

Rule Filters

The viewer Lens editor now authors FilterGroup[] chips using the same selector as Search and Lists. Saved v1 criteria are converted when their meaning is exactly representable; other saved conditions remain visible with a warning until the user explicitly replaces them. For programmatic evaluation, pass a map of rule IDs to selected global IDs as the required third argument to evaluateLens. Missing rule IDs match nothing. The viewer keeps the saved v1 criteria shape private to its JSON migration path; the published Lens package exposes only shared group based manual rules.

Worked Example: Color by Fire Rating

Hand-authored groups, one rule per rating value you care about:

import { evaluateLens, type Lens } from '@ifc-lite/lens';

const fireLens: Lens = {
  id: 'fire-rating',
  name: 'Fire Rating',
  rules: [
    {
      id: 'fr-90',
      name: 'REI 90',
      enabled: true,
      groups: [{
        combinator: 'AND',
        rules: [{
          kind: 'property', setName: 'Pset_WallCommon', setNameKind: 'literal',
          propertyName: 'FireRating', propertyNameKind: 'literal', op: 'eq', value: '90',
        }],
      }],
      action: 'colorize',
      color: '#E53935',
    },
    // ...more rules for other rating values
  ],
};

// Evaluate each rule's groups with @ifc-lite/rules, then map its rows to
// global IDs before applying the Lens actions.
declare const selectedByRule: ReadonlyMap<string, ReadonlySet<number>>;
const result = evaluateLens(fireLens, provider, selectedByRule);

Or let auto-color enumerate every distinct rating and build the palette and legend for you:

import { evaluateAutoColorLens, type AutoColorSpec } from '@ifc-lite/lens';

const spec: AutoColorSpec = {
  source: 'property',
  psetName: 'Pset_WallCommon',
  propertyName: 'FireRating',
};

const result = evaluateAutoColorLens(spec, provider);

result.legend; // [{ label, color, count }, ...] one entry per distinct value

Auto-color groups entities by value in a single pass, sorts groups by size, assigns stable distinct colors, and ghosts entities without a value. AutoColorSpec.source accepts ifcType, attribute, property, quantity, classification, material, model, or group.

Property set and property names are matched as exact strings against whatever the model actually contains; use discovery (below) to find the real names first.

Discovering What a Model Contains

To populate a lens editor UI:

import { discoverClasses, discoverDataSources } from '@ifc-lite/lens';

const classes = discoverClasses(provider);
// sorted unique IFC class names present in the model

const sources = discoverDataSources(provider, { properties: true, materials: true });
// samples entities to list available psets, qsets, classification systems, materials

Applying Results to the Renderer

result.colorMap is a Map<number, [r, g, b, a]> with components in the 0-1 range, which is exactly what SceneContents.setColorOverrides in @ifc-lite/renderer accepts:

import { evaluateLens, BUILTIN_LENSES } from '@ifc-lite/lens';

declare const selectedByRule: ReadonlyMap<string, ReadonlySet<number>>;
const lensResult = evaluateLens(BUILTIN_LENSES[0], provider, selectedByRule);

// scene is a SceneContents, from renderer.getScene()
scene.setColorOverrides(lensResult.colorMap, device, pipeline);

// remove the lens
scene.clearColorOverrides();

Color overrides are shaded from a per-entity color table during opaque model draws, so the base model is never modified or copied. An eligible opaque mesh that streams in after the call is painted too; hiddenIds is applied separately through your visibility mechanism. Ghosted (unmatched) entries carry a shared ghost color you can detect with isGhostColor if you want to filter them out of legends.

This is exactly how the viewer wires it: the Lens panel evaluates the active lens, pushes colorMap into the store, and the geometry streaming hook calls scene.setColorOverrides on the next frame. See Rendering for the renderer setup.

Key Exports

Export Description
evaluateLens(lens, provider, matchedByRule) Apply rule actions to shared evaluator global-ID sets; returns LensEvaluationResult
evaluateAutoColorLens(spec, provider, capturedScope?) Group-by-value colorization with legend and optional captured membership
discoverClasses(provider) / discoverDataSources(provider, categories) Populate editor UIs
BUILTIN_LENSES The seven built-in presets
hexToRgba / rgbaToHex / uniqueColor / isGhostColor / GHOST_COLOR Color helpers

Key types: Lens, LensRule, AutoColorSpec, LensEvaluationResult, LensDataProvider, RGBAColor.

Construction-stage tagging

In Author → Bulk Edit, choose Construction stage preset. It targets the current selection and prepares an integer CESIUM.Stage property, initially 1. Review the selection and value before applying. Assignments support workspace undo and are preserved in exported IFC. Select the By Stage Lens to color the assigned stages; unassigned elements are ghosted.

CESIUM.Stage is vendor metadata, separate from standard IFC tasks and schedules. The preset and Lens adapt the workflow published by the GeoBIM MPL fork, using IFClite's existing editing and visualization paths.