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}