diff --git a/core/dive.c b/core/dive.c index 42ef687ef..d07a9d2aa 100644 --- a/core/dive.c +++ b/core/dive.c @@ -1498,24 +1498,26 @@ static void fixup_dive_pressures(struct dive *dive, struct divecomputer *dc) /* Walk the samples from the beginning to find starting pressures.. */ for (i = 0; i < dc->samples; i++) { + int idx; struct sample *sample = dc->sample + i; if (sample->depth.mm < SURFACE_THRESHOLD) continue; - fixup_start_pressure(dive, sample->sensor[0], sample->pressure[0]); - fixup_start_pressure(dive, sample->sensor[1], sample->pressure[1]); + for (idx = 0; idx < MAX_SENSORS; idx++) + fixup_start_pressure(dive, sample->sensor[idx], sample->pressure[idx]); } /* ..and from the end for ending pressures */ for (i = dc->samples; --i >= 0; ) { + int idx; struct sample *sample = dc->sample + i; if (sample->depth.mm < SURFACE_THRESHOLD) continue; - fixup_end_pressure(dive, sample->sensor[0], sample->pressure[0]); - fixup_end_pressure(dive, sample->sensor[1], sample->pressure[1]); + for (idx = 0; idx < MAX_SENSORS; idx++) + fixup_end_pressure(dive, sample->sensor[idx], sample->pressure[idx]); } simplify_dc_pressures(dc); diff --git a/core/gaspressures.c b/core/gaspressures.c index 86ea8de7a..13196b61f 100644 --- a/core/gaspressures.c +++ b/core/gaspressures.c @@ -64,18 +64,20 @@ static void list_free(pr_track_t *list) } #ifdef DEBUG_PR_TRACK -static void dump_pr_track(pr_track_t **track_pr) +static void dump_pr_track(int cyl, pr_track_t *track_pr) { - int cyl; pr_track_t *list; - for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) { - list = track_pr[cyl]; - while (list) { - printf("cyl%d: start %d end %d t_start %d t_end %d pt %d\n", cyl, - list->start, list->end, list->t_start, list->t_end, list->pressure_time); - list = list->next; - } + printf("cyl%d:\n", cyl); + list = track_pr; + while (list) { + printf(" start %d end %d t_start %d:%02d t_end %d:%02d pt %d\n", + mbar_to_PSI(list->start), + mbar_to_PSI(list->end), + FRACTION(list->t_start, 60), + FRACTION(list->t_end, 60), + list->pressure_time); + list = list->next; } } #endif @@ -197,32 +199,28 @@ static struct pr_interpolate_struct get_pr_interpolate_data(pr_track_t *segment, return interpolate; } -static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi, pr_track_t **track_pr, int sensoridx) +static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi, pr_track_t *track_pr, int cyl) { - int cyl, i; + int i; struct plot_data *entry; pr_interpolate_t interpolate = { 0, 0, 0, 0 }; pr_track_t *last_segment = NULL; - int cur_pr[MAX_CYLINDERS]; // cur_pr[MAX_CYLINDERS] is the CCR diluent cylinder + int cur_pr; + enum interpolation_strategy strategy; - for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) { - enum interpolation_strategy strategy; - if (!track_pr[cyl]) { - /* no segment where this cylinder is used */ - cur_pr[cyl] = -1; - continue; - } - if (dive->cylinder[cyl].cylinder_use == OC_GAS) - strategy = SAC; - else - strategy = TIME; - fill_missing_segment_pressures(track_pr[cyl], strategy); // Interpolate the missing tank pressure values .. - cur_pr[cyl] = track_pr[cyl]->start; // in the pr_track_t lists of structures - } // and keep the starting pressure for each cylinder. + /* no segment where this cylinder is used */ + if (!track_pr) + return; + if (dive->cylinder[cyl].cylinder_use == OC_GAS) + strategy = SAC; + else + strategy = TIME; + fill_missing_segment_pressures(track_pr, strategy); // Interpolate the missing tank pressure values .. + cur_pr = track_pr->start; // in the pr_track_t lists of structures + // and keep the starting pressure for each cylinder. #ifdef DEBUG_PR_TRACK - /* another great debugging tool */ - dump_pr_track(track_pr); + dump_pr_track(cyl, track_pr); #endif /* Transfer interpolated cylinder pressures from pr_track strucktures to plotdata @@ -243,27 +241,32 @@ static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi, entry = pi->entry + i; - cyl = entry->sensor[sensoridx]; - if (cyl < 0) - continue; - save_pressure = &(entry->pressure[sensoridx][SENSOR_PR]); - save_interpolated = &(entry->pressure[sensoridx][INTERPOLATED_PR]); + save_pressure = &(entry->pressure[cyl][SENSOR_PR]); + save_interpolated = &(entry->pressure[cyl][INTERPOLATED_PR]); pressure = *save_pressure ? *save_pressure : *save_interpolated; if (pressure) { // If there is a valid pressure value, last_segment = NULL; // get rid of interpolation data, - cur_pr[cyl] = pressure; // set current pressure + cur_pr = pressure; // set current pressure continue; // and skip to next point. } // If there is NO valid pressure value.. // Find the pressure segment corresponding to this entry.. - segment = track_pr[cyl]; + segment = track_pr; while (segment && segment->t_end < entry->sec) // Find the track_pr with end time.. segment = segment->next; // ..that matches the plot_info time (entry->sec) - if (!segment || !segment->pressure_time) { // No (or empty) segment? - *save_pressure = cur_pr[cyl]; // Just use our current pressure - continue; // and skip to next point. + // After last segment? All done. + if (!segment) + break; + + // Before first segment, or between segments.. Go on, no interpolation. + if (segment->t_start > entry->sec) + continue; + + if (!segment->pressure_time) { // Empty segment? + *save_pressure = cur_pr; // Just use our current pressure + continue; // and skip to next point. } // If there is a valid segment but no tank pressure .. @@ -283,13 +286,13 @@ static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi, magic = (interpolate.end - interpolate.start) / (double)interpolate.pressure_time; /* Use that overall pressure change to update the current pressure */ - cur_pr[cyl] = lrint(interpolate.start + magic * interpolate.acc_pressure_time); + cur_pr = lrint(interpolate.start + magic * interpolate.acc_pressure_time); } } else { magic = (interpolate.end - interpolate.start) / (segment->t_end - segment->t_start); - cur_pr[cyl] = lrint(segment->start + magic * (entry->sec - segment->t_start)); + cur_pr = lrint(segment->start + magic * (entry->sec - segment->t_start)); } - *save_interpolated = cur_pr[cyl]; // and store the interpolated data in plot_info + *save_interpolated = cur_pr; // and store the interpolated data in plot_info } } @@ -328,6 +331,8 @@ static void debug_print_pressures(struct plot_info *pi) } #endif +extern bool has_gaschange_event(struct dive *dive, struct divecomputer *dc, int idx); + /* This function goes through the list of tank pressures, either SENSOR_PRESSURE(entry) or O2CYLINDER_PRESSURE(entry), * of structure plot_info for the dive profile where each item in the list corresponds to one point (node) of the * profile. It finds values for which there are no tank pressures (pressure==0). For each missing item (node) of @@ -338,78 +343,116 @@ static void debug_print_pressures(struct plot_info *pi) * in the pr_track_alloc structures. If diluent_flag = 1, then DILUENT_PRESSURE(entry) is used instead of SENSOR_PRESSURE. * This function is called by create_plot_info_new() in profile.c */ -void populate_pressure_information(struct dive *dive, struct divecomputer *dc, struct plot_info *pi, int sensoridx) +void populate_pressure_information(struct dive *dive, struct divecomputer *dc, struct plot_info *pi, int sensor) { (void) dc; - int i, cylinderid, cylinderindex = -1; - pr_track_t *track_pr[MAX_CYLINDERS] = { NULL, }; + int first, last, cyl; + cylinder_t *cylinder = dive->cylinder + sensor; + pr_track_t *track = NULL; pr_track_t *current = NULL; - bool missing_pr = false; - bool found_any_pr_data = false; + struct plot_data *entry; + struct event *ev; + int missing_pr = 0, dense = 1; /* if we have no pressure data whatsoever, this is pointless, so let's just return */ - for (i = 0; i < MAX_CYLINDERS; i++) { - if (dive->cylinder[i].start.mbar || dive->cylinder[i].sample_start.mbar || - dive->cylinder[i].end.mbar || dive->cylinder[i].sample_end.mbar) { - found_any_pr_data = true; - break; - } - } - if (!found_any_pr_data) + if (!cylinder->start.mbar && !cylinder->end.mbar && + !cylinder->sample_start.mbar && !cylinder->sample_end.mbar) return; - for (i = 0; i < pi->nr; i++) { + /* Get a rough range of where we have any pressures at all */ + first = last = -1; + for (int i = 0; i < pi->nr; i++) { struct plot_data *entry = pi->entry + i; - unsigned pressure; + unsigned pressure = SENSOR_PRESSURE(entry, sensor); - pressure = SENSOR_PRESSURE(entry, sensoridx); - cylinderid = entry->sensor[sensoridx]; - if (cylinderid < 0) - goto GIVE_UP; + if (!pressure) + continue; + if (first < 0) + first = i; + last = i; + } + + /* No sensor data at all? */ + if (first == last) + return; + + /* + * Split the range: + * - missing pressure data + * - gas change events to other cylinders + * + * Note that we only look at gas switches if this cylinder + * itself has a gas change event. + */ + cyl = sensor; + ev = NULL; + if (has_gaschange_event(dive, dc, sensor)) + ev = get_next_event(dc->events, "gaschange"); + + for (int i = first; i <= last; i++) { + struct plot_data *entry = pi->entry + i; + unsigned pressure = SENSOR_PRESSURE(entry, sensor); + int time = entry->sec; + + while (ev && ev->time.seconds <= time) { + cyl = get_cylinder_index(dive, ev); + if (cyl < 0) + cyl = sensor; + ev = get_next_event(ev->next, "gaschange"); + } - /* If track_pr structure already exists, then update it: */ - /* discrete integration of pressure over time to get the SAC rate equivalent */ if (current) { entry->pressure_time = calc_pressure_time(dive, entry - 1, entry); current->pressure_time += entry->pressure_time; current->t_end = entry->sec; + if (pressure) + current->end = pressure; } - /* If 1st record or different cylinder: Create a new track_pr structure: */ - /* track the segments per cylinder and their pressure/time integral */ - if (cylinderid != cylinderindex) { - cylinderindex = entry->sensor[sensoridx]; - current = pr_track_alloc(pressure, entry->sec); - track_pr[cylinderindex] = list_add(track_pr[cylinderindex], current); - continue; - } - + // If we have no pressure information, we will need to + // continue with or without a tracking entry. Mark any + // existing tracking entry as non-dense, and remember + // to fill in interpolated data. if (!pressure) { missing_pr = 1; + dense = 0; continue; } - if (current) - current->end = pressure; - /* Was it continuous? */ - if (SENSOR_PRESSURE(entry - 1, sensoridx)) + // We have a final pressure for 'current' + // If a gas switch has occurred, finish the + // current pressure track entry and continue + // until we get back to this cylinder. + if (cyl != sensor) { + current = NULL; + SENSOR_PRESSURE(entry, sensor) = 0; + continue; + } + + // If we already have a pressure tracking entry, and + // it has not had any missing samples, just continue + // using it - there's nothing to interpolate yet. + if (current && dense) continue; - /* transmitter stopped transmitting cylinder pressure data */ + // We need to start a new tracking entry, either + // because the previous was interrupted by a gas + // switch event, or because the previous one has + // missing entries that need to be interpolated. + // Or maybe we didn't have a previous one at all, + // and this is the first pressure entry. current = pr_track_alloc(pressure, entry->sec); - if (cylinderindex >= 0) - track_pr[cylinderindex] = list_add(track_pr[cylinderindex], current); + track = list_add(track, current); + dense = 1; } if (missing_pr) { - fill_missing_tank_pressures(dive, pi, track_pr, sensoridx); + fill_missing_tank_pressures(dive, pi, track, sensor); } #ifdef PRINT_PRESSURES_DEBUG debug_print_pressures(pi); #endif -GIVE_UP: - for (i = 0; i < MAX_CYLINDERS; i++) - list_free(track_pr[i]); + list_free(track); } diff --git a/core/profile.c b/core/profile.c index 1b5c36621..6e216ec04 100644 --- a/core/profile.c +++ b/core/profile.c @@ -170,15 +170,13 @@ static int get_local_sac(struct plot_data *entry1, struct plot_data *entry2, str /* Get local sac-rate (in ml/min) between entry1 and entry2 */ static int get_local_sac(struct plot_data *entry1, struct plot_data *entry2, struct dive *dive) { - int index = entry1->sensor[0]; + int index = 0; cylinder_t *cyl; int duration = entry2->sec - entry1->sec; int depth, airuse; pressure_t a, b; double atm; - if (entry2->sensor[0] != index) - return 0; if (duration <= 0) return 0; a.mbar = GET_PRESSURE(entry1, 0); @@ -362,21 +360,6 @@ static int count_events(struct divecomputer *dc) return result; } -static int set_cylinder_index(struct plot_info *pi, int i, int cylinderindex, int end) -{ - while (i < pi->nr) { - struct plot_data *entry = pi->entry + i; - if (entry->sec > end) - break; - if (entry->sensor[0] != cylinderindex) { - entry->sensor[0] = cylinderindex; - entry->pressure[0][0] = 0; - } - i++; - } - return i; -} - static int set_setpoint(struct plot_info *pi, int i, int setpoint, int end) { while (i < pi->nr) { @@ -389,40 +372,6 @@ static int set_setpoint(struct plot_info *pi, int i, int setpoint, int end) return i; } -/* normally the first cylinder has index 0... if not, we need to fix this up here */ -static int set_first_cylinder_index(struct plot_info *pi, int i, int cylinderindex, int end) -{ - while (i < pi->nr) { - struct plot_data *entry = pi->entry + i; - if (entry->sec > end) - break; - entry->sensor[0] = cylinderindex; - i++; - } - return i; -} - -static void check_gas_change_events(struct dive *dive, struct divecomputer *dc, struct plot_info *pi) -{ - int i = 0, cylinderindex = 0; - struct event *ev = get_next_event(dc->events, "gaschange"); - - // for dive computers that tell us their first gas as an event on the first sample - // we need to make sure things are setup correctly - cylinderindex = explicit_first_cylinder(dive, dc); - set_first_cylinder_index(pi, 0, cylinderindex, INT_MAX); - - if (!ev) - return; - - do { - i = set_cylinder_index(pi, i, cylinderindex, ev->time.seconds); - cylinderindex = get_cylinder_index(dive, ev); - ev = get_next_event(ev->next, "gaschange"); - } while (ev); - set_cylinder_index(pi, i, cylinderindex, INT_MAX); -} - static void check_setpoint_events(struct dive *dive, struct divecomputer *dc, struct plot_info *pi) { int i = 0; @@ -639,11 +588,10 @@ struct plot_data *populate_plot_entries(struct dive *dive, struct divecomputer * } else { entry->pressures.o2 = sample->setpoint.mbar / 1000.0; } - /* FIXME! sensor index -> cylinder index translation! */ - entry->sensor[0] = sample->sensor[0]; - entry->sensor[1] = sample->sensor[1]; - SENSOR_PRESSURE(entry, 0) = sample->pressure[0].mbar; - SENSOR_PRESSURE(entry, 1) = sample->pressure[1].mbar; + if (sample->pressure[0].mbar) + SENSOR_PRESSURE(entry, sample->sensor[0]) = sample->pressure[0].mbar; + if (sample->pressure[1].mbar) + SENSOR_PRESSURE(entry, sample->sensor[1]) = sample->pressure[1].mbar; if (sample->temperature.mkelvin) entry->temperature = lasttemp = sample->temperature.mkelvin; else @@ -686,38 +634,6 @@ struct plot_data *populate_plot_entries(struct dive *dive, struct divecomputer * #undef INSERT_ENTRY -static void populate_cylinder_pressure_data(int idx, int start, int end, struct plot_info *pi, int sensoridx) -{ - int i; - - /* First: check that none of the entries has sensor pressure for this cylinder index */ - for (i = 0; i < pi->nr; i++) { - struct plot_data *entry = pi->entry + i; - if (entry->sensor[sensoridx] != idx) - continue; - if (SENSOR_PRESSURE(entry, sensoridx)) - return; - } - - /* Then: populate the first entry with the beginning cylinder pressure */ - for (i = 0; i < pi->nr; i++) { - struct plot_data *entry = pi->entry + i; - if (entry->sensor[sensoridx] != idx) - continue; - SENSOR_PRESSURE(entry, sensoridx) = start; - break; - } - - /* .. and the last entry with the ending cylinder pressure */ - for (i = pi->nr; --i >= 0; /* nothing */) { - struct plot_data *entry = pi->entry + i; - if (entry->sensor[sensoridx] != idx) - continue; - SENSOR_PRESSURE(entry, sensoridx) = end; - break; - } -} - /* * Calculate the sac rate between the two plot entries 'first' and 'last'. * @@ -726,6 +642,7 @@ static void populate_cylinder_pressure_data(int idx, int start, int end, struct */ static int sac_between(struct dive *dive, struct plot_data *first, struct plot_data *last) { + int sensor = 0; int airuse; double pressuretime; pressure_t a, b; @@ -735,9 +652,9 @@ static int sac_between(struct dive *dive, struct plot_data *first, struct plot_d return 0; /* Calculate air use - trivial */ - a.mbar = GET_PRESSURE(first, 0); - b.mbar = GET_PRESSURE(last, 0); - cyl = dive->cylinder + first->sensor[0]; + a.mbar = GET_PRESSURE(first, sensor); + b.mbar = GET_PRESSURE(last, sensor); + cyl = dive->cylinder + sensor; airuse = gas_volume(cyl, a) - gas_volume(cyl, b); if (airuse <= 0) return 0; @@ -767,6 +684,7 @@ static void fill_sac(struct dive *dive, struct plot_info *pi, int idx) { struct plot_data *entry = pi->entry + idx; struct plot_data *first, *last; + int sensor = 0; int time; if (entry->sac) @@ -783,13 +701,12 @@ static void fill_sac(struct dive *dive, struct plot_info *pi, int idx) time = entry->sec - 30; while (idx > 0) { struct plot_data *prev = first-1; - if (prev->sensor[0] != first->sensor[0]) - break; + if (prev->depth < SURFACE_THRESHOLD && first->depth < SURFACE_THRESHOLD) break; if (prev->sec < time) break; - if (!GET_PRESSURE(prev, 0)) + if (!GET_PRESSURE(prev, sensor)) break; idx--; first = prev; @@ -800,13 +717,11 @@ static void fill_sac(struct dive *dive, struct plot_info *pi, int idx) time = first->sec + 60; while (++idx < pi->nr) { struct plot_data *next = last+1; - if (next->sensor[0] != last->sensor[0]) - break; if (next->depth < SURFACE_THRESHOLD && last->depth < SURFACE_THRESHOLD) break; if (next->sec > time) break; - if (!GET_PRESSURE(next, 0)) + if (!GET_PRESSURE(next, sensor)) break; last = next; } @@ -828,21 +743,66 @@ static void populate_secondary_sensor_data(struct divecomputer *dc, struct plot_ /* We should try to see if it has interesting pressure data here */ } +/* + * This adds a pressure entry to the plot_info based on the gas change + * information and the manually filled in pressures. + */ +static void add_plot_pressure(struct plot_info *pi, int time, int cyl, int mbar) +{ + for (int i = 0; i < pi->nr; i++) { + struct plot_data *entry = pi->entry + i; + + if (entry->sec < time) + continue; + SENSOR_PRESSURE(entry, cyl) = mbar; + return; + } +} + static void setup_gas_sensor_pressure(struct dive *dive, struct divecomputer *dc, struct plot_info *pi) { - int i; + int prev = -1, i; + struct event *ev; + unsigned int seen[MAX_CYLINDERS] = { 0, }; + unsigned int first[MAX_CYLINDERS] = { 0, }; + unsigned int last[MAX_CYLINDERS] = { 0, }; struct divecomputer *secondary; - /* First, populate the pressures with the manual cylinder data.. */ - for (i = 0; i < MAX_CYLINDERS; i++) { - cylinder_t *cyl = dive->cylinder + i; - int start = cyl->start.mbar ?: cyl->sample_start.mbar; - int end = cyl->end.mbar ?: cyl->sample_end.mbar; + for (ev = get_next_event(dc->events, "gaschange"); ev != NULL; ev = get_next_event(ev->next, "gaschange")) { + int cyl = ev->gas.index; + int sec = ev->time.seconds; - if (!start || !end) + if (cyl < 0) continue; - populate_cylinder_pressure_data(i, start, end, pi, dive->cylinder[i].cylinder_use == OXYGEN); + if (prev >= 0) + last[prev] = sec; + prev = cyl; + + last[cyl] = sec; + if (!seen[cyl]) { + int endtime = sec; + if (dc->samples) + endtime = dc->sample[dc->samples-1].time.seconds; + + // The end time may be updated by a subsequent cylinder change + first[cyl] = sec; + last[cyl] = endtime; + seen[cyl] = 1; + } + } + + for (i = 0; i < MAX_CYLINDERS; i++) { + if (seen[i]) { + cylinder_t *cyl = dive->cylinder + i; + int start = cyl->start.mbar; + int end = cyl->end.mbar; + + if (start) + add_plot_pressure(pi, first[i], i, start); + if (end) + add_plot_pressure(pi, last[i], i, end); + } } /* @@ -862,6 +822,7 @@ static void setup_gas_sensor_pressure(struct dive *dive, struct divecomputer *dc /* calculate DECO STOP / TTS / NDL */ static void calculate_ndl_tts(struct plot_data *entry, struct dive *dive, double surface_pressure) { + int cylinderindex = 0; /* FIXME: This should be configurable */ /* ascent speed up to first deco stop */ const int ascent_s_per_step = 1; @@ -877,7 +838,6 @@ static void calculate_ndl_tts(struct plot_data *entry, struct dive *dive, double surface_pressure, dive, 1), deco_stepsize); int ascent_depth = entry->depth; /* at what time should we give up and say that we got enuff NDL? */ - int cylinderindex = entry->sensor[0]; /* If iterating through a dive, entry->tts_calc needs to be reset */ entry->tts_calc = 0; @@ -971,7 +931,7 @@ void calculate_deco_information(struct dive *dive, struct divecomputer *dc, stru for (j = t0 + time_stepsize; j <= t1; j += time_stepsize) { int depth = interpolate(entry[-1].depth, entry[0].depth, j - t0, t1 - t0); add_segment(depth_to_bar(depth, dive), - &dive->cylinder[entry->sensor[0]].gasmix, time_stepsize, entry->o2pressure.mbar, dive, entry->sac); + &dive->cylinder[0].gasmix, time_stepsize, entry->o2pressure.mbar, dive, entry->sac); if ((t1 - j < time_stepsize) && (j < t1)) time_stepsize = t1 - j; } @@ -1125,7 +1085,7 @@ static void calculate_gas_information_new(struct dive *dive, struct plot_info *p for (i = 1; i < pi->nr; i++) { int fn2, fhe; struct plot_data *entry = pi->entry + i; - int cylinderindex = entry->sensor[0]; + int cylinderindex = 0; amb_pressure = depth_to_bar(entry->depth, dive); @@ -1249,13 +1209,11 @@ void create_plot_info_new(struct dive *dive, struct divecomputer *dc, struct plo last_pi_entry_new = populate_plot_entries(dive, dc, pi); - check_gas_change_events(dive, dc, pi); /* Populate the gas index from the gas change events */ check_setpoint_events(dive, dc, pi); /* Populate setpoints */ setup_gas_sensor_pressure(dive, dc, pi); /* Try to populate our gas pressure knowledge */ if (!fast) { - populate_pressure_information(dive, dc, pi, false); /* .. calculate missing pressure entries for all gasses except o2 */ - if (dc->divemode == CCR) /* For CCR dives.. */ - populate_pressure_information(dive, dc, pi, true); /* .. calculate missing o2 gas pressure entries */ + for (int cyl = 0; cyl < MAX_CYLINDERS; cyl++) + populate_pressure_information(dive, dc, pi, cyl); } fill_o2_values(dc, pi, dive); /* .. and insert the O2 sensor data having 0 values. */ calculate_sac(dive, pi); /* Calculate sac */ @@ -1477,7 +1435,6 @@ void compare_samples(struct plot_data *e1, struct plot_data *e2, char *buf, int last_sec = start->sec; last_pressure = GET_PRESSURE(start, 0); - last_cylidx = start->sensor[0]; data = start; while (data != stop) { @@ -1501,10 +1458,6 @@ void compare_samples(struct plot_data *e1, struct plot_data *e2, char *buf, int if (GET_PRESSURE(data, 0) < last_pressure + 2000) bar_used += last_pressure - GET_PRESSURE(data, 0); - if (data->sensor[0] != last_cylidx) - /* if we change tanks, don't try to do SAC rate later */ - crossed_tankchange = true; - count += 1; last_sec = data->sec; last_pressure = GET_PRESSURE(data, 0); @@ -1548,7 +1501,7 @@ void compare_samples(struct plot_data *e1, struct plot_data *e2, char *buf, int pressurevalue = get_pressure_units(bar_used, &pressure_unit); memcpy(buf2, buf, bufsize); snprintf(buf, bufsize, translate("gettextFromC", "%s %sP:%d %s"), buf2, UTF8_DELTA, pressurevalue, pressure_unit); - cylinder_t *cyl = displayed_dive.cylinder + start->sensor[0]; + cylinder_t *cyl = displayed_dive.cylinder + 0; /* if we didn't cross a tank change and know the cylidner size as well, show SAC rate */ if (!crossed_tankchange && cyl->type.size.mliter) { double volume_value; diff --git a/core/profile.h b/core/profile.h index 988736f30..1cbcd30fd 100644 --- a/core/profile.h +++ b/core/profile.h @@ -21,15 +21,12 @@ struct divecomputer; struct plot_info; struct plot_data { unsigned int in_deco : 1; - char sensor[2]; int sec; - /* pressure[0] is main sensor pressure (diluent for CCR) - * pressure[1] is secondary sensor pressure (O2 for CCR) - * - * pressure[x][0] is sensor pressure + /* + * pressure[x][0] is sensor pressure for cylinder x * pressure[x][1] is interpolated pressure */ - int pressure[2][2]; + int pressure[MAX_CYLINDERS][2]; int temperature; /* Depth info */ int depth; diff --git a/profile-widget/diveprofileitem.cpp b/profile-widget/diveprofileitem.cpp index fcaca3a88..6f2bf98b0 100644 --- a/profile-widget/diveprofileitem.cpp +++ b/profile-widget/diveprofileitem.cpp @@ -683,108 +683,99 @@ void DiveGasPressureItem::modelDataChanged(const QModelIndex &topLeft, const QMo // We don't have enougth data to calculate things, quit. if (!shouldCalculateStuff(topLeft, bottomRight)) return; - int last_index = -1; - QPolygonF boundingPoly, o2Poly; // This is the "Whole Item", but a pressure can be divided in N Polygons. + + int plotted_cyl[MAX_CYLINDERS] = { false, }; + int last_plotted[MAX_CYLINDERS] = { 0, }; + QPolygonF poly[MAX_CYLINDERS]; + QPolygonF boundingPoly; polygons.clear(); - polygons.append(o2Poly); for (int i = 0, count = dataModel->rowCount(); i < count; i++) { - plot_data *entry = dataModel->data().entry + i; - int mbar = GET_PRESSURE(entry, 0); - int o2mbar = GET_PRESSURE(entry, 1); + struct plot_data *entry = dataModel->data().entry + i; - if ((int)entry->sensor[0] != last_index) { - polygons.append(QPolygonF()); // this is the polygon that will be actually drawn on screen. - last_index = entry->sensor[0]; - } - if (!mbar) { - continue; - } - if (o2mbar) { - QPointF o2point(hAxis->posAtValue(entry->sec), vAxis->posAtValue(o2mbar)); - boundingPoly.push_back(o2point); - polygons.first().push_back(o2point); - } + for (int cyl = 0; cyl < MAX_CYLINDERS; cyl++) { + int mbar = GET_PRESSURE(entry, cyl); + int time = entry->sec; - QPointF point(hAxis->posAtValue(entry->sec), vAxis->posAtValue(mbar)); - boundingPoly.push_back(point); // The BoundingRect - polygons.last().push_back(point); // The polygon thta will be plotted. + if (!mbar) + continue; + + QPointF point(hAxis->posAtValue(time), vAxis->posAtValue(mbar)); + boundingPoly.push_back(point); + + if (plotted_cyl[cyl]) { + /* Have we used this culinder in the last two minutes? Continue */ + if (time - last_plotted[cyl] <= 2*60) { + poly[cyl].push_back(point); + last_plotted[cyl] = time; + continue; + } + + /* Finish the previous one, start a new one */ + polygons.append(poly[cyl]); + poly[cyl] = QPolygonF(); + } + + plotted_cyl[cyl] = true; + last_plotted[cyl] = time; + poly[cyl].push_back(point); + } } + + for (int cyl = 0; cyl < MAX_CYLINDERS; cyl++) { + if (!plotted_cyl[cyl]) + continue; + polygons.append(poly[cyl]); + } + setPolygon(boundingPoly); qDeleteAll(texts); texts.clear(); - int mbar, cyl, lastcyl; - int o2mbar, o2cyl; + int seen_cyl[MAX_CYLINDERS] = { false, }; int last_pressure[MAX_CYLINDERS] = { 0, }; int last_time[MAX_CYLINDERS] = { 0, }; - struct plot_data *entry; - - cyl = o2cyl = lastcyl = -1; - mbar = o2mbar = 0; double print_y_offset[8][2] = { { 0, -0.5 }, { 0, -0.5 }, { 0, -0.5 }, { 0, -0.5 }, { 0, -0.5 } ,{ 0, -0.5 }, { 0, -0.5 }, { 0, -0.5 } }; - // CCR dives: These are offset values used to print the gas lables and pressures on a CCR dive profile at - // appropriate Y-coordinates: One doublet of values for each of 8 cylinders. + // These are offset values used to print the gas lables and pressures on a + // dive profile at appropriate Y-coordinates: One doublet of values for each + // of 8 cylinders. // Order of offsets within a doublet: gas lable offset; gas pressure offset. // The array is initialised with default values that apply to non-CCR dives. - bool offsets_initialised = false; - QFlags alignVar= Qt::AlignTop, align_dil = Qt::AlignBottom, align_o2 = Qt::AlignTop; + QFlags alignVar = Qt::AlignTop; + QFlags align[MAX_CYLINDERS]; + double axisRange = (vAxis->maximum() - vAxis->minimum())/1000; // Convert axis pressure range to bar double axisLog = log10(log10(axisRange)); + for (int i = 0, count = dataModel->rowCount(); i < count; i++) { - entry = dataModel->data().entry + i; + struct plot_data *entry = dataModel->data().entry + i; - cyl = entry->sensor[0]; - o2cyl = entry->sensor[1]; - mbar = GET_PRESSURE(entry, 0); - o2mbar = GET_PRESSURE(entry, 1); + for (int cyl = 0; cyl < MAX_CYLINDERS; cyl++) { + int mbar = GET_PRESSURE(entry, cyl); - if (o2mbar) { // Do we have a second cylinder pressure? If so, do - // The first time an o2 value is detected, see if the oxygen cyl pressure graph starts above or below the dil graph - if (!offsets_initialised) { // Initialise the parameters for placing the text correctly near the graph line: - if ((o2mbar > mbar)) { // If above, write o2 start cyl pressure above graph and diluent pressure below graph: - print_y_offset[o2cyl][0] = -7 * axisLog; // y offset for oxygen gas lable (above); pressure offsets=-0.5, already initialised - print_y_offset[cyl][0] = 5 * axisLog; // y offset for diluent gas lable (below) - } else { // ... else write o2 start cyl pressure below graph: - print_y_offset[o2cyl][0] = 5 * axisLog; // o2 lable & pressure below graph; pressure offsets=-0.5, already initialised - print_y_offset[cyl][0] = -7.8 * axisLog; // and diluent lable above graph. - align_dil = Qt::AlignTop; - align_o2 = Qt::AlignBottom; - } - offsets_initialised = true; - } + if (!mbar) + continue; - if (!seen_cyl[o2cyl]) { //For o2, on the left of profile, write lable and pressure - plotPressureValue(o2mbar, entry->sec, align_o2, print_y_offset[o2cyl][1]); - plotGasValue(o2mbar, entry->sec, displayed_dive.cylinder[o2cyl].gasmix, align_o2, print_y_offset[o2cyl][0]); - seen_cyl[o2cyl] = true; - } - last_pressure[o2cyl] = o2mbar; - last_time[o2cyl] = entry->sec; - alignVar = align_dil; - } - - if (!mbar) - continue; - - if (cyl != lastcyl) { // Pressure value near the left hand edge of the profile - other cylinders: - lastcyl = cyl; // For each other cylinder, write the gas lable and pressure if (!seen_cyl[cyl]) { plotPressureValue(mbar, entry->sec, alignVar, print_y_offset[cyl][1]); - plotGasValue(mbar, entry->sec, displayed_dive.cylinder[cyl].gasmix, align_dil, print_y_offset[cyl][0]); + plotGasValue(mbar, entry->sec, displayed_dive.cylinder[cyl].gasmix, alignVar, print_y_offset[cyl][0]); seen_cyl[cyl] = true; + + /* Alternate alignment as we see cylinder use.. */ + align[cyl] = alignVar; + alignVar ^= Qt::AlignTop | Qt::AlignBottom; } + last_pressure[cyl] = mbar; + last_time[cyl] = entry->sec; } - last_pressure[cyl] = mbar; - last_time[cyl] = entry->sec; } - for (cyl = 0; cyl < MAX_CYLINDERS; cyl++) { // For each cylinder, on right hand side of profile, write cylinder pressure - alignVar = ((o2cyl >= 0) && (cyl == o2cyl)) ? align_o2 : align_dil; + // For each cylinder, on right hand side of profile, write cylinder pressure + for (int cyl = 0; cyl < MAX_CYLINDERS; cyl++) { if (last_time[cyl]) { - plotPressureValue(last_pressure[cyl], last_time[cyl], (alignVar | Qt::AlignLeft), print_y_offset[cyl][1]); + plotPressureValue(last_pressure[cyl], last_time[cyl], align[cyl] | Qt::AlignLeft, print_y_offset[cyl][1]); } } } diff --git a/profile-widget/profilewidget2.cpp b/profile-widget/profilewidget2.cpp index 17f3544f3..d8fd8da2c 100644 --- a/profile-widget/profilewidget2.cpp +++ b/profile-widget/profilewidget2.cpp @@ -1407,8 +1407,6 @@ void ProfileWidget2::contextMenuEvent(QContextMenuEvent *event) action->setText(model->data(model->index(i, 0), Qt::DisplayRole).toString() + QString(tr(" (Tank %1)")).arg(i + 1)); connect(action, SIGNAL(triggered(bool)), this, SLOT(changeGas())); action->setData(event->globalPos()); - if (i == entry->sensor[0]) - action->setDisabled(true); gasChange->addAction(action); } } diff --git a/profile-widget/tankitem.cpp b/profile-widget/tankitem.cpp index 89ddffed9..e2b528eb2 100644 --- a/profile-widget/tankitem.cpp +++ b/profile-widget/tankitem.cpp @@ -98,20 +98,24 @@ void TankItem::modelDataChanged(const QModelIndex &topLeft, const QModelIndex &b // walk the list and figure out which tanks go where struct plot_data *entry = pInfoEntry; struct plot_data *lastentry = pInfoEntry; - int cylIdx = entry->sensor[0]; + int cylIdx = 0; // explicit_first_cylinder(dive, dc) int i = -1; int startTime = 0; struct gasmix *gas = &diveCylinderStore.cylinder[cylIdx].gasmix; qreal width, left; + + // FIXME! This used to depend on the sensor indexes that we no longer have + // We should use gaschange events or something while (++i < pInfoNr) { + int newIdx = 0; // get_next_event(dc->events, "gaschange"); entry = &pInfoEntry[i]; lastentry = &pInfoEntry[i-1]; - if (entry->sensor[0] == cylIdx) + if (newIdx == cylIdx) continue; width = hAxis->posAtValue(lastentry->sec) - hAxis->posAtValue(startTime); left = hAxis->posAtValue(startTime); createBar(left, width, gas); - cylIdx = entry->sensor[0]; + cylIdx = newIdx; gas = &diveCylinderStore.cylinder[cylIdx].gasmix; startTime = lastentry->sec; } diff --git a/qt-models/diveplotdatamodel.cpp b/qt-models/diveplotdatamodel.cpp index b4e72b2df..3e0ae57f1 100644 --- a/qt-models/diveplotdatamodel.cpp +++ b/qt-models/diveplotdatamodel.cpp @@ -40,7 +40,7 @@ QVariant DivePlotDataModel::data(const QModelIndex &index, int role) const case USERENTERED: return false; case CYLINDERINDEX: - return item.sensor[0]; + return 0; case SENSOR_PRESSURE: return item.pressure[0][0]; case INTERPOLATED_PRESSURE: