summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--planner.c89
-rw-r--r--planner.h1
-rw-r--r--pref.h1
-rw-r--r--qt-ui/diveplanner.cpp10
-rw-r--r--qt-ui/diveplanner.h1
-rw-r--r--qt-ui/plannerSettings.ui89
-rw-r--r--qt-ui/profile/diveprofileitem.cpp2
-rw-r--r--subsurfacestartup.c1
8 files changed, 129 insertions, 65 deletions
diff --git a/planner.c b/planner.c
index d5852dc7b..60fc31bee 100644
--- a/planner.c
+++ b/planner.c
@@ -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 */
diff --git a/planner.h b/planner.h
index b1e37d5cb..9a2c08b3d 100644
--- a/planner.h
+++ b/planner.h
@@ -2,6 +2,7 @@
#define PLANNER_H
#define LONGDECO 1
+#define NOT_RECREATIONAL 2
#ifdef __cplusplus
extern "C" {
diff --git a/pref.h b/pref.h
index fb01d28ef..56fc79b95 100644
--- a/pref.h
+++ b/pref.h
@@ -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,