diff options
-rw-r--r-- | planner.c | 89 | ||||
-rw-r--r-- | planner.h | 1 | ||||
-rw-r--r-- | pref.h | 1 | ||||
-rw-r--r-- | qt-ui/diveplanner.cpp | 10 | ||||
-rw-r--r-- | qt-ui/diveplanner.h | 1 | ||||
-rw-r--r-- | qt-ui/plannerSettings.ui | 89 | ||||
-rw-r--r-- | qt-ui/profile/diveprofileitem.cpp | 2 | ||||
-rw-r--r-- | subsurfacestartup.c | 1 |
8 files changed, 129 insertions, 65 deletions
@@ -800,6 +800,31 @@ int ascend_velocity(int depth, int avg_depth, int bottom_time) } } +bool trial_ascent(int trial_depth, int stoplevel, int avg_depth, int bottom_time, double tissue_tolerance, struct gasmix *gasmix, int po2, double surface_pressure) +{ + + bool clear_to_ascend = true; + char *trial_cache = NULL; + + cache_deco_state(tissue_tolerance, &trial_cache); + while (trial_depth > stoplevel) { + int deltad = ascend_velocity(trial_depth, avg_depth, bottom_time) * TIMESTEP; + if (deltad > trial_depth) /* don't test against depth above surface */ + deltad = trial_depth; + tissue_tolerance = add_segment(depth_to_mbar(trial_depth, &displayed_dive) / 1000.0, + gasmix, + TIMESTEP, po2, &displayed_dive, prefs.decosac); + if (deco_allowed_depth(tissue_tolerance, surface_pressure, &displayed_dive, 1) > trial_depth - deltad) { + /* We should have stopped */ + clear_to_ascend = false; + break; + } + trial_depth -= deltad; + } + restore_deco_state(trial_cache); + return clear_to_ascend; +} + int plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool show_disclaimer) { struct sample *sample; @@ -812,7 +837,6 @@ int plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool s struct gaschanges *gaschanges = NULL; int gaschangenr; int *stoplevels = NULL; - char *trial_cache = NULL; bool stopping = false; bool clear_to_ascend; int clock, previous_point_time; @@ -880,6 +904,45 @@ int plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool s /* Keep time during the ascend */ bottom_time = clock = previous_point_time = displayed_dive.dc.sample[displayed_dive.dc.samples - 1].time.seconds; gi = gaschangenr - 1; + if(prefs.recreational_mode) { + // How long can we stay at the current depth and still directly ascent to the surface? + while (trial_ascent(depth, 0, avg_depth, bottom_time, tissue_tolerance, &displayed_dive.cylinder[current_cylinder].gasmix, + po2, diveplan->surface_pressure / 1000.0)) { + tissue_tolerance = add_segment(depth_to_mbar(depth, &displayed_dive) / 1000.0, + &displayed_dive.cylinder[current_cylinder].gasmix, + DECOTIMESTEP, po2, &displayed_dive, prefs.bottomsac); + clock += DECOTIMESTEP; + } + clock -= DECOTIMESTEP; + plan_add_segment(diveplan, clock - previous_point_time, depth, gas, po2, false); + previous_point_time = clock; + do { + /* Ascend to surface */ + int deltad = ascend_velocity(depth, avg_depth, bottom_time) * TIMESTEP; + if (ascend_velocity(depth, avg_depth, bottom_time) != last_ascend_rate) { + plan_add_segment(diveplan, clock - previous_point_time, depth, gas, po2, false); + previous_point_time = clock; + last_ascend_rate = ascend_velocity(depth, avg_depth, bottom_time); + } + if (depth - deltad < 0) + deltad = depth; + + tissue_tolerance = add_segment(depth_to_mbar(depth, &displayed_dive) / 1000.0, + &displayed_dive.cylinder[current_cylinder].gasmix, + TIMESTEP, po2, &displayed_dive, prefs.decosac); + clock += TIMESTEP; + depth -= deltad; + } while (depth > 0); + plan_add_segment(diveplan, clock - previous_point_time, 0, gas, po2, false); + create_dive_from_plan(diveplan, is_planner); + add_plan_to_notes(diveplan, &displayed_dive, show_disclaimer, error); + fixup_dc_duration(&displayed_dive.dc); + + free(stoplevels); + free(gaschanges); + + return(error); + } if (best_first_ascend_cylinder != current_cylinder) { stopping = true; @@ -935,28 +998,10 @@ int plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool s --stopidx; /* Save the current state and try to ascend to the next stopdepth */ - int trial_depth = depth; - cache_deco_state(tissue_tolerance, &trial_cache); while (1) { /* Check if ascending to next stop is clear, go back and wait if we hit the ceiling on the way */ - clear_to_ascend = true; - while (trial_depth > stoplevels[stopidx]) { - int deltad = ascend_velocity(trial_depth, avg_depth, bottom_time) * TIMESTEP; - if (deltad > trial_depth) /* don't test against depth above surface */ - deltad = trial_depth; - tissue_tolerance = add_segment(depth_to_mbar(trial_depth, &displayed_dive) / 1000.0, - &displayed_dive.cylinder[current_cylinder].gasmix, - TIMESTEP, po2, &displayed_dive, prefs.decosac); - if (deco_allowed_depth(tissue_tolerance, diveplan->surface_pressure / 1000.0, &displayed_dive, 1) > trial_depth - deltad) { - /* We should have stopped */ - clear_to_ascend = false; - break; - } - trial_depth -= deltad; - } - restore_deco_state(trial_cache); - - if (clear_to_ascend) + if (trial_ascent(depth, stoplevels[stopidx], avg_depth, bottom_time, tissue_tolerance, + &displayed_dive.cylinder[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0)) break; /* We did not hit the ceiling */ /* Add a minute of deco time and then try again */ @@ -970,7 +1015,6 @@ int plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool s tissue_tolerance = add_segment(depth_to_mbar(depth, &displayed_dive) / 1000.0, &displayed_dive.cylinder[current_cylinder].gasmix, DECOTIMESTEP, po2, &displayed_dive, prefs.decosac); - cache_deco_state(tissue_tolerance, &trial_cache); clock += DECOTIMESTEP; /* Finish infinite deco */ if(clock >= 48 * 3600 && depth >= 6000) { @@ -1002,7 +1046,6 @@ int plan(struct diveplan *diveplan, char **cached_datap, bool is_planner, bool s } } } - trial_depth = depth; } if (stopping) { /* Next we will ascend again. Add a waypoint if we have spend deco time */ @@ -2,6 +2,7 @@ #define PLANNER_H #define LONGDECO 1 +#define NOT_RECREATIONAL 2 #ifdef __cplusplus extern "C" { @@ -78,6 +78,7 @@ struct preferences { bool display_runtime; bool display_duration; bool display_transitions; + bool recreational_mode; int bottomsac; int decosac; int o2consumption; // ml per min diff --git a/qt-ui/diveplanner.cpp b/qt-ui/diveplanner.cpp index 8262f3dfc..00a4113ca 100644 --- a/qt-ui/diveplanner.cpp +++ b/qt-ui/diveplanner.cpp @@ -393,6 +393,7 @@ PlannerSettingsWidget::PlannerSettingsWidget(QWidget *parent, Qt::WindowFlags f) prefs.display_duration = s.value("display_duration", prefs.display_duration).toBool(); prefs.display_runtime = s.value("display_runtime", prefs.display_runtime).toBool(); prefs.display_transitions = s.value("display_transitions", prefs.display_transitions).toBool(); + prefs.recreational_mode = s.value("recreational_mode", prefs.recreational_mode).toBool(); prefs.ascrate75 = s.value("ascrate75", prefs.ascrate75).toInt(); prefs.ascrate50 = s.value("ascrate50", prefs.ascrate50).toInt(); prefs.ascratestops = s.value("ascratestops", prefs.ascratestops).toInt(); @@ -414,6 +415,7 @@ PlannerSettingsWidget::PlannerSettingsWidget(QWidget *parent, Qt::WindowFlags f) ui.display_duration->setChecked(prefs.display_duration); ui.display_runtime->setChecked(prefs.display_runtime); ui.display_transitions->setChecked(prefs.display_transitions); + ui.recreational_mode->setChecked(prefs.recreational_mode); ui.bottompo2->setValue(prefs.bottompo2 / 1000.0); ui.decopo2->setValue(prefs.decopo2 / 1000.0); ui.backgasBreaks->setChecked(prefs.doo2breaks); @@ -427,6 +429,7 @@ PlannerSettingsWidget::PlannerSettingsWidget(QWidget *parent, Qt::WindowFlags f) connect(ui.display_duration, SIGNAL(toggled(bool)), plannerModel, SLOT(setDisplayDuration(bool))); connect(ui.display_runtime, SIGNAL(toggled(bool)), plannerModel, SLOT(setDisplayRuntime(bool))); connect(ui.display_transitions, SIGNAL(toggled(bool)), plannerModel, SLOT(setDisplayTransitions(bool))); + connect(ui.recreational_mode, SIGNAL(toggled(bool)), plannerModel, SLOT(setRecreationalMode(bool))); connect(ui.ascRate75, SIGNAL(valueChanged(int)), this, SLOT(setAscRate75(int))); connect(ui.ascRate75, SIGNAL(valueChanged(int)), plannerModel, SLOT(emitDataChanged())); connect(ui.ascRate50, SIGNAL(valueChanged(int)), this, SLOT(setAscRate50(int))); @@ -474,6 +477,7 @@ PlannerSettingsWidget::~PlannerSettingsWidget() s.setValue("display_duration", prefs.display_duration); s.setValue("display_runtime", prefs.display_runtime); s.setValue("display_transitions", prefs.display_transitions); + s.setValue("recreational_mode", prefs.recreational_mode); s.setValue("ascrate75", prefs.ascrate75); s.setValue("ascrate50", prefs.ascrate50); s.setValue("ascratestops", prefs.ascratestops); @@ -861,6 +865,12 @@ void DivePlannerPointsModel::setDisplayTransitions(bool value) emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS - 1)); } +void DivePlannerPointsModel::setRecreationalMode(bool value) +{ + prefs.recreational_mode = value; + emit dataChanged(createIndex(0, 0), createIndex(rowCount() - 1, COLUMNS -1)); +} + void DivePlannerPointsModel::setDropStoneMode(bool value) { prefs.drop_stone_mode = value; diff --git a/qt-ui/diveplanner.h b/qt-ui/diveplanner.h index 196e17546..eed481c04 100644 --- a/qt-ui/diveplanner.h +++ b/qt-ui/diveplanner.h @@ -82,6 +82,7 @@ slots: void setDisplayRuntime(bool value); void setDisplayDuration(bool value); void setDisplayTransitions(bool value); + void setRecreationalMode(bool value); void savePlan(); void saveDuplicatePlan(); void remove(const QModelIndex &index); diff --git a/qt-ui/plannerSettings.ui b/qt-ui/plannerSettings.ui index 0951e324f..09f019e06 100644 --- a/qt-ui/plannerSettings.ui +++ b/qt-ui/plannerSettings.ui @@ -262,62 +262,52 @@ <property name="spacing"> <number>2</number> </property> - <item row="0" column="2"> - <widget class="QSpinBox" name="gflow"> - <property name="suffix"> - <string>%</string> - </property> - <property name="minimum"> - <number>1</number> - </property> - <property name="maximum"> - <number>150</number> - </property> - </widget> - </item> - <item row="0" column="1"> - <widget class="QLabel" name="label_15"> - <property name="text"> - <string>GF low</string> - </property> - </widget> - </item> - <item row="1" column="1"> + <item row="2" column="1"> <widget class="QLabel" name="label_16"> <property name="text"> <string>GF high</string> </property> </widget> </item> - <item row="4" column="1" colspan="2"> + <item row="5" column="1" colspan="2"> <widget class="QCheckBox" name="backgasBreaks"> <property name="text"> <string>Plan backgas breaks</string> </property> </widget> </item> - <item row="6" column="1"> - <spacer name="verticalSpacer_2"> - <property name="orientation"> - <enum>Qt::Vertical</enum> + <item row="2" column="2"> + <widget class="QSpinBox" name="gfhigh"> + <property name="suffix"> + <string>%</string> </property> - <property name="sizeHint" stdset="0"> - <size> - <width>20</width> - <height>40</height> - </size> + <property name="minimum"> + <number>1</number> </property> - </spacer> + <property name="maximum"> + <number>150</number> + </property> + </widget> </item> - <item row="3" column="1" colspan="2"> + <item row="4" column="1" colspan="2"> <widget class="QCheckBox" name="lastStop"> <property name="text"> <string>Last stop at 6m</string> </property> </widget> </item> + <item row="6" column="1"> + <widget class="QComboBox" name="rebreathermode"> + <property name="currentText"> + <string/> + </property> + <property name="maxVisibleItems"> + <number>6</number> + </property> + </widget> + </item> <item row="1" column="2"> - <widget class="QSpinBox" name="gfhigh"> + <widget class="QSpinBox" name="gflow"> <property name="suffix"> <string>%</string> </property> @@ -329,20 +319,37 @@ </property> </widget> </item> - <item row="2" column="1" colspan="2"> + <item row="3" column="1" colspan="2"> <widget class="QCheckBox" name="drop_stone_mode"> <property name="text"> <string>Drop to first depth</string> </property> </widget> </item> - <item row="5" column="1"> - <widget class="QComboBox" name="rebreathermode"> - <property name="currentText"> - <string/> + <item row="7" column="1"> + <spacer name="verticalSpacer_2"> + <property name="orientation"> + <enum>Qt::Vertical</enum> </property> - <property name="maxVisibleItems"> - <number>6</number> + <property name="sizeHint" stdset="0"> + <size> + <width>20</width> + <height>40</height> + </size> + </property> + </spacer> + </item> + <item row="1" column="1"> + <widget class="QLabel" name="label_15"> + <property name="text"> + <string>GF low</string> + </property> + </widget> + </item> + <item row="0" column="1"> + <widget class="QCheckBox" name="recreational_mode"> + <property name="text"> + <string>Recreational mode</string> </property> </widget> </item> diff --git a/qt-ui/profile/diveprofileitem.cpp b/qt-ui/profile/diveprofileitem.cpp index 4ad0ba3ca..7d29d28b4 100644 --- a/qt-ui/profile/diveprofileitem.cpp +++ b/qt-ui/profile/diveprofileitem.cpp @@ -169,7 +169,7 @@ void DiveProfileItem::modelDataChanged(const QModelIndex &topLeft, const QModelI for (int i = 0; i < dataModel->rowCount(); i++, entry++) { int max = maxCeiling(i); // Don't scream if we violate the ceiling by a few cm - if (entry->depth < max - 100) { + if (entry->depth < max - 100 && entry->sec > 0) { profileColor = QColor(Qt::red); if (!eventAdded) { add_event(&displayed_dive.dc, entry->sec, SAMPLE_EVENT_CEILING, -1, max / 1000, "planned waypoint above ceiling"); diff --git a/subsurfacestartup.c b/subsurfacestartup.c index ce66aee52..09858f923 100644 --- a/subsurfacestartup.c +++ b/subsurfacestartup.c @@ -50,6 +50,7 @@ struct preferences default_prefs = { .display_runtime = true, .display_duration = true, .display_transitions = true, + .recreational_mode = false, .bottomsac = 20000, .decosac = 17000, .o2consumption = 720, |