aboutsummaryrefslogtreecommitdiffstats
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
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>
-rw-r--r--dive.c149
-rw-r--r--dive.h1
-rw-r--r--qt-ui/divelistview.cpp14
-rw-r--r--qt-ui/divelistview.h1
4 files changed, 165 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"
diff --git a/dive.h b/dive.h
index 71a9ab8f2..cef1106fd 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 90d0b4627..51720a317 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 42802b6ea..aaec37af5 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();