sct_reader/loaders/euroscope/
sector.rs

1use std::collections::HashMap;
2
3use super::{
4    colour::Colour,
5    error::Error,
6    line::{ColouredLine, LineGroup},
7    partial::{
8        region::{PartialRegion, PartialRegionGroup},
9        sector_info::PartialSectorInfo,
10        PartialSector,
11    },
12    position::{Position, Valid},
13    waypoint::{Airport, Fix, Ndb, Vor},
14};
15
16#[derive(Debug)]
17pub struct Sector {
18    pub sector_info: SectorInfo,
19    pub colours: HashMap<String, Colour>,
20    pub airports: Vec<Airport>,
21    pub vors: Vec<Vor>,
22    pub ndbs: Vec<Ndb>,
23    pub fixes: Vec<Fix>,
24    pub artcc_entries: Vec<LineGroup<ColouredLine>>,
25    pub artcc_low_entries: Vec<LineGroup<ColouredLine>>,
26    pub artcc_high_entries: Vec<LineGroup<ColouredLine>>,
27    pub low_airways: Vec<LineGroup<ColouredLine>>,
28    pub high_airways: Vec<LineGroup<ColouredLine>>,
29    pub sid_entries: Vec<LineGroup<ColouredLine>>,
30    pub star_entries: Vec<LineGroup<ColouredLine>>,
31    pub geo_entries: Vec<LineGroup<ColouredLine>>,
32    pub regions: Vec<RegionGroup>,
33    pub labels: Vec<LabelGroup>,
34
35    pub non_critical_errors: Vec<(usize, String, Error)>,
36}
37
38impl TryFrom<PartialSector> for Sector {
39    type Error = Error;
40    fn try_from(value: PartialSector) -> Result<Self, Self::Error> {
41        let sector_info = SectorInfo::try_from(value.sector_info)?;
42        let regions = value
43            .region_groups
44            .into_iter()
45            .map(|region_group| RegionGroup::try_from(region_group))
46            .collect::<Result<Vec<RegionGroup>, Error>>()?;
47        Ok(Sector {
48            sector_info,
49            colours: value.colours,
50            airports: value.airports,
51            vors: value.vors,
52            ndbs: value.ndbs,
53            fixes: value.fixes,
54            artcc_entries: value.artcc_entries,
55            artcc_low_entries: value.artcc_low_entries,
56            artcc_high_entries: value.artcc_high_entries,
57            low_airways: value.low_airways,
58            high_airways: value.high_airways,
59            sid_entries: value.sid_entries,
60            star_entries: value.star_entries,
61            geo_entries: value.geo_entries,
62            regions,
63            labels: value.labels,
64            non_critical_errors: vec![],
65        })
66    }
67}
68
69#[derive(Debug)]
70pub struct RegionGroup {
71    pub name: String,
72    pub regions: Vec<Region>,
73}
74impl RegionGroup {
75    pub fn new(name: String) -> RegionGroup {
76        RegionGroup {
77            name,
78            regions: vec![],
79        }
80    }
81}
82
83impl TryFrom<PartialRegionGroup> for RegionGroup {
84    type Error = Error;
85    fn try_from(value: PartialRegionGroup) -> Result<Self, Self::Error> {
86        let regions = value
87            .regions
88            .into_iter()
89            .map(Region::try_from)
90            .collect::<Result<Vec<_>, Error>>();
91        if regions.is_err() {
92            println!("NAME: {}", value.name);
93        }
94        let regions = regions?;
95        Ok(RegionGroup {
96            name: value.name,
97            regions,
98        })
99    }
100}
101
102#[derive(Debug)]
103pub struct Region {
104    pub colour: Colour,
105    pub vertices: Vec<Position<Valid>>,
106}
107impl TryFrom<PartialRegion> for Region {
108    type Error = Error;
109    fn try_from(value: PartialRegion) -> Result<Self, Self::Error> {
110        Ok(Region {
111            colour: value.colour.ok_or_else(|| Error::InvalidRegion)?,
112            vertices: value.vertices,
113        })
114    }
115}
116
117#[derive(Debug)]
118pub struct LabelGroup {
119    pub name: String,
120    pub labels: Vec<Label>,
121}
122
123#[derive(Debug)]
124pub struct Label {
125    pub name: String,
126    pub position: Position<Valid>,
127    pub colour: Colour,
128}
129
130#[derive(Debug, Clone)]
131pub struct SectorInfo {
132    pub name: String,
133    pub default_callsign: String,
134    pub default_airport: String,
135    pub default_centre_pt: Position<Valid>,
136    pub n_mi_per_deg_lat: f32,
137    pub n_mi_per_deg_lon: f32,
138    pub magnetic_variation: f32,
139    pub sector_scale: f32,
140}
141
142impl TryFrom<PartialSectorInfo> for SectorInfo {
143    type Error = Error;
144    fn try_from(value: PartialSectorInfo) -> Result<Self, Self::Error> {
145        let name = value.name.ok_or(Error::SectorInfoError)?;
146        let default_callsign = value.default_callsign.ok_or(Error::SectorInfoError)?;
147        let default_airport = value.default_airport.ok_or(Error::SectorInfoError)?;
148        let lat = value.default_centre_pt_lat.ok_or(Error::SectorInfoError)?;
149        let lon = value.default_centre_pt_lon.ok_or(Error::SectorInfoError)?;
150        let default_centre_pt = Position::new(lat, lon).validate()?;
151        let n_mi_per_deg_lat = value.n_mi_per_deg_lat.ok_or(Error::SectorInfoError)?;
152        let n_mi_per_deg_lon = value.n_mi_per_deg_lon.ok_or(Error::SectorInfoError)?;
153        let magnetic_variation = value.magnetic_variation.ok_or(Error::SectorInfoError)?;
154        let sector_scale = value.sector_scale.ok_or(Error::SectorInfoError)?;
155
156        Ok(SectorInfo {
157            name,
158            default_callsign,
159            default_airport,
160            default_centre_pt,
161            n_mi_per_deg_lat,
162            n_mi_per_deg_lon,
163            magnetic_variation,
164            sector_scale,
165        })
166    }
167}