[PATCH 4/5] Planner: automate calculation of best mix for max depth

Rick Walsh rickmwalsh at gmail.com
Fri Jul 1 00:26:09 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    | 72 +++++++++++++++++++++++++++++++++++++-----
 qt-models/cylindermodel.h      |  1 +
 qt-models/diveplannermodel.cpp | 19 ++++++++++-
 qt-models/diveplannermodel.h   |  1 +
 5 files changed, 86 insertions(+), 9 deletions(-)

diff --git a/core/dive.h b/core/dive.h
index 6910eb2..caafce2 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 34bf36c..a7ab3e1 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]);
@@ -287,15 +294,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;
@@ -441,3 +465,35 @@ void CylindersModel::remove(const QModelIndex &index)
 		dc = dc->next;
 	}
 }
+
+bool CylindersModel::updateBestMixes()
+{
+	// Check if any of the cylinders are best mixes, update if needed
+	bool gasUpdated = false;
+	DivePlannerPointsModel::instance()->rememberTanks();
+	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 (((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);
+			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 (((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;
+			gasUpdated = true;
+		}
+	}
+	if (gasUpdated) {
+		DivePlannerPointsModel::instance()->tanksUpdated();
+		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 b7c1393..d0ca714 100644
--- a/qt-models/cylindermodel.h
+++ b/qt-models/cylindermodel.h
@@ -37,6 +37,7 @@ public:
 	void clear();
 	void updateDive();
 	void copyFromDive(struct dive *d);
+	bool updateBestMixes();
 	cylinder_t *cylinderAt(const QModelIndex &index);
 	bool changed;
 
diff --git a/qt-models/diveplannermodel.cpp b/qt-models/diveplannermodel.cpp
index 16a2e40..eb5681b 100644
--- a/qt-models/diveplannermodel.cpp
+++ b/qt-models/diveplannermodel.cpp
@@ -44,6 +44,7 @@ void DivePlannerPointsModel::createSimpleDive()
 		addStop(M_OR_FT(5, 15), 42 * 60, &gas, 0, true);
 		addStop(M_OR_FT(5, 15), 45 * 60, &gas, 0, true);
 	}
+	updateMaxDepth();
 }
 
 void DivePlannerPointsModel::setupStartTime()
@@ -139,6 +140,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;
@@ -260,8 +274,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 0770aa0..034f4bc 100644
--- a/qt-models/diveplannermodel.h
+++ b/qt-models/diveplannermodel.h
@@ -44,6 +44,7 @@ public:
 	void rememberTanks();
 	bool tankInUse(struct gasmix gasmix);
 	void setupCylinders();
+	bool updateMaxDepth();
 	/**
 	 * @return the row number.
 	 */
-- 
2.7.4



More information about the subsurface mailing list