Skip to main content

rfham_geo/grid/
mod.rs

1//! Trait abstractions for geographic grid locator systems.
2//!
3//! A *grid system* divides the Earth's surface into named cells. This module defines the
4//! three traits that every concrete grid system must implement:
5//!
6//! - [`GridIdentifier`] — a validated, string-like cell identifier (e.g. `"CN87"`).
7//! - [`GridPolygon`] — the bounding polygon and centroid for a grid cell.
8//! - [`GridSystem`] — the registry that converts identifiers or coordinates to polygons.
9//!
10//! Concrete implementations (e.g. Maidenhead / QTH locator) live in separate crates and
11//! depend on this module for the shared interface.
12//!
13//! # Implementing a grid system
14//!
15//! ```rust,ignore
16//! use rfham_geo::grid::{GridIdentifier, GridPolygon, GridSystem};
17//!
18//! struct MyId(String);
19//! // impl GridIdentifier for MyId { … }
20//!
21//! struct MyPoly { id: MyId, /* … */ }
22//! // impl GridPolygon for MyPoly { … }
23//!
24//! struct MySystem;
25//! // impl GridSystem for MySystem { … }
26//! ```
27
28use crate::error::GeoError;
29use lat_long::Coordinate;
30use rfham_core::Agency;
31use std::{fmt::Display, str::FromStr};
32
33// ------------------------------------------------------------------------------------------------
34// Public Types
35// ------------------------------------------------------------------------------------------------
36
37/// A validated string-like identifier for a single cell in a geographic grid system.
38///
39/// Identifiers must round-trip through `Display` / `FromStr` and can be constructed from
40/// a [`Coordinate`] via `TryFrom`.
41pub trait GridIdentifier:
42    Clone
43    + Display
44    + FromStr
45    + PartialEq
46    + Eq
47    + Into<String>
48    + AsRef<str>
49    + TryFrom<Coordinate, Error = GeoError>
50{
51    /// Returns `true` if `s` is a syntactically valid identifier for this grid system.
52    fn is_valid(s: &str) -> bool;
53
54    /// Returns the identifier as a `&str` slice.
55    fn as_str(&self) -> &str {
56        self.as_ref()
57    }
58}
59
60/// The bounding polygon and centroid of a single grid cell.
61pub trait GridPolygon: Clone + PartialEq + Eq + TryFrom<Self::Identifier> {
62    type Identifier: GridIdentifier;
63
64    /// Returns a reference to this cell's identifier.
65    fn id(&self) -> &Self::Identifier;
66
67    /// Returns the corner vertices of this cell in order.
68    fn vertices(&self) -> Vec<Coordinate>;
69
70    /// Returns the geographic centroid of this cell.
71    fn centroid(&self) -> Coordinate;
72}
73
74/// A grid system that can convert identifiers and coordinates to cell polygons.
75pub trait GridSystem: Default {
76    type Identifier: GridIdentifier;
77    type Poly: GridPolygon<Identifier = Self::Identifier>;
78
79    /// The human-readable name of this grid system (e.g. `"Maidenhead Locator System"`).
80    fn name(&self) -> &str;
81
82    /// The agency that defines or maintains this grid system.
83    fn defining_agency(&self) -> Agency;
84
85    /// Look up the polygon for a given cell identifier, returning `None` if not found.
86    fn lookup_id(&self, id: &Self::Identifier) -> Result<Option<Self::Poly>, GeoError>;
87
88    /// Look up the polygon for the cell that contains `point`.
89    ///
90    /// The default implementation converts the coordinate to an identifier and delegates
91    /// to [`lookup_id`](Self::lookup_id).
92    fn lookup_point(&self, point: &Coordinate) -> Result<Option<Self::Poly>, GeoError> {
93        self.lookup_id(&Self::Identifier::try_from(*point)?)
94    }
95}