Skip to content

openbim-ifcx-geometry ​

Renderer-neutral geometry and viewer helpers for IFC5 / IFCX: transforms, meshes, curves, point clouds, presentation, a flat render scene, and GLB export.

Crateopenbim-ifcx-geometry 0.1.1 on main
Latest release0.1.1 (2026-10-03)
Distributed ascrates.io openbim-ifcx-geometry
Installcargo add openbim-ifcx-geometry
RequiresRust 1.88.0
LicenseMIT
API documentationrustdoc · docs.rs
Sourcecrates/openbim-ifcx-geometry/

About ​

From the crate's README.md:

Renderer-neutral geometry and viewer helpers for IFC5 / IFCX. It depends on openbim-ifcx and never on a renderer or GPU API.

Implemented for the ifcx_alpha draft:

ModuleAttributeResult
transformusd::xformopAffine Transform (USD row-vector layout, translation in the last row) and world_from_parent
meshusd::usdgeom::meshTriangleMesh: positions, u32 indices, flat face normals
curvesusd::usdgeom::basiscurvesLinear Polylines, or Unsupported for other curve types
pointspoints::array, points::base64, pcd::base64PointCloud: positions and optional linear RGB colours; PCD ascii, binary, binary_compressed
presentationusd::usdgeom::visibility, bsi::ifc::presentation::*, gltf::materialNodePresentation per node; is_visible, resolve_basic_material, resolve_mesh_material apply the reference viewer's precedence over a node's ancestors
glba RenderSceneto_glb: one binary glTF 2.0 file with shared meshes, LINES, POINTS (with COLOR_0), PBR materials, node names set to IFCX paths, and the origin and Z-up to Y-up rotation on a root node
sceneall of the above, over a composed treeRenderScene::from_composition: instances (node path for picking, f64 world transform, f32 render matrix, material), shared f32 mesh, line, and point buffers stored once per shared attribute value, a material table, f64 world bounds, a render origin, and per-value warnings; the walk is bounded by SceneOptions::max_visits and max_path_bytes, and coordinates outside f32 range are left out with a warning

Each decoder takes an attribute's serde_json::Value and returns a typed DecodeError for malformed input. Coordinates are f64 because IFCX files carry georeferenced coordinates; convert to f32 for rendering after applying world transforms.

rust
use openbim_ifcx::{compose, flatten_owned, IfcxFile};
use openbim_ifcx_geometry::{RenderScene, SceneOptions};

let file = IfcxFile::from_json_slice(&std::fs::read("model.ifcx")?)?;
let scene = RenderScene::from_composition(&compose(&flatten_owned(file.data))?, &SceneOptions::default());
for instance in &scene.instances {
    // instance.path, instance.geometry, instance.matrix, scene.materials[instance.material]
}

Buffers hold vertices relative to a per-buffer anchor, and instance matrices map to world coordinates minus scene.origin, so georeferenced models keep sub-millimetre precision in f32.

To look at an IFCX file in any glTF viewer:

sh
cargo run --release -p openbim-ifcx-geometry --example ifcx2glb -- model.ifcx model.glb
# layers, weakest first; --z-up keeps IFCX axes, --local leaves the origin off the root
cargo run --release -p openbim-ifcx-geometry --example ifcx2glb -- base.ifcx overlay.ifcx out.glb
# resolve imports from disk; --mirror maps a URI prefix to an offline copy
cargo run --release -p openbim-ifcx-geometry --example ifcx2glb -- \
    --resolve-imports --mirror https://ifcx.dev/=mirror/ifcx.dev model.ifcx model.glb

Without --resolve-imports, imports are ignored. With it, every layer's imports load through openbim_ifcx::layers::FsResolver, each layer after the layers it imports (a layer overrides its imports, the next layer overrides both); nothing is fetched from the network.

scripts/gltf-validate.sh (opt-in, needs Node.js) exports the fixtures and, with IFCX_UPSTREAM_DIR, every upstream example, and checks them with the Khronos glTF validator. See the repository capabilities, the documentation with a Rust guide, and the viewer, which shows an IFCX file in the browser.

Licensed under MIT.

Public API ​

The crate root, as rustdoc shows it. Follow a name to its rustdoc entry.

