X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=profile.c;h=35a1366bffd90dc42e95edd14fe00f9cd6af951a;hb=f3e70c5496c4da8f1b0b78fa13d8e06908ac12e9;hp=1409f53ff8a505efb5ea502de3bc2e6e56887cda;hpb=adda1c6e86b911c268559a05affd2418767ed239;p=ext%2Fsubsurface.git diff --git a/profile.c b/profile.c index 1409f53..35a1366 100644 --- a/profile.c +++ b/profile.c @@ -14,7 +14,7 @@ int selected_dive = 0; struct plot_info { int nr; int maxtime; - int maxdepth; + int meandepth, maxdepth; int minpressure, maxpressure; int mintemp, maxtemp; struct plot_data { @@ -74,27 +74,36 @@ static void set_source_rgb(struct graphics_context *gc, double r, double g, doub static int get_maxtime(struct plot_info *pi) { int seconds = pi->maxtime; - return MAX(30*60, ROUND_UP(seconds, 60*10)); + /* min 30 minutes, rounded up to 5 minutes, with at least 2.5 minutes to spare */ + return MAX(30*60, ROUND_UP(seconds+150, 60*5)); } -static int round_depth_up(depth_t depth) +static int get_maxdepth(struct plot_info *pi) { - unsigned mm = depth.mm; - /* Minimum 30m */ + unsigned mm = pi->maxdepth; + /* Minimum 30m, rounded up to 10m, with at least 3m to spare */ return MAX(30000, ROUND_UP(mm+3000, 10000)); } typedef struct { int size; double r,g,b; - enum {CENTER,LEFT} halign; - enum {MIDDLE,TOP,BOTTOM} valign; + double hpos, vpos; } text_render_options_t; +#define RIGHT (-1.0) +#define CENTER (-0.5) +#define LEFT (0.0) + +#define TOP (1) +#define MIDDLE (0) +#define BOTTOM (-1) + static void plot_text(struct graphics_context *gc, const text_render_options_t *tro, double x, double y, const char *fmt, ...) { cairo_t *cr = gc->cr; + cairo_font_extents_t fe; cairo_text_extents_t extents; double dx, dy; char buffer[80]; @@ -105,27 +114,10 @@ static void plot_text(struct graphics_context *gc, const text_render_options_t * va_end(args); cairo_set_font_size(cr, tro->size); + cairo_font_extents(cr, &fe); cairo_text_extents(cr, buffer, &extents); - dx = 0; - switch (tro->halign) { - case CENTER: - dx = -(extents.width/2 + extents.x_bearing); - break; - case LEFT: - dx = 0; - break; - } - switch (tro->valign) { - case TOP: - dy = extents.height * 1.2; - break; - case BOTTOM: - dy = -extents.height * 0.8; - break; - case MIDDLE: - dy = 0; - break; - } + dx = tro->hpos * extents.width + extents.x_bearing; + dy = tro->vpos * extents.height + fe.descent; move_to(gc, x, y); cairo_rel_move_to(cr, dx, dy); @@ -181,13 +173,13 @@ static void plot_text_samples(struct graphics_context *gc, struct plot_info *pi) } } -static void plot_depth_text(struct dive *dive, struct graphics_context *gc, struct plot_info *pi) +static void plot_depth_text(struct graphics_context *gc, struct plot_info *pi) { int maxtime, maxdepth; /* Get plot scaling limits */ maxtime = get_maxtime(pi); - maxdepth = round_depth_up(dive->maxdepth); + maxdepth = get_maxdepth(pi); gc->leftx = 0; gc->rightx = maxtime; gc->topy = 0; gc->bottomy = maxdepth; @@ -238,7 +230,7 @@ static void plot_minmax_profile(struct graphics_context *gc, struct plot_info *p plot_minmax_profile_minute(gc, pi, 0, 0.1); } -static void plot_depth_profile(struct dive *dive, struct graphics_context *gc, struct plot_info *pi) +static void plot_depth_profile(struct graphics_context *gc, struct plot_info *pi) { int i; cairo_t *cr = gc->cr; @@ -248,7 +240,7 @@ static void plot_depth_profile(struct dive *dive, struct graphics_context *gc, s /* Get plot scaling limits */ maxtime = get_maxtime(pi); - maxdepth = round_depth_up(dive->maxdepth); + maxdepth = get_maxdepth(pi); /* Time markers: every 5 min */ gc->leftx = 0; gc->rightx = maxtime; @@ -275,8 +267,8 @@ static void plot_depth_profile(struct dive *dive, struct graphics_context *gc, s /* Show mean depth */ set_source_rgba(gc, 1, 0.2, 0.2, 0.40); - move_to(gc, 0, dive->meandepth.mm); - line_to(gc, 1, dive->meandepth.mm); + move_to(gc, 0, pi->meandepth); + line_to(gc, 1, pi->meandepth); cairo_stroke(cr); gc->leftx = 0; gc->rightx = maxtime; @@ -343,14 +335,13 @@ static void plot_single_temp_text(struct graphics_context *gc, int sec, int mkel static void plot_temperature_text(struct graphics_context *gc, struct plot_info *pi) { int i; - int last = 0; + int last = 0, sec = 0; int last_temperature = 0, last_printed_temp = 0; if (!setup_temperature_limits(gc, pi)) return; for (i = 0; i < pi->nr; i++) { - int sec; struct plot_data *entry = pi->entry+i; int mkelvin = entry->temperature; @@ -365,12 +356,11 @@ static void plot_temperature_text(struct graphics_context *gc, struct plot_info last_printed_temp = mkelvin; } /* it would be nice to print the end temperature, if it's different */ - if (last_temperature != last_printed_temp) - plot_single_temp_text(gc, last, last_temperature); + if (abs(last_temperature - last_printed_temp) > 500) + plot_single_temp_text(gc, sec, last_temperature); } -static void plot_temperature_profile(struct dive *dive, struct graphics_context *gc, - struct plot_info *pi) +static void plot_temperature_profile(struct graphics_context *gc, struct plot_info *pi) { int i; cairo_t *cr = gc->cr; @@ -380,94 +370,54 @@ static void plot_temperature_profile(struct dive *dive, struct graphics_context return; set_source_rgba(gc, 0.2, 0.2, 1.0, 0.8); - for (i = 0; i < dive->samples; i++) { - struct sample *sample = dive->sample+i; - if (sample->time.seconds > dive->duration.seconds) - break; /* let's not plot surface temp events */ - int mkelvin = sample->temperature.mkelvin; + for (i = 0; i < pi->nr; i++) { + struct plot_data *entry = pi->entry + i; + int mkelvin = entry->temperature; + int sec = entry->sec; if (!mkelvin) { if (!last) continue; mkelvin = last; } if (last) - line_to(gc, sample->time.seconds, mkelvin); + line_to(gc, sec, mkelvin); else - move_to(gc, sample->time.seconds, mkelvin); + move_to(gc, sec, mkelvin); last = mkelvin; } cairo_stroke(cr); } /* gets both the actual start and end pressure as well as the scaling factors */ -static int get_cylinder_pressure_range(struct dive *dive, struct graphics_context *gc, - struct plot_info *pi, - pressure_t *startp, pressure_t *endp) +static int get_cylinder_pressure_range(struct graphics_context *gc, struct plot_info *pi) { - int i; - int min, max; - gc->leftx = 0; gc->rightx = get_maxtime(pi); - max = 0; - min = 5000000; - if (startp) - startp->mbar = endp->mbar = 0; - - for (i = 0; i < dive->samples; i++) { - int mbar; - struct sample *sample = dive->sample + i; - - /* FIXME! We only track cylinder 0 right now */ - if (sample->cylinderindex) - continue; - mbar = sample->cylinderpressure.mbar; - if (!mbar) - continue; - if (mbar < min) - min = mbar; - if (mbar > max) - max = mbar; - } - if (startp) - startp->mbar = max; - if (endp) - endp->mbar = min; - if (!max) - return 0; - gc->topy = 0; gc->bottomy = max * 1.5; - return 1; + gc->topy = 0; gc->bottomy = pi->maxpressure * 1.5; + return pi->maxpressure != 0; } -static void plot_cylinder_pressure(struct dive *dive, struct graphics_context *gc, - struct plot_info *pi) +static void plot_cylinder_pressure(struct graphics_context *gc, struct plot_info *pi) { - int i, sec = -1; + int i; - if (!get_cylinder_pressure_range(dive, gc, pi, NULL, NULL)) + if (!get_cylinder_pressure_range(gc, pi)) return; cairo_set_source_rgba(gc->cr, 0.2, 1.0, 0.2, 0.80); - move_to(gc, 0, dive->cylinder[0].start.mbar); - for (i = 1; i < dive->samples; i++) { + move_to(gc, 0, pi->maxpressure); + for (i = 1; i < pi->nr; i++) { int mbar; - struct sample *sample = dive->sample + i; + struct plot_data *entry = pi->entry + i; - mbar = sample->cylinderpressure.mbar; + mbar = entry->pressure; if (!mbar) continue; - sec = sample->time.seconds; - if (sec <= dive->duration.seconds) - line_to(gc, sec, mbar); + line_to(gc, entry->sec, mbar); } - /* - * We may have "surface time" events, in which case we don't go - * back to dive duration - */ - if (sec < dive->duration.seconds) - line_to(gc, dive->duration.seconds, dive->cylinder[0].end.mbar); + line_to(gc, pi->maxtime, pi->minpressure); cairo_stroke(gc->cr); } @@ -497,7 +447,7 @@ static double calculate_airuse(struct dive *dive) static void plot_info(struct dive *dive, struct graphics_context *gc) { - text_render_options_t tro = {10, 0.2, 1.0, 0.2, LEFT, TOP}; + text_render_options_t tro = {10, 0.2, 1.0, 0.2, RIGHT, BOTTOM}; const double liters_per_cuft = 28.317; const char *unit, *desc; double airuse; @@ -516,12 +466,17 @@ static void plot_info(struct dive *dive, struct graphics_context *gc) airuse /= liters_per_cuft; break; } - plot_text(gc, &tro, 0.8, 0.8, "vol: %4.2f %s", airuse, unit); + tro.vpos = -1.0; + plot_text(gc, &tro, 0.98, 0.98, "vol: %4.2f %s", airuse, unit); + + tro.vpos = -2.2; if (dive->duration.seconds) { double pressure = 1 + (dive->meandepth.mm / 10000.0); double sac = airuse / pressure * 60 / dive->duration.seconds; - plot_text(gc, &tro, 0.8, 0.85, "SAC: %4.2f %s/min", sac, unit); + plot_text(gc, &tro, 0.98, 0.98, "SAC: %4.2f %s/min", sac, unit); } + + tro.vpos = -3.4; desc = dive->cylinder[0].type.description; if (desc || dive->cylinder[0].gasmix.o2.permille) { int o2 = dive->cylinder[0].gasmix.o2.permille / 10; @@ -529,40 +484,43 @@ static void plot_info(struct dive *dive, struct graphics_context *gc) desc = ""; if (!o2) o2 = 21; - plot_text(gc, &tro, 0.8, 0.9, "%s (%d%%)", desc, o2); + plot_text(gc, &tro, 0.98, 0.98, "%s (%d%%)", desc, o2); } } -static void plot_cylinder_pressure_text(struct dive *dive, struct graphics_context *gc, - struct plot_info *pi) +static int mbar_to_PSI(int mbar) { - pressure_t startp, endp; + pressure_t p = {mbar}; + return to_PSI(p); +} - if (get_cylinder_pressure_range(dive, gc, pi, &startp, &endp)) { +static void plot_cylinder_pressure_text(struct graphics_context *gc, struct plot_info *pi) +{ + if (get_cylinder_pressure_range(gc, pi)) { int start, end; const char *unit = "bar"; switch (output_units.pressure) { case PASCAL: - start = startp.mbar * 100; - end = startp.mbar * 100; + start = pi->maxpressure * 100; + end = pi->minpressure * 100; unit = "pascal"; break; case BAR: - start = (startp.mbar + 500) / 1000; - end = (endp.mbar + 500) / 1000; + start = (pi->maxpressure + 500) / 1000; + end = (pi->minpressure + 500) / 1000; unit = "bar"; break; case PSI: - start = to_PSI(startp); - end = to_PSI(endp); + start = mbar_to_PSI(pi->maxpressure); + end = mbar_to_PSI(pi->minpressure); unit = "psi"; break; } text_render_options_t tro = {10, 0.2, 1.0, 0.2, LEFT, TOP}; - plot_text(gc, &tro, 0, startp.mbar, "%d %s", start, unit); - plot_text(gc, &tro, dive->duration.seconds, endp.mbar, + plot_text(gc, &tro, 0, pi->maxpressure, "%d %s", start, unit); + plot_text(gc, &tro, pi->maxtime, pi->minpressure, "%d %s", end, unit); } } @@ -614,6 +572,27 @@ static struct plot_info *analyze_plot_info(struct plot_info *pi) int i; int nr = pi->nr; + /* Do pressure min/max based on the non-surface data */ + for (i = 0; i < nr; i++) { + struct plot_data *entry = pi->entry+i; + int pressure = entry->pressure; + int temperature = entry->temperature; + + if (pressure) { + if (!pi->minpressure || pressure < pi->minpressure) + pi->minpressure = pressure; + if (pressure > pi->maxpressure) + pi->maxpressure = pressure; + } + + if (temperature) { + if (!pi->mintemp || temperature < pi->mintemp) + pi->mintemp = temperature; + if (temperature > pi->maxtemp) + pi->maxtemp = temperature; + } + } + /* Smoothing function: 5-point triangular smooth */ for (i = 2; i < nr-2; i++) { struct plot_data *entry = pi->entry+i; @@ -641,7 +620,7 @@ static struct plot_info *analyze_plot_info(struct plot_info *pi) */ static struct plot_info *create_plot_info(struct dive *dive) { - int lastdepth, maxtime; + int lastdepth, lastindex; int i, nr = dive->samples + 4, sec; size_t alloc_size = plot_info_size(nr); struct plot_info *pi; @@ -652,45 +631,39 @@ static struct plot_info *create_plot_info(struct dive *dive) memset(pi, 0, alloc_size); pi->nr = nr; sec = 0; - maxtime = 0; + lastindex = 0; lastdepth = -1; for (i = 0; i < dive->samples; i++) { - int depth, pressure, temperature; + int depth; struct sample *sample = dive->sample+i; struct plot_data *entry = pi->entry + i + 2; sec = entry->sec = sample->time.seconds; depth = entry->val = sample->depth.mm; - pressure = entry->pressure = sample->cylinderpressure.mbar; - temperature = entry->temperature = sample->temperature.mkelvin; + entry->pressure = sample->cylinderpressure.mbar; + entry->temperature = sample->temperature.mkelvin; if (depth || lastdepth) - maxtime = sec; + lastindex = i+2; + lastdepth = depth; if (depth > pi->maxdepth) pi->maxdepth = depth; - - if (pressure) { - if (!pi->minpressure || pressure < pi->minpressure) - pi->minpressure = pressure; - if (pressure > pi->maxpressure) - pi->maxpressure = pressure; - } - - if (temperature) { - if (!pi->mintemp || temperature < pi->mintemp) - pi->mintemp = temperature; - if (temperature > pi->maxtemp) - pi->maxtemp = temperature; - } } if (lastdepth) - maxtime = sec + 20; + lastindex = i + 2; /* Fill in the last two entries with empty values but valid times */ i = dive->samples + 2; pi->entry[i].sec = sec + 20; pi->entry[i+1].sec = sec + 40; - pi->maxtime = maxtime; + + pi->nr = lastindex+1; + pi->maxtime = pi->entry[lastindex].sec; + + pi->minpressure = dive->cylinder[0].end.mbar; + pi->maxpressure = dive->cylinder[0].start.mbar; + + pi->meandepth = dive->meandepth.mm; return analyze_plot_info(pi); } @@ -718,18 +691,18 @@ void plot(struct graphics_context *gc, int w, int h, struct dive *dive) gc->maxy = (h - 2*topy); /* Temperature profile */ - plot_temperature_profile(dive, gc, pi); + plot_temperature_profile(gc, pi); /* Cylinder pressure plot */ - plot_cylinder_pressure(dive, gc, pi); + plot_cylinder_pressure(gc, pi); /* Depth profile */ - plot_depth_profile(dive, gc, pi); + plot_depth_profile(gc, pi); /* Text on top of all graphs.. */ plot_temperature_text(gc, pi); - plot_depth_text(dive, gc, pi); - plot_cylinder_pressure_text(dive, gc, pi); + plot_depth_text(gc, pi); + plot_cylinder_pressure_text(gc, pi); /* And info box in the lower right corner.. */ gc->leftx = 0; gc->rightx = 1.0;