From 4c8066bf84fac986f25a2725caa68fa17bacf0aa Mon Sep 17 00:00:00 2001
From: "Robert C. Helling" <helling@atdotde.de>
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 <helling@atdotde.de>
---
 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 c1c4d97..93b15ae 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 745fa3e..7301084 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 b8e5eac..63023b5 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 66be787..196a881 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 b8d251c..84dec0c 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 1a6eeae..038987f 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;
-- 
1.9.3 (Apple Git-50)

