[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