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 <rickmwa...@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

_______________________________________________
subsurface mailing list
subsurface@subsurface-divelog.org
http://lists.subsurface-divelog.org/cgi-bin/mailman/listinfo/subsurface

Reply via email to