Expand description
Tensor-field-driven procedural urban layout generator.
This crate generates realistic road networks and building lots on terrain
defined by a symbios_ground::HeightMap. Roads follow the natural
topography: major roads trace elevation contours while minor roads
run along the gradient, producing organic street grids that adapt to hills
and valleys. On flat terrain the field falls back to an axis-aligned
Manhattan grid.
§Pipeline
- Road generation —
generate_roadsseeds streamlines on a jittered grid and traces them through aTensorFieldusing RK2 integration, snapping and splitting edges to form a planarRoadGraph. - Graph rationalization —
rationalize_graphrewrites the raw tracer output into clean geometry: RDP decimation removes unnecessary points, quadratic Bézier fillets smooth sharp bends, and elevation profiles are Laplacian-smoothed and grade-clamped. Arteries are traced through intersections for global straightening; severed side-streets are reconnected. - Block extraction —
extract_blockswalks the planar graph with a minimum-angle (left-most turn) algorithm, producing closedCityBlockpolygons for every bounded interior face. - Lot subdivision —
extract_lotsrecursively splits each block perpendicular to its longest edge (through the centroid) until pieces are below a configurable area threshold, then computes a street-alignedBuildingLotrectangle with front/side/rear setbacks. - Terrain carving —
carve_roadsandcarve_lotsflatten the heightmap under roads and building foundations with smooth embankment blending at the edges. Both accept a configurableblend_radiusthat controls how far the embankment zone extends — larger values produce wider, gentler slopes on steep terrain.carve_roadsreturns a boolean road-surface mask so thatcarve_lotscan avoid overwriting already-flattened pavement. Road elevations use the rationalized (smoothed) node heights. - Road pruning —
prune_unused_roadsoptionally removes roads that do not serve any building lot, keeping only the minimal connected sub-network via Dijkstra-based Steiner tree construction. - 3D mesh generation —
generate_road_meshesproduces engine-agnosticProceduralMeshvertex buffers for intersection hubs (flat N-gon polygons with embankment skirts) and street ribbons (extruded strips with flanking skirt meshes).
§Quick start
ⓘ
use symbios_ground::HeightMap;
use symbios_tensor::*;
let heightmap = HeightMap::new(128, 128, 4.0);
let config = TensorConfig::default();
// 1. Generate road network
let mut graph = generate_roads(&heightmap, &config).expect("invalid config");
// 2. Rationalize: straighten, fillet, and smooth elevations
rationalize_graph(&mut graph, &heightmap, &RationalizeConfig::default());
// 3. Extract city blocks
extract_blocks(&mut graph);
// 4. Subdivide blocks into building lots
let mut hm = heightmap;
let lots = extract_lots(&graph, &mut hm, &LotConfig::default());
// 5. Carve roads and lots into terrain
let road_mask = carve_roads(&graph, &mut hm, &RoadMeshConfig::default(), 4.0);
carve_lots(&lots, &mut hm, 2.0, Some(&road_mask));
// 6. (Optional) Prune roads that don't serve any lot
prune_unused_roads(&mut graph, &lots);
// 7. Generate 3D road meshes
let meshes = generate_road_meshes(&graph, &hm, &RoadMeshConfig::default());
// meshes.hubs — intersection polygons
// meshes.ribbons — street ribbon strips
// meshes.skirts — embankment skirt meshesRe-exports§
pub use carve::carve_lots;pub use carve::carve_roads;pub use graph::BlockId;pub use graph::CityBlock;pub use graph::EdgeId;pub use graph::NodeId;pub use graph::RoadEdge;pub use graph::RoadGraph;pub use graph::RoadNode;pub use graph::RoadType;pub use lots::BuildingLot;pub use lots::LotConfig;pub use lots::WaterPolicy;pub use lots::extract_lots;pub use polygons::block_centroid;pub use polygons::extract_blocks;pub use prune::prune_unused_roads;pub use rationalize::RationalizeConfig;pub use rationalize::rationalize_graph;pub use rationalize::unify_road_types;pub use roads_3d::ProceduralMesh;pub use roads_3d::RoadMeshConfig;pub use roads_3d::RoadMeshes;pub use roads_3d::SkirtConfig;pub use roads_3d::generate_road_meshes;pub use streaming::CityStreamer;pub use streaming::CityStreamerConfig;pub use streaming::CityTile;pub use tensor::TensorField;pub use tensor::TensorFieldConfig;pub use tracer::GenerationError;pub use tracer::GenerationStage;pub use tracer::TensorConfig;pub use tracer::generate_roads;
Modules§
- carve
- Heightmap carving for roads and building lots.
- geometry
- Low-level 2D geometry primitives used by the tracer and spatial hash.
- graph
- Arena-based road graph with soft-deletion support for edge splitting.
- lots
- Building lot extraction from city blocks.
- polygons
- City block extraction from the planar road graph.
- prune
- Road pruning via Steiner tree construction.
- rationalize
- Graph rationalization: straighten and smooth the road network.
- roads_
3d - Engine-agnostic 3D road mesh generation.
- spatial
- Spatial hash grid for fast proximity and intersection queries during tracing.
- streaming
- On-demand tile-based city streaming for unbounded worlds.
- tensor
- Tensor field derived from heightmap surface normals.
- topology
- Shared topology helpers for the road graph.
- tracer
- Streamline tracer — the core road generation algorithm.