use nalgebra::{Matrix3, Point2, Vector3};
use projective_grid::{
detect_grid, DetectionParams, DetectionRequest, Evidence, LatticeKind, PointFeature,
};
fn hex_model(q: i32, r: i32) -> Point2<f32> {
let sqrt3_2 = 3.0_f32.sqrt() * 0.5;
Point2::new(q as f32 + 0.5 * r as f32, sqrt3_2 * r as f32)
}
fn main() -> Result<(), Box<dyn std::error::Error>> {
let h = Matrix3::new(
1.0, 0.10, 0.0, 0.03, 1.0, 0.0, 0.0006, 0.0004, 1.0,
);
let project = |m: Point2<f32>| -> Point2<f32> {
let v = h * Vector3::new(m.x, m.y, 1.0);
Point2::new(v.x / v.z, v.y / v.z)
};
let (radius, pitch, origin) = (4_i32, 28.0_f32, 200.0_f32);
let mut features: Vec<PointFeature> = Vec::new();
let mut truth: Vec<(i32, i32)> = Vec::new();
for q in -radius..=radius {
for r in (-radius).max(-q - radius)..=radius.min(-q + radius) {
let m = hex_model(q, r);
let p = project(Point2::new(m.x * pitch + origin, m.y * pitch + origin));
features.push(PointFeature::new(features.len(), p));
truth.push((q, r));
}
}
let request = DetectionRequest::new(
LatticeKind::Hex,
Evidence::Positions(&features),
None, DetectionParams::default(),
);
let solution = detect_grid(request)?;
println!(
"input nodes: {} labelled: {} fit max residual: {:.4} px",
features.len(),
solution.grid.entries.len(),
solution
.fit
.as_ref()
.map(|f| f.residuals.max_px)
.unwrap_or(f32::NAN),
);
println!();
println!("detected (q, r) <- feature (true (q, r))");
let mut entries = solution.grid.entries.clone();
entries.sort_by_key(|e| (e.coord.v, e.coord.u));
for e in &entries {
let (tq, tr) = truth[e.source_index];
println!(
" ({:>2}, {:>2}) <- #{:<3} (true ({:>2}, {:>2}))",
e.coord.u, e.coord.v, e.source_index, tq, tr
);
}
Ok(())
}