浏览代码

coord: Add some conversions and tests

Johannes Hofmann 7 年前
父节点
当前提交
f5f4e00d26
共有 1 个文件被更改,包括 83 次插入1 次删除
  1. 83
    1
      src/coord.rs

+ 83
- 1
src/coord.rs 查看文件

@@ -17,9 +17,16 @@ impl LatLon {
17 17
     pub fn new(lat: f64, lon: f64) -> Self {
18 18
         LatLon { lat, lon }
19 19
     }
20
+
21
+    pub fn to_radians(&self) -> LatLonRad {
22
+        let f = PI / 180.0;
23
+        LatLonRad {
24
+            lat: self.lat * f,
25
+            lon: self.lon * f,
26
+        }
27
+    }
20 28
 }
21 29
 
22
-//TODO Add more conversions from/to LatLonRad
23 30
 /// A position in latitude, longitude.
24 31
 /// Values are in radians and usually in these intervals:
25 32
 /// latitude: [-0.5 * π, 0.5 * π]
@@ -35,6 +42,14 @@ impl LatLonRad {
35 42
         LatLonRad { lat, lon }
36 43
     }
37 44
 
45
+    pub fn to_degrees(&self) -> LatLon {
46
+        let f = 180.0 * FRAC_1_PI;
47
+        LatLon {
48
+            lat: self.lat * f,
49
+            lon: self.lon * f,
50
+        }
51
+    }
52
+
38 53
     pub fn to_sphere_xyz(&self, radius: f64) -> SphereXYZ {
39 54
         SphereXYZ {
40 55
             x: radius * self.lat.cos() * self.lon.cos(),
@@ -80,6 +95,18 @@ impl From<LatLon> for MapCoord
80 95
         let x = pos.lon * (1.0 / 360.0) + 0.5;
81 96
         let pi_lat = pos.lat * (PI / 180.0);
82 97
         let y = f64::ln(f64::tan(pi_lat) + 1.0 / f64::cos(pi_lat)) * (-0.5 * FRAC_1_PI) + 0.5;
98
+        debug_assert!(y.is_finite());
99
+
100
+        MapCoord { x, y }
101
+    }
102
+}
103
+
104
+impl From<LatLonRad> for MapCoord
105
+{
106
+    fn from(pos: LatLonRad) -> MapCoord {
107
+        let x = pos.lon * (0.5 * FRAC_1_PI) + 0.5;
108
+        let y = f64::ln(f64::tan(pos.lat) + 1.0 / f64::cos(pos.lat)) * (-0.5 * FRAC_1_PI) + 0.5;
109
+        debug_assert!(y.is_finite());
83 110
 
84 111
         MapCoord { x, y }
85 112
     }
@@ -118,6 +145,13 @@ impl MapCoord {
118 145
             lon: self.x * (2.0 * PI) - PI,
119 146
         }
120 147
     }
148
+
149
+    pub fn to_latlon_deg(&self) -> LatLon {
150
+        LatLon {
151
+            lat: (PI - self.y * (2.0 * PI)).sinh().atan() * (180.0 * FRAC_1_PI),
152
+            lon: self.x * 360.0 - 180.0,
153
+        }
154
+    }
121 155
 }
122 156
 
123 157
 /// A position on the screen in pixels. Top-left corner is (0.0, 0.0).
@@ -424,4 +458,52 @@ mod tests {
424 458
         assert_eq!(TileCoord::new(3, 1, 0).to_quadkey(), Some("001".to_string()));
425 459
         assert_eq!(TileCoord::new(30, 0, 1).to_quadkey(), Some("000000000000000000000000000002".to_string()));
426 460
     }
461
+
462
+    fn approx_eq(a: f64, b: f64) -> bool {
463
+        (a - b).abs() < 1e-10
464
+    }
465
+
466
+    #[test]
467
+    fn approx_eq_test() {
468
+        assert!(approx_eq(1.0, 1.0));
469
+        assert!(approx_eq(0.0, 0.0));
470
+        assert!(approx_eq(0.0, -0.0));
471
+        assert!(approx_eq(1e20, 1e20 + 1.0));
472
+        assert!(approx_eq(1e20, 1e20 - 1.0));
473
+        assert!(!approx_eq(1000.0, 1000.1));
474
+    }
475
+
476
+    #[test]
477
+    fn degree_radians() {
478
+        {
479
+            let rad = LatLon::new(0.0, 0.0).to_radians();
480
+            assert!(approx_eq(rad.lat, 0.0));
481
+            assert!(approx_eq(rad.lon, 0.0));
482
+            let deg = rad.to_degrees();
483
+            assert!(approx_eq(deg.lat, 0.0));
484
+            assert!(approx_eq(deg.lon, 0.0));
485
+        }
486
+        {
487
+            let rad = LatLon::new(-45.0, 180.0).to_radians();
488
+            assert!(approx_eq(rad.lat, -PI / 4.0));
489
+            assert!(approx_eq(rad.lon, PI));
490
+            let deg = rad.to_degrees();
491
+            assert!(approx_eq(deg.lat, -45.0));
492
+            assert!(approx_eq(deg.lon, 180.0));
493
+        }
494
+
495
+        {
496
+            let mc = MapCoord::from(LatLon::new(23.45, 123.45));
497
+            let deg = mc.to_latlon_rad().to_degrees();
498
+            assert!(approx_eq(deg.lat, 23.45));
499
+            assert!(approx_eq(deg.lon, 123.45));
500
+        }
501
+
502
+        {
503
+            let mc = MapCoord::from(LatLonRad::new(-0.345 * PI, -0.987 * PI));
504
+            let rad = mc.to_latlon_deg().to_radians();
505
+            assert!(approx_eq(rad.lat, -0.345 * PI));
506
+            assert!(approx_eq(rad.lon, -0.987 * PI));
507
+        }
508
+    }
427 509
 }