This commit is contained in:
Neil 2023-04-28 13:40:11 -07:00
parent a1896b97fc
commit 1bba902145
3 changed files with 188 additions and 12 deletions

View File

@ -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:

View File

@ -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 *);

View File

@ -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,
<line> "--" / [^-] :=> source
<line> "::" / [^:] :=> score
<line> "[glider]" :=> glider_type
<line> "[flight]" :=> flight_type
<source> * { 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 */
<glider_type> * { fail = "glider type"; goto catch; }
<glider_type> 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,
<glider_reg> ws* @s0 semitext+ @s1 ws* ";" => glider_launch
{ new_glider->reg.a = s0, new_glider->reg.b = s1; continue; }
<glider_launch> * { fail = "glider launch"; goto catch; }
<glider_launch> ws* @s0 airport @s1 ws* ";" => glider_how
{ new_glider->launch.a = s0, new_glider->launch.b = s1; continue; }
<glider_launch> 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;
}
<glider_how> * { fail = "glider how"; goto catch; }
<glider_how> 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; }
<glider_landing> * { fail = "glider landing"; goto catch; }
<glider_landing> ws* @s0 airport @s1 ws* ";" => glider_pilot
{ new_glider->landing.a = s0, new_glider->landing.b = s1; continue; }
<glider_pilot> * { fail = "glider pilot"; goto catch; }
{ new_glider->landing.a = s0, new_glider->landing.b = s1; continue;}
<glider_pilot> * { fail = "glider pilot time"; goto catch; }
<glider_pilot> ws* ";" => glider_dual /* not PIC */
{ new_glider->pilot_min = 0; continue; }
<glider_pilot> 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; }
<glider_dual> * { fail = "glider dual"; goto catch; }
<glider_dual> * { fail = "glider dual time"; goto catch; }
<glider_dual> ws* ";" => glider_instr
{ new_glider->dual_min = 0; continue; }
<glider_dual> 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; }
<glider_instr> * { fail = "glider instr"; goto catch; }
<glider_instr> * { fail = "glider instr time"; goto catch; }
<glider_instr> ws* ";" => glider_remarks
{ new_glider->instr_min = 0; continue; }
<glider_instr> 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; }
<glider_remarks> * { fail = "glider remarks"; goto catch; }
<glider_remarks> 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 */
<flight_type> * { fail = "flight type"; goto catch; }
<flight_type> 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;
}
<flight_reg> * { fail = "flight reg"; goto catch; }
<flight_reg> ws* @s0 semitext+ @s1 ws* ";" => flight_airports
{ new_flight->reg.a = s0, new_flight->reg.b = s1; continue; }
<flight_airports> * { fail = "flight airports"; goto catch; }
<flight_airports> 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;
}
<flight_pic> * { fail = "flight pic"; goto catch; }
<flight_pic> ws* @s0 semitext+ (ws+ semitext+)* @s1 /* ws*? */";"
=> flight_sic
{ new_flight->pilot.a = s0, new_flight->pilot.b = s1; continue; }
<flight_sic> * { fail = "flight sic"; goto catch; }
<flight_sic> ws* ";" => flight_dual
{ new_flight->copilot.a = new_flight->copilot.b = 0; continue; }
<flight_sic> ws* @s0 semitext+ (ws+ semitext+)* @s1 ";"
=> flight_dual
{ new_flight->copilot.a = s0, new_flight->copilot.b = s1; continue; }
<flight_dual> * { fail = "flight dual time"; goto catch; }
<flight_dual> ws* ";" => flight_pilot
{ new_flight->dual_min = 0; continue; }
<flight_dual> 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; }
<flight_pilot> * { fail = "flight pilot time"; goto catch; }
<flight_pilot> ws* ";" => flight_ifrsim
{ new_flight->pilot_min = 0; continue; }
<flight_pilot> 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; }
<flight_ifrsim> * { fail = "flight simulated ifr time"; goto catch; }
<flight_ifrsim> ws* ";" => flight_ifr
{ new_flight->ifrsim_min = 0; continue; }
<flight_ifrsim> 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; }
<flight_ifr> * { fail = "flight ifr time"; goto catch; }
<flight_ifr> ws* ";" => flight_remarks
{ new_flight->ifr_min = 0; continue; }
<flight_ifr> 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; }
<flight_remarks> * { fail = "flight remarks"; goto catch; }
<flight_remarks> ws* "\n" => line
{ new_flight->remarks.a = new_flight->remarks.b = 0;
new_flight = 0; line++; continue; }
<flight_remarks> 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 <<EOD\n"
"# date, reg, sic, pic, source\n");
struct flight_tree_iterator it = flight_tree_iterator(&scan->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");
}