[PATCH 08/11] Planner: automate calculation of best mix for max depth

Rick Walsh rickmwalsh at gmail.com
Wed Jul 6 05:40:35 PDT 2016


Add option to calculate the best mix portion of O2 and He for the dive's max
depth if the user enters * in the MOD and MND cylinder fields. Gas portions
are automatically recalculated if the max depth of the dive changes.

Signed-off-by: Rick Walsh <rickmwalsh at gmail.com>
---
 core/dive.h                    |  2 ++
 qt-models/cylindermodel.cpp    | 78 +++++++++++++++++++++++++++++++++++-------
 qt-models/cylindermodel.h      |  1 +
 qt-models/diveplannermodel.cpp | 19 +++++++++-
 qt-models/diveplannermodel.h   |  1 +
 5 files changed, 88 insertions(+), 13 deletions(-)

diff --git a/core/dive.h b/core/dive.h
index c968746..a0ae0a5 100644
--- a/core/dive.h
+++ b/core/dive.h
@@ -78,6 +78,8 @@ typedef struct
 	volume_t gas_used;
 	volume_t deco_gas_used;
 	enum cylinderuse cylinder_use;
+	bool bestmix_o2;
+	bool bestmix_he;
 } cylinder_t;
 
 typedef struct
diff --git a/qt-models/cylindermodel.cpp b/qt-models/cylindermodel.cpp
index dbe39b0..3a8c433 100644
--- a/qt-models/cylindermodel.cpp
+++ b/qt-models/cylindermodel.cpp
@@ -135,12 +135,19 @@ QVariant CylindersModel::data(const QModelIndex &index, int role) const
 			ret = get_depth_string(cyl->depth, true);
 			break;
 		case MOD:
-			pressure_t modpO2;
-			modpO2.mbar = prefs.bottompo2;
-			ret = get_depth_string(gas_mod(&cyl->gasmix, modpO2, &displayed_dive, M_OR_FT(1,1)));
+			if (cyl->bestmix_o2) {
+				ret = QString("*");
+			} else {
+				pressure_t modpO2;
+				modpO2.mbar = prefs.bottompo2;
+				ret = get_depth_string(gas_mod(&cyl->gasmix, modpO2, &displayed_dive, M_OR_FT(1,1)));
+			}
 			break;
 		case MND:
-			ret = get_depth_string(gas_mnd(&cyl->gasmix, prefs.bestmixend, &displayed_dive, M_OR_FT(1,1)));
+			if (cyl->bestmix_he)
+				ret = QString("*");
+			else
+				ret = get_depth_string(gas_mnd(&cyl->gasmix, prefs.bestmixend, &displayed_dive, M_OR_FT(1,1)));
 			break;
 		case USE:
 			ret = gettextFromC::instance()->trGettext(cylinderuse_text[cyl->cylinder_use]);
