symbios_shape/lib.rs
1//! # Symbios Shape
2//!
3//! **A Sovereign Derivation Engine for CGA Shape Grammars.**
4//!
5//! Symbios Shape is a pure-Rust engine for generating procedural geometry using
6//! Computer-Generated Architecture (CGA) Shape Grammars, as popularised by
7//! Esri CityEngine. It is designed for embedding in game engines (Bevy, Godot)
8//! and offline procedural pipelines where reliability and determinism are paramount.
9//!
10//! ## Key Features
11//!
12//! - **Lightweight**: Depends only on `glam` (math), `nom` (parsing), `rand` (stochastic rules), and optionally `symbios-genetics` — no engine or runtime required.
13//! - **CGA-Compatible Operations**: `Extrude`, `Split`, `Comp`, `Repeat`, `Taper`, `Scale`, `Translate`, `Rotate`, `Align`, `Offset`, `Roof`, `Attach`, `I`, `Mat`.
14//! - **15 Roof Types**: Pyramid, Shed, Gable, Hip, Flat, OpenGable, BoxGable, PyramidHip, Butterfly, MShaped, Gambrel, Mansard, Saltbox, Jerkinhead, DutchGable.
15//! - **Flexible Split Sizing**: Absolute, relative (`'`), and floating (`~`) modes.
16//! - **Rich Face Profiles**: `FaceProfile` describes each terminal's cross-section (Rectangle, Taper, Triangle, Trapezoid, Polygon).
17//! - **Genetic Evolution**: `ShapeGenotype` wraps the rule table for `symbios-genetics` algorithms.
18//! - **Bevy-Ready Output**: `ShapeModel` containing `Terminal` nodes with scope, mesh_id, face_profile, and material.
19//!
20//! ## Example
21//!
22//! ```rust
23//! use symbios_shape::{Interpreter, Scope, Vec3, Quat};
24//! use symbios_shape::grammar::parse_ops;
25//!
26//! let mut interp = Interpreter::new();
27//!
28//! // A simple 3-storey building
29//! interp.add_rule("Lot", parse_ops("Extrude(12) Split(Y) { 3: Ground | ~1: Upper | 2: Roof }").unwrap());
30//! interp.add_rule("Ground", parse_ops(r#"I("GroundFloor")"#).unwrap());
31//! interp.add_rule("Upper", parse_ops(r#"I("Floor")"#).unwrap());
32//! interp.add_rule("Roof", parse_ops(r#"Taper(0.8) I("Roof")"#).unwrap());
33//!
34//! let footprint = Scope::new(Vec3::ZERO, Quat::IDENTITY, Vec3::new(10.0, 0.0, 10.0));
35//! let model = interp.derive(footprint, "Lot").unwrap();
36//!
37//! assert_eq!(model.len(), 3);
38//! assert_eq!(model.terminals[0].mesh_id, "GroundFloor");
39//! assert_eq!(model.terminals[2].mesh_id, "Roof");
40//! assert!(matches!(model.terminals[2].face_profile, symbios_shape::FaceProfile::Taper(t) if (t - 0.8).abs() < 1e-9));
41//! ```
42
43pub mod error;
44pub mod genetics;
45pub mod grammar;
46pub mod interpreter;
47pub mod model;
48pub mod ops;
49pub mod scope;
50
51pub use error::ShapeError;
52pub use interpreter::Interpreter;
53pub use model::{FaceProfile, ShapeModel, Terminal};
54pub use ops::{
55 AttachCase, AttachSelector, Axis, CompTarget, FaceSelector, OffsetCase, OffsetSelector,
56 RoofCase, RoofConfig, RoofFaceSelector, RoofType, ShapeOp, SplitSize, SplitSlot,
57};
58pub use scope::{Quat, Scope, Vec3};