X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=profile.c;h=ad158fe8a1f9aaafb40b792f31dea13667594f5f;hb=edbba678b3cdc8f06a84a965b04f13ef1f4ecaab;hp=6c1e8ce426d63cc3f68262f9e61a75458492c1ad;hpb=86fdd83e7b9cc661940470c7b7d83316b223f572;p=ext%2Fsubsurface.git diff --git a/profile.c b/profile.c index 6c1e8ce..ad158fe 100644 --- a/profile.c +++ b/profile.c @@ -166,11 +166,62 @@ static void plot_text(struct graphics_context *gc, const text_render_options_t * cairo_show_text(cr, buffer); } +struct ev_select { + char *ev_name; + gboolean plot_ev; +}; +static struct ev_select *ev_namelist; +static int evn_allocated; +static int evn_used; + +void evn_foreach(void (*callback)(const char *, int *, void *), void *data) +{ + int i; + + for (i = 0; i < evn_used; i++) { + callback(ev_namelist[i].ev_name, &ev_namelist[i].plot_ev, data); + } +} + +void remember_event(const char *eventname) +{ + int i=0, len; + + if (!eventname || (len = strlen(eventname)) == 0) + return; + while (i < evn_used) { + if (!strncmp(eventname,ev_namelist[i].ev_name,len)) + return; + i++; + } + if (evn_used == evn_allocated) { + evn_allocated += 10; + ev_namelist = realloc(ev_namelist, evn_allocated * sizeof(struct ev_select)); + if (! ev_namelist) + /* we are screwed, but let's just bail out */ + return; + } + ev_namelist[evn_used].ev_name = strdup(eventname); + ev_namelist[evn_used].plot_ev = TRUE; + evn_used++; +} + static void plot_one_event(struct graphics_context *gc, struct plot_info *pi, struct event *event, const text_render_options_t *tro) { int i, depth = 0; int x,y; + /* is plotting this event disabled? */ + if (event->name) { + for (i = 0; i < evn_used; i++) { + if (! strcmp(event->name, ev_namelist[i].ev_name)) { + if (ev_namelist[i].plot_ev) + break; + else + return; + } + } + } for (i = 0; i < pi->nr; i++) { struct plot_data *data = pi->entry + i; if (event->time.seconds < data->sec) @@ -225,6 +276,7 @@ static void plot_text_samples(struct graphics_context *gc, struct plot_info *pi) static const text_render_options_t deep = {14, 1.0, 0.2, 0.2, CENTER, TOP}; static const text_render_options_t shallow = {14, 1.0, 0.2, 0.2, CENTER, BOTTOM}; int i; + int last = -1; for (i = 0; i < pi->nr; i++) { struct plot_data *entry = pi->entry + i; @@ -232,11 +284,18 @@ static void plot_text_samples(struct graphics_context *gc, struct plot_info *pi) if (entry->depth < 2000) continue; - if (entry == entry->max[2]) + if ((entry == entry->max[2]) && entry->depth != last) { render_depth_sample(gc, entry, &deep); + last = entry->depth; + } - if (entry == entry->min[2]) + if ((entry == entry->min[2]) && entry->depth != last) { render_depth_sample(gc, entry, &shallow); + last = entry->depth; + } + + if (entry->depth != last) + last = -1; } } @@ -434,19 +493,13 @@ static int setup_temperature_limits(struct graphics_context *gc, struct plot_inf static void plot_single_temp_text(struct graphics_context *gc, int sec, int mkelvin) { - int deg; + double deg; const char *unit; static const text_render_options_t tro = {12, 0.2, 0.2, 1.0, LEFT, TOP}; - temperature_t temperature = { mkelvin }; - if (output_units.temperature == FAHRENHEIT) { - deg = to_F(temperature); - unit = UTF8_DEGREE "F"; - } else { - deg = to_C(temperature); - unit = UTF8_DEGREE "C"; - } - plot_text(gc, &tro, sec, temperature.mkelvin, "%d%s", deg, unit); + deg = get_temp_units(mkelvin, &unit); + + plot_text(gc, &tro, sec, mkelvin, "%d%s", (int)(deg + 0.5), unit); } static void plot_temperature_text(struct graphics_context *gc, struct plot_info *pi) @@ -566,32 +619,13 @@ static void plot_cylinder_pressure(struct graphics_context *gc, struct plot_info plot_pressure_helper(gc, pi, INTERPOLATED_PR); } -static int mbar_to_PSI(int mbar) -{ - pressure_t p = {mbar}; - return to_PSI(p); -} - static void plot_pressure_value(struct graphics_context *gc, int mbar, int sec, int xalign, int yalign) { int pressure; const char *unit; - switch (output_units.pressure) { - case PASCAL: - pressure = mbar * 100; - unit = "pascal"; - break; - case BAR: - pressure = (mbar + 500) / 1000; - unit = "bar"; - break; - case PSI: - pressure = mbar_to_PSI(mbar); - unit = "psi"; - break; - } + pressure = get_pressure_units(mbar, &unit); text_render_options_t tro = {10, 0.2, 1.0, 0.2, xalign, yalign}; plot_text(gc, &tro, sec, mbar, "%d %s", pressure, unit); } @@ -609,7 +643,7 @@ static void plot_cylinder_pressure_text(struct graphics_context *gc, struct plot return; /* only loop over the actual events from the dive computer */ - for (i = 2; i < pi->nr - 2; i++) { + for (i = 2; i < pi->nr; i++) { entry = pi->entry + i; if (!entry->same_cylinder) { @@ -836,8 +870,10 @@ static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi, for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) { cur_pr[cyl] = track_pr[cyl]->start; } - for (i = 0; i < dive->samples; i++) { - entry = pi->entry + i + 2; + + /* The first two are "fillers" */ + for (i = 2; i < pi->nr; i++) { + entry = pi->entry + i; if (SENSOR_PRESSURE(entry)) { cur_pr[entry->cylinderindex] = SENSOR_PRESSURE(entry); } else { @@ -880,6 +916,68 @@ static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi, } } +static int get_cylinder_index(struct dive *dive, struct event *ev) +{ + int i; + + /* + * Try to find a cylinder that matches the O2 percentage + * in the gas change event 'value' field. + * + * Crazy suunto gas change events. We really should do + * this in libdivecomputer or something. + */ + for (i = 0; i < MAX_CYLINDERS; i++) { + cylinder_t *cyl = dive->cylinder+i; + int o2 = (cyl->gasmix.o2.permille + 5) / 10; + if (o2 == ev->value) + return i; + } + + return 0; +} + +static struct event *get_next_gaschange(struct event *event) +{ + while (event) { + if (!strcmp(event->name, "gaschange")) + return event; + event = event->next; + } + return event; +} + +static int set_cylinder_index(struct plot_info *pi, int i, int cylinderindex, unsigned int end) +{ + while (i < pi->nr) { + struct plot_data *entry = pi->entry+i; + if (entry->sec > end) + break; + if (entry->cylinderindex != cylinderindex) { + entry->cylinderindex = cylinderindex; + entry->pressure[0] = 0; + } + i++; + } + return i; +} + +static void check_gas_change_events(struct dive *dive, struct plot_info *pi) +{ + int i = 0, cylinderindex = 0; + struct event *ev = get_next_gaschange(dive->events); + + if (!ev) + return; + + do { + i = set_cylinder_index(pi, i, cylinderindex, ev->time.seconds); + cylinderindex = get_cylinder_index(dive, ev); + ev = get_next_gaschange(ev->next); + } while (ev); + set_cylinder_index(pi, i, cylinderindex, ~0u); +} + /* * Create a plot-info with smoothing and ranged min/max * @@ -887,17 +985,17 @@ static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi, * sides, so that you can do end-points without having to worry * about it. */ -static struct plot_info *create_plot_info(struct dive *dive) +static struct plot_info *create_plot_info(struct dive *dive, int nr_samples, struct sample *dive_sample) { int cylinderindex = -1; int lastdepth, lastindex; - int i, nr = dive->samples + 4, sec, cyl; + int i, nr = nr_samples + 4, sec, cyl; size_t alloc_size = plot_info_size(nr); struct plot_info *pi; pr_track_t *track_pr[MAX_CYLINDERS] = {NULL, }; pr_track_t *pr_track, *current; gboolean missing_pr = FALSE; - struct plot_data *entry; + struct plot_data *entry = NULL; pi = malloc(alloc_size); if (!pi) @@ -907,19 +1005,36 @@ static struct plot_info *create_plot_info(struct dive *dive) sec = 0; lastindex = 0; lastdepth = -1; - for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) /* initialize the start pressures */ - track_pr[cyl] = pr_track_alloc(dive->cylinder[cyl].start.mbar, -1); - current = track_pr[dive->sample[0].cylinderindex]; - for (i = 0; i < dive->samples; i++) { + for (i = 0; i < nr_samples; i++) { int depth; - struct sample *sample = dive->sample+i; + struct sample *sample = dive_sample+i; entry = pi->entry + i + 2; sec = entry->sec = sample->time.seconds; depth = entry->depth = sample->depth.mm; - entry->same_cylinder = sample->cylinderindex == cylinderindex; - entry->cylinderindex = cylinderindex = sample->cylinderindex; + entry->cylinderindex = sample->cylinderindex; SENSOR_PRESSURE(entry) = sample->cylinderpressure.mbar; + entry->temperature = sample->temperature.mkelvin; + + if (depth || lastdepth) + lastindex = i+2; + + lastdepth = depth; + if (depth > pi->maxdepth) + pi->maxdepth = depth; + } + + check_gas_change_events(dive, pi); + + for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) /* initialize the start pressures */ + track_pr[cyl] = pr_track_alloc(dive->cylinder[cyl].start.mbar, -1); + current = track_pr[pi->entry[2].cylinderindex]; + for (i = 0; i < nr_samples; i++) { + entry = pi->entry + i + 2; + + entry->same_cylinder = entry->cylinderindex == cylinderindex; + cylinderindex = entry->cylinderindex; + /* track the segments per cylinder and their pressure/time integral */ if (!entry->same_cylinder) { current->end = SENSOR_PRESSURE(entry-1); @@ -941,16 +1056,11 @@ static struct plot_info *create_plot_info(struct dive *dive) current->pressure_time += (entry->sec - (entry-1)->sec) * (1 + entry->depth / 10000.0); missing_pr |= !SENSOR_PRESSURE(entry); - entry->temperature = sample->temperature.mkelvin; + } - if (depth || lastdepth) - lastindex = i+2; + if (entry) + current->t_end = entry->sec; - lastdepth = depth; - if (depth > pi->maxdepth) - pi->maxdepth = depth; - } - current->t_end = entry->sec; for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) { /* initialize the end pressures */ int pr = dive->cylinder[cyl].end.mbar; if (pr && track_pr[cyl]) { @@ -958,10 +1068,8 @@ static struct plot_info *create_plot_info(struct dive *dive) pr_track->end = pr; } } - if (lastdepth) - lastindex = i + 2; /* Fill in the last two entries with empty values but valid times */ - i = dive->samples + 2; + i = nr_samples + 2; pi->entry[i].sec = sec + 20; pi->entry[i+1].sec = sec + 40; pi->nr = lastindex+1; @@ -982,7 +1090,24 @@ static struct plot_info *create_plot_info(struct dive *dive) void plot(struct graphics_context *gc, cairo_rectangle_int_t *drawing_area, struct dive *dive) { - struct plot_info *pi = create_plot_info(dive); + struct plot_info *pi; + static struct sample fake[4]; + struct sample *sample = dive->sample; + int nr = dive->samples; + + if (!nr) { + int duration = dive->duration.seconds; + int maxdepth = dive->maxdepth.mm; + sample = fake; + fake[1].time.seconds = duration * 0.05; + fake[1].depth.mm = maxdepth; + fake[2].time.seconds = duration * 0.95; + fake[2].depth.mm = maxdepth; + fake[3].time.seconds = duration * 1.00; + nr = 4; + } + + pi = create_plot_info(dive, nr, sample); cairo_translate(gc->cr, drawing_area->x, drawing_area->y); cairo_set_line_width(gc->cr, 2);