diff options
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, |