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

BREP Structure

Learn about the entity data structure

Projection

Understand 2D projection and hidden line removal

Build docs developers (and LLMs) love