2 /* Utility to compare two SURVEX .pos or .3d files */
3 /* Copyright (C) 1994,1996,1998-2003,2010,2011,2013,2014 Olly Betts
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.
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.
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
31 #include "img_hosted.h"
36 /* Don't complain if values mismatch by a tiny amount (1e-6m i.e. 0.001mm) */
37 #define TOLERANCE 1e-6
39 /* default threshold is 1cm */
40 #define DFLT_MAX_THRESHOLD 0.01
42 static double threshold
= DFLT_MAX_THRESHOLD
;
44 static 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
},
52 #define short_opts "s:"
54 static struct help_msg help
[] = {
56 {HLP_ENCODELONG(0), /*only load the sub-survey with this prefix*/199, 0, 0},
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
64 typedef struct station
{
70 typedef struct added
{
75 static int old_separator
, new_separator
, sort_separator
;
78 cmp_pname(const void *a
, const void *b
)
80 return name_cmp(*(const char **)a
, *(const char **)b
, sort_separator
);
83 static station
**htab
;
84 static bool fChanged
= false;
86 static added
*added_list
= NULL
;
87 static OSSIZE_T c_added
= 0;
93 htab
= osmalloc(TREE_SIZE
* ossizeof(station
*));
94 for (i
= 0; i
< TREE_SIZE
; i
++) htab
[i
] = NULL
;
98 tree_insert(const char *name
, const img_point
*pt
)
100 int v
= hash_string(name
) & (TREE_SIZE
- 1);
101 station
* stn
= osnew(station
);
102 stn
->name
= osstrdup(name
);
109 close_enough(const img_point
* p1
, const img_point
* p2
)
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
;
117 tree_remove(const char *name
, const img_point
*pt
)
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.
124 int v
= hash_string(name
) & (TREE_SIZE
- 1);
127 station
**found
= NULL
;
128 bool was_close_enough
= false;
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
137 if (close_enough(pt
, &((*prev
)->pt
))) {
139 was_close_enough
= true;
140 } else if (!was_close_enough
) {
147 added
*add
= osnew(added
);
148 add
->name
= osstrdup(name
);
149 add
->next
= added_list
;
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
,
167 osfree((*found
)->name
);
181 names
= osmalloc(c_added
* ossizeof(char *));
182 for (i
= 0; i
< c_added
; i
++) {
184 SVX_ASSERT(added_list
);
185 names
[i
] = added_list
->name
;
187 added_list
= old
->next
;
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
]);
202 for (i
= 0; i
< TREE_SIZE
; i
++) {
204 for (p
= htab
[i
]; p
; p
= p
->next
) c
++;
206 if (c
== 0) return fChanged
;
208 names
= osmalloc(c
* ossizeof(char *));
210 for (i
= 0; i
< TREE_SIZE
; i
++) {
212 for (p
= htab
[i
]; p
; p
= p
->next
) names
[c
++] = p
->name
;
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
]);
225 parse_file(const char *fnm
, const char *survey
,
226 void (*tree_func
)(const char *, const img_point
*))
232 img
*pimg
= img_open_survey(fnm
, survey
);
233 if (!pimg
) fatalerror(img_error2msg(img_error()), fnm
);
234 separator
= pimg
->separator
;
237 result
= img_read_item(pimg
, &pt
);
243 tree_func(pimg
->label
, &pt
);
247 fatalerror(img_error2msg(img_error()), fnm
);
249 } while (result
!= img_STOP
);
256 main(int argc
, char **argv
)
259 const char *survey
= NULL
;
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);
270 int opt
= cmdline_getopt();
271 if (opt
== EOF
) break;
272 if (opt
== 's') survey
= optarg
;
274 fnm1
= argv
[optind
++];
275 fnm2
= argv
[optind
++];
277 optarg
= argv
[optind
];
278 threshold
= cmdline_double_arg();
283 old_separator
= parse_file(fnm1
, survey
, tree_insert
);
285 new_separator
= parse_file(fnm2
, survey
, tree_remove
);
287 return tree_check() ? EXIT_FAILURE
: EXIT_SUCCESS
;