summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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();