@@ -258,8 +265,8 @@ bool CylindersModel::setData(const QModelIndex &index, const QVariant &value, in
 		if (CHANGED()) {
 			cyl->gasmix.o2 = string_to_fraction(vString.toUtf8().data());
 			// fO2 + fHe must not be greater than 1
-			if (((cyl->gasmix.o2.permille == 0) ? O2_IN_AIR : cyl->gasmix.o2.permille) + cyl->gasmix.he.permille > 1000)
-				cyl->gasmix.he.permille = 1000 - ((cyl->gasmix.o2.permille == 0) ? O2_IN_AIR : cyl->gasmix.o2.permille);
+			if (get_o2(&cyl->gasmix) + get_he(&cyl->gasmix) > 1000)
+				cyl->gasmix.he.permille = 1000 - get_o2(&cyl->gasmix);
 			pressure_t modpO2;
 			if (displayed_dive.dc.divemode == PSCR)
 				modpO2.mbar = prefs.decopo2 + (1000 - get_o2(&cyl->gasmix)) * SURFACE_PRESSURE *
@@ -267,6 +274,7 @@ bool CylindersModel::setData(const QModelIndex &index, const QVariant &value, in
 			else
 				modpO2.mbar = prefs.decopo2;
 			cyl->depth = gas_mod(&cyl->gasmix, modpO2, &displayed_dive, M_OR_FT(3, 10));
+			cyl->bestmix_o2 = false;
 			changed = true;
 		}
 		break;
@@ -274,8 +282,9 @@ bool CylindersModel::setData(const QModelIndex &index, const QVariant &value, in
 		if (CHANGED()) {
 			cyl->gasmix.he = string_to_fraction(vString.toUtf8().data());
 			// fO2 + fHe must not be greater than 1
-			if (((cyl->gasmix.o2.permille == 0) ? O2_IN_AIR : cyl->gasmix.o2.permille) + cyl->gasmix.he.permille > 1000)
-				cyl->gasmix.o2.permille = 1000 - cyl->gasmix.he.permille;
+			if (get_o2(&cyl->gasmix) + get_he(&cyl->gasmix) > 1000)
+				cyl->gasmix.o2.permille = 1000 - get_he(&cyl->gasmix);
+			cyl->bestmix_he = false;
 			changed = true;
 		}
 		break;
@@ -287,15 +296,32 @@ bool CylindersModel::setData(const QModelIndex &index, const QVariant &value, in
 		break;
 	case MOD:
 		if (CHANGED()) {
-			// Calculate fO2 for input depth
-			cyl->gasmix.o2 = best_o2(string_to_depth(vString.toUtf8().data()), &displayed_dive);
+			if (QString::compare(vString.toUtf8().data(), "*") == 0) {
+				cyl->bestmix_o2 = true;
+				// Calculate fO2 for max depth
+				cyl->gasmix.o2 = best_o2(displayed_dive.maxdepth, &displayed_dive);
+			} else {
+				cyl->bestmix_o2 = false;
+				// Calculate fO2 for input depth
+				cyl->gasmix.o2 = best_o2(string_to_depth(vString.toUtf8().data()), &displayed_dive);
+			}
+			pressure_t modpO2;
+			modpO2.mbar = prefs.decopo2;
+			cyl->depth = gas_mod(&cyl->gasmix, modpO2, &displayed_dive, M_OR_FT(3, 10));
 			changed = true;
 		}
 		break;
 	case MND:
 		if (CHANGED()) {
-			// Calculate fHe for input depth
-			cyl->gasmix.he = best_He(string_to_depth(vString.toUtf8().data()), &displayed_dive);
+			if (QString::compare(vString.toUtf8().data(), "*") == 0) {
+				cyl->bestmix_he = true;
+				// Calculate fO2 for max depth
+				cyl->gasmix.he = best_He(displayed_dive.maxdepth, &displayed_dive);
+			} else {
+				cyl->bestmix_he = false;
+				// Calculate fHe for input depth
+				cyl->gasmix.he = best_He(string_to_depth(vString.toUtf8().data()), &displayed_dive);
+			}
 			changed = true;
 		}
 		break;
@@ -455,3 +481,31 @@ void CylindersModel::updateDecoDepths(pressure_t olddecopo2)
 	}
 	emit dataChanged(createIndex(0, 0), createIndex(MAX_CYLINDERS - 1, COLUMNS - 1));
 }
+
+bool CylindersModel::updateBestMixes()
+{
+	// Check if any of the cylinders are best mixes, update if needed
+	bool gasUpdated = false;
+	for (int i = 0; i < MAX_CYLINDERS; i++) {
+		cylinder_t *cyl = &displayed_dive.cylinder[i];
+		if (cyl->bestmix_o2) {
+			cyl->gasmix.o2 = best_o2(displayed_dive.maxdepth, &displayed_dive);
+			// fO2 + fHe must not be greater than 1
+			if (get_o2(&cyl->gasmix) + get_he(&cyl->gasmix) > 1000)
+				cyl->gasmix.he.permille = 1000 - get_o2(&cyl->gasmix);
+			pressure_t modpO2;
+			modpO2.mbar = prefs.decopo2;
+			cyl->depth = gas_mod(&cyl->gasmix, modpO2, &displayed_dive, M_OR_FT(3, 10));
+			gasUpdated = true;
+		}
+		if (cyl->bestmix_he) {
+			cyl->gasmix.he = best_He(displayed_dive.maxdepth, &displayed_dive);
+			// fO2 + fHe must not be greater than 1
+			if (get_o2(&cyl->gasmix) + get_he(&cyl->gasmix) > 1000)
+				cyl->gasmix.o2.permille = 1000 - get_he(&cyl->gasmix);
+			gasUpdated = true;
+		}
+	}
+	emit dataChanged(createIndex(0, 0), createIndex(MAX_CYLINDERS - 1, COLUMNS - 1));
+	return gasUpdated;
+}
diff --git a/qt-models/cylindermodel.h b/qt-models/cylindermodel.h
index 85cca1a..d4ef8dc 100644
--- a/qt-models/cylindermodel.h
+++ b/qt-models/cylindermodel.h
@@ -38,6 +38,7 @@ public:
 	void updateDive();
 	void copyFromDive(struct dive *d);
 	void updateDecoDepths(pressure_t olddecopo2);
+	bool updateBestMixes();
 	cylinder_t *cylinderAt(const QModelIndex &index);
 	bool changed;
 
diff --git a/qt-models/diveplannermodel.cpp b/qt-models/diveplannermodel.cpp
index f44d94c..0364a59 100644
--- a/qt-models/diveplannermodel.cpp
+++ b/qt-models/diveplannermodel.cpp
@@ -41,6 +41,7 @@ void DivePlannerPointsModel::createSimpleDive()
 		addStop(M_OR_FT(5, 15), 42 * 60, 0, cylinderid, true);
 		addStop(M_OR_FT(5, 15), 45 * 60, 0, cylinderid, true);
 	}
+	updateMaxDepth();
 }
 
 void DivePlannerPointsModel::setupStartTime()
