core: move merge_dives() functios 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:
Berthold Stoeger 2024-06-24 20:47:02 +02:00 committed by bstoeger
parent 8ec1f008ab
commit 4d7291d4a1
6 changed files with 178 additions and 163 deletions

View file

@ -1149,3 +1149,124 @@ std::array<std::unique_ptr<dive>, 2> dive_table::split_dive_at_time(const struct
return {};
return split_dive_at(dive, static_cast<int>(idx), static_cast<int>(idx - 1));
}
/*
* Pick a trip for a dive
*/
static struct dive_trip *get_preferred_trip(const struct dive *a, const struct dive *b)
{
dive_trip *atrip, *btrip;
/* If only one dive has a trip, choose that */
atrip = a->divetrip;
btrip = b->divetrip;
if (!atrip)
return btrip;
if (!btrip)
return atrip;
/* Both dives have a trip - prefer the non-autogenerated one */
if (atrip->autogen && !btrip->autogen)
return btrip;
if (!atrip->autogen && btrip->autogen)
return atrip;
/* Otherwise, look at the trip data and pick the "better" one */
if (atrip->location.empty())
return btrip;
if (btrip->location.empty())
return atrip;
if (atrip->notes.empty())
return btrip;
if (btrip->notes.empty())
return atrip;
/*
* Ok, so both have location and notes.
* Pick the earlier one.
*/
if (a->when < b->when)
return atrip;
return btrip;
}
/*
* Merging two dives can be subtle, because there's two different ways
* of merging:
*
* (a) two distinctly _different_ dives that have the same dive computer
* are merged into one longer dive, because the user asked for it
* in the divelist.
*
* Because this case is with the same dive computer, we *know* the
* two must have a different start time, and "offset" is the relative
* time difference between the two.
*
* (b) two different dive computers that we might want to merge into
* one single dive with multiple dive computers.
*
* This is the "try_to_merge()" case, which will have offset == 0,
* even if the dive times might be different.
*
* If new dives are merged into the dive table, dive a is supposed to
* be the old dive and dive b is supposed to be the newly imported
* dive. If the flag "prefer_downloaded" is set, data of the latter
* will take priority over the former.
*
* The trip the new dive should be associated with (if any) is returned
* in the "trip" output parameter.
*
* The dive site the new dive should be added to (if any) is returned
* in the "dive_site" output parameter.
*/
merge_result dive_table::merge_dives(const struct dive &a_in, const struct dive &b_in, int offset, bool prefer_downloaded) const
{
merge_result res = { };
const dive *a = &a_in;
const dive *b = &b_in;
if (is_dc_planner(&a->dcs[0]))
std::swap(a, b);
res.dive = dive::create_merged_dive(*a, *b, offset, prefer_downloaded);
/* The CNS values will be recalculated from the sample in fixup_dive() */
res.dive->cns = res.dive->maxcns = 0;
res.trip = get_preferred_trip(a, b);
/* we take the first dive site, unless it's empty */
res.site = a->dive_site && !a->dive_site->is_empty() ? a->dive_site : b->dive_site;
if (!dive_site_has_gps_location(res.site) && dive_site_has_gps_location(b->dive_site)) {
/* we picked the first dive site and that didn't have GPS data, but the new dive has
* GPS data (that could be a download from a GPS enabled dive computer).
* Keep the dive site, but add the GPS data */
res.site->location = b->dive_site->location;
}
fixup_dive(*res.dive);
return res;
}
/*
* This could do a lot more merging. Right now it really only
* merges almost exact duplicates - something that happens easily
* with overlapping dive downloads.
*
* If new dives are merged into the dive table, dive a is supposed to
* be the old dive and dive b is supposed to be the newly imported
* dive. If the flag "prefer_downloaded" is set, data of the latter
* will take priority over the former.
*
* Attn: The dive_site parameter of the dive will be set, but the caller
* still has to register the dive in the dive site!
*/
struct std::unique_ptr<dive> dive_table::try_to_merge(const struct dive &a, const struct dive &b, bool prefer_downloaded) const
{
if (!a.likely_same(b))
return {};
auto [res, trip, site] = merge_dives(a, b, 0, prefer_downloaded);
res->dive_site = site; /* Caller has to call site->add_dive()! */
return std::move(res);
}