X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=dive.c;h=67a78cc8ad309189dc14419501e1209b1997e637;hb=3a77eb85101a5fb1dc186b88a3a02d2ae27690c7;hp=5ddb6bc8087faae233843dc46683382934fe6792;hpb=aab4d593bdbffef8442282318778a9833cbc7a43;p=ext%2Fsubsurface.git diff --git a/dive.c b/dive.c index 5ddb6bc..67a78cc 100644 --- a/dive.c +++ b/dive.c @@ -1,8 +1,103 @@ +/* dive.c */ +/* maintains the internal dive list structure */ #include #include #include "dive.h" +void add_event(struct dive *dive, int time, int type, int flags, int value, const char *name) +{ + struct event *ev, **p; + unsigned int size, len = strlen(name); + + size = sizeof(*ev) + len + 1; + ev = malloc(size); + if (!ev) + return; + memset(ev, 0, size); + memcpy(ev->name, name, len); + ev->time.seconds = time; + ev->type = type; + ev->flags = flags; + ev->value = value; + ev->next = NULL; + + p = &dive->events; + while (*p) + p = &(*p)->next; + *p = ev; +} + +double get_depth_units(unsigned int mm, int *frac, const char **units) +{ + int decimals; + double d; + const char *unit; + + switch (output_units.length) { + case METERS: + d = mm / 1000.0; + unit = "m"; + decimals = d < 20; + break; + case FEET: + d = mm_to_feet(mm); + unit = "ft"; + decimals = 0; + break; + } + if (frac) + *frac = decimals; + if (units) + *units = unit; + return d; +} + +struct dive *alloc_dive(void) +{ + const int initial_samples = 5; + unsigned int size; + struct dive *dive; + + size = dive_size(initial_samples); + dive = malloc(size); + if (!dive) + exit(1); + memset(dive, 0, size); + dive->alloc_samples = initial_samples; + return dive; +} + +struct sample *prepare_sample(struct dive **divep) +{ + struct dive *dive = *divep; + if (dive) { + int nr = dive->samples; + int alloc_samples = dive->alloc_samples; + struct sample *sample; + if (nr >= alloc_samples) { + unsigned int size; + + alloc_samples = (alloc_samples * 3)/2 + 10; + size = dive_size(alloc_samples); + dive = realloc(dive, size); + if (!dive) + return NULL; + dive->alloc_samples = alloc_samples; + *divep = dive; + } + sample = dive->sample + nr; + memset(sample, 0, sizeof(*sample)); + return sample; + } + return NULL; +} + +void finish_sample(struct dive *dive, struct sample *sample) +{ + dive->samples++; +} + /* * So when we re-calculate maxdepth and meandepth, we will * not override the old numbers if they are close to the @@ -21,10 +116,46 @@ */ static void update_depth(depth_t *depth, int new) { - int old = depth->mm; + if (new) { + int old = depth->mm; + + if (abs(old - new) > 1000) + depth->mm = new; + } +} + +static void update_duration(duration_t *duration, int new) +{ + if (new) + duration->seconds = new; +} + +static void update_temperature(temperature_t *temperature, int new) +{ + if (new) { + int old = temperature->mkelvin; - if (abs(old - new) > 1000) - depth->mm = new; + if (abs(old - new) > 1000) + temperature->mkelvin = new; + } +} + +static void fixup_pressure(struct dive *dive, struct sample *sample) +{ + unsigned int pressure, index; + cylinder_t *cyl; + + pressure = sample->cylinderpressure.mbar; + if (!pressure) + return; + index = sample->cylinderindex; + if (index >= MAX_CYLINDERS) + return; + cyl = dive->cylinder + index; + if (!cyl->start.mbar) + cyl->start.mbar = pressure; + if (!cyl->end.mbar || pressure < cyl->end.mbar) + cyl->end.mbar = pressure; } struct dive *fixup_dive(struct dive *dive) @@ -33,17 +164,14 @@ struct dive *fixup_dive(struct dive *dive) double depthtime = 0; int lasttime = 0; int start = -1, end = -1; - int startpress = 0, endpress = 0; int maxdepth = 0, mintemp = 0; int lastdepth = 0; int lasttemp = 0; - temperature_t *redundant_temp = NULL; for (i = 0; i < dive->samples; i++) { struct sample *sample = dive->sample + i; int time = sample->time.seconds; int depth = sample->depth.mm; - int press = sample->cylinderpressure.mbar; int temp = sample->temperature.mkelvin; if (lastdepth) @@ -55,26 +183,19 @@ struct dive *fixup_dive(struct dive *dive) if (depth > maxdepth) maxdepth = depth; } - if (press) { - endpress = press; - if (!startpress) - startpress = press; - } + + fixup_pressure(dive, sample); + if (temp) { /* * If we have consecutive identical * temperature readings, throw away - * the redundant ones. We care about - * the "edges" only. + * the redundant ones. */ - if (lasttemp == temp) { - if (redundant_temp) - redundant_temp->mkelvin = 0; - redundant_temp = &sample->temperature; - } else { - redundant_temp = NULL; + if (lasttemp == temp) + sample->temperature.mkelvin = 0; + else lasttemp = temp; - } if (!mintemp || temp < mintemp) mintemp = temp; @@ -85,46 +206,32 @@ struct dive *fixup_dive(struct dive *dive) } if (end < 0) return dive; - dive->duration.seconds = end - start; + + update_duration(&dive->duration, end - start); if (start != end) - update_depth(&dive->meandepth, depthtime / (end - start)); - if (startpress) - dive->beginning_pressure.mbar = startpress; - if (endpress) - dive->end_pressure.mbar = endpress; - if (mintemp) - dive->watertemp.mkelvin = mintemp; + depthtime /= (end - start); - if (maxdepth) - update_depth(&dive->maxdepth, maxdepth); + update_depth(&dive->meandepth, depthtime); + update_temperature(&dive->watertemp, mintemp); + update_depth(&dive->maxdepth, maxdepth); return dive; } /* Don't pick a zero for MERGE_MIN() */ -#define MIN(a,b) ((a)<(b)?(a):(b)) -#define MAX(a,b) ((a)>(b)?(a):(b)) #define MERGE_MAX(res, a, b, n) res->n = MAX(a->n, b->n) #define MERGE_MIN(res, a, b, n) res->n = (a->n)?(b->n)?MIN(a->n, b->n):(a->n):(b->n) - -static int alloc_samples; +#define MERGE_TXT(res, a, b, n) res->n = merge_text(a->n, b->n) static struct dive *add_sample(struct sample *sample, int time, struct dive *dive) { - int nr = dive->samples; - struct sample *d; - - if (nr >= alloc_samples) { - alloc_samples = (alloc_samples + 64) * 3 / 2; - dive = realloc(dive, dive_size(alloc_samples)); - if (!dive) - return NULL; - } - dive->samples = nr+1; - d = dive->sample + nr; + struct sample *p = prepare_sample(&dive); - *d = *sample; - d->time.seconds = time; + if (!p) + return NULL; + *p = *sample; + p->time.seconds = time; + finish_sample(dive, p); return dive; } @@ -220,7 +327,7 @@ static void merge_cylinder_type(cylinder_type_t *res, cylinder_type_t *a, cylind *res = *b; } -static void merge_cylinder_mix(gasmix_t *res, gasmix_t *a, gasmix_t *b) +static void merge_cylinder_mix(struct gasmix *res, struct gasmix *a, struct gasmix *b) { if (a->o2.permille) b = a; @@ -231,6 +338,8 @@ static void merge_cylinder_info(cylinder_t *res, cylinder_t *a, cylinder_t *b) { merge_cylinder_type(&res->type, &a->type, &b->type); merge_cylinder_mix(&res->gasmix, &a->gasmix, &b->gasmix); + MERGE_MAX(res, a, b, start.mbar); + MERGE_MIN(res, a, b, end.mbar); } /* @@ -246,23 +355,20 @@ struct dive *try_to_merge(struct dive *a, struct dive *b) if (a->when != b->when) return NULL; - alloc_samples = 5; - res = malloc(dive_size(alloc_samples)); - if (!res) - return NULL; - memset(res, 0, dive_size(alloc_samples)); + res = alloc_dive(); res->when = a->when; - res->location = merge_text(a->location, b->location); - res->notes = merge_text(a->notes, b->notes); + MERGE_TXT(res, a, b, location); + MERGE_TXT(res, a, b, notes); + MERGE_TXT(res, a, b, buddy); + MERGE_TXT(res, a, b, divemaster); + MERGE_MAX(res, a, b, number); MERGE_MAX(res, a, b, maxdepth.mm); res->meandepth.mm = 0; MERGE_MAX(res, a, b, duration.seconds); MERGE_MAX(res, a, b, surfacetime.seconds); MERGE_MAX(res, a, b, airtemp.mkelvin); MERGE_MIN(res, a, b, watertemp.mkelvin); - MERGE_MAX(res, a, b, beginning_pressure.mbar); - MERGE_MAX(res, a, b, end_pressure.mbar); for (i = 0; i < MAX_CYLINDERS; i++) merge_cylinder_info(res->cylinder+i, a->cylinder + i, b->cylinder + i);