mirror of
https://github.com/subsurface/subsurface.git
synced 2025-02-19 22:16:15 +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);
|
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 */
|
/* copy an element in a list of pictures */
|
||||||
static void copy_pl(struct picture *sp, struct picture *dp)
|
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);
|
dive->airtemp.mkelvin = dc_airtemp(&dive->dc);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* zero out the airtemp in the dive structure if it was just created by
|
/* if the air temperature in the dive data is redundant to the one in its
|
||||||
* running fixup on the dive. keep it if it had been edited by hand */
|
* first divecomputer (i.e., it was added by running fixup on the dive)
|
||||||
static void un_fixup_airtemp(struct dive *a)
|
* 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))
|
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
|
* 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".
|
* 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;
|
int last = dc->samples - 1;
|
||||||
if (last >= 0) {
|
if (last >= 0) {
|
||||||
|
@ -1863,11 +1878,16 @@ static void merge_one_sample(struct sample *sample, int time, struct divecompute
|
||||||
add_sample(sample, time, dc);
|
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'
|
* 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 asamples = a->samples;
|
||||||
int bsamples = b->samples;
|
int bsamples = b->samples;
|
||||||
|
@ -1882,14 +1902,19 @@ static void merge_samples(struct divecomputer *res, struct divecomputer *a, stru
|
||||||
* the reverse offset.
|
* the reverse offset.
|
||||||
*/
|
*/
|
||||||
if (offset < 0) {
|
if (offset < 0) {
|
||||||
|
const int *cylinders_map_tmp;
|
||||||
offset = -offset;
|
offset = -offset;
|
||||||
asamples = bsamples;
|
asamples = bsamples;
|
||||||
bsamples = a->samples;
|
bsamples = a->samples;
|
||||||
as = bs;
|
as = bs;
|
||||||
bs = a->sample;
|
bs = a->sample;
|
||||||
|
cylinders_map_tmp = cylinders_map_a;
|
||||||
|
cylinders_map_a = cylinders_map_b;
|
||||||
|
cylinders_map_b = cylinders_map_tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
int j;
|
||||||
int at, bt;
|
int at, bt;
|
||||||
struct sample sample = { .bearing.degrees = -1, .ndl.seconds = -1 };
|
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) {
|
if (bt < 0) {
|
||||||
add_sample_a:
|
add_sample_a:
|
||||||
merge_one_sample(as, at, res);
|
merge_one_sample(as, at, res);
|
||||||
|
renumber_last_sample(res, cylinders_map_a);
|
||||||
as++;
|
as++;
|
||||||
asamples--;
|
asamples--;
|
||||||
continue;
|
continue;
|
||||||
|
@ -1916,6 +1942,7 @@ static void merge_samples(struct divecomputer *res, struct divecomputer *a, stru
|
||||||
if (at < 0) {
|
if (at < 0) {
|
||||||
add_sample_b:
|
add_sample_b:
|
||||||
merge_one_sample(bs, bt, res);
|
merge_one_sample(bs, bt, res);
|
||||||
|
renumber_last_sample(res, cylinders_map_b);
|
||||||
bs++;
|
bs++;
|
||||||
bsamples--;
|
bsamples--;
|
||||||
continue;
|
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 */
|
/* same-time sample: add a merged sample. Take the non-zero ones */
|
||||||
sample = *bs;
|
sample = *bs;
|
||||||
|
sample_renumber(&sample, 0, cylinders_map_b);
|
||||||
if (as->depth.mm)
|
if (as->depth.mm)
|
||||||
sample.depth = as->depth;
|
sample.depth = as->depth;
|
||||||
if (as->temperature.mkelvin)
|
if (as->temperature.mkelvin)
|
||||||
sample.temperature = as->temperature;
|
sample.temperature = as->temperature;
|
||||||
if (as->pressure[0].mbar)
|
for (j = 0; j < MAX_SENSORS; ++j) {
|
||||||
sample.pressure[0] = as->pressure[0];
|
int sensor_id;
|
||||||
if (as->sensor[0])
|
|
||||||
sample.sensor[0] = as->sensor[0];
|
sensor_id = cylinders_map_a[as->sensor[j]];
|
||||||
if (as->pressure[1].mbar)
|
if (sensor_id < 0)
|
||||||
sample.pressure[1] = as->pressure[1];
|
continue;
|
||||||
if (as->sensor[1])
|
|
||||||
sample.sensor[1] = as->sensor[1];
|
if (as->pressure[j].mbar)
|
||||||
|
sample.pressure[j] = as->pressure[j];
|
||||||
|
if (as->sensor[j])
|
||||||
|
sample.sensor[j] = sensor_id;
|
||||||
|
}
|
||||||
if (as->cns)
|
if (as->cns)
|
||||||
sample.cns = as->cns;
|
sample.cns = as->cns;
|
||||||
if (as->setpoint.mbar)
|
if (as->setpoint.mbar)
|
||||||
|
@ -1980,16 +2012,17 @@ static char *merge_text(const char *a, const char *b, const char *sep)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SORT(a, b, field) \
|
#define SORT(a, b) \
|
||||||
if (a->field != b->field) \
|
if (a != b) \
|
||||||
return a->field < b->field ? -1 : 1
|
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(time_a, time_b);
|
||||||
SORT(a, b, type);
|
SORT_FIELD(a, b, type);
|
||||||
SORT(a, b, flags);
|
SORT_FIELD(a, b, flags);
|
||||||
SORT(a, b, value);
|
SORT_FIELD(a, b, value);
|
||||||
return strcmp(a->name, b->name);
|
return strcmp(a->name, b->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2002,43 +2035,54 @@ static int same_gas(const struct event *a, const struct event *b)
|
||||||
return false;
|
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 **p = &res->events;
|
||||||
struct event *last_gas = NULL;
|
const struct event *last_gas = NULL;
|
||||||
|
|
||||||
/* Always use positive offsets */
|
/* Always use positive offsets */
|
||||||
if (offset < 0) {
|
if (offset < 0) {
|
||||||
struct divecomputer *tmp;
|
const struct divecomputer *tmp;
|
||||||
|
const int *cylinders_map_tmp;
|
||||||
|
|
||||||
offset = -offset;
|
offset = -offset;
|
||||||
tmp = src1;
|
tmp = src1;
|
||||||
src1 = src2;
|
src1 = src2;
|
||||||
src2 = tmp;
|
src2 = tmp;
|
||||||
|
|
||||||
|
cylinders_map_tmp = cylinders_map1;
|
||||||
|
cylinders_map1 = cylinders_map2;
|
||||||
|
cylinders_map2 = cylinders_map_tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
a = src1->events;
|
a = src1->events;
|
||||||
b = src2->events;
|
b = src2->events;
|
||||||
while (b) {
|
|
||||||
b->time.seconds += offset;
|
|
||||||
b = b->next;
|
|
||||||
}
|
|
||||||
b = src2->events;
|
|
||||||
|
|
||||||
while (a || b) {
|
while (a || b) {
|
||||||
int s;
|
int s;
|
||||||
struct event *pick;
|
const struct event *pick;
|
||||||
|
const int *cylinders_map;
|
||||||
|
int event_offset;
|
||||||
|
|
||||||
if (!b) {
|
if (!b) {
|
||||||
*p = a;
|
*p = clone_event(a);
|
||||||
|
event_renumber(*p, cylinders_map1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!a) {
|
if (!a) {
|
||||||
*p = b;
|
*p = clone_event(b);
|
||||||
|
(*p)->time.seconds += offset;
|
||||||
|
event_renumber(*p, cylinders_map2);
|
||||||
break;
|
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) */
|
/* Identical events? Just skip one of them (we pick a) */
|
||||||
if (!s) {
|
if (!s) {
|
||||||
|
@ -2050,9 +2094,13 @@ static void merge_events(struct divecomputer *res, struct divecomputer *src1, st
|
||||||
if (s < 0) {
|
if (s < 0) {
|
||||||
pick = a;
|
pick = a;
|
||||||
a = a->next;
|
a = a->next;
|
||||||
|
event_offset = 0;
|
||||||
|
cylinders_map = cylinders_map1;
|
||||||
} else {
|
} else {
|
||||||
pick = b;
|
pick = b;
|
||||||
b = b->next;
|
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 */
|
/* Add it to the target list */
|
||||||
*p = pick;
|
*p = clone_event(pick);
|
||||||
p = &pick->next;
|
(*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)
|
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 */
|
/* 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 there is a gaschange event up to 30 sec after the initial event,
|
||||||
|
* refrain from adding the initial event */
|
||||||
if (ev && ev->time.seconds < 30)
|
const struct event *ev = dc->events;
|
||||||
return;
|
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 */
|
/* 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;
|
int i;
|
||||||
struct event *ev;
|
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 */
|
/* Remap or delete the sensor indexes */
|
||||||
for (i = 0; i < dc->samples; i++) {
|
for (i = 0; i < dc->samples; i++)
|
||||||
struct sample *s = dc->sample + i;
|
sample_renumber(dc->sample + i, i, 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Remap the gas change indexes */
|
/* Remap the gas change indexes */
|
||||||
for (ev = dc->events; ev; ev = ev->next) {
|
for (ev = dc->events; ev; ev = ev->next)
|
||||||
if (!event_is_gaschange(ev))
|
event_renumber(ev, mapping);
|
||||||
continue;
|
|
||||||
if (ev->gas.index < 0)
|
/* If the initial cylinder of a dive was remapped, add a gas change event to that cylinder */
|
||||||
continue;
|
if (mapping[0] > 0)
|
||||||
ev->gas.index = mapping[ev->gas.index];
|
add_initial_gaschange(dive, dc, 0, mapping[0]);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -2307,28 +2386,61 @@ static int find_unused_cylinder(unsigned int used_map)
|
||||||
return -1;
|
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
|
* We matched things up so that they have the same gasmix and
|
||||||
* use, but we might want to fill in any missing cylinder details
|
* use, but we might want to fill in any missing cylinder details
|
||||||
* in 'a' if we had it from 'b'.
|
* 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)
|
res->type.size.mliter = a->type.size.mliter ?
|
||||||
a->type.size.mliter = b->type.size.mliter;
|
a->type.size.mliter : b->type.size.mliter;
|
||||||
if (!a->type.workingpressure.mbar)
|
res->type.workingpressure.mbar = a->type.workingpressure.mbar ?
|
||||||
a->type.workingpressure.mbar = b->type.workingpressure.mbar;
|
a->type.workingpressure.mbar : b->type.workingpressure.mbar;
|
||||||
if (!a->type.description && b->type.description)
|
res->type.description = !empty_string(a->type.description) ?
|
||||||
a->type.description = strdup(b->type.description);
|
copy_string(a->type.description) : copy_string(b->type.description);
|
||||||
if (!a->start.mbar)
|
res->gasmix = a->gasmix;
|
||||||
a->start.mbar = b->start.mbar;
|
res->start.mbar = a->start.mbar ?
|
||||||
if (!a->end.mbar)
|
a->start.mbar : b->start.mbar;
|
||||||
a->end.mbar = b->end.mbar;
|
res->end.mbar = a->end.mbar ?
|
||||||
|
a->end.mbar : b->end.mbar;
|
||||||
|
|
||||||
if (a->sample_start.mbar && b->sample_start.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)
|
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
|
* 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
|
* 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.
|
* 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 i;
|
||||||
int mapping[MAX_CYLINDERS];
|
|
||||||
unsigned int used_in_a = 0, used_in_b = 0, matched = 0;
|
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 */
|
/* Calculate usage map of cylinders */
|
||||||
for (i = 0; i < MAX_CYLINDERS; i++) {
|
for (i = 0; i < MAX_CYLINDERS; i++) {
|
||||||
if (!cylinder_none(a->cylinder+i) || is_cylinder_used(a, 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++) {
|
for (i = 0; i < MAX_CYLINDERS; i++) {
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
mapping[i] = -1;
|
mapping_a[i] = i;
|
||||||
|
mapping_b[i] = -1;
|
||||||
if (!(used_in_b & (1u << i)))
|
if (!(used_in_b & (1u << i)))
|
||||||
continue;
|
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
|
* - mark 'b' as needing renumbering if the index changed
|
||||||
*/
|
*/
|
||||||
merge_one_cylinder(a->cylinder + j, b->cylinder + i);
|
merge_one_cylinder(res->cylinder + j, a->cylinder + j, b->cylinder + i);
|
||||||
mapping[i] = j;
|
mapping_b[i] = j;
|
||||||
matched |= 1u << 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;
|
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
|
* Go back to 'b' and remap any remaining cylinders that didn't
|
||||||
* match completely.
|
* match completely.
|
||||||
|
@ -2402,7 +2521,7 @@ static void merge_cylinders(struct dive *res, struct dive *a, struct dive *b)
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
/* Already remapped, or not interesting? */
|
/* Already remapped, or not interesting? */
|
||||||
if (mapping[i] >= 0)
|
if (mapping_b[i] >= 0)
|
||||||
continue;
|
continue;
|
||||||
if (!(used_in_b & (1u << i)))
|
if (!(used_in_b & (1u << i)))
|
||||||
continue;
|
continue;
|
||||||
|
@ -2411,32 +2530,24 @@ static void merge_cylinders(struct dive *res, struct dive *a, struct dive *b)
|
||||||
if (j < 0)
|
if (j < 0)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
res->cylinder[j] = b->cylinder[i];
|
copy_cylinder(b->cylinder + i, res->cylinder + j);
|
||||||
memset(b->cylinder+i, 0, sizeof(cylinder_t));
|
mapping_b[i] = j;
|
||||||
mapping[i] = j;
|
|
||||||
used_in_a |= 1u << 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;
|
int i;
|
||||||
|
|
||||||
merge_cylinders(res, a, b);
|
|
||||||
for (i = 0; i < MAX_WEIGHTSYSTEMS; i++)
|
for (i = 0; i < MAX_WEIGHTSYSTEMS; i++)
|
||||||
merge_weightsystem_info(res->weightsystem + i, a->weightsystem + i, b->weightsystem + 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);
|
temperature_t airtemp_a = un_fixup_airtemp(a);
|
||||||
un_fixup_airtemp(b);
|
temperature_t airtemp_b = un_fixup_airtemp(b);
|
||||||
MERGE_NONZERO(res, a, b, airtemp.mkelvin);
|
res->airtemp = airtemp_a.mkelvin ? airtemp_a : airtemp_b;
|
||||||
MERGE_NONZERO(res, a, b, watertemp.mkelvin);
|
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
|
* 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;
|
dive_trip_t *atrip, *btrip;
|
||||||
|
|
||||||
|
@ -2953,14 +3064,9 @@ static void remove_redundant_dc(struct divecomputer *dc, int prefer_downloaded)
|
||||||
} while (dc);
|
} 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));
|
const struct divecomputer *p;
|
||||||
}
|
|
||||||
|
|
||||||
static struct divecomputer *find_matching_computer(struct divecomputer *match, struct divecomputer *list)
|
|
||||||
{
|
|
||||||
struct divecomputer *p;
|
|
||||||
|
|
||||||
while ((p = list) != NULL) {
|
while ((p = list) != NULL) {
|
||||||
list = list->next;
|
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
|
* to match them up. If we find a matching dive computer, we
|
||||||
* merge them. If not, we just take the data from 'a'.
|
* merge them. If not, we just take the data from 'a'.
|
||||||
*/
|
*/
|
||||||
static void interleave_dive_computers(struct divecomputer *res,
|
static void interleave_dive_computers(struct dive *d, struct divecomputer *res,
|
||||||
struct divecomputer *a, struct divecomputer *b, int offset)
|
const struct divecomputer *a, const struct divecomputer *b,
|
||||||
|
const int cylinders_map_a[], const int cylinders_map_b[],
|
||||||
|
int offset)
|
||||||
{
|
{
|
||||||
do {
|
do {
|
||||||
struct divecomputer *match;
|
const struct divecomputer *match;
|
||||||
|
|
||||||
copy_dive_computer(res, a);
|
copy_dive_computer(res, a);
|
||||||
|
|
||||||
match = find_matching_computer(a, b);
|
match = find_matching_computer(a, b);
|
||||||
if (match) {
|
if (match) {
|
||||||
merge_events(res, a, match, offset);
|
merge_events(d, res, a, match, cylinders_map_a, cylinders_map_b, offset);
|
||||||
merge_samples(res, a, match, offset);
|
merge_samples(res, a, match, cylinders_map_a, cylinders_map_b, offset);
|
||||||
/* Use the diveid of the later dive! */
|
/* Use the diveid of the later dive! */
|
||||||
if (offset > 0)
|
if (offset > 0)
|
||||||
res->diveid = match->diveid;
|
res->diveid = match->diveid;
|
||||||
} else {
|
} else {
|
||||||
res->sample = a->sample;
|
copy_dc_renumber(d, a, res, cylinders_map_a);
|
||||||
res->samples = a->samples;
|
|
||||||
res->events = a->events;
|
|
||||||
a->sample = NULL;
|
|
||||||
a->samples = 0;
|
|
||||||
a->events = NULL;
|
|
||||||
}
|
}
|
||||||
a = a->next;
|
a = a->next;
|
||||||
if (!a)
|
if (!a)
|
||||||
|
@ -3035,30 +3138,29 @@ static void interleave_dive_computers(struct divecomputer *res,
|
||||||
* try to throw out old information that *might* be from
|
* try to throw out old information that *might* be from
|
||||||
* that one.
|
* 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;
|
struct divecomputer *tmp;
|
||||||
|
|
||||||
if (a->model && !b->model) {
|
if (a->model && !b->model) {
|
||||||
*res = *a;
|
copy_dc_renumber(d, a, res, cylinders_map_a);
|
||||||
clear_dc(a);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (b->model && !a->model) {
|
if (b->model && !a->model) {
|
||||||
*res = *b;
|
copy_dc_renumber(d, b, res, cylinders_map_b);
|
||||||
clear_dc(b);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
*res = *a;
|
copy_dc_renumber(d, a, res, cylinders_map_a);
|
||||||
clear_dc(a);
|
|
||||||
tmp = res;
|
tmp = res;
|
||||||
while (tmp->next)
|
while (tmp->next)
|
||||||
tmp = tmp->next;
|
tmp = tmp->next;
|
||||||
|
|
||||||
tmp->next = calloc(1, sizeof(*tmp));
|
tmp->next = calloc(1, sizeof(*tmp));
|
||||||
*tmp->next = *b;
|
copy_dc_renumber(d, b, tmp->next, cylinders_map_b);
|
||||||
clear_dc(b);
|
|
||||||
|
|
||||||
remove_redundant_dc(res, prefer_downloaded);
|
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
|
* in the "trip" output paramater. If "trip" is NULL, then the dive will
|
||||||
* instead be added to this trip.
|
* 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 *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) {
|
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")) {
|
if (same_string(a->dc.model, "planned dive")) {
|
||||||
struct dive *tmp = a;
|
const struct dive *tmp = a;
|
||||||
a = b;
|
a = b;
|
||||||
b = tmp;
|
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, visibility);
|
||||||
MERGE_NONZERO(res, a, b, picture_list);
|
MERGE_NONZERO(res, a, b, picture_list);
|
||||||
taglist_merge(&res->tag_list, a->tag_list, b->tag_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_equipment(res, a, b);
|
||||||
merge_temperatures(res, a, b);
|
merge_temperatures(res, a, b);
|
||||||
if (prefer_downloaded) {
|
if (prefer_downloaded) {
|
||||||
/* If we prefer downloaded, do those first, and get rid of "might be same" computers */
|
/* 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))
|
} 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
|
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 */
|
/* 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)))
|
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;
|
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 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 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 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 dive *try_to_merge(struct dive *a, struct dive *b, bool prefer_downloaded);
|
||||||
extern struct event *clone_event(const struct event *src_ev);
|
extern struct event *clone_event(const struct event *src_ev);
|
||||||
extern void copy_events(const struct divecomputer *s, struct divecomputer *d);
|
extern void copy_events(const struct divecomputer *s, struct divecomputer *d);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue