From d5d7fdc9af98756cd8b241502f6493c518d6fa0f Mon Sep 17 00:00:00 2001 From: "Robert C. Helling" Date: Mon, 17 Nov 2014 17:39:40 +0100 Subject: [PATCH] For CCR dives, show plot for diluent and O2 cylinder pressures Also fixes a bug in the diluent pressure interpolation Signed-off-by: Robert C. Helling Signed-off-by: Dirk Hohndel --- TODO.CCR | 2 +- gaspressures.c | 32 ++++++++++++++++++++----------- profile.c | 26 +++++++++++++++---------- profile.h | 2 ++ qt-ui/diveplanner.cpp | 2 +- qt-ui/profile/diveprofileitem.cpp | 27 +++++++++++++++++++++++++- 6 files changed, 67 insertions(+), 24 deletions(-) diff --git a/TODO.CCR b/TODO.CCR index c1c4d9750..93b15aec9 100644 --- a/TODO.CCR +++ b/TODO.CCR @@ -1,5 +1,5 @@ TODO for CCR support -- tank pressure plot (see test40.xml) +- make tank pressure plot work for bailout dives - bailout handling in SAC rate calculation - UI to modify the tank type for CCR (i.e., set the diluent and oxygen cylinders) diff --git a/gaspressures.c b/gaspressures.c index 745fa3e52..73010846a 100644 --- a/gaspressures.c +++ b/gaspressures.c @@ -99,6 +99,8 @@ static void dump_pr_track(pr_track_t **track_pr) */ static void fill_missing_segment_pressures(pr_track_t *list, enum interpolation_strategy strategy) { + double magic; + while (list) { int start = list->start, end; pr_track_t *tmp = list; @@ -144,10 +146,12 @@ static void fill_missing_segment_pressures(pr_track_t *list, enum interpolation_ } break; case TIME: - if (list->t_end && (tmp->t_start - tmp->t_end)) - list->end = start - (start - end) * (list->t_end - tmp->t_end) / (tmp->t_start - tmp->t_end); - else + if (list->t_end && (tmp->t_start - tmp->t_end)) { + magic = (list->t_start - tmp->t_end) / (tmp->t_start - tmp->t_end); + list->end = rint(start - (start - end) * magic); + } else { list->end = start; + } break; case CONSTANT: list->end = start; @@ -219,7 +223,7 @@ 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 o2_flag) +static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi, pr_track_t **track_pr, bool o2_flag) { int cyl, i; struct plot_data *entry; @@ -291,16 +295,22 @@ static void fill_missing_tank_pressures(struct dive *dive, struct plot_info *pi, *save_pressure = cur_pr[cyl]; // Just use our current pressure continue; // and skip to next point. } + // If there is a valid segment but no tank pressure .. interpolate = get_pr_interpolate_data(segment, pi, i, pressure); // Set up an interpolation structure + if(dive->cylinder[cyl].cylinder_use == OC_GAS) { - /* if this segment has pressure_time, then calculate a new interpolated pressure */ - if (interpolate.pressure_time) { - /* Overall pressure change over total pressure-time for this segment*/ - magic = (interpolate.end - interpolate.start) / (double)interpolate.pressure_time; + /* if this segment has pressure_time, then calculate a new interpolated pressure */ + if (interpolate.pressure_time) { + /* Overall pressure change over total pressure-time for this segment*/ + magic = (interpolate.end - interpolate.start) / (double)interpolate.pressure_time; - /* Use that overall pressure change to update the current pressure */ - cur_pr[cyl] = rint(interpolate.start + magic * interpolate.acc_pressure_time); + /* Use that overall pressure change to update the current pressure */ + cur_pr[cyl] = rint(interpolate.start + magic * interpolate.acc_pressure_time); + } + } else { + magic = (interpolate.end - interpolate.start) / (segment->t_end - segment->t_start); + cur_pr[cyl] = rint(segment->start + magic * (entry->sec - segment->t_start)); } *save_interpolated = cur_pr[cyl]; // and store the interpolated data in plot_info } @@ -341,7 +351,7 @@ static void debug_print_pressures(struct plot_info *pi) } #endif -/* This function goes through the list of tank pressures, either SENSOR_PRESSURE(entry) or DILUENT_PRESSURE(entry), +/* 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 * tank pressure it creates a pr_track_alloc structure that represents a segment on the dive profile and that diff --git a/profile.c b/profile.c index b8e5eac70..63023b5f4 100644 --- a/profile.c +++ b/profile.c @@ -612,34 +612,40 @@ 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) +static void populate_cylinder_pressure_data(int idx, int start, int end, struct plot_info *pi, bool o2flag) { 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->cylinderindex != idx) + if (entry->cylinderindex != idx && !o2flag) continue; - if (SENSOR_PRESSURE(entry)) + if (CYLINDER_PRESSURE(o2flag, entry)) 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->cylinderindex != idx) + if (entry->cylinderindex != idx && !o2flag) continue; - SENSOR_PRESSURE(entry) = start; + if (o2flag) + O2CYLINDER_PRESSURE(entry) = start; + else + SENSOR_PRESSURE(entry) = 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->cylinderindex != idx) + if (entry->cylinderindex != idx && !o2flag) continue; - SENSOR_PRESSURE(entry) = end; + if (o2flag) + O2CYLINDER_PRESSURE(entry) = end; + else + SENSOR_PRESSURE(entry) = end; break; } } @@ -688,7 +694,7 @@ static void setup_gas_sensor_pressure(struct dive *dive, struct divecomputer *dc if (!start || !end) continue; - populate_cylinder_pressure_data(i, start, end, pi); + populate_cylinder_pressure_data(i, start, end, pi, dive->cylinder[i].cylinder_use == OXYGEN); } /* @@ -1013,9 +1019,9 @@ void create_plot_info_new(struct dive *dive, struct divecomputer *dc, struct plo check_gas_change_events(dive, dc, pi); /* Populate the gas index from the gas change events */ setup_gas_sensor_pressure(dive, dc, pi); /* Try to populate our gas pressure knowledge */ - populate_pressure_information(dive, dc, pi, false); /* .. calculate missing pressure entries for all gasses except diluent */ + populate_pressure_information(dive, dc, pi, false); /* .. calculate missing pressure entries for all gasses except o2 */ if (dc->dctype == CCR) /* For CCR dives.. */ - populate_pressure_information(dive, dc, pi, true); /* .. calculate missing diluent gas pressure entries */ + populate_pressure_information(dive, dc, pi, true); /* .. calculate missing o2 gas pressure entries */ fill_o2_values(dc, pi, dive); /* .. and insert the O2 sensor data having 0 values. */ calculate_sac(dive, pi); /* Calculate sac */ diff --git a/profile.h b/profile.h index 66be78789..196a88126 100644 --- a/profile.h +++ b/profile.h @@ -92,9 +92,11 @@ int get_maxdepth(struct plot_info *pi); #define INTERPOLATED_PR 1 #define SENSOR_PRESSURE(_entry) (_entry)->pressure[SENSOR_PR] #define O2CYLINDER_PRESSURE(_entry) (_entry)->o2cylinderpressure[SENSOR_PR] +#define CYLINDER_PRESSURE(_o2, _entry) (_o2 ? O2CYLINDER_PRESSURE(_entry) : SENSOR_PRESSURE(_entry)) #define INTERPOLATED_PRESSURE(_entry) (_entry)->pressure[INTERPOLATED_PR] #define INTERPOLATED_O2CYLINDER_PRESSURE(_entry) (_entry)->o2cylinderpressure[INTERPOLATED_PR] #define GET_PRESSURE(_entry) (SENSOR_PRESSURE(_entry) ? SENSOR_PRESSURE(_entry) : INTERPOLATED_PRESSURE(_entry)) +#define GET_O2CYLINDER_PRESSURE(_entry) (O2CYLINDER_PRESSURE(_entry) ? O2CYLINDER_PRESSURE(_entry) : INTERPOLATED_O2CYLINDER_PRESSURE(_entry)) #define SAC_WINDOW 45 /* sliding window in seconds for current SAC calculation */ #ifdef __cplusplus diff --git a/qt-ui/diveplanner.cpp b/qt-ui/diveplanner.cpp index b8d251c2c..84dec0c9a 100644 --- a/qt-ui/diveplanner.cpp +++ b/qt-ui/diveplanner.cpp @@ -36,7 +36,7 @@ QString gasToStr(struct gasmix gas) { uint o2 = (get_o2(&gas) + 5) / 10, he = (get_he(&gas) + 5) / 10; - QString result = gasmix_is_air(&gas) ? QObject::tr("AIR") : he == 0 ? QString("EAN%1").arg(o2, 2, 10, QChar('0')) : QString("%1/%2").arg(o2).arg(he); + QString result = gasmix_is_air(&gas) ? QObject::tr("AIR") : he == 0 ? (o2 == 100 ? QObject::tr("OXYGEN") : QString("EAN%1").arg(o2, 2, 10, QChar('0'))) : QString("%1/%2").arg(o2).arg(he); return result; } diff --git a/qt-ui/profile/diveprofileitem.cpp b/qt-ui/profile/diveprofileitem.cpp index 1a6eeae5c..038987fe7 100644 --- a/qt-ui/profile/diveprofileitem.cpp +++ b/qt-ui/profile/diveprofileitem.cpp @@ -574,12 +574,18 @@ void DiveGasPressureItem::modelDataChanged(const QModelIndex &topLeft, const QMo if (!shouldCalculateStuff(topLeft, bottomRight)) return; int last_index = -1; - QPolygonF boundingPoly; // This is the "Whole Item", but a pressure can be divided in N Polygons. + int o2mbar; + QPolygonF boundingPoly, o2Poly; // This is the "Whole Item", but a pressure can be divided in N Polygons. polygons.clear(); + if (displayed_dive.dc.dctype == CCR) + polygons.append(o2Poly); for (int i = 0, count = dataModel->rowCount(); i < count; i++) { + o2mbar = 0; plot_data *entry = dataModel->data().entry + i; int mbar = GET_PRESSURE(entry); + if (displayed_dive.dc.dctype == CCR) + o2mbar = GET_O2CYLINDER_PRESSURE(entry); if (entry->cylinderindex != last_index) { polygons.append(QPolygonF()); // this is the polygon that will be actually drawned on screen. @@ -588,6 +594,11 @@ void DiveGasPressureItem::modelDataChanged(const QModelIndex &topLeft, const QMo if (!mbar) { continue; } + if (o2mbar) { + QPointF o2point(hAxis->posAtValue(entry->sec), vAxis->posAtValue(o2mbar)); + boundingPoly.push_back(o2point); + polygons.first().push_back(o2point); + } QPointF point(hAxis->posAtValue(entry->sec), vAxis->posAtValue(mbar)); boundingPoly.push_back(point); // The BoundingRect @@ -603,9 +614,23 @@ void DiveGasPressureItem::modelDataChanged(const QModelIndex &topLeft, const QMo struct plot_data *entry; cyl = -1; + o2mbar = 0; for (int i = 0, count = dataModel->rowCount(); i < count; i++) { entry = dataModel->data().entry + i; mbar = GET_PRESSURE(entry); + if (displayed_dive.dc.dctype == CCR) + o2mbar = GET_O2CYLINDER_PRESSURE(entry); + + if (o2mbar) { + if (!seen_cyl[displayed_dive.oxygen_cylinder_index]) { + plotPressureValue(o2mbar, entry->sec, Qt::AlignRight | Qt::AlignBottom); + plotGasValue(o2mbar, entry->sec, Qt::AlignRight | Qt::AlignBottom, displayed_dive.cylinder[displayed_dive.oxygen_cylinder_index].gasmix); + seen_cyl[displayed_dive.oxygen_cylinder_index] = true; + } + last_pressure[displayed_dive.oxygen_cylinder_index] = o2mbar; + last_time[displayed_dive.oxygen_cylinder_index] = entry->sec; + } + if (!mbar) continue;