mirror of
https://github.com/subsurface/subsurface.git
synced 2024-11-30 22:20:21 +00:00
Undo: don't modify source-dives on merge
For undo, it is crucial that commands don't modify existing dives. Unfortunately, dive merging would write into the data-structures of the to-be-merged dives. To prevent it from doing so, make the input dives const-pointers. This led to a whole cascade of functions that had to take const and significant churn. Signed-off-by: Berthold Stoeger <bstoeger@mail.tuwien.ac.at>
This commit is contained in:
parent
1afd295c41
commit
8c2383b495
2 changed files with 259 additions and 153 deletions
410
core/dive.c
410
core/dive.c
|
@ -488,6 +488,18 @@ static void copy_dc(const struct divecomputer *sdc, struct divecomputer *ddc)
|
|||
copy_events(sdc, ddc);
|
||||
}
|
||||
|
||||
static void dc_cylinder_renumber(struct dive *dive, struct divecomputer *dc, const int mapping[]);
|
||||
|
||||
/* copy dive computer and renumber the cylinders */
|
||||
static void copy_dc_renumber(struct dive *d, const struct divecomputer *sdc, struct divecomputer *ddc, const int cylinders_map[])
|
||||
{
|
||||
*ddc = *sdc;
|
||||
ddc->model = copy_string(sdc->model);
|
||||
copy_samples(sdc, ddc);
|
||||
copy_events(sdc, ddc);
|
||||
dc_cylinder_renumber(d, ddc, cylinders_map);
|
||||
}
|
||||
|
||||
/* copy an element in a list of pictures */
|
||||
static void copy_pl(struct picture *sp, struct picture *dp)
|
||||
{
|
||||
|
@ -1389,12 +1401,15 @@ static void fixup_airtemp(struct dive *dive)
|
|||
dive->airtemp.mkelvin = dc_airtemp(&dive->dc);
|
||||
}
|
||||
|
||||
/* zero out the airtemp in the dive structure if it was just created by
|
||||
* running fixup on the dive. keep it if it had been edited by hand */
|
||||
static void un_fixup_airtemp(struct dive *a)
|
||||
/* if the air temperature in the dive data is redundant to the one in its
|
||||
* first divecomputer (i.e., it was added by running fixup on the dive)
|
||||
* return 0, otherwise return the air temperature given in the dive */
|
||||
static temperature_t un_fixup_airtemp(const struct dive *a)
|
||||
{
|
||||
temperature_t res = a->airtemp;
|
||||
if (a->airtemp.mkelvin && a->airtemp.mkelvin == dc_airtemp(&a->dc))
|
||||
a->airtemp.mkelvin = 0;
|
||||
res.mkelvin = 0;
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -1837,7 +1852,7 @@ struct sample *add_sample(const struct sample *sample, int time, struct divecomp
|
|||
* that the time in between the dives is at the surface, not some "last
|
||||
* sample that happened to be at a depth of 1.2m".
|
||||
*/
|
||||
static void merge_one_sample(struct sample *sample, int time, struct divecomputer *dc)
|
||||
static void merge_one_sample(const struct sample *sample, int time, struct divecomputer *dc)
|
||||
{
|
||||
int last = dc->samples - 1;
|
||||
if (last >= 0) {
|
||||
|
@ -1863,11 +1878,16 @@ static void merge_one_sample(struct sample *sample, int time, struct divecompute
|
|||
add_sample(sample, time, dc);
|
||||
}
|
||||
|
||||
static void renumber_last_sample(struct divecomputer *dc, const int mapping[]);
|
||||
static void sample_renumber(struct sample *s, int i, const int mapping[]);
|
||||
|
||||
/*
|
||||
* Merge samples. Dive 'a' is "offset" seconds before Dive 'b'
|
||||
*/
|
||||
static void merge_samples(struct divecomputer *res, struct divecomputer *a, struct divecomputer *b, int offset)
|
||||
static void merge_samples(struct divecomputer *res,
|
||||
const struct divecomputer *a, const struct divecomputer *b,
|
||||
const int *cylinders_map_a, const int *cylinders_map_b,
|
||||
int offset)
|
||||
{
|
||||
int asamples = a->samples;
|
||||
int bsamples = b->samples;
|
||||
|
@ -1882,14 +1902,19 @@ static void merge_samples(struct divecomputer *res, struct divecomputer *a, stru
|
|||
* the reverse offset.
|
||||
*/
|
||||
if (offset < 0) {
|
||||
const int *cylinders_map_tmp;
|
||||
offset = -offset;
|
||||
asamples = bsamples;
|
||||
bsamples = a->samples;
|
||||
as = bs;
|
||||
bs = a->sample;
|
||||
cylinders_map_tmp = cylinders_map_a;
|
||||
cylinders_map_a = cylinders_map_b;
|
||||
cylinders_map_b = cylinders_map_tmp;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
int j;
|
||||
int at, bt;
|
||||
struct sample sample = { .bearing.degrees = -1, .ndl.seconds = -1 };
|
||||
|
||||
|
@ -1907,6 +1932,7 @@ static void merge_samples(struct divecomputer *res, struct divecomputer *a, stru
|
|||
if (bt < 0) {
|
||||
add_sample_a:
|
||||
merge_one_sample(as, at, res);
|
||||
renumber_last_sample(res, cylinders_map_a);
|
||||
as++;
|
||||
asamples--;
|
||||
continue;
|
||||
|
@ -1916,6 +1942,7 @@ static void merge_samples(struct divecomputer *res, struct divecomputer *a, stru
|
|||
if (at < 0) {
|
||||
add_sample_b:
|
||||
merge_one_sample(bs, bt, res);
|
||||
renumber_last_sample(res, cylinders_map_b);
|
||||
bs++;
|
||||
bsamples--;
|
||||
continue;
|
||||
|
@ -1928,18 +1955,23 @@ static void merge_samples(struct divecomputer *res, struct divecomputer *a, stru
|
|||
|
||||
/* same-time sample: add a merged sample. Take the non-zero ones */
|
||||
sample = *bs;
|
||||
sample_renumber(&sample, 0, cylinders_map_b);
|
||||
if (as->depth.mm)
|
||||
sample.depth = as->depth;
|
||||
if (as->temperature.mkelvin)
|
||||
sample.temperature = as->temperature;
|
||||
if (as->pressure[0].mbar)
|
||||
sample.pressure[0] = as->pressure[0];
|
||||
if (as->sensor[0])
|
||||
sample.sensor[0] = as->sensor[0];
|
||||
if (as->pressure[1].mbar)
|
||||
sample.pressure[1] = as->pressure[1];
|
||||
if (as->sensor[1])
|
||||
sample.sensor[1] = as->sensor[1];
|
||||
for (j = 0; j < MAX_SENSORS; ++j) {
|
||||
int sensor_id;
|
||||
|
||||
sensor_id = cylinders_map_a[as->sensor[j]];
|
||||
if (sensor_id < 0)
|
||||
continue;
|
||||
|
||||
if (as->pressure[j].mbar)
|
||||
sample.pressure[j] = as->pressure[j];
|
||||
if (as->sensor[j])
|
||||
sample.sensor[j] = sensor_id;
|
||||
}
|
||||
if (as->cns)
|
||||
sample.cns = as->cns;
|
||||
if (as->setpoint.mbar)
|
||||
|
@ -1980,16 +2012,17 @@ static char *merge_text(const char *a, const char *b, const char *sep)
|
|||
return res;
|
||||
}
|
||||
|
||||
#define SORT(a, b, field) \
|
||||
if (a->field != b->field) \
|
||||
return a->field < b->field ? -1 : 1
|
||||
#define SORT(a, b) \
|
||||
if (a != b) \
|
||||
return a < b ? -1 : 1
|
||||
#define SORT_FIELD(a, b, field) SORT(a->field, b->field)
|
||||
|
||||
static int sort_event(const struct event *a, const struct event *b)
|
||||
static int sort_event(const struct event *a, const struct event *b, int time_a, int time_b)
|
||||
{
|
||||
SORT(a, b, time.seconds);
|
||||
SORT(a, b, type);
|
||||
SORT(a, b, flags);
|
||||
SORT(a, b, value);
|
||||
SORT(time_a, time_b);
|
||||
SORT_FIELD(a, b, type);
|
||||
SORT_FIELD(a, b, flags);
|
||||
SORT_FIELD(a, b, value);
|
||||
return strcmp(a->name, b->name);
|
||||
}
|
||||
|
||||
|
@ -2002,43 +2035,54 @@ static int same_gas(const struct event *a, const struct event *b)
|
|||
return false;
|
||||
}
|
||||
|
||||
static void merge_events(struct divecomputer *res, struct divecomputer *src1, struct divecomputer *src2, int offset)
|
||||
static void event_renumber(struct event *ev, const int mapping[]);
|
||||
static void add_initial_gaschange(struct dive *dive, struct divecomputer *dc, int offset, int idx);
|
||||
|
||||
static void merge_events(struct dive *d, struct divecomputer *res,
|
||||
const struct divecomputer *src1, const struct divecomputer *src2,
|
||||
const int *cylinders_map1, const int *cylinders_map2,
|
||||
int offset)
|
||||
{
|
||||
struct event *a, *b;
|
||||
const struct event *a, *b;
|
||||
struct event **p = &res->events;
|
||||
struct event *last_gas = NULL;
|
||||
const struct event *last_gas = NULL;
|
||||
|
||||
/* Always use positive offsets */
|
||||
if (offset < 0) {
|
||||
struct divecomputer *tmp;
|
||||
const struct divecomputer *tmp;
|
||||
const int *cylinders_map_tmp;
|
||||
|
||||
offset = -offset;
|
||||
tmp = src1;
|
||||
src1 = src2;
|
||||
src2 = tmp;
|
||||
|
||||
cylinders_map_tmp = cylinders_map1;
|
||||
cylinders_map1 = cylinders_map2;
|
||||
cylinders_map2 = cylinders_map_tmp;
|
||||
}
|
||||
|
||||
a = src1->events;
|
||||
b = src2->events;
|
||||
while (b) {
|
||||
b->time.seconds += offset;
|
||||
b = b->next;
|
||||
}
|
||||
b = src2->events;
|
||||
|
||||
while (a || b) {
|
||||
int s;
|
||||
struct event *pick;
|
||||
const struct event *pick;
|
||||
const int *cylinders_map;
|
||||
int event_offset;
|
||||
|
||||
if (!b) {
|
||||
*p = a;
|
||||
*p = clone_event(a);
|
||||
event_renumber(*p, cylinders_map1);
|
||||
break;
|
||||
}
|
||||
if (!a) {
|
||||
*p = b;
|
||||
*p = clone_event(b);
|
||||
(*p)->time.seconds += offset;
|
||||
event_renumber(*p, cylinders_map2);
|
||||
break;
|
||||
}
|
||||
s = sort_event(a, b);
|
||||
s = sort_event(a, b, a->time.seconds, b->time.seconds + offset);
|
||||
|
||||
/* Identical events? Just skip one of them (we pick a) */
|
||||
if (!s) {
|
||||
|
@ -2050,9 +2094,13 @@ static void merge_events(struct divecomputer *res, struct divecomputer *src1, st
|
|||
if (s < 0) {
|
||||
pick = a;
|
||||
a = a->next;
|
||||
event_offset = 0;
|
||||
cylinders_map = cylinders_map1;
|
||||
} else {
|
||||
pick = b;
|
||||
b = b->next;
|
||||
event_offset = offset;
|
||||
cylinders_map = cylinders_map2;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2066,9 +2114,17 @@ static void merge_events(struct divecomputer *res, struct divecomputer *src1, st
|
|||
}
|
||||
|
||||
/* Add it to the target list */
|
||||
*p = pick;
|
||||
p = &pick->next;
|
||||
*p = clone_event(pick);
|
||||
(*p)->time.seconds += event_offset;
|
||||
event_renumber(*p, cylinders_map);
|
||||
p = &(*p)->next;
|
||||
}
|
||||
|
||||
/* If the initial cylinder of a divecomputer was remapped, add a gas change event to that cylinder */
|
||||
if (cylinders_map1[0] > 0)
|
||||
add_initial_gaschange(d, res, 0, cylinders_map1[0]);
|
||||
if (cylinders_map2[0] > 0)
|
||||
add_initial_gaschange(d, res, offset, cylinders_map2[0]);
|
||||
}
|
||||
|
||||
static void merge_weightsystem_info(weightsystem_t *res, const weightsystem_t *a, const weightsystem_t *b)
|
||||
|
@ -2151,58 +2207,81 @@ extern void fill_pressures(struct gas_pressures *pressures, const double amb_pre
|
|||
}
|
||||
|
||||
/* Force an initial gaschange event to the (old) gas #0 */
|
||||
static void add_initial_gaschange(struct dive *dive, struct divecomputer *dc)
|
||||
static void add_initial_gaschange(struct dive *dive, struct divecomputer *dc, int offset, int idx)
|
||||
{
|
||||
const struct event *ev = get_next_event(dc->events, "gaschange");
|
||||
|
||||
if (ev && ev->time.seconds < 30)
|
||||
return;
|
||||
/* if there is a gaschange event up to 30 sec after the initial event,
|
||||
* refrain from adding the initial event */
|
||||
const struct event *ev = dc->events;
|
||||
while(ev && (ev = get_next_event(ev, "gaschange")) != NULL) {
|
||||
if (ev->time.seconds > offset + 30)
|
||||
break;
|
||||
else if (ev->time.seconds > offset)
|
||||
return;
|
||||
ev = ev->next;
|
||||
}
|
||||
|
||||
/* Old starting gas mix */
|
||||
add_gas_switch_event(dive, dc, 0, 0);
|
||||
add_gas_switch_event(dive, dc, offset, idx);
|
||||
}
|
||||
|
||||
static void dc_cylinder_renumber(struct dive *dive, struct divecomputer *dc, int mapping[])
|
||||
static void sample_renumber(struct sample *s, int i, const int mapping[])
|
||||
{
|
||||
int j;
|
||||
|
||||
for (j = 0; j < MAX_SENSORS; j++) {
|
||||
int sensor;
|
||||
|
||||
sensor = mapping[s->sensor[j]];
|
||||
if (sensor == -1) {
|
||||
// Remove sensor and gas pressure info
|
||||
if (i == 0) {
|
||||
s->sensor[j] = 0;
|
||||
s->pressure[j].mbar = 0;
|
||||
} else {
|
||||
s->sensor[j] = s[-1].sensor[j];
|
||||
s->pressure[j].mbar = s[-1].pressure[j].mbar;
|
||||
}
|
||||
} else {
|
||||
s->sensor[j] = sensor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void renumber_last_sample(struct divecomputer *dc, const int mapping[])
|
||||
{
|
||||
int idx;
|
||||
|
||||
if (dc->samples <= 0)
|
||||
return;
|
||||
idx = dc->samples - 1;
|
||||
sample_renumber(dc->sample + idx, idx, mapping);
|
||||
}
|
||||
|
||||
static void event_renumber(struct event *ev, const int mapping[])
|
||||
{
|
||||
if (!event_is_gaschange(ev))
|
||||
return;
|
||||
if (ev->gas.index < 0)
|
||||
return;
|
||||
ev->gas.index = mapping[ev->gas.index];
|
||||
}
|
||||
|
||||
static void dc_cylinder_renumber(struct dive *dive, struct divecomputer *dc, const int mapping[])
|
||||
{
|
||||
int i;
|
||||
struct event *ev;
|
||||
|
||||
/* Did the first gas get remapped? Add gas switch event */
|
||||
if (mapping[0] > 0)
|
||||
add_initial_gaschange(dive, dc);
|
||||
|
||||
/* Remap or delete the sensor indexes */
|
||||
for (i = 0; i < dc->samples; i++) {
|
||||
struct sample *s = dc->sample + i;
|
||||
int j;
|
||||
|
||||
for (j = 0; j < MAX_SENSORS; j++) {
|
||||
int sensor;
|
||||
|
||||
sensor = mapping[s->sensor[j]];
|
||||
if (sensor == -1) {
|
||||
// Remove sensor and gas pressure info
|
||||
if (i == 0) {
|
||||
s->sensor[j] = 0;
|
||||
s->pressure[j].mbar = 0;
|
||||
} else {
|
||||
s->sensor[j] = s[-1].sensor[j];
|
||||
s->pressure[j].mbar = s[-1].pressure[j].mbar;
|
||||
}
|
||||
} else {
|
||||
s->sensor[j] = sensor;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < dc->samples; i++)
|
||||
sample_renumber(dc->sample + i, i, mapping);
|
||||
|
||||
/* Remap the gas change indexes */
|
||||
for (ev = dc->events; ev; ev = ev->next) {
|
||||
if (!event_is_gaschange(ev))
|
||||
continue;
|
||||
if (ev->gas.index < 0)
|
||||
continue;
|
||||
ev->gas.index = mapping[ev->gas.index];
|
||||
}
|
||||
for (ev = dc->events; ev; ev = ev->next)
|
||||
event_renumber(ev, mapping);
|
||||
|
||||
/* If the initial cylinder of a dive was remapped, add a gas change event to that cylinder */
|
||||
if (mapping[0] > 0)
|
||||
add_initial_gaschange(dive, dc, 0, mapping[0]);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2307,28 +2386,61 @@ static int find_unused_cylinder(unsigned int used_map)
|
|||
return -1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy a single cylinder
|
||||
*/
|
||||
static void copy_cylinder(const cylinder_t *s, cylinder_t *d)
|
||||
{
|
||||
d->type.size.mliter = s->type.size.mliter;
|
||||
d->type.workingpressure.mbar = s->type.workingpressure.mbar;
|
||||
d->type.description = copy_string(s->type.description);
|
||||
d->gasmix = s->gasmix;
|
||||
d->start.mbar = s->start.mbar;
|
||||
d->end.mbar = s->end.mbar;
|
||||
d->sample_start.mbar = s->sample_start.mbar;
|
||||
d->sample_end.mbar = s->sample_end.mbar;
|
||||
d->depth = s->depth;
|
||||
d->manually_added = s->manually_added;
|
||||
d->gas_used.mliter = s->gas_used.mliter;
|
||||
d->deco_gas_used.mliter = s->deco_gas_used.mliter;
|
||||
d->bestmix_o2 = s->bestmix_o2;
|
||||
d->bestmix_he = s->bestmix_he;
|
||||
}
|
||||
|
||||
/*
|
||||
* We matched things up so that they have the same gasmix and
|
||||
* use, but we might want to fill in any missing cylinder details
|
||||
* in 'a' if we had it from 'b'.
|
||||
*/
|
||||
static void merge_one_cylinder(cylinder_t *a, cylinder_t *b)
|
||||
static void merge_one_cylinder(cylinder_t *res, const cylinder_t *a, const cylinder_t *b)
|
||||
{
|
||||
if (!a->type.size.mliter)
|
||||
a->type.size.mliter = b->type.size.mliter;
|
||||
if (!a->type.workingpressure.mbar)
|
||||
a->type.workingpressure.mbar = b->type.workingpressure.mbar;
|
||||
if (!a->type.description && b->type.description)
|
||||
a->type.description = strdup(b->type.description);
|
||||
if (!a->start.mbar)
|
||||
a->start.mbar = b->start.mbar;
|
||||
if (!a->end.mbar)
|
||||
a->end.mbar = b->end.mbar;
|
||||
res->type.size.mliter = a->type.size.mliter ?
|
||||
a->type.size.mliter : b->type.size.mliter;
|
||||
res->type.workingpressure.mbar = a->type.workingpressure.mbar ?
|
||||
a->type.workingpressure.mbar : b->type.workingpressure.mbar;
|
||||
res->type.description = !empty_string(a->type.description) ?
|
||||
copy_string(a->type.description) : copy_string(b->type.description);
|
||||
res->gasmix = a->gasmix;
|
||||
res->start.mbar = a->start.mbar ?
|
||||
a->start.mbar : b->start.mbar;
|
||||
res->end.mbar = a->end.mbar ?
|
||||
a->end.mbar : b->end.mbar;
|
||||
|
||||
if (a->sample_start.mbar && b->sample_start.mbar)
|
||||
a->sample_start.mbar = a->sample_start.mbar > b->sample_start.mbar ? a->sample_start.mbar : b->sample_start.mbar;
|
||||
res->sample_start.mbar = a->sample_start.mbar > b->sample_start.mbar ? a->sample_start.mbar : b->sample_start.mbar;
|
||||
else
|
||||
res->sample_start.mbar = 0;
|
||||
if (a->sample_end.mbar && b->sample_end.mbar)
|
||||
a->sample_end.mbar = a->sample_end.mbar < b->sample_end.mbar ? a->sample_end.mbar : b->sample_end.mbar;
|
||||
res->sample_end.mbar = a->sample_end.mbar < b->sample_end.mbar ? a->sample_end.mbar : b->sample_end.mbar;
|
||||
else
|
||||
res->sample_end.mbar = 0;
|
||||
|
||||
res->depth = a->depth;
|
||||
res->manually_added = a->manually_added;
|
||||
res->gas_used.mliter = a->gas_used.mliter + b->gas_used.mliter;
|
||||
res->deco_gas_used.mliter = a->deco_gas_used.mliter + b->deco_gas_used.mliter;
|
||||
res->bestmix_o2 = a->bestmix_o2 && b->bestmix_o2;
|
||||
res->bestmix_he = a->bestmix_he && b->bestmix_he;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2338,13 +2450,19 @@ static void merge_one_cylinder(cylinder_t *a, cylinder_t *b)
|
|||
* Logic: take all the cylinder information from the preferred dive ('a'), and
|
||||
* then try to match each of the cylinders in the other dive by the gasmix that
|
||||
* is the best match and hasn't been used yet.
|
||||
*
|
||||
* For each dive, a cylinder-renumbering table is returned. Currently, only
|
||||
* cylinders of dive 'b' are renumbered.
|
||||
*/
|
||||
static void merge_cylinders(struct dive *res, struct dive *a, struct dive *b)
|
||||
static void merge_cylinders(struct dive *res, const struct dive *a, const struct dive *b,
|
||||
int mapping_a[], int mapping_b[])
|
||||
{
|
||||
int i, renumber = 0;
|
||||
int mapping[MAX_CYLINDERS];
|
||||
int i;
|
||||
unsigned int used_in_a = 0, used_in_b = 0, matched = 0;
|
||||
|
||||
/* First, clear all cylinders in destination */
|
||||
memset(res->cylinder, 0, sizeof(res->cylinder));
|
||||
|
||||
/* Calculate usage map of cylinders */
|
||||
for (i = 0; i < MAX_CYLINDERS; i++) {
|
||||
if (!cylinder_none(a->cylinder+i) || is_cylinder_used(a, i))
|
||||
|
@ -2357,7 +2475,8 @@ static void merge_cylinders(struct dive *res, struct dive *a, struct dive *b)
|
|||
for (i = 0; i < MAX_CYLINDERS; i++) {
|
||||
int j;
|
||||
|
||||
mapping[i] = -1;
|
||||
mapping_a[i] = i;
|
||||
mapping_b[i] = -1;
|
||||
if (!(used_in_b & (1u << i)))
|
||||
continue;
|
||||
|
||||
|
@ -2377,11 +2496,15 @@ static void merge_cylinders(struct dive *res, struct dive *a, struct dive *b)
|
|||
*
|
||||
* - mark 'b' as needing renumbering if the index changed
|
||||
*/
|
||||
merge_one_cylinder(a->cylinder + j, b->cylinder + i);
|
||||
mapping[i] = j;
|
||||
merge_one_cylinder(res->cylinder + j, a->cylinder + j, b->cylinder + i);
|
||||
mapping_b[i] = j;
|
||||
matched |= 1u << j;
|
||||
if (j != i)
|
||||
renumber = 1;
|
||||
}
|
||||
|
||||
/* Now copy all the used cylinders from 'a' which are used, but have not been matched */
|
||||
for (i = 0; i < MAX_CYLINDERS; i++) {
|
||||
if (used_in_a & (1u << i) && !(matched & (1u << i)))
|
||||
copy_cylinder(a->cylinder + i, res->cylinder + i);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -2390,10 +2513,6 @@ static void merge_cylinders(struct dive *res, struct dive *a, struct dive *b)
|
|||
*/
|
||||
used_in_a |= matched;
|
||||
|
||||
/* Now copy all the cylinder info raw from 'a' (whether used/matched or not) */
|
||||
memcpy(res->cylinder, a->cylinder, sizeof(res->cylinder));
|
||||
memset(a->cylinder, 0, sizeof(a->cylinder));
|
||||
|
||||
/*
|
||||
* Go back to 'b' and remap any remaining cylinders that didn't
|
||||
* match completely.
|
||||
|
@ -2402,7 +2521,7 @@ static void merge_cylinders(struct dive *res, struct dive *a, struct dive *b)
|
|||
int j;
|
||||
|
||||
/* Already remapped, or not interesting? */
|
||||
if (mapping[i] >= 0)
|
||||
if (mapping_b[i] >= 0)
|
||||
continue;
|
||||
if (!(used_in_b & (1u << i)))
|
||||
continue;
|
||||
|
@ -2411,32 +2530,24 @@ static void merge_cylinders(struct dive *res, struct dive *a, struct dive *b)
|
|||
if (j < 0)
|
||||
continue;
|
||||
|
||||
res->cylinder[j] = b->cylinder[i];
|
||||
memset(b->cylinder+i, 0, sizeof(cylinder_t));
|
||||
mapping[i] = j;
|
||||
copy_cylinder(b->cylinder + i, res->cylinder + j);
|
||||
mapping_b[i] = j;
|
||||
used_in_a |= 1u << j;
|
||||
if (i != j)
|
||||
renumber = 1;
|
||||
}
|
||||
|
||||
if (renumber)
|
||||
cylinder_renumber(b, mapping);
|
||||
}
|
||||
|
||||
static void merge_equipment(struct dive *res, struct dive *a, struct dive *b)
|
||||
static void merge_equipment(struct dive *res, const struct dive *a, const struct dive *b)
|
||||
{
|
||||
int i;
|
||||
|
||||
merge_cylinders(res, a, b);
|
||||
for (i = 0; i < MAX_WEIGHTSYSTEMS; i++)
|
||||
merge_weightsystem_info(res->weightsystem + i, a->weightsystem + i, b->weightsystem + i);
|
||||
}
|
||||
|
||||
static void merge_temperatures(struct dive *res, struct dive *a, struct dive *b)
|
||||
static void merge_temperatures(struct dive *res, const struct dive *a, const struct dive *b)
|
||||
{
|
||||
un_fixup_airtemp(a);
|
||||
un_fixup_airtemp(b);
|
||||
MERGE_NONZERO(res, a, b, airtemp.mkelvin);
|
||||
temperature_t airtemp_a = un_fixup_airtemp(a);
|
||||
temperature_t airtemp_b = un_fixup_airtemp(b);
|
||||
res->airtemp = airtemp_a.mkelvin ? airtemp_a : airtemp_b;
|
||||
MERGE_NONZERO(res, a, b, watertemp.mkelvin);
|
||||
}
|
||||
|
||||
|
@ -2459,7 +2570,7 @@ static void pick_trip(struct dive *res, const struct dive *pick)
|
|||
/*
|
||||
* Pick a trip for a dive
|
||||
*/
|
||||
static struct dive *get_preferred_trip(struct dive *a, struct dive *b)
|
||||
static const struct dive *get_preferred_trip(const struct dive *a, const struct dive *b)
|
||||
{
|
||||
dive_trip_t *atrip, *btrip;
|
||||
|
||||
|
@ -2953,14 +3064,9 @@ static void remove_redundant_dc(struct divecomputer *dc, int prefer_downloaded)
|
|||
} while (dc);
|
||||
}
|
||||
|
||||
static void clear_dc(struct divecomputer *dc)
|
||||
static const struct divecomputer *find_matching_computer(const struct divecomputer *match, const struct divecomputer *list)
|
||||
{
|
||||
memset(dc, 0, sizeof(*dc));
|
||||
}
|
||||
|
||||
static struct divecomputer *find_matching_computer(struct divecomputer *match, struct divecomputer *list)
|
||||
{
|
||||
struct divecomputer *p;
|
||||
const struct divecomputer *p;
|
||||
|
||||
while ((p = list) != NULL) {
|
||||
list = list->next;
|
||||
|
@ -2990,28 +3096,25 @@ static void copy_dive_computer(struct divecomputer *res, const struct divecomput
|
|||
* to match them up. If we find a matching dive computer, we
|
||||
* merge them. If not, we just take the data from 'a'.
|
||||
*/
|
||||
static void interleave_dive_computers(struct divecomputer *res,
|
||||
struct divecomputer *a, struct divecomputer *b, int offset)
|
||||
static void interleave_dive_computers(struct dive *d, struct divecomputer *res,
|
||||
const struct divecomputer *a, const struct divecomputer *b,
|
||||
const int cylinders_map_a[], const int cylinders_map_b[],
|
||||
int offset)
|
||||
{
|
||||
do {
|
||||
struct divecomputer *match;
|
||||
const struct divecomputer *match;
|
||||
|
||||
copy_dive_computer(res, a);
|
||||
|
||||
match = find_matching_computer(a, b);
|
||||
if (match) {
|
||||
merge_events(res, a, match, offset);
|
||||
merge_samples(res, a, match, offset);
|
||||
merge_events(d, res, a, match, cylinders_map_a, cylinders_map_b, offset);
|
||||
merge_samples(res, a, match, cylinders_map_a, cylinders_map_b, offset);
|
||||
/* Use the diveid of the later dive! */
|
||||
if (offset > 0)
|
||||
res->diveid = match->diveid;
|
||||
} else {
|
||||
res->sample = a->sample;
|
||||
res->samples = a->samples;
|
||||
res->events = a->events;
|
||||
a->sample = NULL;
|
||||
a->samples = 0;
|
||||
a->events = NULL;
|
||||
copy_dc_renumber(d, a, res, cylinders_map_a);
|
||||
}
|
||||
a = a->next;
|
||||
if (!a)
|
||||
|
@ -3035,30 +3138,29 @@ static void interleave_dive_computers(struct divecomputer *res,
|
|||
* try to throw out old information that *might* be from
|
||||
* that one.
|
||||
*/
|
||||
static void join_dive_computers(struct divecomputer *res, struct divecomputer *a, struct divecomputer *b, int prefer_downloaded)
|
||||
static void join_dive_computers(struct dive *d, struct divecomputer *res,
|
||||
const struct divecomputer *a, const struct divecomputer *b,
|
||||
const int cylinders_map_a[], const int cylinders_map_b[],
|
||||
int prefer_downloaded)
|
||||
{
|
||||
struct divecomputer *tmp;
|
||||
|
||||
if (a->model && !b->model) {
|
||||
*res = *a;
|
||||
clear_dc(a);
|
||||
copy_dc_renumber(d, a, res, cylinders_map_a);
|
||||
return;
|
||||
}
|
||||
if (b->model && !a->model) {
|
||||
*res = *b;
|
||||
clear_dc(b);
|
||||
copy_dc_renumber(d, b, res, cylinders_map_b);
|
||||
return;
|
||||
}
|
||||
|
||||
*res = *a;
|
||||
clear_dc(a);
|
||||
copy_dc_renumber(d, a, res, cylinders_map_a);
|
||||
tmp = res;
|
||||
while (tmp->next)
|
||||
tmp = tmp->next;
|
||||
|
||||
tmp->next = calloc(1, sizeof(*tmp));
|
||||
*tmp->next = *b;
|
||||
clear_dc(b);
|
||||
copy_dc_renumber(d, b, tmp->next, cylinders_map_b);
|
||||
|
||||
remove_redundant_dc(res, prefer_downloaded);
|
||||
}
|
||||
|
@ -3335,10 +3437,12 @@ int count_dives_with_suit(const char *suit)
|
|||
* in the "trip" output paramater. If "trip" is NULL, then the dive will
|
||||
* instead be added to this trip.
|
||||
*/
|
||||
struct dive *merge_dives(struct dive *a, struct dive *b, int offset, bool prefer_downloaded, struct dive_trip **trip)
|
||||
struct dive *merge_dives(const struct dive *a, const struct dive *b, int offset, bool prefer_downloaded, struct dive_trip **trip)
|
||||
{
|
||||
struct dive *res = alloc_dive();
|
||||
struct dive *preferred_trip;
|
||||
const struct dive *dl = NULL;
|
||||
const struct dive *preferred_trip;
|
||||
int cylinders_map_a[MAX_CYLINDERS], cylinders_map_b[MAX_CYLINDERS];
|
||||
|
||||
if (offset) {
|
||||
/*
|
||||
|
@ -3352,7 +3456,7 @@ struct dive *merge_dives(struct dive *a, struct dive *b, int offset, bool prefer
|
|||
}
|
||||
|
||||
if (same_string(a->dc.model, "planned dive")) {
|
||||
struct dive *tmp = a;
|
||||
const struct dive *tmp = a;
|
||||
a = b;
|
||||
b = tmp;
|
||||
}
|
||||
|
@ -3373,15 +3477,17 @@ struct dive *merge_dives(struct dive *a, struct dive *b, int offset, bool prefer
|
|||
MERGE_NONZERO(res, a, b, visibility);
|
||||
MERGE_NONZERO(res, a, b, picture_list);
|
||||
taglist_merge(&res->tag_list, a->tag_list, b->tag_list);
|
||||
merge_cylinders(res, a, b, cylinders_map_a, cylinders_map_b);
|
||||
merge_equipment(res, a, b);
|
||||
merge_temperatures(res, a, b);
|
||||
if (prefer_downloaded) {
|
||||
/* If we prefer downloaded, do those first, and get rid of "might be same" computers */
|
||||
join_dive_computers(&res->dc, &b->dc, &a->dc, 1);
|
||||
join_dive_computers(res, &res->dc, &dl->dc, &a->dc, cylinders_map_b, cylinders_map_a, 1);
|
||||
} else if (offset && might_be_same_device(&a->dc, &b->dc))
|
||||
interleave_dive_computers(&res->dc, &a->dc, &b->dc, offset);
|
||||
interleave_dive_computers(res, &res->dc, &a->dc, &b->dc, cylinders_map_a, cylinders_map_b, offset);
|
||||
else
|
||||
join_dive_computers(&res->dc, &a->dc, &b->dc, 0);
|
||||
join_dive_computers(res, &res->dc, &a->dc, &b->dc, cylinders_map_a, cylinders_map_b, 0);
|
||||
|
||||
/* we take the first dive site, unless it's empty */
|
||||
if (a->dive_site_uuid && !dive_site_is_empty(get_dive_site_by_uuid(a->dive_site_uuid)))
|
||||
res->dive_site_uuid = a->dive_site_uuid;
|
||||
|
|
|
@ -573,7 +573,7 @@ extern int split_dive_dont_insert(const struct dive *dive, struct dive **new1, s
|
|||
extern void split_dive(struct dive *);
|
||||
extern int split_dive_at_time_dont_insert(const struct dive *dive, duration_t time, struct dive **new1, struct dive **new2);
|
||||
extern void split_dive_at_time(struct dive *dive, duration_t time);
|
||||
extern struct dive *merge_dives(struct dive *a, struct dive *b, int offset, bool prefer_downloaded, struct dive_trip **trip);
|
||||
extern struct dive *merge_dives(const struct dive *a, const struct dive *b, int offset, bool prefer_downloaded, struct dive_trip **trip);
|
||||
extern struct dive *try_to_merge(struct dive *a, struct dive *b, bool prefer_downloaded);
|
||||
extern struct event *clone_event(const struct event *src_ev);
|
||||
extern void copy_events(const struct divecomputer *s, struct divecomputer *d);
|
||||
|
|
Loading…
Reference in a new issue