4
0
Эх сурвалжийг харах

Calculate altitudes in LOC records

The RFC specifies that altitudes in LOC records are offset by 100,000m, which is now taken into account when displaying them.
Benjamin Sago 4 жил өмнө
parent
commit
d5692e8d6e
2 өөрчлөгдсөн 68 нэмэгдсэн , 5 устгасан
  1. 67 4
      dns/src/record/loc.rs
  2. 1 1
      src/output.rs

+ 67 - 4
dns/src/record/loc.rs

@@ -36,7 +36,7 @@ pub struct LOC {
 
     /// The altitude of the centre of the sphere, measured in centimetres
     /// above a base of 100,000 metres below the GPS reference spheroid.
-    pub altitude: u32,
+    pub altitude: Altitude,
 }
 
 /// A measure of size, in centimetres, represented by a base and an exponent.
@@ -56,6 +56,13 @@ pub struct Position {
     direction: Direction,
 }
 
+/// A position on the vertical axis.
+#[derive(PartialEq, Debug, Copy, Clone)]
+pub struct Altitude {
+    metres: i64,
+    centimetres: i64,
+}
+
 /// One of the directions a position could be in, relative to the equator or
 /// prime meridian.
 #[derive(PartialEq, Debug, Copy, Clone)]
@@ -105,8 +112,9 @@ impl Wire for LOC {
         let longitude = Position::from_u32(longitude_num, false);
         trace!("Parsed longitude -> {:?} ({:?})", longitude_num, longitude);
 
-        let altitude = c.read_u32::<BigEndian>()?;
-        trace!("Parsed altitude -> {:?}", altitude);
+        let altitude_num = c.read_u32::<BigEndian>()?;
+        let altitude = Altitude::from_u32(altitude_num);
+        trace!("Parsed altitude -> {:?} ({:})", altitude_num, altitude);
 
         Ok(Self {
             size, horizontal_precision, vertical_precision, latitude, longitude, altitude,
@@ -170,6 +178,17 @@ impl Position {
     }
 }
 
+impl Altitude {
+    fn from_u32(input: u32) -> Self {
+        let mut input = i64::from(input);
+        input -= 100_000_00;  // 100,000m
+        let metres = input / 100;
+        let centimetres = input % 100;
+        Self { metres, centimetres }
+    }
+}
+
+
 impl fmt::Display for Size {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
         write!(f, "{}e{}", self.base, self.power_of_ten)
@@ -203,6 +222,19 @@ impl fmt::Display for Direction {
     }
 }
 
+impl fmt::Display for Altitude {
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        // Usually there's a space between the number and the unit, but
+        // spaces are already used to delimit segments in the record summary
+        if self.centimetres == 0 {
+            write!(f, "{}m", self.metres)
+        }
+        else {
+            write!(f, "{}.{:02}m", self.metres, self.centimetres)
+        }
+    }
+}
+
 
 #[cfg(test)]
 mod test {
@@ -228,7 +260,7 @@ mod test {
                        vertical_precision: 0,
                        latitude:  Position::from_u32(0x_8b_0d_2c_8c, true),
                        longitude: Position::from_u32(0x_7f_f8_fc_a5, false),
-                       altitude:  0x_00_98_96_80,
+                       altitude:  Altitude::from_u32(0x_00_98_96_80),
                    });
     }
 
@@ -427,3 +459,34 @@ mod position_test {
                    None);
     }
 }
+
+
+#[cfg(test)]
+mod altitude_test {
+    use super::*;
+    use pretty_assertions::assert_eq;
+
+    #[test]
+    fn base_level() {
+        assert_eq!(Altitude::from_u32(10000000).to_string(),
+                   String::from("0m"));
+    }
+
+    #[test]
+    fn up_high() {
+        assert_eq!(Altitude::from_u32(20000000).to_string(),
+                   String::from("100000m"));
+    }
+
+    #[test]
+    fn down_low() {
+        assert_eq!(Altitude::from_u32(0).to_string(),
+                   String::from("-100000m"));
+    }
+
+    #[test]
+    fn with_decimal() {
+        assert_eq!(Altitude::from_u32(50505050).to_string(),
+                   String::from("405050.50m"));
+    }
+}

+ 1 - 1
src/output.rs

@@ -401,7 +401,7 @@ fn json_record(record: &Record) -> JsonValue {
                 "point": {
                     "latitude": rec.latitude.map(|e| e.to_string()),
                     "longitude": rec.longitude.map(|e| e.to_string()),
-                    "altitude": rec.altitude,
+                    "altitude": rec.altitude.to_string(),
                 },
             })
         }