diff --git a/src/topsky/map.rs b/src/topsky/map.rs index a984ffa..8856688 100644 --- a/src/topsky/map.rs +++ b/src/topsky/map.rs @@ -258,22 +258,22 @@ impl Text { #[derive(Clone, Debug, Reflect, Serialize)] pub enum FontSize { - Exact(i32), - Add(i32), - Subtract(i32), - Multiply(i32), + Exact(f64), + Add(f64), + Subtract(f64), + Multiply(f64), Default, } impl FontSize { fn parse(pair: Pair) -> Self { let mut fontsize = pair.into_inner(); - if fontsize.as_str() == "0" { + let default_or_modifier = fontsize.next().unwrap(); + if matches!(default_or_modifier.as_rule(), Rule::fontsize_default) { Self::Default } else { - let modifier = fontsize.next().unwrap().as_str(); let size = fontsize.next().unwrap().as_str().parse().unwrap(); - match modifier { + match default_or_modifier.as_str() { "=" => Self::Exact(size), "+" => Self::Add(size), "-" => Self::Subtract(size), @@ -343,6 +343,7 @@ pub enum MapRule { Color(String), AsrData, Active(Active), + Global, ScreenSpecific, Layer(i32), Symbol(MapSymbol), @@ -379,10 +380,13 @@ impl MapRule { Rule::mapline => Some(MapRule::Line(MapLine::parse(pair))), Rule::text => Some(MapRule::Text(Text::parse(pair))), Rule::screen_specific => Some(MapRule::ScreenSpecific), + Rule::global => Some(MapRule::Global), + // TODO Rule::circle => None, Rule::coordline => None, Rule::coord => None, Rule::coordpoly => None, + Rule::fontstyle => None, _ => { eprintln!("unhandled {ruletype:?}"); unreachable!() diff --git a/src/topsky/symbol.rs b/src/topsky/symbol.rs index 60e10db..4f9b9e4 100644 --- a/src/topsky/symbol.rs +++ b/src/topsky/symbol.rs @@ -47,6 +47,16 @@ fn parse_symbol_rules(pairs: Pairs) -> Vec { symbolrule.next().unwrap().as_str().parse::().unwrap() % 360; SymbolRule::Arc(pos, radius, start_angle, end_angle) } + Rule::arc_ellipse => { + let pos = parse_point(symbolrule.next().unwrap()); + let radius_x = symbolrule.next().unwrap().as_str().parse().unwrap(); + let radius_y = symbolrule.next().unwrap().as_str().parse().unwrap(); + let start_angle = + symbolrule.next().unwrap().as_str().parse::().unwrap() % 360; + let end_angle = + symbolrule.next().unwrap().as_str().parse::().unwrap() % 360; + SymbolRule::EllipticArc(pos, radius_x, radius_y, start_angle, end_angle) + } Rule::fillarc => { let pos = parse_point(symbolrule.next().unwrap()); let radius = symbolrule.next().unwrap().as_str().parse().unwrap(); @@ -56,6 +66,27 @@ fn parse_symbol_rules(pairs: Pairs) -> Vec { symbolrule.next().unwrap().as_str().parse::().unwrap() % 360; SymbolRule::FilledArc(pos, radius, start_angle, end_angle) } + Rule::fillarc_ellipse => { + let pos = parse_point(symbolrule.next().unwrap()); + let radius_x = symbolrule.next().unwrap().as_str().parse().unwrap(); + let radius_y = symbolrule.next().unwrap().as_str().parse().unwrap(); + let start_angle = + symbolrule.next().unwrap().as_str().parse::().unwrap() % 360; + let end_angle = + symbolrule.next().unwrap().as_str().parse::().unwrap() % 360; + SymbolRule::FilledEllipticArc(pos, radius_x, radius_y, start_angle, end_angle) + } + Rule::ellipse_circle => { + let pos = parse_point(symbolrule.next().unwrap()); + let radius = symbolrule.next().unwrap().as_str().parse().unwrap(); + SymbolRule::FilledArc(pos, radius, 0, 0) + } + Rule::ellipse => { + let pos = parse_point(symbolrule.next().unwrap()); + let radius_x = symbolrule.next().unwrap().as_str().parse().unwrap(); + let radius_y = symbolrule.next().unwrap().as_str().parse().unwrap(); + SymbolRule::FilledEllipticArc(pos, radius_x, radius_y, 0, 0) + } Rule::polygon => SymbolRule::Polygon(symbolrule.map(parse_point).collect()), _ => { unreachable!() @@ -126,6 +157,10 @@ ARC:0:0:5:0:360 SYMBOL:HISTORY FILLARC:0:0:1:0:360 +SYMBOL:APPFix +ARC:0:0:2:6:0:360 +ARC:0:0:6:2:0:360 + SYMBOL:NODAPS_DIV POLYGON:-4:0:0:-4:4:0:0:4 ARC:0:0:8:0:0"#; @@ -170,6 +205,17 @@ ARC:0:0:8:0:0"#; } ); + assert_eq!( + symbols.get("APPFix").unwrap(), + &SymbolDef { + name: "APPFix".to_string(), + rules: vec![ + SymbolRule::EllipticArc((0.0, 0.0), 2.0, 6.0, 0, 0), + SymbolRule::EllipticArc((0.0, 0.0), 6.0, 2.0, 0, 0), + ] + } + ); + assert_eq!( symbols.get("NODAPS_DIV").unwrap(), &SymbolDef { diff --git a/src/topsky/topsky.pest b/src/topsky/topsky.pest index 609c4b8..2c82295 100644 --- a/src/topsky/topsky.pest +++ b/src/topsky/topsky.pest @@ -15,14 +15,16 @@ colordef = { override_sct = { "OVERRIDE_SCT_MAP:" ~ override_folder ~ name ~ NL? } override_folder = { ((!("\\" | NL) ~ ANY)+ ~ "\\")? } +// TODO DEFAULT_SCREEN-SPECIFIC, DEFAULT_GLOBAL + map = { "MAP:" ~ name ~ NL ~ map_setting+ } // MAP map_setting = _{ (" " | "\t")* ~ ( - folder | color | asrdata | active | layer | mapsymbol - | fontsize | zoom | style | mapline | text | screen_specific | circle - | coordline | coordpoly | coord + folder | color | asrdata | active | layer | mapsymbol | fontstyle + | fontsize | zoom | style | mapline | text | global | screen_specific + | circle | coordline | coordpoly | coord ) ~ NL? } @@ -34,6 +36,7 @@ color = { "COLOR:" ~ name } asrdata = { "ASRDATA:" ~ (wildcard | (name ~ ("," ~ name)*)) } active = { "ACTIVE:" ~ (active_sched | active_id | active_rwy_with_excludes | active_rwy | active_always ) } +andactive = { "AND_ACTIVE:" ~ (active_sched | active_id | active_rwy_with_excludes | active_rwy | active_always ) } active_always = { "1" } active_id = { "ID:" ~ (wildcard | names) ~ ":" ~ (wildcard | names) ~ ":" @@ -54,7 +57,11 @@ layer = { "LAYER:" ~ number } mapsymbol = { "SYMBOL" ~ ("/" ~ textalign)? ~ ":" ~ name ~ ":" ~ (coordinate | name) ~ (":" ~ mapsymbollabel)? } mapsymbollabel = { name ~ ":" ~ point } -fontsize = { "FONTSIZE:" ~ (font_symbol ~ ":" ~ number | "0")} +fontstyle = { "FONTSTYLE:" ~ (fontstyle_set | fontstyle_default) } +fontstyle_default = { "0" } +fontstyle_set = { number ~ ":" ~ boolean ~ ":" ~ boolean ~ ":" ~ boolean } +fontsize = { "FONTSIZE:" ~ ((font_symbol ~ ":" ~ decimal) | fontsize_default)} +fontsize_default = { "0" } font_symbol = { "=" | "+" | "-" | "*" } zoom = { "ZOOM:" ~ decimal } @@ -72,6 +79,7 @@ horizontalalign = { "L" | "C" | "R" } verticalalign = { "T" | "C" | "B" } screen_specific = { "SCREEN-SPECIFIC" } +global = { "GLOBAL" } circle = { "CIRCLE:" ~ coordinate ~ ":" ~ decimal ~ ":" ~ decimal } @@ -81,20 +89,35 @@ coordline = { "COORDLINE" } coordpoly = { "COORDPOLY:" | number } // SYMBOLDEF -symbolrule = _{ (moveto | line | fillarc | arc | polygon | pixel) ~ NL? } +symbolrule = _{ ( + moveto | line | fillarc_ellipse | fillarc | arc_ellipse | arc | polygon | pixel | ellipse | ellipse_circle +) ~ NL? } moveto = { "MOVETO:" ~ point } line = { "LINETO:" ~ point } fillarc = { "FILLARC:" ~ point ~ ":" ~ decimal ~ ":" ~ number ~ ":" ~ number } +fillarc_ellipse = { + "FILLARC:" ~ point ~ ":" ~ decimal ~ ":" ~ decimal ~ ":" ~ number ~ ":" ~ number +} arc = { "ARC:" ~ point ~ ":" ~ decimal ~ ":" ~ number ~ ":" ~ number } +arc_ellipse = { + "ARC:" ~ point ~ ":" ~ decimal ~ ":" ~ decimal ~ ":" ~ number ~ ":" ~ number +} +ellipse = { + "ELLIPSE:" ~ point ~ ":" ~ decimal ~ ":" ~ decimal +} +ellipse_circle = { + "ELLIPSE:" ~ point ~ ":" ~ decimal +} polygon = { "POLYGON" ~ (":" ~ point)+ } pixel = { "SETPIXEL:" ~ point } +// TODO: SCTDATA -name = @{ (ASCII_ALPHA | ASCII_DIGIT | "_" | "-" | " " | "/" | "," | "." | "(" | ")" | "&")+ } +name = @{ (!(NL | ":") ~ ANY)+ } names = { name ~ ("," ~ name)* } wildcard = { "*" } @@ -114,8 +137,11 @@ runway = { icao ~ rwy_designator } icao = { ASCII_ALPHA_UPPER{4} } rwy_designator = { ASCII_DIGIT{2} ~ ("L" | "C" | "R")? } point = { decimal ~ ":" ~ decimal } -number = @{ "-"? ~ ("0" | (ASCII_NONZERO_DIGIT ~ ASCII_DIGIT*)) } -decimal = @{ "-"? ~ ASCII_DIGIT+ ~ ("." ~ ASCII_DIGIT+)? } +number = @{ ("-"|"+")? ~ ASCII_DIGIT+ } +decimal = @{ ("-"|"+")? ~ ASCII_DIGIT+ ~ ("." ~ ASCII_DIGIT+)? } +boolean = { "0" | "1" } NL = _{ ((" " | "\t")* ~ NEWLINE)+ } -COMMENT = _{ "//" ~ (!NL ~ ANY)* ~ NL } +// per documentation only "//" but ";" is used quite often and apparently ignored +// in the ES topsky plugin +COMMENT = _{ (" " | "\t")* ~ ("//" | ";") ~ (!NL ~ ANY)* ~ NL }