From e5961c3b3bc95a045e5130b596076a096fc25bde Mon Sep 17 00:00:00 2001 From: dave Date: Wed, 28 Jun 2006 22:34:31 +0200 Subject: [PATCH] [svn r7460] I've added this here so I don't lose it again --- noinfo/cavestats.c | 320 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 320 insertions(+) create mode 100644 noinfo/cavestats.c diff --git a/noinfo/cavestats.c b/noinfo/cavestats.c new file mode 100644 index 000000000..d48a0de1f --- /dev/null +++ b/noinfo/cavestats.c @@ -0,0 +1,320 @@ +/* cavestats.c */ +/* Print statistics on a cave */ +/* Copyright (C) 2004 David Loeffler + * Based on 3dtopos.c by Olly Betts + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#include +#include +#include +#include +#include + +#include "cmdline.h" +#include "filelist.h" +#include "filename.h" +#include "img.h" +#include "message.h" +#include "osalloc.h" + +int cmp_station(const void *a, const void *b); + +static const struct option long_opts[] = { + /* const char *name; int has_arg (0 no_argument, 1 required_*, 2 optional_*); int *flag; int val; */ + {"survey", required_argument, 0, 's'}, + {"help", no_argument, 0, HLP_HELP}, + {"version", no_argument, 0, HLP_VERSION}, + {"compact", no_argument, 0, 'c'}, + {0, 0, 0, 0} +}; + +#define short_opts "s:c" + +static struct help_msg help[] = { +/* <-- */ + {HLP_ENCODELONG(0), "only load the sub-survey with this prefix"}, + {0, 0} +}; + +typedef struct { + const char *name; + img_point pt; +} station; + +static station basept; + +static int separator; + +int +cmp_station(const void *a, const void *b) +{ + img_point pta, ptb; + double crossprod; + pta = ((const station *)a)->pt; + ptb = ((const station *)b)->pt; + + if(pta.x == basept.pt.x && pta.y == basept.pt.y) return -1; + if(ptb.x == basept.pt.x && ptb.y == basept.pt.y) return 1; + /* These two lines mean that the basepoint should compare as being before everything. + Otherwise somewhat unpredictable behaviour occurs! */ + crossprod = (pta.x - basept.pt.x)*(ptb.y - basept.pt.y) - (pta.y - basept.pt.y)*(ptb.x - basept.pt.x); + if(crossprod > 0) return 1; + if(crossprod < 0) return -1; + else return 0; +} + +static station *stns; +static OSSIZE_T c_stns = 0; +static station *hull; +static OSSIZE_T c_hull = 0; + +int +main(int argc, char **argv) +{ + char *fnm; + img *pimg; + int result; + OSSIZE_T c_labels = 0; + OSSIZE_T c_totlabel = 0; + char *p, *p_end; + const char *survey = NULL; + bool compact_output = 0; + double totlen = 0, planlen = 0; + img_point lastpt; + int num_legs = 0; + + msg_init(argv); + + cmdline_set_syntax_message("3D_FILE", NULL); /* TRANSLATE */ + cmdline_init(argc, argv, short_opts, long_opts, NULL, help, 1, 1); + while (1) { + int opt = cmdline_getopt(); + if (opt == EOF) break; + if (opt == 's') survey = optarg; + if (opt == 'c') compact_output = 1; + } + + fnm = argv[optind++]; + + pimg = img_open_survey(fnm, survey); + if (!pimg) fatalerror(img_error(), fnm); + separator = pimg->separator; + + /* Output headings line */ + if (!compact_output) printf("Statistics for %s (prefix %s)\n", fnm, survey); + + do { + img_point pt; + result = img_read_item(pimg, &pt); + switch (result) { + case img_LINE: + if(!pimg->flags) + { + planlen += sqrt((pt.x - lastpt.x)*(pt.x - lastpt.x) + (pt.y - lastpt.y)*(pt.y - lastpt.y)); + totlen += sqrt((pt.x - lastpt.x)*(pt.x - lastpt.x) + (pt.y - lastpt.y)*(pt.y - lastpt.y) + (pt.z - lastpt.z)*(pt.z - lastpt.z)); + } + num_legs++; + case img_MOVE: + lastpt = pt; + break; + case img_LABEL: + if(pimg->flags & img_SFLAG_UNDERGROUND) + { + c_labels++; + c_totlabel += strlen(pimg->label) + 1; + } + break; + case img_BAD: + img_close(pimg); + fatalerror(img_error(), fnm); + } + } while (result != img_STOP); + + /* + 1 to allow for reading coordinates of legs after the last label */ + stns = osmalloc(ossizeof(station) * (c_labels + 1)); + p = osmalloc(c_totlabel); + p_end = p + c_totlabel; + + img_rewind(pimg); + + do { + result = img_read_item(pimg, &(stns[c_stns].pt)); + switch (result) { + case img_LINE: + case img_MOVE: + break; + case img_LABEL: + if (!(pimg->flags & img_SFLAG_UNDERGROUND)) break; + if (c_stns < c_labels) { + OSSIZE_T len = strlen(pimg->label) + 1; + if (p + len <= p_end) { + memcpy(p, pimg->label, len); + stns[c_stns++].name = p; + p += len; + break; + } + } + /* FALLTHRU */ + case img_BAD: + img_close(pimg); + fatalerror(/*Bad 3d image file `%s'*/106, fnm); + } + } while (result != img_STOP); + + if (c_stns != c_labels || p != p_end) { + img_close(pimg); + fatalerror(/*Bad 3d image file `%s'*/106, fnm); + } + + img_close(pimg); + if (c_stns == 0) + { + printf("No survey data!\n"); + return EXIT_SUCCESS; + } + station wmost, nmost, emost, smost, umost, lmost; + wmost = emost = nmost = smost = umost = lmost = stns[0]; + { + OSSIZE_T i; + for(i = 0; i < c_stns; i++) + { + if(stns[i].pt.x < wmost.pt.x) wmost = stns[i]; + if(stns[i].pt.x > emost.pt.x) emost = stns[i]; + if(stns[i].pt.y > nmost.pt.y) nmost = stns[i]; + if(stns[i].pt.y < smost.pt.y) smost = stns[i]; + if(stns[i].pt.z > umost.pt.z) umost = stns[i]; + if(stns[i].pt.z < lmost.pt.z) lmost = stns[i]; + } + } + + basept = wmost; /* any extreme point will do */ + + qsort(stns, c_stns, sizeof(station), cmp_station); + + /* Now, having sorted the stations, any duplicate stations caused by *equates will appear consecutive. */ + + { + OSSIZE_T i; + int real_stn_count = 1; + for(i = 1; i < c_stns; i++) + if(stns[i].pt.x != stns[i-1].pt.x || stns[i].pt.y != stns[i-1].pt.y || stns[i].pt.z != stns[i-1].pt.z) + real_stn_count++; + if (!compact_output) + { + printf((real_stn_count == 1 ? msg(172) : msg(173)), real_stn_count); + printf((num_legs == 1 ? msg(174) : msg(175)), num_legs); + putnl(); + //printf((num_legs - real_stn_count == 0 ? msg(138) : msg(139)), num_legs - real_stn_count + 1); + // Can't do this, as we don't know the number of connected components + } + } + + + if (!compact_output) + { + printf("Total length of survey legs = %.2fm\n", totlen); + + printf(msg(133), planlen); + putnl(); + + printf(msg(135), (umost.pt.z - lmost.pt.z)); + printf(umost.name); + printf(msg(136), umost.pt.z); + printf(lmost.name); + printf(msg(137), lmost.pt.z); + putnl(); + + printf(msg(148), (nmost.pt.y - smost.pt.y)); + printf(nmost.name); + printf(msg(136), nmost.pt.y); + printf(smost.name); + printf(msg(137), smost.pt.y); + putnl(); + + printf(msg(149), (emost.pt.x - wmost.pt.x)); + printf(emost.name); + printf(msg(136), emost.pt.x); + printf(wmost.name); + printf(msg(137), wmost.pt.x); + putnl(); + } + if(c_stns == 1) + { + if (!compact_output) printf("Horizontal extent = 0.00m (from %s to %s)\n", stns[0].name, stns[0].name); + else printf("0.00\t0.00\t0.00\n"); + return EXIT_SUCCESS; + } + + if(c_stns == 2) + { + if (!compact_output) printf("Horizontal extent = %.2fm (from %s to %s)\n", planlen, stns[0].name, stns[1].name); + else printf("%.2f\t%.2f\t%.2f", planlen, umost.pt.z-lmost.pt.z, planlen); + return EXIT_SUCCESS; + } + + // Noddy equivalent of a stack... + c_hull = 3; + hull = osmalloc(ossizeof(station) * c_stns); + hull[0] = stns[0]; + hull[1] = stns[1]; + hull[2] = stns[2]; + OSSIZE_T i = 3; + while(i < c_stns) + { + double sa; + sa = (hull[c_hull - 1].pt.x - stns[i].pt.x)*(hull[c_hull - 2].pt.y - stns[i].pt.y) + - (hull[c_hull - 2].pt.x - stns[i].pt.x)*(hull[c_hull - 1].pt.y - stns[i].pt.y); + if(sa > 0) + { + hull[c_hull++] = stns[i++]; + } + else + { + c_hull--; + } + } + { + OSSIZE_T j; + station s1, s2; + double d, e, r; + s1 = s2 = hull[0]; + r = 0; + j = 0; + d = 0; + for(i = 0; i < c_hull; i++) + { + d = sqrt((hull[j % c_hull].pt.x - hull[i].pt.x)*(hull[j % c_hull].pt.x - hull[i].pt.x) + (hull[j % c_hull].pt.y - hull[i].pt.y)*(hull[j % c_hull].pt.y - hull[i].pt.y)); + while((e = sqrt((hull[(j+1) % c_hull].pt.x - hull[i].pt.x)*(hull[(j+1) % c_hull].pt.x - hull[i].pt.x) + (hull[(j+1) % c_hull].pt.y - hull[i].pt.y)*(hull[(j+1) % c_hull].pt.y - hull[i].pt.y))) >= d) + { + j++; d = e; + } + if(d > r) + { + r = d; + s1 = hull[i]; + s2 = hull[j % c_hull]; + } + } + if (!compact_output) printf("Horizontal extent = %.2fm (from %s to %s)\n", r, s1.name, s2.name); + else printf("%.2f\t%.2f\t%.2f\n", totlen, umost.pt.z - lmost.pt.z, r); + } + return EXIT_SUCCESS; +}