[PATCH 2/2] Add support to "split" a dive with surface time in the middle

Linus Torvalds torvalds at linux-foundation.org
Thu Oct 1 18:24:55 PDT 2015


From: Linus Torvalds <torvalds at linux-foundation.org>
Date: Thu, 1 Oct 2015 21:17:37 -0400
Subject: [PATCH 2/2] 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 at linux-foundation.org>
---
 dive.c                 | 149 +++++++++++++++++++++++++++++++++++++++++++++++++
 dive.h                 |   1 +
 qt-ui/divelistview.cpp |  14 +++++
 qt-ui/divelistview.h   |   1 +
 4 files changed, 165 insertions(+)

diff --git a/dive.c b/dive.c
index 49b2312d248d..4de181c70305 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"
diff --git a/dive.h b/dive.h
index 71a9ab8f25aa..cef1106fde5a 100644
--- a/dive.h
+++ b/dive.h
@@ -721,6 +721,7 @@ extern void fixup_dc_duration(struct divecomputer *dc);
 extern int dive_getUniqID(struct dive *d);
 extern unsigned int dc_airtemp(struct divecomputer *dc);
 extern unsigned int dc_watertemp(struct divecomputer *dc);
+extern int split_dive(struct dive *);
 extern struct dive *merge_dives(struct dive *a, struct dive *b, int offset, bool prefer_downloaded);
 extern struct dive *try_to_merge(struct dive *a, struct dive *b, bool prefer_downloaded);
 extern void renumber_dives(int start_nr, bool selected_only);
diff --git a/qt-ui/divelistview.cpp b/qt-ui/divelistview.cpp
index 90d0b4627641..51720a3173d0 100644
--- a/qt-ui/divelistview.cpp
+++ b/qt-ui/divelistview.cpp
@@ -616,6 +616,19 @@ void DiveListView::mergeDives()
 	MainWindow::instance()->refreshDisplay();
 }
 
+void DiveListView::splitDives()
+{
+	int i;
+	struct dive *dive;
+
+	for_each_dive (i, dive) {
+		if (dive->selected)
+			split_dive(dive);
+	}
+	MainWindow::instance()->refreshProfile();
+	MainWindow::instance()->refreshDisplay();
+}
+
 void DiveListView::renumberDives()
 {
 	RenumberDialog::instance()->renumberOnlySelected();
@@ -882,6 +895,7 @@ void DiveListView::contextMenuEvent(QContextMenuEvent *event)
 	if (amount_selected >= 1) {
 		popup.addAction(tr("Renumber dive(s)"), this, SLOT(renumberDives()));
 		popup.addAction(tr("Shift dive times"), this, SLOT(shiftTimes()));
+		popup.addAction(tr("Split selected dives"), this, SLOT(splitDives()));
 		popup.addAction(tr("Load image(s) from file(s)"), this, SLOT(loadImages()));
 		popup.addAction(tr("Load image(s) from web"), this, SLOT(loadWebImages()));
 	}
diff --git a/qt-ui/divelistview.h b/qt-ui/divelistview.h
index 42802b6ea79e..aaec37af5889 100644
--- a/qt-ui/divelistview.h
+++ b/qt-ui/divelistview.h
@@ -49,6 +49,7 @@ slots:
 	void addToTripAbove();
 	void addToTripBelow();
 	void mergeDives();
+	void splitDives();
 	void renumberDives();
 	void shiftTimes();
 	void loadImages();
-- 
2.4.2.387.gf86f31a



More information about the subsurface mailing list