ModuleSummary
curvesPolylines from usd::usdgeom::basiscurves.
errorThe error shared by every attribute decoder in this crate.
glbBinary glTF 2.0 (GLB) export of a RenderScene.
mathSmall vector helpers shared by the decoders.
meshIndexed triangle meshes from usd::usdgeom::mesh.
pointsPoint clouds from points::array, points::base64, and pcd::base64 (ifcx_alpha).
presentationVisibility, colour, opacity, and glTF PBR materials (ifcx_alpha).
sceneA flat, renderer-neutral render scene over a composed node tree.
transformLocal and world transforms from usd::xformop.
ItemKindSummary
AlphaModeenumglTF alphaMode.
AttributestraitA node's attributes keyed by namespaced attribute id, as in a file's schemas (for example points::array or gltf::material).
BasicMaterialstructColour and opacity from bsi::ifc::presentation.
BoundsstructAn axis-aligned box in f64.
CurveGeometryenumThe result of decoding a curves attribute that is well formed.
DecodeErrorenumWhy an attribute value could not be decoded into geometry.
GeometryKindenumThe kind of geometry an instance draws.
GeometryRefenumWhat an instance draws: an index into one of the scene's buffer lists.
GlbErrorenumWhy a scene could not be written as GLB.
GlbOptionsstructOptions for to_glb.
GltfMaterialstructA gltf::material value with glTF 2.0 defaults filled in.
InstancestructOne drawn geometry of one node at one path.
is_visiblefunctionWhether a node is drawn, given whether its parent is (true for a root) and the node's own visibility. An invisible node hides its subtree; a descendant cannot become visible again.
LineBufferstructShared line segments, from the linear curves of usd::usdgeom::basiscurves.
MaterialenumThe material a mesh is drawn with.
MeshBufferstructA shared triangle mesh, from usd::usdgeom::mesh.
NodePresentationstructOne node's own presentation attributes, before any inheritance.
NormalTexturestructA normal map reference. The texture is recorded, not loaded.
OcclusionTexturestructAn occlusion map reference. The texture is recorded, not loaded.
OriginenumWhere the render origin of a scene lies.
PointBufferstructShared points, from pcd::base64, points::array, or points::base64.
PointCloudstructDecoded points of one node, in the node's local coordinates.
PolylinestructOne connected line strip in the node's local coordinates.
RenderScenestructA flat render scene; see the module docs.
resolve_basic_materialfunctionColour and opacity for a node, from the node and its ancestors given nearest first. The nearest diffuseColor wins, and opacity comes from that same node (default 1); an opacity on a node without diffuseColor is not used. Used for curves, and for meshes without a glTF material.
resolve_mesh_materialfunctionThe material for a mesh node, from the node and its ancestors given nearest first. The nearest gltf::material wins over any bsi::ifc::presentation attribute; without one, see resolve_basic_material.
SceneOptionsstructOptions for RenderScene::from_composition.
SceneWarningstructA value skipped while building a scene; see the module docs.
SceneWarningKindenumWhy part of a node was left out of a scene.
to_glbfunctionWrites scene as a binary glTF 2.0 file.
TransformstructAn affine 4×4 transform in USD's row-vector layout.
TriangleMeshstructAn indexed triangle mesh in the node's local coordinates.
UnsupportedCurvestructA curve type this crate does not turn into polylines.
Vec3type aliasA point or direction in 3D, x, y, z.
VisibilityenumUSD visibility token of one node.
world_from_parentfunctionWorld transform of a node from its parent's world transform and its own local transform, if it has one. A node without a local transform inherits its parent's world transform unchanged. Use Transform::IDENTITY as the parent of a root.

Examples ​

  • ifcx2glb: cargo run -p openbim-ifcx-geometry --example ifcx2glb

Within the workspace ​

Changes ​

Unreleased, on main:

Changed ​

  • ifcx2glb --resolve-imports stacks each layer after the layers it imports, following openbim-ifcx's new layer order (buildingSMART/IFC5-development#144), so a layer overrides its imports. The library API is unchanged (#36).

Latest release, 0.1.1 (2026-10-03):

No breaking change. Requires openbim-ifcx 0.1.1.

Added ​

  • ifcx2glb --resolve-imports loads every layer's imports through openbim_ifcx::layers::FsResolver before exporting, stacked as upstream's ifcx compose does; --mirror PREFIX=DIR (repeatable) maps a URI prefix such as https://ifcx.dev/ to an offline copy. The example now flattens with flatten_owned (#42, #43).
  • Test fixture imports-panel-type.ifcx, whose panels inherit a type only its import defines, and tests/imports.rs, which exports it with the import resolved (#42).
  • Dev-dependency on openbim-ifcx with feature fs, for the example and its test.
  • SceneOptions::max_visits (default 10 million) and SceneOptions::max_path_bytes (default 1 GiB), with builders and DEFAULT_* constants, bound the render-scene walk. When one is reached the walk stops with a SceneWarningKind::LimitReached warning (#41).
  • SceneWarningKind::OutOfRange for geometry and instances whose coordinates the scene's f32 buffers and matrices cannot hold (#41).

Fixed ​

  • RenderScene::from_composition no longer visits an exponential number of paths: composition shares sub-trees, so 40 nodes naming the next one twice as children described 2^40 instances. Deep trees with long child names no longer build instance paths without bound. Found while fuzzing (#41).
  • Coordinates beyond f32 range (for example a translation of 5e299) no longer produce infinite render matrices, buffers, or origins, which to_glb wrote as JSON null; such geometry and instances are left out with an OutOfRange warning. to_glb writes an infinite alphaCutoff as f32::MAX and a NaN one as 0.5. Found by fuzzing (#41).
  • PointCloud::from_pcd returns InvalidPcd for ASCII data whose COUNT values overflow usize when summed, instead of panicking with overflow checks on (or reading the wrong column without). Found while fuzzing (#41).

Full history: crates/openbim-ifcx-geometry/CHANGELOG.md, and every release of every crate on the project changelog.

Released under the MIT licence. No buildingSMART files or texts are published here.