source: git/src/survexport.cc@ 1258f47

RELEASE/1.2 debug-ci debug-ci-sanitisers faster-cavernlog log-select main stereo-2025 walls-data walls-data-hanging-as-warning warn-only-for-hanging-survey
Last change on this file since 1258f47 was b349e7e2, checked in by Olly Betts <olly@…>, 8 years ago

survexport: Output .pos based on program name

If the program name is 3dtopos then produce .pos output to provide
an easy drop-in replacement for compatibility with current releases
of Tunnel.

  • Property mode set to 100644
File size: 13.2 KB
Line 
1/* survexport.cc
2 * Convert a processed survey data file to another format.
3 */
4
5/* Copyright (C) 1994-2004,2008,2010,2011,2013,2014,2018 Olly Betts
6 * Copyright (C) 2004 John Pybus (SVG Output code)
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23#ifdef HAVE_CONFIG_H
24#include <config.h>
25#endif
26
27#include <math.h>
28#include <stdio.h>
29#include <stdlib.h>
30#include <string.h>
31
32#include "export.h"
33#include "mainfrm.h"
34
35#include "cmdline.h"
36#include "filename.h"
37#include "img_hosted.h"
38#include "message.h"
39#include "str.h"
40#include "useful.h"
41
42#include <string>
43
44using namespace std;
45
46int
47main(int argc, char **argv)
48{
49 double pan = 0;
50 double tilt = -90.0;
51 export_format format = FMT_MAX_PLUS_ONE_;
52 int show_mask = 0;
53 const char *survey = NULL;
54 double grid = 0.0; /* grid spacing (or 0 for no grid) */
55 double text_height = DEFAULT_TEXT_HEIGHT; /* for station labels */
56 double marker_size = DEFAULT_MARKER_SIZE; /* for station markers */
57 double scale = 500.0;
58 SurveyFilter* filter = NULL;
59
60 {
61 /* Default to .pos output if installed as 3dtopos. */
62 char* progname = baseleaf_from_fnm(argv[0]);
63 if (strcasecmp(progname, "3dtopos") == 0) {
64 format = FMT_POS;
65 }
66 osfree(progname);
67 }
68
69 const int OPT_FMT_BASE = 20000;
70 enum {
71 OPT_SCALE = 0x100, OPT_BEARING, OPT_TILT, OPT_PLAN, OPT_ELEV,
72 OPT_LEGS, OPT_SURF, OPT_SPLAYS, OPT_CROSSES, OPT_LABELS, OPT_ENTS,
73 OPT_FIXES, OPT_EXPORTS, OPT_XSECT, OPT_WALLS, OPT_PASG,
74 OPT_CENTRED, OPT_FULL_COORDS, OPT_CLAMP_TO_GROUND, OPT_DEFAULTS
75 };
76 static const struct option long_opts[] = {
77 /* const char *name; int has_arg (0 no_argument, 1 required, 2 options_*); int *flag; int val */
78 {"survey", required_argument, 0, 's'},
79 {"scale", required_argument, 0, OPT_SCALE},
80 {"bearing", required_argument, 0, OPT_BEARING},
81 {"tilt", required_argument, 0, OPT_TILT},
82 {"plan", no_argument, 0, OPT_PLAN},
83 {"elevation", no_argument, 0, OPT_ELEV},
84 {"legs", no_argument, 0, OPT_LEGS},
85 {"surface-legs", no_argument, 0, OPT_SURF},
86 {"splays", no_argument, 0, OPT_SPLAYS},
87 {"crosses", no_argument, 0, OPT_CROSSES},
88 {"station-names", no_argument, 0, OPT_LABELS},
89 {"entrances", no_argument, 0, OPT_ENTS},
90 {"fixes", no_argument, 0, OPT_FIXES},
91 {"exports", no_argument, 0, OPT_EXPORTS},
92 {"cross-sections", no_argument, 0, OPT_XSECT},
93 {"walls", no_argument, 0, OPT_WALLS},
94 {"passages", no_argument, 0, OPT_PASG},
95 {"origin-in-centre", no_argument, 0, OPT_CENTRED},
96 {"full-coordinates", no_argument, 0, OPT_FULL_COORDS},
97 {"clamp-to-ground", no_argument, 0, OPT_CLAMP_TO_GROUND},
98 {"defaults", no_argument, 0, OPT_DEFAULTS},
99 {"grid", optional_argument, 0, 'g'},
100 {"text-height", required_argument, 0, 't'},
101 {"marker-size", required_argument, 0, 'm'},
102 {"csv", no_argument, 0, OPT_FMT_BASE + FMT_CSV},
103 {"dxf", no_argument, 0, OPT_FMT_BASE + FMT_DXF},
104 {"eps", no_argument, 0, OPT_FMT_BASE + FMT_EPS},
105 {"gpx", no_argument, 0, OPT_FMT_BASE + FMT_GPX},
106 {"hpgl", no_argument, 0, OPT_FMT_BASE + FMT_HPGL},
107 {"json", no_argument, 0, OPT_FMT_BASE + FMT_JSON},
108 {"kml", no_argument, 0, OPT_FMT_BASE + FMT_KML},
109 {"plt", no_argument, 0, OPT_FMT_BASE + FMT_PLT},
110 {"skencil", no_argument, 0, OPT_FMT_BASE + FMT_SK},
111 {"pos", no_argument, 0, OPT_FMT_BASE + FMT_POS},
112 {"svg", no_argument, 0, OPT_FMT_BASE + FMT_SVG},
113 {"help", no_argument, 0, HLP_HELP},
114 {"version", no_argument, 0, HLP_VERSION},
115 // US spelling:
116 {"origin-in-center", no_argument, 0, OPT_CENTRED},
117 // Abbreviation:
118 {"full-coords", no_argument, 0, OPT_FULL_COORDS},
119 {0,0,0,0}
120 };
121
122#define short_opts "s:g::t:m:"
123
124 static struct help_msg help[] = {
125 /* <-- */
126 {HLP_ENCODELONG(0), /*only load the sub-survey with this prefix*/199, 0},
127 {HLP_ENCODELONG(1), /*scale (50, 0.02, 1:50 and 2:100 all mean 1:50)*/217, 0},
128 {HLP_ENCODELONG(2), /*bearing (90, 90d, 100g all mean 90°)*/460, 0},
129 {HLP_ENCODELONG(3), /*tilt (45, 45d, 50g, 100% all mean 45°)*/461, 0},
130 {HLP_ENCODELONG(4), /*plan view (equivalent to --tilt=-90)*/462, 0},
131 {HLP_ENCODELONG(5), /*elevation view (equivalent to --tilt=0)*/463, 0},
132 {HLP_ENCODELONG(6), /*underground survey legs*/476, 0},
133 {HLP_ENCODELONG(7), /*surface survey legs*/464, 0},
134 {HLP_ENCODELONG(8), /*splay legs*/465, 0},
135 {HLP_ENCODELONG(9), /*station markers*/474, 0},
136 {HLP_ENCODELONG(10), /*station labels*/475, 0},
137 {HLP_ENCODELONG(11), /*entrances*/466, 0},
138 {HLP_ENCODELONG(12), /*fixed points*/467, 0},
139 {HLP_ENCODELONG(13), /*exported stations*/468, 0},
140 {HLP_ENCODELONG(14), /*cross-sections*/469, 0},
141 {HLP_ENCODELONG(15), /*walls*/470, 0},
142 {HLP_ENCODELONG(16), /*passages*/471, 0},
143 {HLP_ENCODELONG(17), /*origin in centre*/472, 0},
144 {HLP_ENCODELONG(18), /*full coordinates*/473, 0},
145 {HLP_ENCODELONG(19), /*clamp to ground*/478, 0},
146 {HLP_ENCODELONG(20), /*include items exported by default*/155, 0},
147 {HLP_ENCODELONG(21), /*generate grid (default %sm)*/148, STRING(DEFAULT_GRID_SPACING)},
148 {HLP_ENCODELONG(22), /*station labels text height (default %s)*/149, STRING(DEFAULT_TEXT_HEIGHT)},
149 {HLP_ENCODELONG(23), /*station marker size (default %s)*/152, STRING(DEFAULT_MARKER_SIZE)},
150 {HLP_ENCODELONG(24), /*produce CSV output*/102, 0},
151 {HLP_ENCODELONG(25), /*produce DXF output*/156, 0},
152 {HLP_ENCODELONG(26), /*produce EPS output*/454, 0},
153 {HLP_ENCODELONG(27), /*produce GPX output*/455, 0},
154 {HLP_ENCODELONG(28), /*produce HPGL output*/456, 0},
155 {HLP_ENCODELONG(29), /*produce JSON output*/457, 0},
156 {HLP_ENCODELONG(30), /*produce KML output*/458, 0},
157 /* TRANSLATORS: "Compass" and "Carto" are the names of software packages,
158 * so should not be translated. */
159 {HLP_ENCODELONG(31), /*produce Compass PLT output for Carto*/159, 0},
160 /* TRANSLATORS: "Skencil" is the name of a software package, so should not be
161 * translated. */
162 {HLP_ENCODELONG(32), /*produce Skencil output*/158, 0},
163 {HLP_ENCODELONG(33), /*produce Survex POS output*/459, 0},
164 {HLP_ENCODELONG(34), /*produce SVG output*/160, 0},
165 {0, 0, 0}
166 };
167
168 msg_init(argv);
169
170 string optmap[sizeof(show_mask) * CHAR_BIT];
171
172 int long_index;
173 bool always_include_defaults = false;
174 cmdline_init(argc, argv, short_opts, long_opts, &long_index, help, 1, 2);
175 while (1) {
176 long_index = -1;
177 int opt = cmdline_getopt();
178 if (opt == EOF) break;
179 int bit = 0;
180 switch (opt) {
181 case OPT_LEGS:
182 bit = LEGS;
183 break;
184 case OPT_SURF:
185 bit = SURF;
186 break;
187 case OPT_SPLAYS:
188 bit = SPLAYS;
189 break;
190 case OPT_CROSSES:
191 bit = STNS;
192 break;
193 case OPT_LABELS:
194 bit = LABELS;
195 break;
196 case OPT_ENTS:
197 bit = ENTS;
198 break;
199 case OPT_FIXES:
200 bit = FIXES;
201 break;
202 case OPT_EXPORTS:
203 bit = EXPORTS;
204 break;
205 case OPT_XSECT:
206 bit = XSECT;
207 break;
208 case OPT_WALLS:
209 bit = WALLS;
210 break;
211 case OPT_PASG:
212 bit = PASG;
213 break;
214 case OPT_CENTRED:
215 bit = CENTRED;
216 break;
217 case OPT_FULL_COORDS:
218 bit = FULL_COORDS;
219 break;
220 case OPT_CLAMP_TO_GROUND:
221 bit = CLAMP_TO_GROUND;
222 break;
223 case OPT_DEFAULTS:
224 always_include_defaults = true;
225 break;
226 case 'g': /* Grid */
227 if (optarg) {
228 grid = cmdline_double_arg();
229 } else {
230 grid = (double)DEFAULT_GRID_SPACING;
231 }
232 bit = GRID;
233 break;
234 case OPT_SCALE: {
235 char* colon = strchr(optarg, ':');
236 if (!colon) {
237 /* --scale=1000 => 1:1000 => scale = 1000 */
238 scale = cmdline_double_arg();
239 if (scale < 1.0) {
240 /* --scale=0.001 => 1:1000 => scale = 1000 */
241 scale = 1.0 / scale;
242 }
243 } else if (colon - optarg == 1 && optarg[0] == '1') {
244 /* --scale=1:1000 => 1:1000 => scale = 1000 */
245 optarg += 2;
246 scale = cmdline_double_arg();
247 optarg -= 2;
248 } else {
249 /* --scale=2:1000 => 1:500 => scale = 500 */
250 *colon = '\0';
251 scale = cmdline_double_arg();
252 optarg = colon + 1;
253 scale = cmdline_double_arg() / scale;
254 *colon = ':';
255 }
256 bit = SCALE;
257 break;
258 }
259 case OPT_BEARING: {
260 int units = 0;
261 size_t len = strlen(optarg);
262 if (len > 0) {
263 char ch = optarg[len - 1];
264 switch (ch) {
265 case 'd':
266 case 'g':
267 units = ch;
268 optarg[len - 1] = '\0';
269 break;
270 }
271 pan = cmdline_double_arg();
272 optarg[len - 1] = ch;
273 } else {
274 pan = cmdline_double_arg();
275 }
276 if (units == 'g') {
277 pan *= 0.9;
278 }
279 bit = EXPORT_3D;
280 break;
281 }
282 case OPT_TILT: {
283 int units = 0;
284 size_t len = strlen(optarg);
285 if (len > 0) {
286 char ch = optarg[len - 1];
287 switch (ch) {
288 case '%':
289 case 'd':
290 case 'g':
291 units = ch;
292 optarg[len - 1] = '\0';
293 break;
294 }
295 tilt = cmdline_double_arg();
296 optarg[len - 1] = ch;
297 } else {
298 tilt = cmdline_double_arg();
299 }
300 if (units == 'g') {
301 tilt *= 0.9;
302 } else if (units == '%') {
303 tilt = deg(atan(tilt * 0.01));
304 }
305 bit = EXPORT_3D;
306 break;
307 }
308 case OPT_PLAN:
309 tilt = -90.0;
310 bit = EXPORT_3D;
311 break;
312 case OPT_ELEV:
313 tilt = 0.0;
314 bit = EXPORT_3D;
315 break;
316 case 't': /* Text height */
317 text_height = cmdline_double_arg();
318 bit = TEXT_HEIGHT;
319 break;
320 case 'm': /* Marker size */
321 marker_size = cmdline_double_arg();
322 bit = MARKER_SIZE;
323 break;
324 case 's':
325 if (survey) {
326 if (!filter) {
327 filter = new SurveyFilter();
328 filter->add(survey);
329 }
330 filter->add(optarg);
331 } else {
332 survey = optarg;
333 }
334 break;
335 default:
336 if (opt >= OPT_FMT_BASE && opt < OPT_FMT_BASE + FMT_MAX_PLUS_ONE_) {
337 format = export_format(opt - OPT_FMT_BASE);
338 }
339 }
340 if (bit) {
341 show_mask |= bit;
342 int i = 0;
343 while (((bit >> i) & 1) == 0) ++i;
344
345 if (!optmap[i].empty()) optmap[i] += ' ';
346
347 // Reconstruct what the command line option was.
348 if (long_index < 0) {
349 optmap[i] += '-';
350 optmap[i] += char(opt);
351 if (optarg) {
352 if (optarg == argv[optind - 1]) {
353 optmap[i] += ' ';
354 }
355 optmap[i] += optarg;
356 }
357 } else {
358 optmap[i] += "--";
359 optmap[i] += long_opts[long_index].name;
360 if (optarg) {
361 if (optarg == argv[optind - 1]) {
362 optmap[i] += ' ';
363 } else {
364 optmap[i] += '=';
365 }
366 optmap[i] += optarg;
367 }
368 }
369 }
370 }
371
372 // A single --survey is handled by img at load-time. Multiple --survey are
373 // handled via a SurveyFilter at export time.
374 if (filter) survey = NULL;
375
376 const char* fnm_in = argv[optind++];
377 const char* fnm_out = argv[optind];
378 if (fnm_out) {
379 if (format == FMT_MAX_PLUS_ONE_) {
380 // Select format based on extension.
381 size_t len = strlen(fnm_out);
382 for (size_t i = 0; i < FMT_MAX_PLUS_ONE_; ++i) {
383 const auto& info = export_format_info[i];
384 size_t l = strlen(info.extension);
385 if (len > l + 1 &&
386 strcasecmp(fnm_out + len - l, info.extension) == 0) {
387 format = export_format(i);
388 break;
389 }
390 }
391 if (format == FMT_MAX_PLUS_ONE_) {
392 fatalerror(/*Export format not specified and not known from output file extension*/252);
393 }
394 }
395 } else {
396 if (format == FMT_MAX_PLUS_ONE_) {
397 fatalerror(/*Export format not specified*/253);
398 }
399 char *baseleaf = baseleaf_from_fnm(fnm_in);
400 /* note : memory allocated by fnm_out gets leaked in this case... */
401 fnm_out = add_ext(baseleaf, export_format_info[format].extension);
402 osfree(baseleaf);
403 }
404
405 const auto& format_info_mask = export_format_info[format].mask;
406 unsigned not_allowed = show_mask &~ format_info_mask;
407 if (not_allowed) {
408 printf("warning: The following options are not supported for this export format and will be ignored:\n");
409 int i = 0;
410 int bit = 1;
411 while (not_allowed) {
412 if (not_allowed & bit) {
413 // E.g. --walls maps to two bits in show_mask, but the options
414 // are only put on the least significant in such cases.
415 if (!optmap[i].empty())
416 printf("%s\n", optmap[i].c_str());
417 not_allowed &= ~bit;
418 }
419 ++i;
420 bit <<= 1;
421 }
422 show_mask &= format_info_mask;
423 }
424
425 if (always_include_defaults || show_mask == 0) {
426 show_mask |= export_format_info[format].defaults;
427 }
428
429 if (!(format_info_mask & EXPORT_3D)) {
430 pan = 0.0;
431 tilt = -90.0;
432 }
433
434 Model model;
435 int err = model.Load(fnm_in, survey);
436 if (err) fatalerror(err, fnm_in);
437 if (filter) filter->SetSeparator(model.GetSeparator());
438
439 try {
440 if (!Export(fnm_out, model.GetSurveyTitle(),
441 model.GetDateString(),
442 model, filter,
443 pan, tilt, show_mask, format,
444 grid, text_height, marker_size,
445 scale)) {
446 fatalerror(/*Couldn’t write file “%s”*/402, fnm_out);
447 }
448 } catch (const wxString & m) {
449 wxFprintf(stderr, wxT("%s: %s: %s\n"),
450 msg_appname(), wmsg(/*error*/93), m);
451 }
452
453 return 0;
454}
Note: See TracBrowser for help on using the repository browser.