Skip to main content

n3gb_rs/coord/
mod.rs

1mod bng_transformations;
2
3pub(crate) use bng_transformations::{
4    convert_line_to_bng, convert_multipolygon_to_bng, convert_polygon_to_bng, convert_to_bng,
5};
6
7use geo_types::Point;
8
9/// Coordinate reference system for input geometry data.
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
11pub enum Crs {
12    /// WGS84 (EPSG:4326) - longitude/latitude coordinates
13    #[default]
14    Wgs84,
15    /// British National Grid (EPSG:27700) - easting/northing coordinates
16    Bng,
17}
18
19/// Which backend to use when converting WGS84 coordinates to BNG.
20///
21/// When PROJ grid files are installed both methods agree to within ~1mm.
22/// The difference matters when grid files are absent:
23///
24/// | Scenario | `Proj` | `Ostn15` |
25/// |---|---|---|
26/// | PROJ + grid files installed | ~1mm | ~1mm |
27/// | PROJ installed, no grid files | ~5m (silent!) | ~1mm |
28/// | PROJ not installed | build fails | ~1mm |
29///
30/// `Ostn15` is the safer default for libraries — accuracy is guaranteed
31/// regardless of what the user has installed on their system.
32#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
33pub enum ConversionMethod {
34    /// Use the `lonlat_bng` crate with OSTN15 data embedded at compile time.
35    ///
36    /// Always ~1mm accurate. No system dependencies.
37    #[default]
38    Ostn15,
39    /// Use the `proj` system library (equivalent to pyproj).
40    ///
41    /// Requires `libproj` and the `uk_os_OSTN15_NTv2_OSGBtoETRS.tif` grid file.
42    /// Without the grid file PROJ silently falls back to a ~5m Helmert transform.
43    Proj,
44}
45
46/// Trait for types that can provide x/y coordinates.
47///
48/// Implemented for `(f64, f64)` tuples and `geo_types::Point<f64>`.
49/// This allows functions to accept either type.
50pub trait Coordinate {
51    /// Returns the x-coordinate (easting or longitude).
52    ///
53    /// # Returns
54    /// The x-coordinate (easting or longitude).
55    fn x(&self) -> f64;
56    /// Returns the y-coordinate (northing or latitude).
57    ///
58    /// # Returns
59    /// The y-coordinate (northing or latitude).
60    fn y(&self) -> f64;
61}
62
63impl Coordinate for (f64, f64) {
64    /// Returns the x-coordinate (first tuple element).
65    ///
66    /// # Returns
67    /// The first element of the tuple.
68    fn x(&self) -> f64 {
69        self.0
70    }
71    /// Returns the y-coordinate (second tuple element).
72    ///
73    /// # Returns
74    /// The second element of the tuple.
75    fn y(&self) -> f64 {
76        self.1
77    }
78}
79
80impl Coordinate for Point<f64> {
81    /// Returns the x-coordinate of the point.
82    ///
83    /// # Returns
84    /// The point's x-coordinate.
85    fn x(&self) -> f64 {
86        Point::x(*self)
87    }
88    /// Returns the y-coordinate of the point.
89    ///
90    /// # Returns
91    /// The point's y-coordinate.
92    fn y(&self) -> f64 {
93        Point::y(*self)
94    }
95}
96
97#[cfg(test)]
98mod tests {
99    use super::*;
100
101    #[test]
102    fn test_coordinate_trait_tuple() {
103        let tuple = (100.0, 200.0);
104        assert_eq!(tuple.x(), 100.0);
105        assert_eq!(tuple.y(), 200.0);
106    }
107
108    #[test]
109    fn test_coordinate_trait_point() {
110        let point = Point::new(100.0, 200.0);
111        assert_eq!(point.x(), 100.0);
112        assert_eq!(point.y(), 200.0);
113    }
114
115    #[test]
116    fn test_crs_enum_default() {
117        assert_eq!(Crs::default(), Crs::Wgs84);
118    }
119}