mirror of
https://expo.survex.com/repositories/expoweb/.git/
synced 2024-11-23 07:41:56 +00:00
321 lines
8.3 KiB
C
321 lines
8.3 KiB
C
/* 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 <config.h>
|
|
#endif
|
|
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#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", totlen, 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;
|
|
}
|