X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=profile.c;h=e5d8aa9b9065d5cc335e9a74413da3bd2eae1aae;hb=93d07f631aec470fb9f920f66ccb03ce699942b5;hp=56716f5f767c11646d0edaade51d2b9b4d1b427f;hpb=98efa0794aa12eea203216e6f5e7e0bdd336d488;p=ext%2Fsubsurface.git diff --git a/profile.c b/profile.c index 56716f5..e5d8aa9 100644 --- a/profile.c +++ b/profile.c @@ -96,6 +96,24 @@ void set_source_rgb(struct graphics_context *gc, double r, double g, double b) #define ROUND_UP(x,y) ((((x)+(y)-1)/(y))*(y)) +/* debugging tool - not normally used */ +static void dump_pi (struct plot_info *pi) +{ + int i; + + printf("pi:{nr:%d maxtime:%d meandepth:%d maxdepth:%d \n" + " minpressure:%d maxpressure:%d endpressure:%d mintemp:%d maxtemp:%d\n", + pi->nr, pi->maxtime, pi->meandepth, pi->maxdepth, + pi->minpressure, pi->maxpressure, pi->endpressure, pi->mintemp, pi->maxtemp); + for (i = 0; i < pi->nr; i++) + printf(" entry[%d]:{same_cylinder:%d cylinderindex:%d sec:%d pressure:{%d,%d}\n" + " temperature:%d depth:%d smoothed:%d}\n", + i, pi->entry[i].same_cylinder, pi->entry[i].cylinderindex, pi->entry[i].sec, + pi->entry[i].pressure[0], pi->entry[i].pressure[1], + pi->entry[i].temperature, pi->entry[i].depth, pi->entry[i].smoothed); + printf(" }\n"); +} + /* * When showing dive profiles, we scale things to the * current dive. However, we don't scale past less than @@ -276,6 +294,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; @@ -283,11 +302,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; } } @@ -485,19 +511,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) @@ -617,32 +637,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); } @@ -660,7 +661,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) { @@ -887,8 +888,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 { @@ -993,6 +996,19 @@ static void check_gas_change_events(struct dive *dive, struct plot_info *pi) set_cylinder_index(pi, i, cylinderindex, ~0u); } +/* for computers that track gas changes through events */ +static int count_gas_change_events(struct dive *dive) +{ + int count = 0; + struct event *ev = get_next_gaschange(dive->events); + + while (ev) { + count++; + ev = get_next_gaschange(ev->next); + } + return count; +} + /* * Create a plot-info with smoothing and ranged min/max * @@ -1000,51 +1016,106 @@ static void check_gas_change_events(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; - size_t alloc_size = plot_info_size(nr); + int i, pi_idx, nr, sec, cyl; + size_t alloc_size; 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; + struct event *ev; + /* we want to potentially add synthetic plot_info elements for the gas changes */ + nr = nr_samples + 4 + 2 * count_gas_change_events(dive); + alloc_size = plot_info_size(nr); pi = malloc(alloc_size); if (!pi) return pi; memset(pi, 0, alloc_size); pi->nr = nr; + pi_idx = 2; /* the two extra events at the start */ + /* check for gas changes before the samples start */ + ev = get_next_gaschange(dive->events); + while (ev && ev->time.seconds < dive_sample->time.seconds) { + entry = pi->entry + pi_idx; + entry->sec = ev->time.seconds; + entry->depth = 0; /* is that always correct ? */ + pi_idx++; + ev = get_next_gaschange(ev->next); + } + if (ev && ev->time.seconds == dive_sample->time.seconds) { + /* we already have a sample at the time of the event */ + ev = get_next_gaschange(ev->next); + } sec = 0; lastindex = 0; lastdepth = -1; - for (i = 0; i < dive->samples; i++) { + for (i = 0; i < nr_samples; i++) { int depth; - struct sample *sample = dive->sample+i; - - entry = pi->entry + i + 2; - sec = entry->sec = sample->time.seconds; + int delay = 0; + struct sample *sample = dive_sample+i; + + entry = pi->entry + i + pi_idx; + while (ev && ev->time.seconds < sample->time.seconds) { + /* insert two fake plot info structures for the end of + * the old tank and the start of the new tank */ + entry->sec = ev->time.seconds; + (entry+1)->sec = ev->time.seconds + 1; + /* we need a fake depth - let's interpolate */ + if (i) { + entry->depth = sample->depth.mm - + (sample->depth.mm - (sample-1)->depth.mm) / 2; + } else + entry->depth = sample->depth.mm; + (entry+1)->depth = entry->depth; + pi_idx += 2; + entry = pi->entry + i + pi_idx; + ev = get_next_gaschange(ev->next); + } + if (ev && ev->time.seconds == sample->time.seconds) { + /* we already have a sample at the time of the event + * just add a new one for the old tank and delay the + * real even by one second (to keep time monotonous) */ + entry->sec = ev->time.seconds; + entry->depth = sample->depth.mm; + pi_idx++; + entry = pi->entry + i + pi_idx; + ev = get_next_gaschange(ev->next); + delay = 1; + } + sec = entry->sec = sample->time.seconds + delay; depth = entry->depth = sample->depth.mm; entry->cylinderindex = sample->cylinderindex; SENSOR_PRESSURE(entry) = sample->cylinderpressure.mbar; entry->temperature = sample->temperature.mkelvin; if (depth || lastdepth) - lastindex = i+2; + lastindex = i+pi_idx; lastdepth = depth; if (depth > pi->maxdepth) pi->maxdepth = depth; } - + entry = pi->entry + i + pi_idx; + /* are there still unprocessed gas changes? that would be very strange */ + while (ev) { + entry->sec = ev->time.seconds; + entry->depth = 0; /* why are there gas changes after the dive is over? */ + pi_idx++; + entry = pi->entry + i + pi_idx; + ev = get_next_gaschange(ev->next); + } + nr_samples += pi_idx - 2; 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[dive->sample[0].cylinderindex]; - for (i = 0; i < dive->samples; i++) { + 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; @@ -1073,7 +1144,9 @@ static struct plot_info *create_plot_info(struct dive *dive) missing_pr |= !SENSOR_PRESSURE(entry); } - current->t_end = entry->sec; + if (entry) + 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]) { @@ -1081,12 +1154,12 @@ 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; + /* the number of actual entries - we may have allocated more if there + * were gas change events, but this is how many were filled */ pi->nr = lastindex+1; pi->maxtime = pi->entry[lastindex].sec; @@ -1100,12 +1173,31 @@ static struct plot_info *create_plot_info(struct dive *dive) } for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) list_free(track_pr[cyl]); + if (0) /* awesome for debugging - not useful otherwise */ + dump_pi(pi); return analyze_plot_info(pi); } 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);