//! PERF-2 P1 (`docs/perf2_campaign.md`): the chunked polyline index used //! by the O-grid's sliding outer ring must return the brute-force scan's //! point BIT FOR BIT — the recorded marches are gated on digit identity. //! The polygon is the shape the ring sees: a convex hull offset sampled //! 24 points per corner (a rounded cylinder + flag outline, ~3,000 //! points); the queries sit inside, on and outside it, and on a lattice //! whose points fall exactly on vertices and segment mid-points (ties). use rtx_cfd::mesh::patch_gen::{PolylineIndex, nearest_on_polyline}; use std::f64::consts::PI; /// A rounded "cylinder + flag" convex outline: a circle of radius 0.05 at /// the origin joined to a rectangle to x = 0.4, corners rounded with /// radius 0.06 sampled 24 per corner, plus fine sampling on the arcs. fn outline() -> Vec<[f64; 2]> { let mut pts = Vec::new(); // Left semicircle (the cylinder side), 256 points. for m in 0..256 { let th = PI / 2.0 + PI * m as f64 / 255.0; pts.push([0.11 * th.cos(), 0.11 * th.sin()]); } // Bottom edge to the tip, 1,200 points. for m in 1..1200 { pts.push([-0.0 + 0.46 * m as f64 / 1200.0, -0.11]); } // Right rounded end, 512 points. for m in 0..512 { let th = -PI / 2.0 + PI * m as f64 / 511.0; pts.push([0.46 + 0.11 * th.cos(), 0.11 * th.sin()]); } // Top edge back, 1,200 points. for m in 1..1200 { pts.push([0.46 - 0.46 * m as f64 / 1200.0, 0.11]); } pts } #[test] fn indexed_nearest_point_is_the_brute_force_point_bit_for_bit() { let pts = outline(); let index = PolylineIndex::new(&pts); let mut queries: Vec<[f64; 2]> = Vec::new(); // A lattice through the whole region (inside, on, outside). for i in 0..120 { for j in 0..60 { queries.push([-0.2 + 0.8 * i as f64 / 119.0, -0.25 + 0.5 * j as f64 / 59.0]); } } // Every vertex, every segment mid-point, and points pushed off them. let n = pts.len(); for i in 0..n { let (a, b) = (pts[i], pts[(i + 1) % n]); queries.push(a); queries.push([0.5 * (a[0] + b[0]), 0.5 * (a[1] + b[1])]); queries.push([a[0] * 1.3, a[1] * 1.3]); queries.push([a[0] * 0.7 + 0.01, a[1] * 0.7]); } // A deterministic pseudo-random cloud. let mut state = 0x9e37_79b9_7f4a_7c15_u64; for _ in 0..20_000 { state ^= state << 13; state ^= state >> 7; state ^= state << 17; let u = (state >> 11) as f64 / (1u64 << 53) as f64; state ^= state << 13; state ^= state >> 7; state ^= state << 17; let v = (state >> 11) as f64 / (1u64 << 53) as f64; queries.push([-0.3 + 1.0 * u, -0.3 + 0.6 * v]); } let mut mismatches = 0; for &q in &queries { let a = nearest_on_polyline(&pts, q); let b = index.nearest(q); if a[0].to_bits() != b[0].to_bits() || a[1].to_bits() != b[1].to_bits() { mismatches += 1; if mismatches < 5 { eprintln!("mismatch at q = {q:?}: brute {a:?} vs index {b:?}"); } } } println!( " polyline index: {} points, {} chunks tested over {} queries, {mismatches} mismatches", pts.len(), pts.len().div_ceil(32), queries.len() ); assert_eq!(mismatches, 0); }