Skip to main content

projective_grid/
lib.rs

1//! Generic 2D projective grid construction and homography tools.
2//!
3//! This crate turns a cloud of 2D points into a labelled grid.
4//!
5//! # Start here: [`detect_regular_grid`]
6//!
7//! [`detect_regular_grid`] is the zero-config onboarding entry point.
8//! Hand it a `&[Point2<f32>]`; it returns a [`RegularGridDetection`]
9//! with every recovered corner carrying its `(i, j)` label and the
10//! index back into your input slice — **no caller-written validator
11//! scaffolding required**:
12//!
13//! ```rust
14//! use nalgebra::Point2;
15//! use projective_grid::detect_regular_grid;
16//!
17//! let mut points = Vec::new();
18//! for j in 0..4 {
19//!     for i in 0..5 {
20//!         points.push(Point2::new(i as f32 * 30.0, j as f32 * 30.0));
21//!     }
22//! }
23//! let grid = detect_regular_grid(&points).expect("clean grid detects");
24//! assert_eq!(grid.points.len(), 20);
25//! ```
26//!
27//! For tuning, use [`RegularGridDetector`] + [`RegularGridParams`].
28//! The detector internally estimates the cell size and grid axes from
29//! the point cloud and drives the pipeline with a built-in open
30//! regular-grid policy.
31//!
32//! # Advanced / specialized entry points
33//!
34//! When you need pattern-specific rules (parity, marker slots, colour
35//! splits), reach for the validator-driven path:
36//!
37//! - [`detect_square_grid`] — square-lattice recovery driven by a
38//!   caller-supplied [`SeedQuadValidator`] + [`GrowValidator`] pair.
39//!   This is what the chessboard / ChArUco / puzzleboard detectors
40//!   build on. [`detect_regular_grid`] is a thin wrapper over it with
41//!   a built-in permissive policy.
42//! - [`detect_topological_grid`] — Shu/Brunton/Fiala 2009 topological
43//!   recovery, image-free. Requires per-corner grid axes inline on
44//!   the input via [`TopologicalInputCorner`].
45//!
46//! [`SeedQuadValidator`]: square::seed::finder::SeedQuadValidator
47//! [`GrowValidator`]: square::grow::GrowValidator
48//!
49//! All entry points share a common output shape: a `(i, j) →
50//! corner_idx` map plus per-stage diagnostics. Use
51//! [`merge_components_local`] to attempt to merge multiple
52//! disjoint components into a single grid.
53//!
54//! The crate is pattern-agnostic — it knows nothing about chessboards,
55//! ArUco markers, or images. Lower-level primitives (KD-tree,
56//! circular stats, mean-shift, DLT homography, BFS grow, Delaunay
57//! triangulation) are exposed under their natural modules for callers
58//! who want to compose their own pipeline.
59//!
60//! # Module layout
61//!
62//! | Module | Responsibility |
63//! |---|---|
64//! | [`square::regular`] | Zero-config point-cloud regular-grid detection (onboarding entry point) |
65//! | `square::cleanup` | Generic output cleanup (private; used internally) |
66//! | [`square::grow`] | Seed-and-grow BFS over a square lattice |
67//! | [`square::extension`] | Boundary extension via globally-fit or local homography |
68//! | [`square::seed`] | 2×2 seed primitives (cell size, midpoint violation) |
69//! | [`square::validate`](mod@square::validate) | Post-grow line / local-H residual checks |
70//! | [`square::mesh`] / [`square::rectify`] | Per-cell mesh / global homography rectification |
71//! | [`square::smoothness`] | Midpoint prediction + step-aware outlier detection |
72//! | [`square::alignment`] | D4 transforms on integer grid coordinates |
73//! | [`hex`] | Hex grid: alignment, mesh, rectify, smoothness (no grow path yet) |
74//! | [`circular_stats`] | Undirected-angle helpers (smoothing, plateau peak picking, double-angle 2-means) |
75//! | [`global_step`] / [`local_step`] | Cell-size estimation primitives |
76//! | [`homography`] | 4-point + DLT homography with reprojection-quality diagnostics |
77#![deny(missing_docs)]
78
79mod float_helpers;
80
81pub mod affine;
82pub mod circular_stats;
83pub mod component_merge;
84pub mod global_step;
85pub mod hex;
86pub mod homography;
87pub mod local_step;
88pub mod square;
89pub mod topological;
90
91/// Trait alias for floating-point types supported by this crate.
92///
93/// Both `f32` and `f64` satisfy this bound. All public generic types default
94/// to `f32` for backward compatibility.
95pub trait Float: nalgebra::RealField + Copy {}
96impl<T: nalgebra::RealField + Copy> Float for T {}
97
98// --- Generic building blocks (no square / hex assumption) --------------------
99pub use affine::AffineTransform2D;
100pub use global_step::{estimate_global_cell_size, GlobalStepEstimate, GlobalStepParams};
101pub use homography::{
102    estimate_homography, estimate_homography_with_quality, homography_from_4pt,
103    homography_from_4pt_with_quality, Homography, HomographyQuality,
104};
105pub use local_step::{estimate_local_steps, LocalStep, LocalStepParams, LocalStepPointData};
106
107// --- Square-grid surface re-exported at the crate root --------
108pub use square::alignment::{GridAlignment, GridTransform, GRID_TRANSFORMS_D4};
109pub use square::index::GridCoords;
110pub use square::mesh::SquareGridHomographyMesh;
111pub use square::rectify::SquareGridHomography;
112pub use square::smoothness::{
113    square_find_inconsistent_corners, square_find_inconsistent_corners_step_aware,
114    square_predict_grid_position,
115};
116
117// --- Square-grid onboarding entry point ----------------------
118pub use square::regular::{
119    detect_regular_grid, DetectedGridPoint, RegularGridDetection, RegularGridDetector,
120    RegularGridError, RegularGridParams, RegularGridStats,
121};
122
123// --- Square-grid validator-driven (advanced) entry points ----
124pub use square::detect::{
125    detect_square_grid, detect_square_grid_all, ExtensionStrategy, MultiComponentParams,
126    SquareGridDetection, SquareGridParams, SquareGridStats,
127};
128
129// --- Topological-grid surface --------------------------------
130pub use topological::{
131    build_grid_topological, detect_topological_grid, recover_topological_grid, AxisClusterCenters,
132    AxisEstimate, TopologicalComponent, TopologicalError, TopologicalGrid, TopologicalInputCorner,
133    TopologicalParams, TopologicalStats, TriangleClass,
134};
135
136// --- Component merge (shared by both pipelines) --------------
137pub use component_merge::{
138    merge_components_local, ComponentInput, ComponentMergeResult, ComponentMergeStats,
139    LocalMergeParams,
140};