Skip to main content

proj_core/
coord.rs

1/// A 2D coordinate.
2///
3/// At the public API boundary, units match the CRS:
4/// - **Geographic CRS**: degrees (x = longitude, y = latitude)
5/// - **Projected CRS**: meters (x = easting, y = northing)
6#[derive(Debug, Clone, Copy, PartialEq)]
7pub struct Coord {
8    pub x: f64,
9    pub y: f64,
10}
11
12impl Coord {
13    pub fn new(x: f64, y: f64) -> Self {
14        Self { x, y }
15    }
16}
17
18impl From<(f64, f64)> for Coord {
19    fn from((x, y): (f64, f64)) -> Self {
20        Self { x, y }
21    }
22}
23
24impl From<Coord> for (f64, f64) {
25    fn from(c: Coord) -> Self {
26        (c.x, c.y)
27    }
28}
29
30#[cfg(feature = "geo-types")]
31impl From<geo_types::Coord<f64>> for Coord {
32    fn from(c: geo_types::Coord<f64>) -> Self {
33        Self { x: c.x, y: c.y }
34    }
35}
36
37#[cfg(feature = "geo-types")]
38impl From<Coord> for geo_types::Coord<f64> {
39    fn from(c: Coord) -> Self {
40        geo_types::Coord { x: c.x, y: c.y }
41    }
42}
43
44/// Trait for types that can be transformed through a [`Transform`](crate::Transform).
45///
46/// The transform returns the same type as the input, so `geo_types::Coord<f64>` in
47/// gives `geo_types::Coord<f64>` out, and `(f64, f64)` in gives `(f64, f64)` out.
48pub trait Transformable: Sized {
49    fn into_coord(self) -> Coord;
50    fn from_coord(c: Coord) -> Self;
51}
52
53impl Transformable for Coord {
54    fn into_coord(self) -> Coord {
55        self
56    }
57    fn from_coord(c: Coord) -> Self {
58        c
59    }
60}
61
62impl Transformable for (f64, f64) {
63    fn into_coord(self) -> Coord {
64        Coord {
65            x: self.0,
66            y: self.1,
67        }
68    }
69    fn from_coord(c: Coord) -> Self {
70        (c.x, c.y)
71    }
72}
73
74#[cfg(feature = "geo-types")]
75impl Transformable for geo_types::Coord<f64> {
76    fn into_coord(self) -> Coord {
77        Coord {
78            x: self.x,
79            y: self.y,
80        }
81    }
82    fn from_coord(c: Coord) -> Self {
83        geo_types::Coord { x: c.x, y: c.y }
84    }
85}
86
87#[cfg(test)]
88mod tests {
89    use super::*;
90
91    #[test]
92    fn coord_from_tuple() {
93        let c: Coord = (1.0, 2.0).into();
94        assert_eq!(c.x, 1.0);
95        assert_eq!(c.y, 2.0);
96    }
97
98    #[test]
99    fn tuple_from_coord() {
100        let t: (f64, f64) = Coord::new(3.0, 4.0).into();
101        assert_eq!(t, (3.0, 4.0));
102    }
103
104    #[test]
105    fn transformable_roundtrip_tuple() {
106        let original = (10.0, 20.0);
107        let coord = original.into_coord();
108        let back = <(f64, f64)>::from_coord(coord);
109        assert_eq!(original, back);
110    }
111}