From 1bba9021453ba517cbb0ac9f155d9924615abffa Mon Sep 17 00:00:00 2001 From: Neil Date: Fri, 28 Apr 2023 13:40:11 -0700 Subject: [PATCH] flight --- src/driver.c | 4 ++ src/scan.h | 15 +++++ src/scan.re.c | 181 ++++++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 188 insertions(+), 12 deletions(-) diff --git a/src/driver.c b/src/driver.c index 4d962ca..025e190 100644 --- a/src/driver.c +++ b/src/driver.c @@ -36,6 +36,10 @@ int main(void) { if(!freopen(intent, "w", stdout)) goto catch; scan_glider_graph(&scn); + intent = "derived/flight.gnu"; + if(!freopen(intent, "w", stdout)) goto catch; + scan_flight_graph(&scn); + intent = 0; goto finally; catch: diff --git a/src/scan.h b/src/scan.h index c139551..4c7f0e1 100644 --- a/src/scan.h +++ b/src/scan.h @@ -51,6 +51,19 @@ struct glider { #include "../src/tree.h" +/* Flight array. */ +struct flight { + struct pair type, reg, launch, landing, pilot, copilot; + unsigned dual_min, pilot_min, ifrsim_min, ifr_min; + struct pair remarks; +}; +#define TREE_NAME flight +#define TREE_KEY union line64 +#define TREE_VALUE struct flight +#define TREE_HEAD +#include "../src/tree.h" + + struct scan { struct { struct source_array array; @@ -63,9 +76,11 @@ struct scan { struct linemap_tree dates; } scores; struct glider_tree gliders; + struct flight_tree flights; }; void scan_(struct scan *); struct scan scan(struct journal *); void scan_score_graph(struct scan *); void scan_glider_graph(struct scan *); +void scan_flight_graph(struct scan *); diff --git a/src/scan.re.c b/src/scan.re.c index ca86804..3adba81 100644 --- a/src/scan.re.c +++ b/src/scan.re.c @@ -66,6 +66,19 @@ static int glider_compare(const union line64 a, const union line64 b) #include "../src/tree.h" +/* Flight tree. */ +static void flight_to_string(const union line64 line, const struct flight *f, + char (*const a)[12]) { (void)f; date32_to_string(line.date, a); } +static int flight_compare(const union line64 a, const union line64 b) + { return a.u64 > b.u64; } +#define TREE_NAME flight +#define TREE_KEY union line64 +#define TREE_VALUE struct flight +#define TREE_COMPARE +#define TREE_TO_STRING +#define TREE_BODY +#include "../src/tree.h" + /*!conditions:re2c*/ @@ -78,6 +91,7 @@ static int scan_day(struct scan *const scan, union date32 date, const char *fail = "perhaps a bat?"; struct score *new_score = 0; struct glider *new_glider = 0; + struct flight *new_flight = 0; assert(scan && date.u32 && buffer); YYCURSOR = YYMARKER = yyt1 = buffer; /*!re2c /**/ @@ -109,6 +123,7 @@ static int scan_day(struct scan *const scan, union date32 date, "--" / [^-] :=> source "::" / [^:] :=> score "[glider]" :=> glider_type + "[flight]" :=> flight_type * { fail = "source unrecognized"; goto catch; } @@ -219,8 +234,7 @@ static int scan_day(struct scan *const scan, union date32 date, eg, [glider] 2-33A; C-GCLK; CYQQ; A; 2000'; CYQQ; ;:13;; Peters D1 */ * { fail = "glider type"; goto catch; } ws* @s0 semitext+ @s1 ws* ";" => glider_reg { - const union line64 key - = {{ (uint32_t)line, {{ date.day, date.month, date.year }} }}; + const union line64 key = {{ (uint32_t)line, date }}; assert(!new_glider); if(line > UINT32_MAX) { fail = "line overflow"; goto catch; } switch(glider_tree_bulk_assign(&scan->gliders, key, &new_glider)) { @@ -234,8 +248,15 @@ static int scan_day(struct scan *const scan, union date32 date, ws* @s0 semitext+ @s1 ws* ";" => glider_launch { new_glider->reg.a = s0, new_glider->reg.b = s1; continue; } * { fail = "glider launch"; goto catch; } - ws* @s0 airport @s1 ws* ";" => glider_how - { new_glider->launch.a = s0, new_glider->launch.b = s1; continue; } + ws* @s0 airport @s1 ws* ";" => glider_how { + new_glider->launch.a = s0, new_glider->launch.b = s1; + date32_to_string(date, &datestr); + fprintf(stderr, "%s: glider <%.*s> at <%.*s>\n", datestr, + (int)(new_glider->reg.b - new_glider->reg.a), + new_glider->reg.a, + (int)(s1 - s0), s0); + continue; + } * { fail = "glider how"; goto catch; } ws* @s0 [MWA] ws* ";" => glider_height { switch(*s0) { @@ -250,27 +271,27 @@ static int scan_day(struct scan *const scan, union date32 date, { if(!pair_to_natural(s0, s1, &new_glider->height_ft)); continue; } * { fail = "glider landing"; goto catch; } ws* @s0 airport @s1 ws* ";" => glider_pilot - { new_glider->landing.a = s0, new_glider->landing.b = s1; continue; } - * { fail = "glider pilot"; goto catch; } + { new_glider->landing.a = s0, new_glider->landing.b = s1; continue;} + * { fail = "glider pilot time"; goto catch; } ws* ";" => glider_dual /* not PIC */ { new_glider->pilot_min = 0; continue; } ws* @s0 natural? @s1 ":" @t0 minutes @t1 ws* ";" => glider_dual { if(!pair_colon_to_minutes(s0, s1, t0, t1, - &new_glider->pilot_min)) { fail = "pilot time"; goto catch; } + &new_glider->pilot_min)) { fail = "glider pilot time"; goto catch; } continue; } - * { fail = "glider dual"; goto catch; } + * { fail = "glider dual time"; goto catch; } ws* ";" => glider_instr { new_glider->dual_min = 0; continue; } ws* @s0 natural? @s1 ":" @t0 minutes @t1 ws* ";" => glider_instr { if(!pair_colon_to_minutes(s0, s1, t0, t1, - &new_glider->dual_min)) { fail = "dual time"; goto catch; } + &new_glider->dual_min)) { fail = "glider dual time"; goto catch; } continue; } - * { fail = "glider instr"; goto catch; } + * { fail = "glider instr time"; goto catch; } ws* ";" => glider_remarks { new_glider->instr_min = 0; continue; } ws* @s0 natural? @s1 ":" @t0 minutes @t1 ws* ";" => glider_remarks { if(!pair_hours_to_minutes(s0, s1, t0, t1, - &new_glider->instr_min)) { fail = "instr time"; goto catch; } + &new_glider->instr_min)) { fail = "glider instr time"; goto catch; } continue; } * { fail = "glider remarks"; goto catch; } ws* "\n" => line @@ -280,6 +301,84 @@ static int scan_day(struct scan *const scan, union date32 date, { new_glider->remarks.a = s0, new_glider->remarks.b = s1; new_glider = 0; line++; continue; } + + /* type; registration; launch -- landing; pic; sic; + single engine day dual; pilot; instrument simulated; actual; remarks */ + * { fail = "flight type"; goto catch; } + ws* @s0 semitext+ @s1 ws* ";" => flight_reg { + const union line64 key + = {{ (uint32_t)line, {{ date.day, date.month, date.year }} }}; + assert(!new_flight); + if(line > UINT32_MAX) { fail = "line overflow"; goto catch; } + switch(flight_tree_bulk_assign(&scan->flights, key, &new_flight)) { + case TREE_PRESENT: fail = "duplicate key"; + case TREE_ERROR: goto catch; + case TREE_ABSENT: break; + } + new_flight->type.a = s0, new_flight->type.b = s1; + continue; + } + * { fail = "flight reg"; goto catch; } + ws* @s0 semitext+ @s1 ws* ";" => flight_airports + { new_flight->reg.a = s0, new_flight->reg.b = s1; continue; } + * { fail = "flight airports"; goto catch; } + ws* @s0 airport @s1 ws* "--" + ws* @t0 airport @t1 ws* ";" => flight_pic { + new_flight->launch.a = s0, new_flight->launch.b = s1; + new_flight->landing.a = t0, new_flight->landing.b = t1; + date32_to_string(date, &datestr); + fprintf(stderr, "%s: flight <%.*s> at <%.*s>\n", datestr, + (int)(new_flight->reg.b - new_flight->reg.a), + new_flight->reg.a, + (int)(s1 - s0), s0); + continue; + } + * { fail = "flight pic"; goto catch; } + ws* @s0 semitext+ (ws+ semitext+)* @s1 /* ws*? */";" + => flight_sic + { new_flight->pilot.a = s0, new_flight->pilot.b = s1; continue; } + * { fail = "flight sic"; goto catch; } + ws* ";" => flight_dual + { new_flight->copilot.a = new_flight->copilot.b = 0; continue; } + ws* @s0 semitext+ (ws+ semitext+)* @s1 ";" + => flight_dual + { new_flight->copilot.a = s0, new_flight->copilot.b = s1; continue; } + * { fail = "flight dual time"; goto catch; } + ws* ";" => flight_pilot + { new_flight->dual_min = 0; continue; } + ws* @s0 zero_natural? @s1 "." @t0 [0-9] @t1 "h" ws* ";" + => flight_pilot { if(!pair_hours_to_minutes(s0, s1, t0, t1, + &new_flight->dual_min)) { fail = "flight dual time"; goto catch; } + continue; } + * { fail = "flight pilot time"; goto catch; } + ws* ";" => flight_ifrsim + { new_flight->pilot_min = 0; continue; } + ws* @s0 zero_natural? @s1 "." @t0 [0-9] @t1 "h" ws* ";" + => flight_ifrsim { if(!pair_hours_to_minutes(s0, s1, t0, t1, + &new_flight->pilot_min)) { fail = "flight pilot time"; + goto catch; } continue; } + * { fail = "flight simulated ifr time"; goto catch; } + ws* ";" => flight_ifr + { new_flight->ifrsim_min = 0; continue; } + ws* @s0 zero_natural? @s1 "." @t0 [0-9] @t1 "h" ws* ";" + => flight_ifr { if(!pair_hours_to_minutes(s0, s1, t0, t1, + &new_flight->ifrsim_min)) { fail = "flight simulated ifr time"; + goto catch; } continue; } + * { fail = "flight ifr time"; goto catch; } + ws* ";" => flight_remarks + { new_flight->ifr_min = 0; continue; } + ws* @s0 zero_natural? @s1 "." @t0 [0-9] @t1 "h" ws* ";" + => flight_remarks { if(!pair_hours_to_minutes(s0, s1, t0, t1, + &new_flight->ifr_min)) { fail = "flight ifr time"; goto catch; } + continue; } + * { fail = "flight remarks"; goto catch; } + ws* "\n" => line + { new_flight->remarks.a = new_flight->remarks.b = 0; + new_flight = 0; line++; continue; } + ws* @s0 glyph+ (ws+ glyph+)* @s1 "\n" => line + { new_flight->remarks.a = s0, new_flight->remarks.b = s1; + new_flight = 0; line++; continue; } + */ } assert(0); /* Never gets here. */ catch: @@ -323,7 +422,9 @@ struct scan scan(struct journal *const jrnl) { /* Scans make trees bulk-loaded; fix to real tree. */ if(!linemap_tree_bulk_finish(&scan.sources.dates) - || !linemap_tree_bulk_finish(&scan.scores.dates)) goto catch; + || !linemap_tree_bulk_finish(&scan.scores.dates) + || !glider_tree_bulk_finish(&scan.gliders) + || !flight_tree_bulk_finish(&scan.flights)) goto catch; fprintf(stderr, "List of scores: %s.\n" "Mapped to indices: %s.\n" @@ -495,3 +596,59 @@ void scan_glider_graph(struct scan *const scan) { /*"#set style fill solid 0.1 #pattern 5 (better, but restarts)\n" "plot $Data using 1:($6/60) with fillsteps lw 2\n"*/); } + +void scan_flight_graph(struct scan *const scan) { + assert(scan); + fprintf(stderr, "Flight: %s.\n", flight_tree_to_string(&scan->flights)); + printf("set terminal pngcairo dashed transparent truecolor" + " size 840, 480 fontscale 1\n" + "set output \"glider.png\"\n"); + printf("$Data <flights); + while(flight_tree_next(&it)) { + const union line64 line = flight_tree_key(&it); + const struct flight *flight = flight_tree_value(&it); + char datestr[12]; + date32_to_string(line.date, &datestr); + const struct source *src = source_lookup(scan, line); + assert(src); + if(!src->name.a) { fprintf(stderr, + "Source has no source at %s; ignoring.\n", datestr); continue; } + printf("%s, ", datestr); + printf("%.*s, %" PRIu32 ", %" PRIu32, + (int)(flight->reg.b - flight->reg.a), flight->reg.a, + flight->dual_min, flight->pilot_min); + printf(", %.*s\n", (int)(src->name.b - src->name.a), src->name.a); + } + printf("EOD\n" + "# theozh https://stackoverflow.com/a/75466214/2472827\n" + "# get a unique list from datablock\n" + "addToList(list,col) = list.( strstrt(list,'\"'.strcol(col).'\"') \\\n" + " > 0 ? '' : ' \"'.strcol(col).'\"')\n" + "Uniqs = ''\n" + "stats $Data u (Uniqs=addToList(Uniqs,2)) nooutput\n" + "Uniq(i) = word(Uniqs,i)\n" + "getIndex(s) = sum [_i=1:words(Uniqs)] s eq word(Uniqs,_i) ? _i : 0\n" + "\n" + "stats $Data u 3 nooutput\n" + "sicsum = STATS_sum\n" + "stats $Data u 4 nooutput\n" + "picsum = STATS_sum\n" + "\n" + "myTimeFmt = \"%%Y-%%m-%%d\"\n" + "set format x myTimeFmt timedate\n" + "set xtics format myTimeFmt rotate by -30\n" + "set format y \"%%tH:%%tM\" timedate\n" + "set grid\n" + "set key out reverse Left noautotitle\n" + "set style fill solid 0.5\n" + "unset border\n" + "plot total=0 $Data u" + " (timecolumn(1,myTimeFmt)):(dy=($3+$4)*60,total=total+dy)" + " w steps lc \"black\" dt 3, \\\n" + " total=0 '' u (timecolumn(1,myTimeFmt)):" + "(dy=($3+$4)*60,total=total+dy,total/2.): \\\n" + " (43200):(total/2.):(getIndex(strcol(2))) w boxxy lc var, \\\n" + " for [i=1:words(Uniqs)] keyentry w boxxy lc i ti Uniq(i)\n"); +}