1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
//! Core coordinate types and transformation traits.
use crate::error::Result;
/// A 2D coordinate pair (x, y or lon, lat or easting, northing).
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Point2D {
/// First component (x, easting, or longitude in degrees).
pub x: f64,
/// Second component (y, northing, or latitude in degrees).
pub y: f64,
}
impl Point2D {
/// Create a new 2D point.
pub fn new(x: f64, y: f64) -> Self {
Point2D { x, y }
}
/// Interpret this point as (longitude, latitude) in degrees.
pub fn lonlat(lon: f64, lat: f64) -> Self {
Point2D { x: lon, y: lat }
}
/// Return the coordinates as a tuple (x, y).
pub fn to_tuple(self) -> (f64, f64) {
(self.x, self.y)
}
}
impl From<(f64, f64)> for Point2D {
fn from((x, y): (f64, f64)) -> Self {
Point2D::new(x, y)
}
}
impl From<Point2D> for (f64, f64) {
fn from(p: Point2D) -> Self {
(p.x, p.y)
}
}
impl std::fmt::Display for Point2D {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({:.6}, {:.6})", self.x, self.y)
}
}
/// A 3D coordinate (x, y, z or lon, lat, height).
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct Point3D {
/// X or longitude.
pub x: f64,
/// Y or latitude.
pub y: f64,
/// Z or ellipsoidal height.
pub z: f64,
}
impl Point3D {
/// Create a new 3D point.
pub fn new(x: f64, y: f64, z: f64) -> Self {
Point3D { x, y, z }
}
/// Return the 2D part.
pub fn xy(&self) -> Point2D {
Point2D::new(self.x, self.y)
}
}
impl From<(f64, f64, f64)> for Point3D {
fn from((x, y, z): (f64, f64, f64)) -> Self {
Point3D::new(x, y, z)
}
}
/// A coordinate transformation that converts between two coordinate systems.
pub trait CoordTransform {
/// Transform a single point forward.
fn transform_fwd(&self, point: Point2D) -> Result<Point2D>;
/// Transform a single point inverse.
fn transform_inv(&self, point: Point2D) -> Result<Point2D>;
/// Transform a slice of points forward in-place.
fn transform_fwd_many(&self, points: &mut [Point2D]) -> Vec<Result<()>> {
points
.iter_mut()
.map(|p| {
let result = self.transform_fwd(*p)?;
*p = result;
Ok(())
})
.collect()
}
/// Transform a slice of points inverse in-place.
fn transform_inv_many(&self, points: &mut [Point2D]) -> Vec<Result<()>> {
points
.iter_mut()
.map(|p| {
let result = self.transform_inv(*p)?;
*p = result;
Ok(())
})
.collect()
}
}