Skip to main content
The scene graph system in OpenGeometry provides a hierarchical structure for managing collections of geometric entities. It enables organizing, manipulating, and rendering multiple BREP bodies as a cohesive scene.

Overview

The scene graph consists of two primary structures defined in src/scenegraph.rs:
  • OGScene - A named collection of geometric entities
  • OGSceneManager - Manages multiple scenes and provides WASM-exposed API

OGScene

A scene is a container for geometric entities:
pub struct OGScene {
    pub id: String,           // UUID identifier
    pub name: String,         // Human-readable name
    pub entities: Vec<SceneEntity>,
}

SceneEntity

Each entity in a scene wraps a BREP body:
pub struct SceneEntity {
    pub id: String,      // Unique entity ID
    pub kind: String,    // Type: "OGLine", "OGCuboid", etc.
    pub brep: Brep,      // Underlying boundary representation
}
The kind field identifies the primitive or shape type that generated the BREP, enabling type-aware operations.

Creating Scenes

Basic Scene Creation

use opengeometry::scenegraph::OGScene;

let scene = OGScene::new("My Building");
println!("Scene ID: {}", scene.id);
Scenes are automatically assigned a UUID and start with an empty entity list.

Adding Entities

Entities are added using the upsert_entity method:
use opengeometry::scenegraph::SceneEntity;
use opengeometry::brep::Brep;
use uuid::Uuid;

let mut scene = OGScene::new("Test Scene");

let entity = SceneEntity {
    id: Uuid::new_v4().to_string(),
    kind: "OGCuboid".to_string(),
    brep: cuboid.brep().clone(),
};

scene.upsert_entity(entity);
Upsert behavior:
  • If entity ID exists → replaces existing entity
  • If entity ID is new → appends to entity list

Removing Entities

let removed = scene.remove_entity("entity-uuid");
if removed {
    println!("Entity removed");
}
Returns true if entity was found and removed, false otherwise.

OGSceneManager

The scene manager provides a stateful API for working with multiple scenes:
pub struct OGSceneManager {
    scenes: HashMap<String, OGScene>,
    current_scene_id: Option<String>,
}

Creating Scenes

let mut manager = OGSceneManager::new();
let scene_id = manager.create_scene_internal("Floor Plan");
The newly created scene automatically becomes the current scene.

Managing Active Scene

// Set current scene
manager.set_current_scene(scene_id)?;

// Get current scene ID
if let Some(id) = manager.get_current_scene_id() {
    println!("Current scene: {}", id);
}

Removing Scenes

let removed = manager.remove_scene(scene_id);
If the removed scene was current, the manager automatically selects another scene as current.

Adding Entities to Scenes

The scene manager provides convenience methods for adding primitives:

From BREP

manager.add_brep_entity_to_scene_internal(
    &scene_id,
    "wall-1",
    "CustomShape",
    &brep
)?;

From Primitives

use opengeometry::primitives::cuboid::OGCuboid;

let cuboid = OGCuboid::new(1.0, 2.0, 3.0);
manager.add_cuboid_to_scene_internal(&scene_id, "box-1", &cuboid)?;
Supported primitives:
  • add_line_to_scene_internal
  • add_polyline_to_scene_internal
  • add_arc_to_scene_internal
  • add_rectangle_to_scene_internal
  • add_polygon_to_scene_internal
  • add_cuboid_to_scene_internal
  • add_cylinder_to_scene_internal
  • add_sphere_to_scene_internal
  • add_wedge_to_scene_internal
Each method:
  1. Extracts the BREP from the primitive
  2. Creates a SceneEntity with appropriate kind
  3. Adds to the specified scene

Scene to BREP Relationship

Every entity in a scene contains a complete BREP representation:
OGScene
  └─ SceneEntity ("wall-1")
       ├─ kind: "OGCuboid"
       └─ brep: Brep { vertices, edges, faces }
  └─ SceneEntity ("window-1")
       ├─ kind: "OGRectangle" 
       └─ brep: Brep { vertices, edges, faces }
This design means:
  • Each entity is self-contained
  • No shared vertex/edge pools between entities
  • Easy to add/remove entities without topology updates
  • Straightforward serialization

2D Projection

Scenes can be projected to 2D with hidden line removal:
use opengeometry::export::{CameraParameters, HlrOptions};

let camera = CameraParameters::default();
let hlr = HlrOptions::default();

let scene_2d = scene.project_to_2d(&camera, &hlr);
This projects all entities in the scene and combines them into a single 2D representation.

Via Scene Manager

let scene_2d = manager.project_scene_to_2d(
    &scene_id,
    &camera,
    &hlr
)?;

// Or as JSON
let json = manager.project_scene_to_2d_json(&scene_id, &camera, &hlr)?;

WASM API

The OGSceneManager is exposed to JavaScript via wasm-bindgen:
import { OGSceneManager } from 'opengeometry';

const manager = new OGSceneManager();

// Create scene
const sceneId = manager.createScene('My Scene');

// Add entity
manager.addCuboidToScene(sceneId, 'box-1', cuboid);

// Project to 2D
const cameraJson = JSON.stringify({ /* camera params */ });
const projection = manager.projectTo2DCamera(sceneId, cameraJson);

WASM Methods

Scene Management:
  • createScene(name: string): string
  • removeScene(sceneId: string): boolean
  • setCurrentScene(sceneId: string)
  • getCurrentSceneId(): string | undefined
  • listScenes(): string (JSON array)
Entity Management:
  • addBrepEntityToScene(sceneId, entityId, kind, brepJson)
  • addLineToScene(sceneId, entityId, line)
  • addCuboidToScene(sceneId, entityId, cuboid)
  • … (one method per primitive type)
  • removeEntityFromScene(sceneId, entityId): boolean
Projection:
  • projectTo2DCamera(sceneId, cameraJson, hlrJson): string
  • projectTo2DLines(sceneId, cameraJson, hlrJson): string

Current Scene Shortcuts

Many methods have variants that operate on the current scene:
manager.addCuboidToCurrentScene('box-1', cuboid);
manager.projectCurrentTo2DCamera(cameraJson);

Scene Serialization

Scenes and entities are fully serializable:
// Serialize scene
let json = serde_json::to_string(&scene)?;

// Via manager (WASM)
let json = manager.get_scene_serialized(scene_id)?;
Serialized format includes:
  • Scene ID and name
  • All entities with their IDs, kinds, and complete BREP data

Example: Building a Multi-Entity Scene

use opengeometry::scenegraph::OGSceneManager;
use opengeometry::primitives::cuboid::OGCuboid;
use opengeometry::primitives::cylinder::OGCylinder;

let mut manager = OGSceneManager::new();
let scene_id = manager.create_scene_internal("Building");

// Add foundation
let foundation = OGCuboid::new(10.0, 10.0, 0.5);
manager.add_cuboid_to_scene_internal(&scene_id, "foundation", &foundation)?;

// Add columns
for i in 0..4 {
    let column = OGCylinder::new(0.3, 3.0, 32);
    let id = format!("column-{}", i);
    manager.add_cylinder_to_scene_internal(&scene_id, &id, &column)?;
}

println!("Scene has {} entities", manager.scenes[&scene_id].entities.len());

Performance Considerations

  • Entity lookup: O(n) search by ID (consider HashMap for large scenes)
  • BREP cloning: Each add operation clones the BREP
  • Projection: All entities processed together, efficient for batch operations
  • Serialization: Full scene serialization can be expensive for large models

Next Steps

Last modified on March 7, 2026