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}