source: git/src/diffpos.c @ 73e8a51

stereo-2025
Last change on this file since 73e8a51 was 36b8060, checked in by Olly Betts <olly@…>, 4 months ago

Eliminate fopenWithPthAndExt() use in img.c

Now we have img_read_stream_survey() we can easily move this handling
out of img.c and into Survex-specific code.

Making this change revealed that the filename_opened member of
the img struct is only ever set to NULL when used outside of Survex
and set but never actually used inside of Survex, so remove this
member and document that it was always NULL.

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