]> git.tdb.fi Git - ext/subsurface.git/blob - dive.c
Only update mean/max depths with computed ones if they are way off
[ext/subsurface.git] / dive.c
1 #include <string.h>
2 #include <stdio.h>
3
4 #include "dive.h"
5
6 /*
7  * So when we re-calculate maxdepth and meandepth, we will
8  * not override the old numbers if they are close to the
9  * new ones.
10  *
11  * Why? Because a dive computer may well actually track the
12  * max depth and mean depth at finer granularity than the
13  * samples it stores. So it's possible that the max and mean
14  * have been reported more correctly originally.
15  *
16  * Only if the values calulcated from the samples are clearly
17  * different do we override the normal depth values.
18  *
19  * This considers 1m to be "clearly different". That's
20  * a totally random number.
21  */
22 static void update_depth(depth_t *depth, int new)
23 {
24         int old = depth->mm;
25
26         if (abs(old - new) > 1000)
27                 depth->mm = new;
28 }
29
30 struct dive *fixup_dive(struct dive *dive)
31 {
32         int i;
33         double depthtime = 0;
34         int lasttime = 0;
35         int start = -1, end = -1;
36         int startpress = 0, endpress = 0;
37         int starttemp = 0, endtemp = 0;
38         int maxdepth = 0, mintemp = 0;
39         int lastdepth = 0;
40
41         for (i = 0; i < dive->samples; i++) {
42                 struct sample *sample = dive->sample + i;
43                 int time = sample->time.seconds;
44                 int depth = sample->depth.mm;
45                 int press = sample->tankpressure.mbar;
46                 int temp = sample->temperature.mkelvin;
47
48                 if (lastdepth)
49                         end = time;
50
51                 if (depth) {
52                         if (start < 0)
53                                 start = lasttime;
54                         if (depth > maxdepth)
55                                 maxdepth = depth;
56                 }
57                 if (press) {
58                         endpress = press;
59                         if (!startpress)
60                                 startpress = press;
61                 }
62                 if (temp) {
63                         endtemp = temp;
64                         if (!starttemp)
65                                 starttemp = temp;
66                         if (!mintemp || temp < mintemp)
67                                 mintemp = temp;
68                 }
69                 depthtime += (time - lasttime) * (lastdepth + depth) / 2;
70                 lastdepth = depth;
71                 lasttime = time;
72         }
73         if (end < 0)
74                 return dive;
75         dive->duration.seconds = end - start;
76         if (start != end)
77                 update_depth(&dive->meandepth, depthtime / (end - start));
78         if (startpress)
79                 dive->beginning_pressure.mbar = startpress;
80         if (endpress)
81                 dive->end_pressure.mbar = endpress;
82         if (mintemp)
83                 dive->watertemp.mkelvin = mintemp;
84
85         if (maxdepth)
86                 update_depth(&dive->maxdepth, maxdepth);
87
88         return dive;
89 }
90
91 /* Don't pick a zero for MERGE_MIN() */
92 #define MIN(a,b) ((a)<(b)?(a):(b))
93 #define MAX(a,b) ((a)>(b)?(a):(b))
94 #define MERGE_MAX(res, a, b, n) res->n = MAX(a->n, b->n)
95 #define MERGE_MIN(res, a, b, n) res->n = (a->n)?(b->n)?MIN(a->n, b->n):(a->n):(b->n)
96
97 static int alloc_samples;
98
99 static struct dive *add_sample(struct sample *sample, int time, struct dive *dive)
100 {
101         int nr = dive->samples;
102         struct sample *d;
103
104         if (nr >= alloc_samples) {
105                 alloc_samples = (alloc_samples + 64) * 3 / 2;
106                 dive = realloc(dive, dive_size(alloc_samples));
107                 if (!dive)
108                         return NULL;
109         }
110         dive->samples = nr+1;
111         d = dive->sample + nr;
112
113         *d = *sample;
114         d->time.seconds = time;
115         return dive;
116 }
117
118 /*
119  * Merge samples. Dive 'a' is "offset" seconds before Dive 'b'
120  */
121 static struct dive *merge_samples(struct dive *res, struct dive *a, struct dive *b, int offset)
122 {
123         int asamples = a->samples;
124         int bsamples = b->samples;
125         struct sample *as = a->sample;
126         struct sample *bs = b->sample;
127
128         for (;;) {
129                 int at, bt;
130                 struct sample sample;
131
132                 if (!res)
133                         return NULL;
134
135                 at = asamples ? as->time.seconds : -1;
136                 bt = bsamples ? bs->time.seconds + offset : -1;
137
138                 /* No samples? All done! */
139                 if (at < 0 && bt < 0)
140                         return fixup_dive(res);
141
142                 /* Only samples from a? */
143                 if (bt < 0) {
144 add_sample_a:
145                         res = add_sample(as, at, res);
146                         as++;
147                         asamples--;
148                         continue;
149                 }
150
151                 /* Only samples from b? */
152                 if (at < 0) {
153 add_sample_b:
154                         res = add_sample(bs, bt, res);
155                         bs++;
156                         bsamples--;
157                         continue;
158                 }
159
160                 if (at < bt)
161                         goto add_sample_a;
162                 if (at > bt)
163                         goto add_sample_b;
164
165                 /* same-time sample: add a merged sample. Take the non-zero ones */
166                 sample = *bs;
167                 if (as->depth.mm)
168                         sample.depth = as->depth;
169                 if (as->temperature.mkelvin)
170                         sample.temperature = as->temperature;
171                 if (as->tankpressure.mbar)
172                         sample.tankpressure = as->tankpressure;
173                 if (as->tankindex)
174                         sample.tankindex = as->tankindex;
175
176                 res = add_sample(&sample, at, res);
177
178                 as++;
179                 bs++;
180                 asamples--;
181                 bsamples--;
182         }
183 }
184
185 static char *merge_text(const char *a, const char *b)
186 {
187         char *res;
188
189         if (!a || !*a)
190                 return (char *)b;
191         if (!b || !*b)
192                 return (char *)a;
193         if (!strcmp(a,b))
194                 return (char *)a;
195         res = malloc(strlen(a) + strlen(b) + 9);
196         if (!res)
197                 return (char *)a;
198         sprintf(res, "(%s) or (%s)", a, b);
199         return res;
200 }
201
202 /*
203  * This could do a lot more merging. Right now it really only
204  * merges almost exact duplicates - something that happens easily
205  * with overlapping dive downloads.
206  */
207 struct dive *try_to_merge(struct dive *a, struct dive *b)
208 {
209         int i;
210         struct dive *res;
211
212         if (a->when != b->when)
213                 return NULL;
214
215         alloc_samples = 5;
216         res = malloc(dive_size(alloc_samples));
217         if (!res)
218                 return NULL;
219         memset(res, 0, dive_size(alloc_samples));
220
221         res->when = a->when;
222         res->name = merge_text(a->name, b->name);
223         res->location = merge_text(a->location, b->location);
224         res->notes = merge_text(a->notes, b->notes);
225         MERGE_MAX(res, a, b, maxdepth.mm);
226         res->meandepth.mm = 0;
227         MERGE_MAX(res, a, b, duration.seconds);
228         MERGE_MAX(res, a, b, surfacetime.seconds);
229         MERGE_MAX(res, a, b, airtemp.mkelvin);
230         MERGE_MIN(res, a, b, watertemp.mkelvin);
231         MERGE_MAX(res, a, b, beginning_pressure.mbar);
232         MERGE_MAX(res, a, b, end_pressure.mbar);
233         for (i = 0; i < MAX_MIXES; i++) {
234                 if (a->gasmix[i].o2.permille) {
235                         res->gasmix[i] = a->gasmix[i];
236                         continue;
237                 }
238                 res->gasmix[i] = b->gasmix[i];
239         }
240         return merge_samples(res, a, b, 0);
241 }