sct_reader/loaders/euroscope/
waypoint.rs

1use std::fmt::Display;
2
3use super::{
4    position::{Heading, Position, Valid},
5    AirspaceClass,
6};
7
8pub trait Waypoint {
9    fn identifier(&self) -> &String;
10    fn position(&self) -> Position<Valid>;
11}
12
13#[derive(Debug, Clone)]
14pub struct Fix {
15    pub identifier: String,
16    pub position: Position<Valid>,
17}
18impl Waypoint for Fix {
19    fn identifier(&self) -> &String {
20        &self.identifier
21    }
22    fn position(&self) -> Position<Valid> {
23        self.position
24    }
25}
26
27#[derive(Debug, Clone)]
28pub struct Vor {
29    pub identifier: String,
30    pub position: Position<Valid>,
31    pub frequency: String,
32}
33impl Waypoint for Vor {
34    fn identifier(&self) -> &String {
35        &self.identifier
36    }
37    fn position(&self) -> Position<Valid> {
38        self.position
39    }
40}
41impl Vor {
42    pub fn frequency(&self) -> &String {
43        &self.frequency
44    }
45}
46
47#[derive(Debug, Clone)]
48pub struct Ndb {
49    pub identifier: String,
50    pub position: Position<Valid>,
51    pub frequency: String,
52}
53impl Waypoint for Ndb {
54    fn identifier(&self) -> &String {
55        &self.identifier
56    }
57    fn position(&self) -> Position<Valid> {
58        self.position
59    }
60}
61impl Ndb {
62    pub fn frequency(&self) -> &String {
63        &self.frequency
64    }
65}
66
67#[derive(Debug, Clone)]
68pub struct Airport {
69    pub identifier: String,
70    pub position: Position<Valid>,
71    pub tower_frequency: String,
72    pub airspace_class: AirspaceClass,
73    pub runways: Vec<RunwayStrip>,
74}
75impl Waypoint for Airport {
76    fn identifier(&self) -> &String {
77        &self.identifier
78    }
79    fn position(&self) -> Position<Valid> {
80        self.position
81    }
82}
83impl Airport {
84    pub fn tower_frequency(&self) -> &String {
85        &self.tower_frequency
86    }
87    pub fn airspace_class(&self) -> AirspaceClass {
88        self.airspace_class
89    }
90}
91
92#[derive(Debug, Clone)]
93pub struct RunwayStrip {
94    pub end_a: RunwayEnd,
95    pub end_b: RunwayEnd,
96}
97
98#[derive(Debug, Clone, PartialEq)]
99pub struct RunwayEnd {
100    pub number: u8,
101    pub td_threshold_pos: Position<Valid>,
102    pub se_threshold_pos: Position<Valid>,
103    pub modifier: RunwayModifier,
104    pub magnetic_hdg: Heading,
105}
106impl RunwayEnd {
107    pub fn identifier(&self) -> String {
108        format!("{:02}{}", self.number, self.modifier)
109    }
110    pub fn reciprocal(&self) -> RunwayEnd {
111        let number = self.reciprocal_number();
112        let td_threshold_pos = self.se_threshold_pos;
113        let se_threshold_pos = self.td_threshold_pos;
114        let modifier = self.modifier.reciprocal();
115        let magnetic_hdg = self.magnetic_hdg.reciprocal();
116        RunwayEnd {
117            number,
118            td_threshold_pos,
119            se_threshold_pos,
120            modifier,
121            magnetic_hdg,
122        }
123    }
124    fn reciprocal_number(&self) -> u8 {
125        if self.number > 18 {
126            self.number - 18
127        } else {
128            self.number + 18
129        }
130    }
131}
132
133#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
134pub enum RunwayModifier {
135    Left,
136    Right,
137    Centre,
138    Grass,
139    None,
140}
141impl RunwayModifier {
142    pub fn reciprocal(&self) -> RunwayModifier {
143        match self {
144            Self::Left => Self::Right,
145            Self::Right => Self::Left,
146            Self::Centre => Self::Centre,
147            Self::Grass => Self::Grass,
148            Self::None => Self::None,
149        }
150    }
151}
152
153impl Display for RunwayModifier {
154    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
155        write!(
156            f,
157            "{}",
158            match self {
159                Self::Left => "L",
160                Self::Right => "R",
161                Self::Centre => "C",
162                Self::Grass => "G",
163                Self::None => "",
164            }
165        )
166    }
167}