facett-flow/tests/large_scene.rs
//! Explicit large-scene acceptance, not a benchmark or a performance threshold.
//! Run with `--features hit-test --test large_scene -- --ignored --nocapture`.
#![cfg(feature = "hit-test")]
use facett_flow::{Edge, FlowScene, Graph, Hit};
use std::time::Instant;
#[test]
#[ignore = "allocates a one-million-node graph; run explicitly for large-scene acceptance"]
fn million_nodes_report_node_edge_and_miss_candidates() {
let start = Instant::now();
let mut graph = Graph::demo(1_000_000);
// Two sentinel nodes sit outside the dense five-stage fixture, so the expected
// edge hit cannot accidentally be a neighbouring node. Retain all original
// node/edge counts; only positions and one valid edge are changed.
graph.nodes[0].position = [-1_000.0, -1_000.0];
graph.nodes[1].position = [-600.0, -800.0];
graph.edges[0] = Edge {
from: graph.nodes[0].id.clone(),
to: graph.nodes[1].id.clone(),
};
let fixture_ms = start.elapsed().as_secs_f64() * 1000.0;
let start = Instant::now();
let scene = FlowScene::with_key(graph, 1_000_000).unwrap();
let scene_ms = start.elapsed().as_secs_f64() * 1000.0;
assert_eq!(scene.graph().nodes.len(), 1_000_000);
assert_eq!(scene.graph().edges.len(), 1_600_000);
let cases = [
("node", egui::pos2(-1_000.0, -1_000.0), Some(Hit::Node(0))),
(
"edge",
scene.edge_point(0, 0.5).unwrap(),
Some(Hit::Edge(0)),
),
("miss", egui::pos2(-5_000.0, -5_000.0), None),
];
let queries: Vec<_> = cases
.into_iter()
.map(|(name, point, expected)| {
let start = Instant::now();
let (hit, candidates) = scene.hit_with_candidates(point, 0.5);
let query_us = start.elapsed().as_secs_f64() * 1_000_000.0;
assert_eq!(hit, expected, "{name} query");
serde_json::json!({
"case":name,"hit":format!("{hit:?}"),"candidates_tested":candidates,
"edge_bounds_scanned":if name == "node" {0}else{scene.graph().edges.len()},
"query_us":query_us,
})
})
.collect();
println!(
"{}",
serde_json::json!({
"fixture":"five-stage demo plus isolated two-node sentinel edge",
"nodes":scene.graph().nodes.len(),"edges":scene.graph().edges.len(),
"build":if cfg!(debug_assertions){"debug"}else{"release"},
"fixture_ms":fixture_ms,"scene_ms":scene_ms,"queries":queries,
"interpretation":"Single local correctness run. Candidates count exact node/curve tests after bounds filtering; edge queries still scan every edge bound. No speed threshold or optimization claim.",
})
);
}