mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-30 22:20:21 +00:00
core: move split_dive*() functions to struct dive_table
These functions have to access other dives in the list to calculate CNS, etc, so let's call them from there. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
parent
a2903b31a7
commit
8ec1f008ab
5 changed files with 217 additions and 216 deletions
|
@ -833,9 +833,9 @@ static std::array<std::unique_ptr<dive>, 2> doSplitDives(const dive *d, duration
|
||||||
{
|
{
|
||||||
// Split the dive
|
// Split the dive
|
||||||
if (time.seconds < 0)
|
if (time.seconds < 0)
|
||||||
return split_dive(*d);
|
return divelog.dives.split_dive(*d);
|
||||||
else
|
else
|
||||||
return split_dive_at_time(*d, time);
|
return divelog.dives.split_dive_at_time(*d, time);
|
||||||
}
|
}
|
||||||
|
|
||||||
SplitDives::SplitDives(dive *d, duration_t time) : SplitDivesBase(d, doSplitDives(d, time))
|
SplitDives::SplitDives(dive *d, duration_t time) : SplitDivesBase(d, doSplitDives(d, time))
|
||||||
|
@ -844,7 +844,7 @@ SplitDives::SplitDives(dive *d, duration_t time) : SplitDivesBase(d, doSplitDive
|
||||||
}
|
}
|
||||||
|
|
||||||
SplitDiveComputer::SplitDiveComputer(dive *d, int dc_num) :
|
SplitDiveComputer::SplitDiveComputer(dive *d, int dc_num) :
|
||||||
SplitDivesBase(d, split_divecomputer(*d, dc_num))
|
SplitDivesBase(d, divelog.dives.split_divecomputer(*d, dc_num))
|
||||||
{
|
{
|
||||||
setText(Command::Base::tr("split dive computer"));
|
setText(Command::Base::tr("split dive computer"));
|
||||||
}
|
}
|
||||||
|
|
209
core/dive.cpp
209
core/dive.cpp
|
@ -2296,176 +2296,6 @@ merge_result merge_dives(const struct dive &a_in, const struct dive &b_in, int o
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Split a dive that has a surface interval from samples 'a' to 'b'
|
|
||||||
* into two dives, but don't add them to the log yet.
|
|
||||||
* Returns the nr of the old dive or <0 on failure.
|
|
||||||
* Moreover, on failure both output dives are set to NULL.
|
|
||||||
* On success, the newly allocated dives are returned in out1 and out2.
|
|
||||||
*/
|
|
||||||
static std::array<std::unique_ptr<dive>, 2> split_dive_at(const struct dive &dive, int a, int b)
|
|
||||||
{
|
|
||||||
size_t nr = divelog.dives.get_idx(&dive);
|
|
||||||
|
|
||||||
/* if we can't find the dive in the dive list, don't bother */
|
|
||||||
if (nr == std::string::npos)
|
|
||||||
return {};
|
|
||||||
|
|
||||||
/* Splitting should leave at least 3 samples per dive */
|
|
||||||
if (a < 3 || static_cast<size_t>(b + 4) > dive.dcs[0].samples.size())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
/* We're not trying to be efficient here.. */
|
|
||||||
auto d1 = std::make_unique<struct dive>(dive);
|
|
||||||
auto d2 = std::make_unique<struct dive>(dive);
|
|
||||||
d1->id = dive_getUniqID();
|
|
||||||
d2->id = dive_getUniqID();
|
|
||||||
d1->divetrip = d2->divetrip = nullptr;
|
|
||||||
|
|
||||||
/* now unselect the first first segment so we don't keep all
|
|
||||||
* dives selected by mistake. But do keep the second one selected
|
|
||||||
* so the algorithm keeps splitting the dive further */
|
|
||||||
d1->selected = false;
|
|
||||||
|
|
||||||
struct divecomputer &dc1 = d1->dcs[0];
|
|
||||||
struct divecomputer &dc2 = d2->dcs[0];
|
|
||||||
/*
|
|
||||||
* Cut off the samples of d1 at the beginning
|
|
||||||
* of the interval.
|
|
||||||
*/
|
|
||||||
dc1.samples.resize(a);
|
|
||||||
|
|
||||||
/* And get rid of the 'b' first samples of d2 */
|
|
||||||
dc2.samples.erase(dc2.samples.begin(), dc2.samples.begin() + b);
|
|
||||||
|
|
||||||
/* Now the secondary dive computers */
|
|
||||||
int32_t t = dc2.samples[0].time.seconds;
|
|
||||||
for (auto it1 = d1->dcs.begin() + 1; it1 != d1->dcs.end(); ++it1) {
|
|
||||||
auto it = std::find_if(it1->samples.begin(), it1->samples.end(),
|
|
||||||
[t](auto &sample) { return sample.time.seconds >= t; });
|
|
||||||
it1->samples.erase(it, it1->samples.end());
|
|
||||||
}
|
|
||||||
for (auto it2 = d2->dcs.begin() + 1; it2 != d2->dcs.end(); ++it2) {
|
|
||||||
auto it = std::find_if(it2->samples.begin(), it2->samples.end(),
|
|
||||||
[t](auto &sample) { return sample.time.seconds >= t; });
|
|
||||||
it2->samples.erase(it2->samples.begin(), it);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* This is where we cut off events from d1,
|
|
||||||
* and shift everything in d2
|
|
||||||
*/
|
|
||||||
d2->when += t;
|
|
||||||
auto it1 = d1->dcs.begin();
|
|
||||||
auto it2 = d2->dcs.begin();
|
|
||||||
while (it1 != d1->dcs.end() && it2 != d2->dcs.end()) {
|
|
||||||
it2->when += t;
|
|
||||||
for (auto &sample: it2->samples)
|
|
||||||
sample.time.seconds -= t;
|
|
||||||
|
|
||||||
/* Remove the events past 't' from d1 */
|
|
||||||
auto it = std::lower_bound(it1->events.begin(), it1->events.end(), t,
|
|
||||||
[] (struct event &ev, int t)
|
|
||||||
{ return ev.time.seconds < t; });
|
|
||||||
it1->events.erase(it, it1->events.end());
|
|
||||||
|
|
||||||
/* Remove the events before 't' from d2, and shift the rest */
|
|
||||||
it = std::lower_bound(it2->events.begin(), it2->events.end(), t,
|
|
||||||
[] (struct event &ev, int t)
|
|
||||||
{ return ev.time.seconds < t; });
|
|
||||||
it2->events.erase(it2->events.begin(), it);
|
|
||||||
for (auto &ev: it2->events)
|
|
||||||
ev.time.seconds -= t;
|
|
||||||
|
|
||||||
++it1;
|
|
||||||
++it2;
|
|
||||||
}
|
|
||||||
|
|
||||||
divelog.dives.force_fixup_dive(*d1);
|
|
||||||
divelog.dives.force_fixup_dive(*d2);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Was the dive numbered? If it was the last dive, then we'll
|
|
||||||
* increment the dive number for the tail part that we split off.
|
|
||||||
* Otherwise the tail is unnumbered.
|
|
||||||
*/
|
|
||||||
if (d2->number) {
|
|
||||||
if (divelog.dives.size() == nr + 1)
|
|
||||||
d2->number++;
|
|
||||||
else
|
|
||||||
d2->number = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return { std::move(d1), std::move(d2) };
|
|
||||||
}
|
|
||||||
|
|
||||||
/* in freedive mode we split for as little as 10 seconds on the surface,
|
|
||||||
* otherwise we use a minute */
|
|
||||||
static bool should_split(const struct divecomputer *dc, int t1, int t2)
|
|
||||||
{
|
|
||||||
int threshold = dc->divemode == FREEDIVE ? 10 : 60;
|
|
||||||
|
|
||||||
return t2 - t1 >= threshold;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Try to split a dive into multiple dives at a surface interval point.
|
|
||||||
*
|
|
||||||
* NOTE! We will split when there is at least one surface event that has
|
|
||||||
* non-surface events on both sides.
|
|
||||||
*
|
|
||||||
* The surface interval points are determined using the first dive computer.
|
|
||||||
*
|
|
||||||
* In other words, this is a (simplified) reversal of the dive merging.
|
|
||||||
*/
|
|
||||||
std::array<std::unique_ptr<dive>, 2> split_dive(const struct dive &dive)
|
|
||||||
{
|
|
||||||
const struct divecomputer *dc = &dive.dcs[0];
|
|
||||||
bool at_surface = true;
|
|
||||||
if (dc->samples.empty())
|
|
||||||
return {};
|
|
||||||
auto surface_start = dc->samples.begin();
|
|
||||||
for (auto it = dc->samples.begin() + 1; it != dc->samples.end(); ++it) {
|
|
||||||
bool surface_sample = it->depth.mm < SURFACE_THRESHOLD;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We care about the transition from and to depth 0,
|
|
||||||
* not about the depth staying similar.
|
|
||||||
*/
|
|
||||||
if (at_surface == surface_sample)
|
|
||||||
continue;
|
|
||||||
at_surface = surface_sample;
|
|
||||||
|
|
||||||
// Did it become surface after having been non-surface? We found the start
|
|
||||||
if (at_surface) {
|
|
||||||
surface_start = it;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Going down again? We want at least a minute from
|
|
||||||
// the surface start.
|
|
||||||
if (surface_start == dc->samples.begin())
|
|
||||||
continue;
|
|
||||||
if (!should_split(dc, surface_start->time.seconds, std::prev(it)->time.seconds))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
return split_dive_at(dive, surface_start - dc->samples.begin(), it - dc->samples.begin() - 1);
|
|
||||||
}
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<std::unique_ptr<dive>, 2> split_dive_at_time(const struct dive &dive, duration_t time)
|
|
||||||
{
|
|
||||||
auto it = std::find_if(dive.dcs[0].samples.begin(), dive.dcs[0].samples.end(),
|
|
||||||
[time](auto &sample) { return sample.time.seconds >= time.seconds; });
|
|
||||||
if (it == dive.dcs[0].samples.end())
|
|
||||||
return {};
|
|
||||||
size_t idx = it - dive.dcs[0].samples.begin();
|
|
||||||
if (idx < 1)
|
|
||||||
return {};
|
|
||||||
return split_dive_at(dive, static_cast<int>(idx), static_cast<int>(idx - 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* "dc_maxtime()" is how much total time this dive computer
|
* "dc_maxtime()" is how much total time this dive computer
|
||||||
* has for this dive. Note that it can differ from "duration"
|
* has for this dive. Note that it can differ from "duration"
|
||||||
|
@ -2606,45 +2436,6 @@ std::unique_ptr<dive> clone_delete_divecomputer(const struct dive &d, int dc_num
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* This splits the dive src by dive computer. The first output dive has all
|
|
||||||
* dive computers except num, the second only dive computer num.
|
|
||||||
* The dives will not be associated with a trip.
|
|
||||||
* On error, both output parameters are set to NULL.
|
|
||||||
*/
|
|
||||||
std::array<std::unique_ptr<dive>, 2> split_divecomputer(const struct dive &src, int num)
|
|
||||||
{
|
|
||||||
if (num < 0 || src.dcs.size() < 2 || static_cast<size_t>(num) >= src.dcs.size())
|
|
||||||
return {};
|
|
||||||
|
|
||||||
// Copy the dive with full divecomputer list
|
|
||||||
auto out1 = std::make_unique<dive>(src);
|
|
||||||
|
|
||||||
// Remove all DCs, stash them and copy the dive again.
|
|
||||||
// Then, we have to dives without DCs and a list of DCs.
|
|
||||||
std::vector<divecomputer> dcs;
|
|
||||||
std::swap(out1->dcs, dcs);
|
|
||||||
auto out2 = std::make_unique<dive>(*out1);
|
|
||||||
|
|
||||||
// Give the dives new unique ids and remove them from the trip.
|
|
||||||
out1->id = dive_getUniqID();
|
|
||||||
out2->id = dive_getUniqID();
|
|
||||||
out1->divetrip = out2->divetrip = NULL;
|
|
||||||
|
|
||||||
// Now copy the divecomputers
|
|
||||||
out1->dcs.reserve(src.dcs.size() - 1);
|
|
||||||
for (auto [idx, dc]: enumerated_range(dcs)) {
|
|
||||||
auto &dcs = idx == num ? out2->dcs : out1->dcs;
|
|
||||||
dcs.push_back(std::move(dc));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recalculate gas data, etc.
|
|
||||||
divelog.dives.fixup_dive(*out1);
|
|
||||||
divelog.dives.fixup_dive(*out2);
|
|
||||||
|
|
||||||
return { std::move(out1), std::move(out2) };
|
|
||||||
}
|
|
||||||
|
|
||||||
//Calculate O2 in best mix
|
//Calculate O2 in best mix
|
||||||
fraction_t best_o2(depth_t depth, const struct dive *dive, bool in_planner)
|
fraction_t best_o2(depth_t depth, const struct dive *dive, bool in_planner)
|
||||||
{
|
{
|
||||||
|
|
|
@ -151,7 +151,6 @@ extern const struct divecomputer *get_dive_dc(const struct dive *dive, int nr);
|
||||||
|
|
||||||
extern std::unique_ptr<dive> clone_make_first_dc(const struct dive &d, int dc_number);
|
extern std::unique_ptr<dive> clone_make_first_dc(const struct dive &d, int dc_number);
|
||||||
extern std::unique_ptr<dive> clone_delete_divecomputer(const struct dive &d, int dc_number);
|
extern std::unique_ptr<dive> clone_delete_divecomputer(const struct dive &d, int dc_number);
|
||||||
extern std::array<std::unique_ptr<dive>, 2> split_divecomputer(const struct dive &src, int num);
|
|
||||||
|
|
||||||
extern bool dive_site_has_gps_location(const struct dive_site *ds);
|
extern bool dive_site_has_gps_location(const struct dive_site *ds);
|
||||||
extern int dive_has_gps_location(const struct dive *dive);
|
extern int dive_has_gps_location(const struct dive *dive);
|
||||||
|
@ -184,8 +183,6 @@ extern bool dive_less_than_ptr(const struct dive *a, const struct dive *b);
|
||||||
extern bool dive_or_trip_less_than(struct dive_or_trip a, struct dive_or_trip b);
|
extern bool dive_or_trip_less_than(struct dive_or_trip a, struct dive_or_trip b);
|
||||||
extern int get_dive_salinity(const struct dive *dive);
|
extern int get_dive_salinity(const struct dive *dive);
|
||||||
extern int dive_getUniqID();
|
extern int dive_getUniqID();
|
||||||
extern std::array<std::unique_ptr<dive>, 2> split_dive(const struct dive &dive);
|
|
||||||
extern std::array<std::unique_ptr<dive>, 2> split_dive_at_time(const struct dive &dive, duration_t time);
|
|
||||||
|
|
||||||
struct merge_result {
|
struct merge_result {
|
||||||
std::unique_ptr<struct dive> dive;
|
std::unique_ptr<struct dive> dive;
|
||||||
|
|
|
@ -405,6 +405,7 @@ int dive_table::calculate_cns(struct dive &dive) const
|
||||||
dive.cns = lrint(cns);
|
dive.cns = lrint(cns);
|
||||||
return dive.cns;
|
return dive.cns;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return air usage (in liters).
|
* Return air usage (in liters).
|
||||||
*/
|
*/
|
||||||
|
@ -939,3 +940,212 @@ bool has_dive(unsigned int deviceid, unsigned int diveid)
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This splits the dive src by dive computer. The first output dive has all
|
||||||
|
* dive computers except num, the second only dive computer num.
|
||||||
|
* The dives will not be associated with a trip.
|
||||||
|
* On error, both output parameters are set to NULL.
|
||||||
|
*/
|
||||||
|
std::array<std::unique_ptr<dive>, 2> dive_table::split_divecomputer(const struct dive &src, int num) const
|
||||||
|
{
|
||||||
|
if (num < 0 || src.dcs.size() < 2 || static_cast<size_t>(num) >= src.dcs.size())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
// Copy the dive with full divecomputer list
|
||||||
|
auto out1 = std::make_unique<dive>(src);
|
||||||
|
|
||||||
|
// Remove all DCs, stash them and copy the dive again.
|
||||||
|
// Then, we have to dives without DCs and a list of DCs.
|
||||||
|
std::vector<divecomputer> dcs;
|
||||||
|
std::swap(out1->dcs, dcs);
|
||||||
|
auto out2 = std::make_unique<dive>(*out1);
|
||||||
|
|
||||||
|
// Give the dives new unique ids and remove them from the trip.
|
||||||
|
out1->id = dive_getUniqID();
|
||||||
|
out2->id = dive_getUniqID();
|
||||||
|
out1->divetrip = out2->divetrip = NULL;
|
||||||
|
|
||||||
|
// Now copy the divecomputers
|
||||||
|
out1->dcs.reserve(src.dcs.size() - 1);
|
||||||
|
for (auto [idx, dc]: enumerated_range(dcs)) {
|
||||||
|
auto &dcs = idx == num ? out2->dcs : out1->dcs;
|
||||||
|
dcs.push_back(std::move(dc));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recalculate gas data, etc.
|
||||||
|
fixup_dive(*out1);
|
||||||
|
fixup_dive(*out2);
|
||||||
|
|
||||||
|
return { std::move(out1), std::move(out2) };
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Split a dive that has a surface interval from samples 'a' to 'b'
|
||||||
|
* into two dives, but don't add them to the log yet.
|
||||||
|
* Returns the nr of the old dive or <0 on failure.
|
||||||
|
* Moreover, on failure both output dives are set to NULL.
|
||||||
|
* On success, the newly allocated dives are returned in out1 and out2.
|
||||||
|
*/
|
||||||
|
std::array<std::unique_ptr<dive>, 2> dive_table::split_dive_at(const struct dive &dive, int a, int b) const
|
||||||
|
{
|
||||||
|
size_t nr = get_idx(&dive);
|
||||||
|
|
||||||
|
/* if we can't find the dive in the dive list, don't bother */
|
||||||
|
if (nr == std::string::npos)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
bool is_last_dive = size() == nr + 1;
|
||||||
|
|
||||||
|
/* Splitting should leave at least 3 samples per dive */
|
||||||
|
if (a < 3 || static_cast<size_t>(b + 4) > dive.dcs[0].samples.size())
|
||||||
|
return {};
|
||||||
|
|
||||||
|
/* We're not trying to be efficient here.. */
|
||||||
|
auto d1 = std::make_unique<struct dive>(dive);
|
||||||
|
auto d2 = std::make_unique<struct dive>(dive);
|
||||||
|
d1->id = dive_getUniqID();
|
||||||
|
d2->id = dive_getUniqID();
|
||||||
|
d1->divetrip = d2->divetrip = nullptr;
|
||||||
|
|
||||||
|
/* now unselect the first first segment so we don't keep all
|
||||||
|
* dives selected by mistake. But do keep the second one selected
|
||||||
|
* so the algorithm keeps splitting the dive further */
|
||||||
|
d1->selected = false;
|
||||||
|
|
||||||
|
struct divecomputer &dc1 = d1->dcs[0];
|
||||||
|
struct divecomputer &dc2 = d2->dcs[0];
|
||||||
|
/*
|
||||||
|
* Cut off the samples of d1 at the beginning
|
||||||
|
* of the interval.
|
||||||
|
*/
|
||||||
|
dc1.samples.resize(a);
|
||||||
|
|
||||||
|
/* And get rid of the 'b' first samples of d2 */
|
||||||
|
dc2.samples.erase(dc2.samples.begin(), dc2.samples.begin() + b);
|
||||||
|
|
||||||
|
/* Now the secondary dive computers */
|
||||||
|
int32_t t = dc2.samples[0].time.seconds;
|
||||||
|
for (auto it1 = d1->dcs.begin() + 1; it1 != d1->dcs.end(); ++it1) {
|
||||||
|
auto it = std::find_if(it1->samples.begin(), it1->samples.end(),
|
||||||
|
[t](auto &sample) { return sample.time.seconds >= t; });
|
||||||
|
it1->samples.erase(it, it1->samples.end());
|
||||||
|
}
|
||||||
|
for (auto it2 = d2->dcs.begin() + 1; it2 != d2->dcs.end(); ++it2) {
|
||||||
|
auto it = std::find_if(it2->samples.begin(), it2->samples.end(),
|
||||||
|
[t](auto &sample) { return sample.time.seconds >= t; });
|
||||||
|
it2->samples.erase(it2->samples.begin(), it);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This is where we cut off events from d1,
|
||||||
|
* and shift everything in d2
|
||||||
|
*/
|
||||||
|
d2->when += t;
|
||||||
|
auto it1 = d1->dcs.begin();
|
||||||
|
auto it2 = d2->dcs.begin();
|
||||||
|
while (it1 != d1->dcs.end() && it2 != d2->dcs.end()) {
|
||||||
|
it2->when += t;
|
||||||
|
for (auto &sample: it2->samples)
|
||||||
|
sample.time.seconds -= t;
|
||||||
|
|
||||||
|
/* Remove the events past 't' from d1 */
|
||||||
|
auto it = std::lower_bound(it1->events.begin(), it1->events.end(), t,
|
||||||
|
[] (struct event &ev, int t)
|
||||||
|
{ return ev.time.seconds < t; });
|
||||||
|
it1->events.erase(it, it1->events.end());
|
||||||
|
|
||||||
|
/* Remove the events before 't' from d2, and shift the rest */
|
||||||
|
it = std::lower_bound(it2->events.begin(), it2->events.end(), t,
|
||||||
|
[] (struct event &ev, int t)
|
||||||
|
{ return ev.time.seconds < t; });
|
||||||
|
it2->events.erase(it2->events.begin(), it);
|
||||||
|
for (auto &ev: it2->events)
|
||||||
|
ev.time.seconds -= t;
|
||||||
|
|
||||||
|
++it1;
|
||||||
|
++it2;
|
||||||
|
}
|
||||||
|
|
||||||
|
force_fixup_dive(*d1);
|
||||||
|
force_fixup_dive(*d2);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Was the dive numbered? If it was the last dive, then we'll
|
||||||
|
* increment the dive number for the tail part that we split off.
|
||||||
|
* Otherwise the tail is unnumbered.
|
||||||
|
*/
|
||||||
|
if (d2->number && is_last_dive)
|
||||||
|
d2->number++;
|
||||||
|
else
|
||||||
|
d2->number = 0;
|
||||||
|
|
||||||
|
return { std::move(d1), std::move(d2) };
|
||||||
|
}
|
||||||
|
|
||||||
|
/* in freedive mode we split for as little as 10 seconds on the surface,
|
||||||
|
* otherwise we use a minute */
|
||||||
|
static bool should_split(const struct divecomputer *dc, int t1, int t2)
|
||||||
|
{
|
||||||
|
int threshold = dc->divemode == FREEDIVE ? 10 : 60;
|
||||||
|
|
||||||
|
return t2 - t1 >= threshold;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try to split a dive into multiple dives at a surface interval point.
|
||||||
|
*
|
||||||
|
* NOTE! We will split when there is at least one surface event that has
|
||||||
|
* non-surface events on both sides.
|
||||||
|
*
|
||||||
|
* The surface interval points are determined using the first dive computer.
|
||||||
|
*
|
||||||
|
* In other words, this is a (simplified) reversal of the dive merging.
|
||||||
|
*/
|
||||||
|
std::array<std::unique_ptr<dive>, 2> dive_table::split_dive(const struct dive &dive) const
|
||||||
|
{
|
||||||
|
const struct divecomputer *dc = &dive.dcs[0];
|
||||||
|
bool at_surface = true;
|
||||||
|
if (dc->samples.empty())
|
||||||
|
return {};
|
||||||
|
auto surface_start = dc->samples.begin();
|
||||||
|
for (auto it = dc->samples.begin() + 1; it != dc->samples.end(); ++it) {
|
||||||
|
bool surface_sample = it->depth.mm < SURFACE_THRESHOLD;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We care about the transition from and to depth 0,
|
||||||
|
* not about the depth staying similar.
|
||||||
|
*/
|
||||||
|
if (at_surface == surface_sample)
|
||||||
|
continue;
|
||||||
|
at_surface = surface_sample;
|
||||||
|
|
||||||
|
// Did it become surface after having been non-surface? We found the start
|
||||||
|
if (at_surface) {
|
||||||
|
surface_start = it;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Going down again? We want at least a minute from
|
||||||
|
// the surface start.
|
||||||
|
if (surface_start == dc->samples.begin())
|
||||||
|
continue;
|
||||||
|
if (!should_split(dc, surface_start->time.seconds, std::prev(it)->time.seconds))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
return split_dive_at(dive, surface_start - dc->samples.begin(), it - dc->samples.begin() - 1);
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<std::unique_ptr<dive>, 2> dive_table::split_dive_at_time(const struct dive &dive, duration_t time) const
|
||||||
|
{
|
||||||
|
auto it = std::find_if(dive.dcs[0].samples.begin(), dive.dcs[0].samples.end(),
|
||||||
|
[time](auto &sample) { return sample.time.seconds >= time.seconds; });
|
||||||
|
if (it == dive.dcs[0].samples.end())
|
||||||
|
return {};
|
||||||
|
size_t idx = it - dive.dcs[0].samples.begin();
|
||||||
|
if (idx < 1)
|
||||||
|
return {};
|
||||||
|
return split_dive_at(dive, static_cast<int>(idx), static_cast<int>(idx - 1));
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#include "divesitetable.h"
|
#include "divesitetable.h"
|
||||||
#include "units.h"
|
#include "units.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
struct dive;
|
struct dive;
|
||||||
struct divelog;
|
struct divelog;
|
||||||
|
@ -33,8 +32,12 @@ struct dive_table : public sorted_owning_table<dive, &comp_dives> {
|
||||||
int get_dive_nr_at_idx(int idx) const;
|
int get_dive_nr_at_idx(int idx) const;
|
||||||
timestamp_t get_surface_interval(timestamp_t when) const;
|
timestamp_t get_surface_interval(timestamp_t when) const;
|
||||||
struct dive *find_next_visible_dive(timestamp_t when);
|
struct dive *find_next_visible_dive(timestamp_t when);
|
||||||
|
std::array<std::unique_ptr<dive>, 2> split_divecomputer(const struct dive &src, int num) const;
|
||||||
|
std::array<std::unique_ptr<dive>, 2> split_dive(const struct dive &dive) const;
|
||||||
|
std::array<std::unique_ptr<dive>, 2> split_dive_at_time(const struct dive &dive, duration_t time) const;
|
||||||
private:
|
private:
|
||||||
int calculate_cns(struct dive &dive) const; // Note: writes into dive->cns
|
int calculate_cns(struct dive &dive) const; // Note: writes into dive->cns
|
||||||
|
std::array<std::unique_ptr<dive>, 2> split_dive_at(const struct dive &dive, int a, int b) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* this is used for both git and xml format */
|
/* this is used for both git and xml format */
|
||||||
|
|
Loading…
Reference in a new issue