Skip to main content

projective_grid/
expert.rs

1//! Expert composition surface for detector builders.
2//!
3//! Ordinary grid detection needs only the crate-root facade. This namespace
4//! exposes the smaller set of reusable policies and tuning types needed by a
5//! detector that adds pattern-specific admission, recovery, or validation.
6//! Its stage-shaped types may evolve more quickly than the stable facade.
7
8/// Expert orientation clustering primitives.
9pub mod orientation {
10    pub use crate::cluster::{
11        angular_dist_pi, cluster_axes, wrap_pi, AxisAssignment, AxisClusterCenters,
12        AxisClusterDebug, AxisFeature, AxisObservation, ClusterParams,
13    };
14    pub use crate::orient::{
15        synthesize_oriented2, synthesize_oriented2_from_oriented1, synthesize_oriented3,
16    };
17}
18
19/// Projective fitting helpers used by workspace geometry adapters.
20pub mod geometry {
21    pub use crate::geometry::*;
22}
23
24/// Lattice prediction and symmetry primitives.
25pub mod lattice {
26    use crate::GridEntry;
27
28    pub use crate::lattice::{
29        predict_grid_position, GridTransform, Hex, Lattice, PredictedPosition, Square,
30        D4_TRANSFORMS, D6_TRANSFORMS, HEX_AXIAL_OFFSETS, SQUARE_CARDINAL_OFFSETS,
31    };
32
33    /// Canonicalise square-grid coordinates while preserving entry provenance.
34    ///
35    /// This is intended for detector adapters that add or remove entries after
36    /// the generic detector has returned. Ordinary users should consume the
37    /// already-normalised [`crate::GridDetection`] instead.
38    pub fn normalize_square_entries(entries: Vec<GridEntry>) -> Vec<GridEntry> {
39        crate::result::LabelledGrid::normalized_square_entries(entries)
40    }
41}
42
43/// Square-topology assembly for pattern-specific detector builders.
44pub mod square {
45    use crate::{Coord, GridError, OrientedFeature};
46
47    use super::TopologicalParams;
48
49    /// One feature label at the topology/component-merge checkpoint.
50    #[derive(Clone, Copy, Debug, PartialEq, Eq)]
51    #[non_exhaustive]
52    pub struct ComponentEntry {
53        coord: Coord,
54        source_index: usize,
55    }
56
57    impl ComponentEntry {
58        /// Grid coordinate in the detector's axis-slot frame.
59        pub fn coord(&self) -> Coord {
60            self.coord
61        }
62
63        /// Caller-owned source index of the labelled feature.
64        pub fn source_index(&self) -> usize {
65            self.source_index
66        }
67    }
68
69    /// A merged square-grid component before validation, fit, and public
70    /// coordinate normalization.
71    #[derive(Clone, Debug, PartialEq, Eq)]
72    #[non_exhaustive]
73    pub struct Component {
74        entries: Vec<ComponentEntry>,
75    }
76
77    impl Component {
78        /// Labels ordered by `(v, u, source_index)` for deterministic
79        /// downstream processing.
80        pub fn entries(&self) -> &[ComponentEntry] {
81            &self.entries
82        }
83    }
84
85    /// Assemble `(Square, Oriented2)` evidence through topology walking and
86    /// local-geometry component merge.
87    ///
88    /// This is the narrow composition seam for target detectors that own
89    /// pattern-specific recovery or validation. Coordinates deliberately keep
90    /// the topological walk's axis-slot orientation; ordinary users should call
91    /// [`crate::detect_grid`] and consume its canonical coordinates instead.
92    pub fn assemble_oriented2_components(
93        features: &[OrientedFeature<2>],
94        params: &TopologicalParams,
95    ) -> Result<Vec<Component>, GridError> {
96        crate::topological::assemble_square_oriented2_components(features, params).map(
97            |components| {
98                components
99                    .into_iter()
100                    .map(|component| {
101                        let mut entries: Vec<ComponentEntry> = component
102                            .into_iter()
103                            .map(|(coord, feature_index)| ComponentEntry {
104                                coord,
105                                source_index: features[feature_index].point.source_index,
106                            })
107                            .collect();
108                        entries.sort_by_key(|entry| {
109                            (entry.coord.v, entry.coord.u, entry.source_index)
110                        });
111                        Component { entries }
112                    })
113                    .collect()
114            },
115        )
116    }
117}
118
119/// Labelled-component merge primitives.
120pub mod component {
121    pub use crate::shared::merge::{merge_components_local, LocalMergeParams};
122}
123
124/// Pattern-aware candidate attachment primitives.
125pub mod attachment {
126    pub use crate::shared::grow::{
127        Admit, FillEdgeCtx, GrowResult, LabelledNeighbour, SquareAttachPolicy,
128    };
129}
130
131/// Interior-hole fill primitives.
132pub mod fill {
133    pub use crate::shared::fill::{fill_grid_holes, FillParams, FillStats};
134}
135
136/// Drop-only structural validation primitives.
137pub mod validation {
138    pub use crate::shared::validate::{
139        validate, LabelledEntry, ValidationParams, ValidationResult,
140    };
141
142    /// Direct wrong-label and connected-component filters.
143    pub mod wrong_label_filters {
144        pub use crate::shared::validate::wrong_label_filters::{drop_set, DropSet};
145    }
146}
147
148pub use crate::detect::DetectionTuning;
149pub use crate::shared::recovery_schedule::{RecoveryParams, RecoverySchedule};
150pub use crate::topological::TopologicalParams;