summaryrefslogtreecommitdiffstats
path: root/dive.c
diff options
context:
space:
mode:
authorGravatar Linus Torvalds <torvalds@linux-foundation.org>2015-10-01 21:17:37 -0400
committerGravatar Dirk Hohndel <dirk@hohndel.org>2015-10-01 22:29:43 -0400
commit7c427dcc020064e0ea867c77ee86db6e1f4755bb (patch)
treea27def977fcbad963d41e0e88dba42c4fb7cad34 /dive.c
parentb5b7bdda81acd0ee8c14a081f8bfd38d9809cec8 (diff)
downloadsubsurface-7c427dcc020064e0ea867c77ee86db6e1f4755bb.tar.gz
Add support to "split" a dive with surface time in the middle
Right now this requires that (a) the dive have only one divecomputer associated with it. Trying to split a dive with multiple dive computers would be *much* harder to do, since you'd have to try to line up the surface interval between computers etc. So just don't do it after downloading multiple dive computers for the same dive. (b) there must be at least one minute between the sample that came up to the surface and the sample that goes down again. If you just peeked your head above the surface, don't try to split things into two dives. Maybe we can relax this for freediving or something. also note that the split dive will only get new numbering if the dive that was split was the very last dive in the divelist. Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Dirk Hohndel <dirk@hohndel.org>
Diffstat (limited to 'dive.c')
-rw-r--r--dive.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/dive.c b/dive.c
index 49b2312d2..4de181c70 100644
--- a/dive.c
+++ b/dive.c
@@ -2831,6 +2831,155 @@ struct dive *merge_dives(struct dive *a, struct dive *b, int offset, bool prefer
return res;
}
+// copy_dive(), but retaining the new ID for the copied dive
+static struct dive *create_new_copy(struct dive *from)
+{
+ struct dive *to = alloc_dive();
+ int id;
+
+ // alloc_dive() gave us a new ID, we just need to
+ // make sure it's not overwritten.
+ id = to->id;
+ copy_dive(from, to);
+ to->id = id;
+ return to;
+}
+
+/*
+ * Split a dive that has a surface interval from samples 'a' to 'b'
+ * into two dives.
+ */
+static int split_dive_at(struct dive *dive, int a, int b)
+{
+ int i, t;
+ struct dive *d1, *d2;
+ struct divecomputer *dc1, *dc2;
+ struct event *event, **evp;
+
+ /* We're not trying to be efficient here.. */
+ d1 = create_new_copy(dive);
+ d2 = create_new_copy(dive);
+
+ dc1 = &d1->dc;
+ dc2 = &d2->dc;
+ /*
+ * Cut off the samples of d1 at the beginning
+ * of the interval.
+ */
+ dc1->samples = a;
+
+ /* And get rid of the 'b' first samples of d2 */
+ dc2->samples -= b;
+ memmove(dc2->sample, dc2->sample+b, dc2->samples * sizeof(struct sample));
+
+ /*
+ * This is where we cut off events from d1,
+ * and shift everything in d2
+ */
+ t = dc2->sample[0].time.seconds;
+ d2->when += t;
+ for (i = 0; i < dc2->samples; i++)
+ dc2->sample[i].time.seconds -= t;
+
+ /* Remove the events past 't' from d1 */
+ evp = &dc1->events;
+ while ((event = *evp) != NULL && event->time.seconds < t)
+ evp = &event->next;
+ *evp = NULL;
+ while (event) {
+ struct event *next = event->next;
+ free(event);
+ event = next;
+ }
+
+ /* Remove the events before 't' from d2, and shift the rest */
+ evp = &dc2->events;
+ while ((event = *evp) != NULL) {
+ if (event->time.seconds < t) {
+ *evp = event->next;
+ free(event);
+ } else {
+ event->time.seconds -= t;
+ }
+ }
+
+ fixup_dive(d1);
+ fixup_dive(d2);
+
+
+
+ i = get_divenr(dive);
+ delete_single_dive(i);
+ add_single_dive(i, d1);
+
+ /*
+ * 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 (dive_table.nr == i+1)
+ d2->number++;
+ else
+ d2->number = 0;
+ }
+ add_single_dive(i+1, d2);
+
+ mark_divelist_changed(true);
+
+ return 1;
+}
+
+/*
+ * Try to split a dive into multiple dives at a surface interval point.
+ *
+ * NOTE! We will not split dives with multiple dive computers, and
+ * only split when there is at least one surface event that has
+ * non-surface events on both sides.
+ *
+ * In other words, this is a (simplified) reversal of the dive merging.
+ */
+int split_dive(struct dive *dive)
+{
+ int i;
+ int at_surface, surface_start;
+ struct divecomputer *dc;
+
+ if (!dive || (dc = &dive->dc)->next)
+ return 0;
+
+ surface_start = 0;
+ at_surface = 1;
+ for (i = 1; i < dc->samples; i++) {
+ struct sample *sample = dc->sample+i;
+ int surface_sample = sample->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 = i;
+ continue;
+ }
+
+ // Goind down again? We want at least a minute from
+ // the surface start.
+ if (!surface_start)
+ continue;
+ if (sample->time.seconds - dc->sample[surface_start].time.seconds < 60)
+ continue;
+
+ return split_dive_at(dive, surface_start, i-1);
+ }
+ return 0;
+}
+
/*
* "dc_maxtime()" is how much total time this dive computer
* has for this dive. Note that it can differ from "duration"