Storm Sewer: interactive in-app network — snapping, tracked objects, analyze the drawing
Replaces the .ssn-file workflow with an interactive one driven by the canvas: - Structures (SS_INLET / SS_JUNCTION / SS_OUTFALL) prompt invert/rim/area/C on the command line and commit a CIRCLE tagged with STORMSEWER_STRUCT XDATA [kind, invert, rim, area, C]. Outfalls skip area/C. - SS_PIPE picks a START and END structure (entity-pick), snapping its endpoints to their centers, prompts diameter/n, and stores connectivity (the two structure handles) in STORMSEWER_PIPE XDATA [diameter, n, from, to]. - SS_ANALYZE / SS_REPORT / SS_PROFILE rebuild the network from the drawn entities (data.rs::network_from_entities) and analyze it directly; SS_ANALYZE overlays flow/HGL labels without redrawing the geometry. Because the data lives on the entities as XDATA, the network round-trips to DWG/DXF. One additive line in src/app/update.rs adds SS_PIPE to the inject_picked_entity allow-list so the command can read the picked structure's center for snapping. 15 module tests cover the XDATA round-trip, analyze-from-drawing, and the command step machines. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
9b44eb6400
commit
1e68219b43
7 changed files with 609 additions and 104 deletions
|
|
@ -14,6 +14,51 @@ use stormsewer::network::{Analysis, AnalysisOptions, Network, Node, Pipe};
|
|||
use stormsewer::parse::parse_ssn;
|
||||
use stormsewer::report::format_analysis;
|
||||
|
||||
use super::data;
|
||||
|
||||
/// Default network-level analysis parameters used when analyzing a drawn
|
||||
/// network (per-entity data carries geometry/area; rainfall is global).
|
||||
fn default_params() -> (IdfCurve, AnalysisOptions) {
|
||||
(IdfCurve::new(60.0, 10.0, 0.8), AnalysisOptions::default())
|
||||
}
|
||||
|
||||
/// Annotation labels only (flow + HGL), for overlaying on an already-drawn
|
||||
/// network without re-drawing its geometry.
|
||||
fn build_annotations(net: &Network, a: &Analysis) -> Vec<EntityType> {
|
||||
draw_network(net, a, &DrawConfig::default())
|
||||
.plan_labels
|
||||
.iter()
|
||||
.map(|l| label(l.x, l.y, l.text.clone(), l.height))
|
||||
.collect()
|
||||
}
|
||||
|
||||
// ── Public API: analyze the network drawn in the active document ────────────
|
||||
|
||||
/// Reconstruct the network from drawn entities, analyze it, and return
|
||||
/// annotation entities (flow/HGL labels) + the report.
|
||||
pub fn analyze_doc<'a>(entities: impl Iterator<Item = &'a EntityType>) -> Result<(Vec<EntityType>, String), String> {
|
||||
let net = data::network_from_entities(entities)?;
|
||||
let (idf, opts) = default_params();
|
||||
let a = run_analysis(&net, &idf, &opts)?;
|
||||
Ok((build_annotations(&net, &a), format_analysis(&a)))
|
||||
}
|
||||
|
||||
/// Reconstruct from drawn entities and return the HGL long-section entities.
|
||||
pub fn profile_doc<'a>(entities: impl Iterator<Item = &'a EntityType>) -> Result<Vec<EntityType>, String> {
|
||||
let net = data::network_from_entities(entities)?;
|
||||
let (idf, opts) = default_params();
|
||||
let a = run_analysis(&net, &idf, &opts)?;
|
||||
Ok(build_profile(&net, &a))
|
||||
}
|
||||
|
||||
/// Reconstruct from drawn entities and return the formatted report.
|
||||
pub fn report_doc<'a>(entities: impl Iterator<Item = &'a EntityType>) -> Result<String, String> {
|
||||
let net = data::network_from_entities(entities)?;
|
||||
let (idf, opts) = default_params();
|
||||
let a = run_analysis(&net, &idf, &opts)?;
|
||||
Ok(format_analysis(&a))
|
||||
}
|
||||
|
||||
/// The built-in demonstration network (properly sized, with plan coordinates).
|
||||
fn demo() -> (Network, IdfCurve, AnalysisOptions) {
|
||||
let net = Network {
|
||||
|
|
|
|||
Loading…
Reference in a new issue