@@ -136,6 +137,19 @@ void DivePlannerPointsModel::setupCylinders()
 	CylindersModel::instance()->copyFromDive(&displayed_dive);
 }
 
+// Update the dive's maximum depth.  Returns true if max depth changed
+bool DivePlannerPointsModel::updateMaxDepth()
+{
+	int prevMaxDepth = displayed_dive.maxdepth.mm;
+	displayed_dive.maxdepth.mm = 0;
+	for (int i = 0; i < rowCount(); i++) {
+		divedatapoint p = at(i);
+		if (p.depth > displayed_dive.maxdepth.mm)
+			displayed_dive.maxdepth.mm = p.depth;
+	}
+	return (displayed_dive.maxdepth.mm != prevMaxDepth);
+}
+
 QStringList &DivePlannerPointsModel::getGasList()
 {
 	static QStringList list;
@@ -257,8 +271,11 @@ bool DivePlannerPointsModel::setData(const QModelIndex &index, const QVariant &v
 		divedatapoint &p = divepoints[index.row()];
 		switch (index.column()) {
 		case DEPTH:
-			if (value.toInt() >= 0)
+			if (value.toInt() >= 0) {
 				p.depth = units_to_depth(value.toInt());
+				if (updateMaxDepth())
+					CylindersModel::instance()->updateBestMixes();
+			}
 			break;
 		case RUNTIME:
 			p.time = value.toInt() * 60;
diff --git a/qt-models/diveplannermodel.h b/qt-models/diveplannermodel.h
index da84119..2525e76 100644
--- a/qt-models/diveplannermodel.h
+++ b/qt-models/diveplannermodel.h
@@ -44,6 +44,7 @@ public:
 	void rememberTanks();
 	bool tankInUse(int cylinderid);
 	void setupCylinders();
+	bool updateMaxDepth();
 	/**
 	 * @return the row number.
 	 */
-- 
2.7.4



More information about the subsurface mailing list