diff options
author | Robert C. Helling <helling@atdotde.de> | 2017-08-23 22:43:33 +0200 |
---|---|---|
committer | Dirk Hohndel <dirk@hohndel.org> | 2017-08-29 06:49:44 -0700 |
commit | 82aac4efff7e0836e879e52b4e4e0f7301b165a9 (patch) | |
tree | f5f053d47bbd804c6545c668ee433c290b47f87f | |
parent | 58d79488714ff7773916f3efe0970c424c8bd1cd (diff) | |
download | subsurface-82aac4efff7e0836e879e52b4e4e0f7301b165a9.tar.gz |
Make plan take dive and decotimestep as arguments
...rather than use a global variable and a macro.
This should be a no-op in preparation to allow planning
several versions of a dive.
Signed-off-by: Robert C. Helling <helling@atdotde.de>
-rw-r--r-- | core/dive.h | 5 | ||||
-rw-r--r-- | core/planner.c | 107 | ||||
-rw-r--r-- | qt-models/diveplannermodel.cpp | 4 | ||||
-rw-r--r-- | tests/testplan.cpp | 28 |
4 files changed, 73 insertions, 71 deletions
diff --git a/core/dive.h b/core/dive.h index 1f007182d..0e0678c20 100644 --- a/core/dive.h +++ b/core/dive.h @@ -835,6 +835,8 @@ extern void subsurface_command_line_exit(int *, char ***); #define FRACTION(n, x) ((unsigned)(n) / (x)), ((unsigned)(n) % (x)) +#define DECOTIMESTEP 60 /* seconds. Unit of deco stop times */ + struct deco_state { double tissue_n2_sat[16]; double tissue_he_sat[16]; @@ -903,11 +905,12 @@ struct divedatapoint *create_dp(int time_incr, int depth, int cylinderid, int po #if DEBUG_PLAN void dump_plan(struct diveplan *diveplan); #endif -bool plan(struct diveplan *diveplan, struct deco_state **cached_datap, bool is_planner, bool show_disclaimer); +bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct deco_state **cached_datap, bool is_planner, bool show_disclaimer); void calc_crushing_pressure(double pressure); void vpmb_start_gradient(); void clear_vpmb_state(); + void delete_single_dive(int idx); struct event *get_next_event(struct event *event, const char *name); diff --git a/core/planner.c b/core/planner.c index b4e4326c3..553e152fa 100644 --- a/core/planner.c +++ b/core/planner.c @@ -19,7 +19,6 @@ #include "version.h" #define TIMESTEP 2 /* second */ -#define DECOTIMESTEP 60 /* seconds. Unit of deco stop times */ int decostoplevels_metric[] = { 0, 3000, 6000, 9000, 12000, 15000, 18000, 21000, 24000, 27000, 30000, 33000, 36000, 39000, 42000, 45000, 48000, 51000, 54000, 57000, @@ -616,7 +615,7 @@ bool enough_gas(int current_cylinder) // Work out the stops. Return value is if there were any mandatory stops. -bool plan(struct diveplan *diveplan, struct deco_state **cached_datap, bool is_planner, bool show_disclaimer) +bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct deco_state **cached_datap, bool is_planner, bool show_disclaimer) { int bottom_depth; int bottom_gi; @@ -654,8 +653,8 @@ bool plan(struct diveplan *diveplan, struct deco_state **cached_datap, bool is_p set_vpmb_conservatism(diveplan->vpmb_conservatism); if (!diveplan->surface_pressure) diveplan->surface_pressure = SURFACE_PRESSURE; - displayed_dive.surface_pressure.mbar = diveplan->surface_pressure; - clear_deco(displayed_dive.surface_pressure.mbar / 1000.0); + dive->surface_pressure.mbar = diveplan->surface_pressure; + clear_deco(dive->surface_pressure.mbar / 1000.0); max_bottom_ceiling_pressure.mbar = first_ceiling_pressure.mbar = 0; create_dive_from_plan(diveplan, is_planner); @@ -677,13 +676,13 @@ bool plan(struct diveplan *diveplan, struct deco_state **cached_datap, bool is_p *(decostoplevels + 1) = M_OR_FT(3,10); /* Let's start at the last 'sample', i.e. the last manually entered waypoint. */ - sample = &displayed_dive.dc.sample[displayed_dive.dc.samples - 1]; + sample = &dive->dc.sample[dive->dc.samples - 1]; - current_cylinder = get_cylinderid_at_time(&displayed_dive, &displayed_dive.dc, sample->time); - gas = displayed_dive.cylinder[current_cylinder].gasmix; + current_cylinder = get_cylinderid_at_time(dive, &dive->dc, sample->time); + gas = dive->cylinder[current_cylinder].gasmix; po2 = sample->setpoint.mbar; - depth = displayed_dive.dc.sample[displayed_dive.dc.samples - 1].depth.mm; + depth = dive->dc.sample[dive->dc.samples - 1].depth.mm; average_max_depth(diveplan, &avg_depth, &max_depth); last_ascend_rate = ascent_velocity(depth, avg_depth, bottom_time); @@ -721,25 +720,25 @@ bool plan(struct diveplan *diveplan, struct deco_state **cached_datap, bool is_p stopidx += gaschangenr; /* Keep time during the ascend */ - bottom_time = clock = previous_point_time = displayed_dive.dc.sample[displayed_dive.dc.samples - 1].time.seconds; + bottom_time = clock = previous_point_time = dive->dc.sample[dive->dc.samples - 1].time.seconds; gi = gaschangenr - 1; /* Set tissue tolerance and initial vpmb gradient at start of ascent phase */ - diveplan->surface_interval = tissue_at_end(&displayed_dive, cached_datap); + diveplan->surface_interval = tissue_at_end(dive, cached_datap); nuclear_regeneration(clock); vpmb_start_gradient(); if (decoMode() == RECREATIONAL) { bool safety_stop = prefs.safetystop && max_depth >= 10000; - track_ascent_gas(depth, &displayed_dive.cylinder[current_cylinder], avg_depth, bottom_time, safety_stop); + track_ascent_gas(depth, &dive->cylinder[current_cylinder], avg_depth, bottom_time, safety_stop); // How long can we stay at the current depth and still directly ascent to the surface? do { - add_segment(depth_to_bar(depth, &displayed_dive), - &displayed_dive.cylinder[current_cylinder].gasmix, - DECOTIMESTEP, po2, &displayed_dive, prefs.bottomsac); - update_cylinder_pressure(&displayed_dive, depth, depth, DECOTIMESTEP, prefs.bottomsac, &displayed_dive.cylinder[current_cylinder], false); - clock += DECOTIMESTEP; - } while (trial_ascent(depth, 0, avg_depth, bottom_time, &displayed_dive.cylinder[current_cylinder].gasmix, + add_segment(depth_to_bar(depth, dive), + &dive->cylinder[current_cylinder].gasmix, + timestep, po2, dive, prefs.bottomsac); + update_cylinder_pressure(dive, depth, depth, timestep, prefs.bottomsac, &dive->cylinder[current_cylinder], false); + clock += timestep; + } while (trial_ascent(depth, 0, avg_depth, bottom_time, &dive->cylinder[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0) && enough_gas(current_cylinder)); @@ -747,8 +746,8 @@ bool plan(struct diveplan *diveplan, struct deco_state **cached_datap, bool is_p // In the best of all worlds, we would roll back also the last add_segment in terms of caching deco state, but // let's ignore that since for the eventual ascent in recreational mode, nobody looks at the ceiling anymore, // so we don't really have to compute the deco state. - update_cylinder_pressure(&displayed_dive, depth, depth, -DECOTIMESTEP, prefs.bottomsac, &displayed_dive.cylinder[current_cylinder], false); - clock -= DECOTIMESTEP; + update_cylinder_pressure(dive, depth, depth, -timestep, prefs.bottomsac, &dive->cylinder[current_cylinder], false); + clock -= timestep; plan_add_segment(diveplan, clock - previous_point_time, depth, current_cylinder, po2, true); previous_point_time = clock; do { @@ -775,8 +774,8 @@ bool plan(struct diveplan *diveplan, struct deco_state **cached_datap, bool is_p } while (depth > 0); plan_add_segment(diveplan, clock - previous_point_time, 0, current_cylinder, 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); + add_plan_to_notes(diveplan, dive, show_disclaimer, error); + fixup_dc_duration(&dive->dc); free(stoplevels); free(gaschanges); @@ -785,7 +784,7 @@ bool plan(struct diveplan *diveplan, struct deco_state **cached_datap, bool is_p if (best_first_ascend_cylinder != current_cylinder) { current_cylinder = best_first_ascend_cylinder; - gas = displayed_dive.cylinder[current_cylinder].gasmix; + gas = dive->cylinder[current_cylinder].gasmix; #if DEBUG_PLAN & 16 printf("switch to gas %d (%d/%d) @ %5.2lfm\n", best_first_ascend_cylinder, @@ -794,7 +793,7 @@ bool plan(struct diveplan *diveplan, struct deco_state **cached_datap, bool is_p } // VPM-B or Buehlmann Deco - tissue_at_end(&displayed_dive, cached_datap); + tissue_at_end(dive, cached_datap); previous_deco_time = 100000000; deco_time = 10000000; cache_deco_state(&bottom_cache); // Lets us make several iterations @@ -823,17 +822,17 @@ bool plan(struct diveplan *diveplan, struct deco_state **cached_datap, bool is_p breaktime = -1; breakcylinder = 0; o2time = 0; - first_ceiling_pressure.mbar = depth_to_mbar(deco_allowed_depth(tissue_tolerance_calc(&displayed_dive, - depth_to_bar(depth, &displayed_dive)), + first_ceiling_pressure.mbar = depth_to_mbar(deco_allowed_depth(tissue_tolerance_calc(dive, + depth_to_bar(depth, dive)), diveplan->surface_pressure / 1000.0, - &displayed_dive, + dive, 1), - &displayed_dive); + dive); if (max_bottom_ceiling_pressure.mbar > first_ceiling_pressure.mbar) first_ceiling_pressure.mbar = max_bottom_ceiling_pressure.mbar; last_ascend_rate = ascent_velocity(depth, avg_depth, bottom_time); - if ((current_cylinder = get_gasidx(&displayed_dive, &gas)) == -1) { + if ((current_cylinder = get_gasidx(dive, &gas)) == -1) { report_error(translate("gettextFromC", "Can't find gas %s"), gasname(&gas)); current_cylinder = 0; } @@ -853,9 +852,9 @@ bool plan(struct diveplan *diveplan, struct deco_state **cached_datap, bool is_p if (depth - deltad < stoplevels[stopidx]) deltad = depth - stoplevels[stopidx]; - add_segment(depth_to_bar(depth, &displayed_dive), - &displayed_dive.cylinder[current_cylinder].gasmix, - TIMESTEP, po2, &displayed_dive, prefs.decosac); + add_segment(depth_to_bar(depth, dive), + &dive->cylinder[current_cylinder].gasmix, + TIMESTEP, po2, dive, prefs.decosac); clock += TIMESTEP; depth -= deltad; /* Print VPM-Gradient as gradient factor, this has to be done from within deco.c */ @@ -882,19 +881,19 @@ bool plan(struct diveplan *diveplan, struct deco_state **cached_datap, bool is_p if (current_cylinder != gaschanges[gi].gasidx) { if (!prefs.switch_at_req_stop || !trial_ascent(depth, stoplevels[stopidx - 1], avg_depth, bottom_time, - &displayed_dive.cylinder[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0) || get_o2(&displayed_dive.cylinder[current_cylinder].gasmix) < 160) { + &dive->cylinder[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0) || get_o2(&dive->cylinder[current_cylinder].gasmix) < 160) { current_cylinder = gaschanges[gi].gasidx; - gas = displayed_dive.cylinder[current_cylinder].gasmix; + gas = dive->cylinder[current_cylinder].gasmix; #if DEBUG_PLAN & 16 printf("switch to gas %d (%d/%d) @ %5.2lfm\n", gaschanges[gi].gasidx, (get_o2(&gas) + 5) / 10, (get_he(&gas) + 5) / 10, gaschanges[gi].depth / 1000.0); #endif /* Stop for the minimum duration to switch gas */ - add_segment(depth_to_bar(depth, &displayed_dive), - &displayed_dive.cylinder[current_cylinder].gasmix, - prefs.min_switch_duration, po2, &displayed_dive, prefs.decosac); + add_segment(depth_to_bar(depth, dive), + &dive->cylinder[current_cylinder].gasmix, + prefs.min_switch_duration, po2, dive, prefs.decosac); clock += prefs.min_switch_duration; - if (prefs.doo2breaks && get_o2(&displayed_dive.cylinder[current_cylinder].gasmix) == 1000) + if (prefs.doo2breaks && get_o2(&dive->cylinder[current_cylinder].gasmix) == 1000) o2time += prefs.min_switch_duration; } else { /* The user has selected the option to switch gas only at required stops. @@ -911,7 +910,7 @@ bool plan(struct diveplan *diveplan, struct deco_state **cached_datap, bool is_p while (1) { /* Check if ascending to next stop is clear, go back and wait if we hit the ceiling on the way */ if (trial_ascent(depth, stoplevels[stopidx], avg_depth, bottom_time, - &displayed_dive.cylinder[current_cylinder].gasmix, po2, diveplan->surface_pressure / 1000.0)) + &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 */ @@ -933,28 +932,28 @@ bool plan(struct diveplan *diveplan, struct deco_state **cached_datap, bool is_p */ if (pendinggaschange) { current_cylinder = gaschanges[gi + 1].gasidx; - gas = displayed_dive.cylinder[current_cylinder].gasmix; + gas = dive->cylinder[current_cylinder].gasmix; #if DEBUG_PLAN & 16 printf("switch to gas %d (%d/%d) @ %5.2lfm\n", gaschanges[gi + 1].gasidx, (get_o2(&gas) + 5) / 10, (get_he(&gas) + 5) / 10, gaschanges[gi + 1].depth / 1000.0); #endif /* Stop for the minimum duration to switch gas */ - add_segment(depth_to_bar(depth, &displayed_dive), - &displayed_dive.cylinder[current_cylinder].gasmix, - prefs.min_switch_duration, po2, &displayed_dive, prefs.decosac); + add_segment(depth_to_bar(depth, dive), + &dive->cylinder[current_cylinder].gasmix, + prefs.min_switch_duration, po2, dive, prefs.decosac); clock += prefs.min_switch_duration; - if (prefs.doo2breaks && get_o2(&displayed_dive.cylinder[current_cylinder].gasmix) == 1000) + if (prefs.doo2breaks && get_o2(&dive->cylinder[current_cylinder].gasmix) == 1000) o2time += prefs.min_switch_duration; pendinggaschange = false; } /* Deco stop should end when runtime is at a whole minute */ int this_decotimestep; - this_decotimestep = DECOTIMESTEP - clock % DECOTIMESTEP; + this_decotimestep = timestep - clock % timestep; - add_segment(depth_to_bar(depth, &displayed_dive), - &displayed_dive.cylinder[current_cylinder].gasmix, - this_decotimestep, po2, &displayed_dive, prefs.decosac); + add_segment(depth_to_bar(depth, dive), + &dive->cylinder[current_cylinder].gasmix, + this_decotimestep, po2, dive, prefs.decosac); clock += this_decotimestep; /* Finish infinite deco */ if (clock >= 48 * 3600 && depth >= 6000) { @@ -965,8 +964,8 @@ bool plan(struct diveplan *diveplan, struct deco_state **cached_datap, bool is_p /* The backgas breaks option limits time on oxygen to 12 minutes, followed by 6 minutes on * backgas (first defined gas). This could be customized if there were demand. */ - if (get_o2(&displayed_dive.cylinder[current_cylinder].gasmix) == 1000) { - o2time += DECOTIMESTEP; + if (get_o2(&dive->cylinder[current_cylinder].gasmix) == 1000) { + o2time += timestep; if (o2time >= 12 * 60) { breaktime = 0; breakcylinder = current_cylinder; @@ -974,18 +973,18 @@ bool plan(struct diveplan *diveplan, struct deco_state **cached_datap, bool is_p plan_add_segment(diveplan, clock - previous_point_time, depth, current_cylinder, po2, false); previous_point_time = clock; current_cylinder = 0; - gas = displayed_dive.cylinder[current_cylinder].gasmix; + gas = dive->cylinder[current_cylinder].gasmix; } } else { if (breaktime >= 0) { - breaktime += DECOTIMESTEP; + breaktime += timestep; if (breaktime >= 6 * 60) { o2time = 0; if (is_final_plan) plan_add_segment(diveplan, clock - previous_point_time, depth, current_cylinder, po2, false); previous_point_time = clock; current_cylinder = breakcylinder; - gas = displayed_dive.cylinder[current_cylinder].gasmix; + gas = dive->cylinder[current_cylinder].gasmix; breaktime = -1; } } @@ -1011,8 +1010,8 @@ bool plan(struct diveplan *diveplan, struct deco_state **cached_datap, bool is_p } create_dive_from_plan(diveplan, is_planner); - add_plan_to_notes(diveplan, &displayed_dive, show_disclaimer, error); - fixup_dc_duration(&displayed_dive.dc); + add_plan_to_notes(diveplan, dive, show_disclaimer, error); + fixup_dc_duration(&dive->dc); free(stoplevels); free(gaschanges); diff --git a/qt-models/diveplannermodel.cpp b/qt-models/diveplannermodel.cpp index 54a5ce7b6..a997c08a1 100644 --- a/qt-models/diveplannermodel.cpp +++ b/qt-models/diveplannermodel.cpp @@ -842,7 +842,7 @@ void DivePlannerPointsModel::createTemporaryPlan() dump_plan(&diveplan); #endif if (recalcQ() && !diveplan_empty(&diveplan)) { - plan(&diveplan, &cache, isPlanner(), false); + plan(&diveplan, &displayed_dive, DECOTIMESTEP, &cache, isPlanner(), false); emit calculatedPlanNotes(); } // throw away the cache @@ -878,7 +878,7 @@ void DivePlannerPointsModel::createPlan(bool replanCopy) setRecalc(oldRecalc); //TODO: C-based function here? - plan(&diveplan, &cache, isPlanner(), true); + plan(&diveplan, &displayed_dive, DECOTIMESTEP, &cache, isPlanner(), true); free(cache); if (!current_dive || displayed_dive.id != current_dive->id) { // we were planning a new dive, not re-planning an existing on diff --git a/tests/testplan.cpp b/tests/testplan.cpp index 7b4671cfd..c67b365e9 100644 --- a/tests/testplan.cpp +++ b/tests/testplan.cpp @@ -10,7 +10,7 @@ #define DEBUG 1 // testing the dive plan algorithm -extern bool plan(struct diveplan *diveplan, struct deco_state **cached_datap, bool is_planner, bool show_disclaimer); +extern bool plan(struct diveplan *diveplan, struct dive *dive, int timestep, struct deco_state **cached_datap, bool is_planner, bool show_disclaimer); extern pressure_t first_ceiling_pressure; @@ -364,7 +364,7 @@ void TestPlan::testMetric() struct diveplan testPlan = {}; setupPlan(&testPlan); - plan(&testPlan, &cache, 1, 0); + plan(&testPlan, &displayed_dive, 60, &cache, 1, 0); #if DEBUG free(displayed_dive.notes); @@ -404,7 +404,7 @@ void TestPlan::testImperial() struct diveplan testPlan = {}; setupPlan(&testPlan); - plan(&testPlan, &cache, 1, 0); + plan(&testPlan, &displayed_dive, 60, &cache, 1, 0); #if DEBUG free(displayed_dive.notes); @@ -444,7 +444,7 @@ void TestPlan::testVpmbMetric45m30minTx() setupPlanVpmb45m30mTx(&testPlan); setCurrentAppState("PlanDive"); - plan(&testPlan, &cache, 1, 0); + plan(&testPlan, &displayed_dive, 60, &cache, 1, 0); #if DEBUG free(displayed_dive.notes); @@ -474,7 +474,7 @@ void TestPlan::testVpmbMetric60m10minTx() setupPlanVpmb60m10mTx(&testPlan); setCurrentAppState("PlanDive"); - plan(&testPlan, &cache, 1, 0); + plan(&testPlan, &displayed_dive, 60, &cache, 1, 0); #if DEBUG free(displayed_dive.notes); @@ -504,7 +504,7 @@ void TestPlan::testVpmbMetric60m30minAir() setupPlanVpmb60m30minAir(&testPlan); setCurrentAppState("PlanDive"); - plan(&testPlan, &cache, 1, 0); + plan(&testPlan, &displayed_dive, 60, &cache, 1, 0); #if DEBUG free(displayed_dive.notes); @@ -534,7 +534,7 @@ void TestPlan::testVpmbMetric60m30minEan50() setupPlanVpmb60m30minEan50(&testPlan); setCurrentAppState("PlanDive"); - plan(&testPlan, &cache, 1, 0); + plan(&testPlan, &displayed_dive, 60, &cache, 1, 0); #if DEBUG free(displayed_dive.notes); @@ -570,7 +570,7 @@ void TestPlan::testVpmbMetric60m30minTx() setupPlanVpmb60m30minTx(&testPlan); setCurrentAppState("PlanDive"); - plan(&testPlan, &cache, 1, 0); + plan(&testPlan, &displayed_dive, 60, &cache, 1, 0); #if DEBUG free(displayed_dive.notes); @@ -606,7 +606,7 @@ void TestPlan::testVpmbMetric100m60min() setupPlanVpmb100m60min(&testPlan); setCurrentAppState("PlanDive"); - plan(&testPlan, &cache, 1, 0); + plan(&testPlan, &displayed_dive, 60, &cache, 1, 0); #if DEBUG free(displayed_dive.notes); @@ -648,7 +648,7 @@ void TestPlan::testVpmbMetricMultiLevelAir() setupPlanVpmbMultiLevelAir(&testPlan); setCurrentAppState("PlanDive"); - plan(&testPlan, &cache, 1, 0); + plan(&testPlan, &displayed_dive, 60, &cache, 1, 0); #if DEBUG free(displayed_dive.notes); @@ -678,7 +678,7 @@ void TestPlan::testVpmbMetric100m10min() setupPlanVpmb100m10min(&testPlan); setCurrentAppState("PlanDive"); - plan(&testPlan, &cache, 1, 0); + plan(&testPlan, &displayed_dive, 60, &cache, 1, 0); #if DEBUG free(displayed_dive.notes); @@ -724,7 +724,7 @@ void TestPlan::testVpmbMetricRepeat() setupPlanVpmb30m20min(&testPlan); setCurrentAppState("PlanDive"); - plan(&testPlan, &cache, 1, 0); + plan(&testPlan, &displayed_dive, 60, &cache, 1, 0); #if DEBUG free(displayed_dive.notes); @@ -744,7 +744,7 @@ void TestPlan::testVpmbMetricRepeat() int firstDiveRunTimeSeconds = displayed_dive.dc.duration.seconds; setupPlanVpmb100mTo70m30min(&testPlan); - plan(&testPlan, &cache, 1, 0); + plan(&testPlan, &displayed_dive, 60, &cache, 1, 0); #if DEBUG free(displayed_dive.notes); @@ -780,7 +780,7 @@ void TestPlan::testVpmbMetricRepeat() QVERIFY(compareDecoTime(displayed_dive.dc.duration.seconds, 127u * 60u + 20u, 127u * 60u + 20u)); setupPlanVpmb30m20min(&testPlan); - plan(&testPlan, &cache, 1, 0); + plan(&testPlan, &displayed_dive, 60, &cache, 1, 0); #if DEBUG free(displayed_dive.notes); |