source: git/src/diffpos.c @ f96897b

walls-datawalls-data-hanging-as-warning
Last change on this file since f96897b was 4c83f84, checked in by Olly Betts <olly@…>, 3 weeks ago

Don't check HAVE_CONFIG_H in most cases

This check is only useful for img.c, which is intended to be usable
outside of Survex (and had fallbacks for functions which may not be
available which will get used if built in a non-autotools project).
For all the other source files it's just useless boilerplate.

  • Property mode set to 100644
File size: 7.3 KB
Line 
1/* diffpos.c */
2/* Utility to compare two SURVEX .pos or .3d files */
3/* Copyright (C) 1994,1996,1998-2003,2010,2011,2013,2014 Olly Betts
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include <config.h>
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <math.h>
26
27#include "cmdline.h"
28#include "debug.h"
29#include "filelist.h"
30#include "hash.h"
31#include "img_hosted.h"
32#include "namecmp.h"
33#include "useful.h"
34
35/* Don't complain if values mismatch by a tiny amount (1e-6m i.e. 0.001mm) */
36#define TOLERANCE 1e-6
37
38/* default threshold is 1cm */
39#define DFLT_MAX_THRESHOLD 0.01
40
41static double threshold = DFLT_MAX_THRESHOLD;
42
43static const struct option long_opts[] = {
44   /* const char *name; int has_arg (0 no_argument, 1 required_*, 2 optional_*); int *flag; int val; */
45   {"survey", required_argument, 0, 's'},
46   {"help", no_argument, 0, HLP_HELP},
47   {"version", no_argument, 0, HLP_VERSION},
48   {0, 0, 0, 0}
49};
50
51#define short_opts "s:"
52
53static struct help_msg help[] = {
54/*                              <-- */
55   {HLP_ENCODELONG(0),        /*only load the sub-survey with this prefix*/199, 0},
56   {0, 0, 0}
57};
58
59/* We use a hashtable with linked list buckets - this is how many hash table
60 * entries we have.  0x2000 with sizeof(void *) == 4 uses 32K. */
61#define TREE_SIZE 0x2000
62
63typedef struct station {
64   struct station *next;
65   char *name;
66   img_point pt;
67} station;
68
69typedef struct added {
70   struct added *next;
71   char *name;
72} added;
73
74static int old_separator, new_separator, sort_separator;
75
76static int
77cmp_pname(const void *a, const void *b)
78{
79   return name_cmp(*(const char **)a, *(const char **)b, sort_separator);
80}
81
82static station **htab;
83static bool fChanged = false;
84
85static added *added_list = NULL;
86static OSSIZE_T c_added = 0;
87
88static void
89tree_init(void)
90{
91   size_t i;
92   htab = osmalloc(TREE_SIZE * ossizeof(station *));
93   for (i = 0; i < TREE_SIZE; i++) htab[i] = NULL;
94}
95
96static void
97tree_insert(const char *name, const img_point *pt)
98{
99   int v = hash_string(name) & (TREE_SIZE - 1);
100   station * stn = osnew(station);
101   stn->name = osstrdup(name);
102   stn->pt = *pt;
103   stn->next = htab[v];
104   htab[v] = stn;
105}
106
107static int
108close_enough(const img_point * p1, const img_point * p2)
109{
110    return fabs(p1->x - p2->x) - threshold <= TOLERANCE &&
111           fabs(p1->y - p2->y) - threshold <= TOLERANCE &&
112           fabs(p1->z - p2->z) - threshold <= TOLERANCE;
113}
114
115static void
116tree_remove(const char *name, const img_point *pt)
117{
118   /* We need to handle duplicate labels - normal .3d files shouldn't have them
119    * (though some older ones do due to a couple of bugs in earlier versions of
120    * Survex) but extended .3d files repeat the label where a loop is broken,
121    * and data read from foreign formats might repeat labels.
122    */
123   int v = hash_string(name) & (TREE_SIZE - 1);
124   station **prev;
125   station *p;
126   station **found = NULL;
127   bool was_close_enough = false;
128
129   for (prev = &htab[v]; *prev; prev = &((*prev)->next)) {
130      if (strcmp((*prev)->name, name) == 0) {
131         /* Handle stations with the same name.  Stations are inserted at the
132          * start of the linked list, so pick the *last* matching station in
133          * the list as then we match the first stations with the same name in
134          * each file.
135          */
136         if (close_enough(pt, &((*prev)->pt))) {
137            found = prev;
138            was_close_enough = true;
139         } else if (!was_close_enough) {
140            found = prev;
141         }
142      }
143   }
144
145   if (!found) {
146      added *add = osnew(added);
147      add->name = osstrdup(name);
148      add->next = added_list;
149      added_list = add;
150      c_added++;
151      fChanged = true;
152      return;
153   }
154
155   if (!was_close_enough) {
156      /* TRANSLATORS: for diffpos: */
157      printf(msg(/*Moved by (%3.2f,%3.2f,%3.2f): %s*/500),
158             pt->x - (*found)->pt.x,
159             pt->y - (*found)->pt.y,
160             pt->z - (*found)->pt.z,
161             name);
162      putnl();
163      fChanged = true;
164   }
165
166   osfree((*found)->name);
167   p = *found;
168   *found = p->next;
169   osfree(p);
170}
171
172static int
173tree_check(void)
174{
175   size_t c = 0;
176   char **names;
177   size_t i;
178
179   if (c_added) {
180      names = osmalloc(c_added * ossizeof(char *));
181      for (i = 0; i < c_added; i++) {
182         added *old;
183         SVX_ASSERT(added_list);
184         names[i] = added_list->name;
185         old = added_list;
186         added_list = old->next;
187         osfree(old);
188      }
189      SVX_ASSERT(added_list == NULL);
190      sort_separator = new_separator;
191      qsort(names, c_added, sizeof(char *), cmp_pname);
192      for (i = 0; i < c_added; i++) {
193         /* TRANSLATORS: for diffpos: */
194         printf(msg(/*Added: %s*/501), names[i]);
195         putnl();
196         osfree(names[i]);
197      }
198      osfree(names);
199   }
200
201   for (i = 0; i < TREE_SIZE; i++) {
202      station *p;
203      for (p = htab[i]; p; p = p->next) c++;
204   }
205   if (c == 0) return fChanged;
206
207   names = osmalloc(c * ossizeof(char *));
208   c = 0;
209   for (i = 0; i < TREE_SIZE; i++) {
210      station *p;
211      for (p = htab[i]; p; p = p->next) names[c++] = p->name;
212   }
213   sort_separator = old_separator;
214   qsort(names, c, sizeof(char *), cmp_pname);
215   for (i = 0; i < c; i++) {
216      /* TRANSLATORS: for diffpos: */
217      printf(msg(/*Deleted: %s*/502), names[i]);
218      putnl();
219   }
220   return true;
221}
222
223static int
224parse_file(const char *fnm, const char *survey,
225           void (*tree_func)(const char *, const img_point *))
226{
227   img_point pt;
228   int result;
229   int separator;
230
231   img *pimg = img_open_survey(fnm, survey);
232   if (!pimg) fatalerror(img_error2msg(img_error()), fnm);
233   separator = pimg->separator;
234
235   do {
236      result = img_read_item(pimg, &pt);
237      switch (result) {
238       case img_MOVE:
239       case img_LINE:
240         break;
241       case img_LABEL:
242         tree_func(pimg->label, &pt);
243         break;
244       case img_BAD:
245         img_close(pimg);
246         fatalerror(img_error2msg(img_error()), fnm);
247      }
248   } while (result != img_STOP);
249
250   img_close(pimg);
251   return separator;
252}
253
254int
255main(int argc, char **argv)
256{
257   char *fnm1, *fnm2;
258   const char *survey = NULL;
259
260   msg_init(argv);
261
262   /* TRANSLATORS: Part of diffpos --help */
263   cmdline_set_syntax_message(/*FILE1 FILE2 [THRESHOLD]*/218,
264                              /* TRANSLATORS: Part of diffpos --help */
265                              /*FILE1 and FILE2 can be .pos or .3d files\nTHRESHOLD is the max. ignorable change along any axis in metres (default %s)*/255,
266                              STRING(DFLT_MAX_THRESHOLD));
267   cmdline_init(argc, argv, short_opts, long_opts, NULL, help, 2, 3);
268   while (1) {
269      int opt = cmdline_getopt();
270      if (opt == EOF) break;
271      if (opt == 's') survey = optarg;
272   }
273   fnm1 = argv[optind++];
274   fnm2 = argv[optind++];
275   if (argv[optind]) {
276      optarg = argv[optind];
277      threshold = cmdline_double_arg();
278   }
279
280   tree_init();
281
282   old_separator = parse_file(fnm1, survey, tree_insert);
283
284   new_separator = parse_file(fnm2, survey, tree_remove);
285
286   return tree_check() ? EXIT_FAILURE : EXIT_SUCCESS;
287}
Note: See TracBrowser for help on using the repository browser.