diff options
author | Stefan Fuchs <sfuchs@gmx.de> | 2017-02-11 20:24:18 +0100 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2017-03-11 08:01:35 -0800 |
commit | 7f8c3592ce29d5fd4cd177d8e86ede9fdf3ab747 (patch) | |
tree | 2c339a577a304a6f58e5518534e31f8d449af229 /core | |
parent | b8e044dee350076984e998d4d797ec4e7a191f41 (diff) | |
download | subsurface-7f8c3592ce29d5fd4cd177d8e86ede9fdf3ab747.tar.gz |
Minimum gas calculation - Calculations and UI parameters
Add minimum gas calculation to planner output.
Add the two UI parameters prefs.sacfactor and prefs.problemsolvingtime.
Connect UI signals and slots for recalculation of diveplan.
Disable minimum gas calculation if there was already a warning before.
If minimum gas result is larger then cylinder start pressure give warning message instead of result.
Add line break before pO2 warnings but only if warnings exist.
Signed-off-by: Joachim Ritter <jritter@bitsenke.de>
Signed-off-by: Stefan Fuchs <sfuchs@gmx.de>
Diffstat (limited to 'core')
-rw-r--r-- | core/planner.c | 69 | ||||
-rw-r--r-- | core/pref.h | 2 | ||||
-rw-r--r-- | core/subsurface-qt/SettingsObjectWrapper.cpp | 38 | ||||
-rw-r--r-- | core/subsurface-qt/SettingsObjectWrapper.h | 8 | ||||
-rw-r--r-- | core/subsurfacestartup.c | 2 |
5 files changed, 112 insertions, 7 deletions
diff --git a/core/planner.c b/core/planner.c index ad7678188..ab4ba2dd2 100644 --- a/core/planner.c +++ b/core/planner.c @@ -546,6 +546,7 @@ static void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool bool gaschange_before; bool lastentered = true; struct divedatapoint *nextdp = NULL; + struct divedatapoint *lastbottomdp = NULL; plan_verbatim = prefs.verbatim_plan; plan_display_runtime = prefs.display_runtime; @@ -639,6 +640,17 @@ static void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool if (dp->time - lasttime < 10 && !(gaschange_after && dp->next && dp->depth != dp->next->depth)) continue; + /* Store pointer to last entered datapoint for minimum gas calculation */ + /* Do this only if depth is larger than last/2nd last deco stop at ~6m */ + int secondlastdecostop = 0; + if (prefs.units.length == METERS ) { + secondlastdecostop = decostoplevels_metric[2]; + } else { + secondlastdecostop = decostoplevels_imperial[2]; + } + if (dp->entered && !nextdp->entered && dp->depth > secondlastdecostop) + lastbottomdp = dp; + len = strlen(buffer); if (plan_verbatim) { /* When displaying a verbatim plan, we output a waypoint for every gas change. @@ -847,10 +859,13 @@ static void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool snprintf(temp, sz_temp, "%s %.*f|%.*f%s/min):", translate("gettextFromC", "Gas consumption (based on SAC"), sacdecimals, bottomsacvalue, sacdecimals, decosacvalue, sacunit); len += snprintf(buffer + len, sz_buffer - len, "<div>%s<br>", temp); + + /* Print gas consumption: This loop covers all cylinders */ for (int gasidx = 0; gasidx < MAX_CYLINDERS; gasidx++) { - double volume, pressure, deco_volume, deco_pressure; - const char *unit, *pressure_unit; + double volume, pressure, deco_volume, deco_pressure, mingas_volume, mingas_pressure, mingas_depth; + const char *unit, *pressure_unit, *depth_unit; char warning[1000] = ""; + char mingas[1000] = ""; cylinder_t *cyl = &dive->cylinder[gasidx]; if (cylinder_none(cyl)) break; @@ -867,23 +882,59 @@ static void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool * This only works if we have working pressure for the cylinder * 10bar is a made up number - but it seemed silly to pretend you could breathe cylinder down to 0 */ if (cyl->end.mbar < 10000) - snprintf(warning, sizeof(warning), " — <span style='color: red;'>%s </span> %s", + snprintf(warning, sizeof(warning), "<br> — <span style='color: red;'>%s </span> %s", translate("gettextFromC", "Warning:"), translate("gettextFromC", "this is more gas than available in the specified cylinder!")); else if ((float) cyl->end.mbar * cyl->type.size.mliter / 1000.0 / gas_compressibility_factor(&cyl->gasmix, cyl->end.mbar / 1000.0) < (float) cyl->deco_gas_used.mliter) - snprintf(warning, sizeof(warning), " — <span style='color: red;'>%s </span> %s", + snprintf(warning, sizeof(warning), "<br> — <span style='color: red;'>%s </span> %s", translate("gettextFromC", "Warning:"), translate("gettextFromC", "not enough reserve for gas sharing on ascent!")); - snprintf(temp, sz_temp, translate("gettextFromC", "%.0f%s/%.0f%s of %s (%.0f%s/%.0f%s in planned ascent)"), volume, unit, pressure, pressure_unit, gasname(&cyl->gasmix), deco_volume, unit, deco_pressure, pressure_unit); + /* Do and print minimum gas calculation for last bottom gas, but only for OC mode */ + /* and if no other warning was set before. */ + else + if (lastbottomdp && gasidx == lastbottomdp->cylinderid + && dive->dc.divemode == OC) { + /* Calculate minimum gas volume. */ + volume_t mingasv; + mingasv.mliter = prefs.problemsolvingtime * prefs.bottomsac * prefs.sacfactor / 100.0 + * depth_to_bar(lastbottomdp->depth, dive) + + cyl->deco_gas_used.mliter * prefs.sacfactor / 100.0; + /* Calculate minimum gas pressure for cyclinder. */ + pressure_t mingasp; + mingasp.mbar = isothermal_pressure(&cyl->gasmix, 1.0, + mingasv.mliter, cyl->type.size.mliter) * 1000; + /* Translate all results into correct units */ + mingas_volume = get_volume_units(mingasv.mliter, NULL, &unit); + mingas_pressure = get_pressure_units(mingasp.mbar, &pressure_unit); + mingas_depth = get_depth_units(lastbottomdp->depth, NULL, &depth_unit); + /* Print it to results */ + if (cyl->start.mbar > mingasp.mbar) snprintf(mingas, sizeof(mingas), + translate("gettextFromC", "<br> — <span style='color: green;'>Minimum gas</span> (based on %.1fxSAC/+%dmin@%.0f%s): %.0f%s/%.0f%s"), + prefs.sacfactor / 100.0, prefs.problemsolvingtime, + mingas_depth, depth_unit, + mingas_volume, unit, + mingas_pressure, pressure_unit); + else snprintf(warning, sizeof(warning), "<br> — <span style='color: red;'>%s </span> %s", + translate("gettextFromC", "Warning:"), + translate("gettextFromC", "required minimum gas for ascent already exceeding start pressure of cylinder!")); + } + /* Print the gas consumption for every cylinder here to temp buffer. */ + snprintf(temp, sz_temp, translate("gettextFromC", "%.0f%s/%.0f%s of <span style='color: red;'><b>%s</b></span> (%.0f%s/%.0f%s in planned ascent)"), volume, unit, pressure, pressure_unit, gasname(&cyl->gasmix), deco_volume, unit, deco_pressure, pressure_unit); + } else { - snprintf(temp, sz_temp, translate("gettextFromC", "%.0f%s (%.0f%s during planned ascent) of %s"), volume, unit, deco_volume, unit, gasname(&cyl->gasmix)); + snprintf(temp, sz_temp, translate("gettextFromC", "%.0f%s (%.0f%s during planned ascent) of <span style='color: red;'><b>%s</b></span>"), + volume, unit, deco_volume, unit, gasname(&cyl->gasmix)); } - len += snprintf(buffer + len, sz_buffer - len, "%s%s<br>", temp, warning); + /* Gas consumption: Now finally print all strings to output */ + len += snprintf(buffer + len, sz_buffer - len, "%s%s%s<br>", temp, warning, mingas); } + + /* Print warnings for pO2 */ dp = diveplan->dp; + bool o2warning_exist = false; if (dive->dc.divemode != CCR) { while (dp) { if (dp->time != 0) { @@ -896,6 +947,8 @@ static void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool int decimals; double depth_value = get_depth_units(dp->depth, &decimals, &depth_unit); len = strlen(buffer); + if (!o2warning_exist) len += snprintf(buffer + len, sz_buffer - len, "<br>"); + o2warning_exist = true; snprintf(temp, sz_temp, translate("gettextFromC", "high pO₂ value %.2f at %d:%02u with gas %s at depth %.*f %s"), pressures.o2, FRACTION(dp->time, 60), gasname(gasmix), decimals, depth_value, depth_unit); @@ -906,6 +959,8 @@ static void add_plan_to_notes(struct diveplan *diveplan, struct dive *dive, bool int decimals; double depth_value = get_depth_units(dp->depth, &decimals, &depth_unit); len = strlen(buffer); + if (!o2warning_exist) len += snprintf(buffer + len, sz_buffer - len, "<br>"); + o2warning_exist = true; snprintf(temp, sz_temp, translate("gettextFromC", "low pO₂ value %.2f at %d:%02u with gas %s at depth %.*f %s"), pressures.o2, FRACTION(dp->time, 60), gasname(gasmix), decimals, depth_value, depth_unit); diff --git a/core/pref.h b/core/pref.h index 1360fba14..9122800bb 100644 --- a/core/pref.h +++ b/core/pref.h @@ -105,6 +105,8 @@ struct preferences { int ascratestops; int ascratelast6m; int descrate; + int sacfactor; + int problemsolvingtime; int bottompo2; int decopo2; enum deco_mode display_deco_mode; diff --git a/core/subsurface-qt/SettingsObjectWrapper.cpp b/core/subsurface-qt/SettingsObjectWrapper.cpp index dfb486065..f5d2e0f9a 100644 --- a/core/subsurface-qt/SettingsObjectWrapper.cpp +++ b/core/subsurface-qt/SettingsObjectWrapper.cpp @@ -1240,6 +1240,16 @@ int DivePlannerSettings::descrate() const return prefs.descrate; } +int DivePlannerSettings::sacfactor() const +{ + return prefs.sacfactor; +} + +int DivePlannerSettings::problemsolvingtime() const +{ + return prefs.problemsolvingtime; +} + int DivePlannerSettings::bottompo2() const { return prefs.bottompo2; @@ -1441,6 +1451,30 @@ void DivePlannerSettings::setDescrate(int value) emit descrateChanged(value); } +void DivePlannerSettings::setSacFactor(int value) +{ + if (value == prefs.sacfactor) + return; + + QSettings s; + s.beginGroup(group); + s.setValue("sacfactor", value); + prefs.sacfactor = value; + emit sacFactorChanged(value); +} + +void DivePlannerSettings::setProblemSolvingTime(int value) +{ + if (value == prefs.problemsolvingtime) + return; + + QSettings s; + s.beginGroup(group); + s.setValue("problemsolvingtime", value); + prefs.problemsolvingtime = value; + emit problemSolvingTimeChanged(value); +} + void DivePlannerSettings::setBottompo2(int value) { if (value == prefs.bottompo2) @@ -2279,6 +2313,8 @@ void SettingsObjectWrapper::load() GET_INT("ascratestops", ascratestops); GET_INT("ascratelast6m", ascratelast6m); GET_INT("descrate", descrate); + GET_INT("sacfactor", sacfactor); + GET_INT("problemsolvingtime", problemsolvingtime); GET_INT("bottompo2", bottompo2); GET_INT("decopo2", decopo2); GET_INT("bestmixend", bestmixend.mm); @@ -2331,6 +2367,8 @@ void SettingsObjectWrapper::sync() s.setValue("ascratestops", prefs.ascratestops); s.setValue("ascratelast6m", prefs.ascratelast6m); s.setValue("descrate", prefs.descrate); + s.setValue("sacfactor", prefs.sacfactor); + s.setValue("problemsolvingtime", prefs.problemsolvingtime); s.setValue("bottompo2", prefs.bottompo2); s.setValue("decopo2", prefs.decopo2); s.setValue("bestmixend", prefs.bestmixend.mm); diff --git a/core/subsurface-qt/SettingsObjectWrapper.h b/core/subsurface-qt/SettingsObjectWrapper.h index 7fdd10498..1d35dd5d5 100644 --- a/core/subsurface-qt/SettingsObjectWrapper.h +++ b/core/subsurface-qt/SettingsObjectWrapper.h @@ -402,6 +402,8 @@ class DivePlannerSettings : public QObject { Q_PROPERTY(int ascratestops READ ascratestops WRITE setAscratestops NOTIFY ascratestopsChanged) Q_PROPERTY(int ascratelast6m READ ascratelast6m WRITE setAscratelast6m NOTIFY ascratelast6mChanged) Q_PROPERTY(int descrate READ descrate WRITE setDescrate NOTIFY descrateChanged) + Q_PROPERTY(int sacfactor READ sacfactor WRITE setSacFactor NOTIFY sacFactorChanged) + Q_PROPERTY(int problemsolvingtime READ problemsolvingtime WRITE setProblemSolvingTime NOTIFY problemSolvingTimeChanged) Q_PROPERTY(int bottompo2 READ bottompo2 WRITE setBottompo2 NOTIFY bottompo2Changed) Q_PROPERTY(int decopo2 READ decopo2 WRITE setDecopo2 NOTIFY decopo2Changed) Q_PROPERTY(int bestmixend READ bestmixend WRITE setBestmixend NOTIFY bestmixendChanged) @@ -427,6 +429,8 @@ public: int ascratestops() const; int ascratelast6m() const; int descrate() const; + int sacfactor() const; + int problemsolvingtime() const; int bottompo2() const; int decopo2() const; int bestmixend() const; @@ -451,6 +455,8 @@ public slots: void setAscratestops(int value); void setAscratelast6m(int value); void setDescrate(int value); + void setSacFactor(int value); + void setProblemSolvingTime(int value); void setBottompo2(int value); void setDecopo2(int value); void setBestmixend(int value); @@ -475,6 +481,8 @@ signals: void ascratestopsChanged(int value); void ascratelast6mChanged(int value); void descrateChanged(int value); + void sacFactorChanged(int value); + void problemSolvingTimeChanged(int value); void bottompo2Changed(int value); void decopo2Changed(int value); void bestmixendChanged(int value); diff --git a/core/subsurfacestartup.c b/core/subsurfacestartup.c index 1f9518136..89ecbd2fb 100644 --- a/core/subsurfacestartup.c +++ b/core/subsurfacestartup.c @@ -50,6 +50,8 @@ struct preferences default_prefs = { .ascratestops = 6000 / 60, .ascratelast6m = 1000 / 60, .descrate = 18000 / 60, + .sacfactor = 400, + .problemsolvingtime = 4, .bottompo2 = 1400, .decopo2 = 1600, .bestmixend.mm = 30000, |