source: git/src/cad3d.c @ bd2e33a

RELEASE/1.2debug-cidebug-ci-sanitisersstereowalls-data
Last change on this file since bd2e33a was bd2e33a, checked in by Olly Betts <olly@…>, 10 years ago

src/: Make cad3d remap control characters and spaces in station
names when generating PLT output in the same way aven does.

  • Property mode set to 100644
File size: 25.6 KB
Line 
1/* cad3d.c
2 * Converts a .3d file to CAD-like formats (DXF, Skencil, SVG) and also Compass
3 * PLT.
4 *
5 * Also useful as an example of how to use the img code in your own programs
6 */
7
8/* Copyright (C) 1994-2004,2008,2010,2011,2013,2014 Olly Betts
9 * Copyright (C) 2004 John Pybus (SVG Output code)
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
15 *
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
24 */
25
26/* #define DEBUG_CAD3D */
27
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31
32#include <float.h>
33#include <math.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <string.h>
37
38#include "cmdline.h"
39#include "debug.h"
40#include "filename.h"
41#include "hash.h"
42#include "img_hosted.h"
43#include "message.h"
44#include "str.h"
45#include "useful.h"
46
47/* default values - can be overridden with --text-height and --marker-size
48 * respectively */
49#define TEXT_HEIGHT     0.6
50#define MARKER_SIZE     0.8
51
52#define GRID_SPACING    100
53
54#define POINTS_PER_INCH 72.0
55#define POINTS_PER_MM (POINTS_PER_INCH / MM_PER_INCH)
56
57#define SQRT_2          1.41421356237309504880168872420969
58
59#define LEGS 1
60#define STNS 2
61#define LABELS 4
62
63/* default to DXF */
64#define FMT_DEFAULT FMT_DXF
65
66static FILE *fh;
67
68/* bounds */
69static double min_x, min_y, min_z, max_x, max_y, max_z;
70
71static double text_height; /* for station labels */
72static double marker_size; /* for station markers */
73static double grid; /* grid spacing (or 0 for no grid) */
74static double scale = 500.0;
75static double factor;
76static const char *unit = "mm";
77
78static img *pimg;
79static const char *survey = NULL;
80
81static void
82dxf_header(void)
83{
84   fprintf(fh, "0\nSECTION\n"
85               "2\nHEADER\n");
86   fprintf(fh, "9\n$EXTMIN\n"); /* lower left corner of drawing */
87   fprintf(fh, "10\n%#-.6f\n", min_x); /* x */
88   fprintf(fh, "20\n%#-.6f\n", min_y); /* y */
89   fprintf(fh, "30\n%#-.6f\n", min_z); /* min z */
90   fprintf(fh, "9\n$EXTMAX\n"); /* upper right corner of drawing */
91   fprintf(fh, "10\n%#-.6f\n", max_x); /* x */
92   fprintf(fh, "20\n%#-.6f\n", max_y); /* y */
93   fprintf(fh, "30\n%#-.6f\n", max_z); /* max z */
94   fprintf(fh, "9\n$PDMODE\n70\n3\n"); /* marker style as CROSS */
95   fprintf(fh, "9\n$PDSIZE\n40\n%6.2f\n", marker_size); /* marker size */
96   fprintf(fh, "0\nENDSEC\n");
97
98   fprintf(fh, "0\nSECTION\n"
99               "2\nTABLES\n");
100   fprintf(fh, "0\nTABLE\n" /* Define CONTINUOUS and DASHED line types. */
101               "2\nLTYPE\n"
102               "70\n10\n"
103               "0\nLTYPE\n"
104               "2\nCONTINUOUS\n"
105               "70\n64\n"
106               "3\nContinuous\n"
107               "72\n65\n"
108               "73\n0\n"
109               "40\n0.0\n"
110               "0\nLTYPE\n"
111               "2\nDASHED\n"
112               "70\n64\n"
113               "3\nDashed\n"
114               "72\n65\n"
115               "73\n2\n"
116               "40\n2.5\n"
117               "49\n1.25\n"
118               "49\n-1.25\n"
119               "0\nENDTAB\n");
120   fprintf(fh, "0\nTABLE\n"
121               "2\nLAYER\n");
122   fprintf(fh, "70\n10\n"); /* max # off layers in this DXF file : 10 */
123   /* First Layer: CentreLine */
124   fprintf(fh, "0\nLAYER\n2\nCentreLine\n");
125   fprintf(fh, "70\n64\n"); /* shows layer is referenced by entities */
126   fprintf(fh, "62\n5\n"); /* color: kept the same used by SpeleoGen */
127   fprintf(fh, "6\nCONTINUOUS\n"); /* linetype */
128   /* Next Layer: Stations */
129   fprintf(fh, "0\nLAYER\n2\nStations\n");
130   fprintf(fh, "70\n64\n"); /* shows layer is referenced by entities */
131   fprintf(fh, "62\n7\n"); /* color: kept the same used by SpeleoGen */
132   fprintf(fh, "6\nCONTINUOUS\n"); /* linetype */
133   /* Next Layer: Labels */
134   fprintf(fh, "0\nLAYER\n2\nLabels\n");
135   fprintf(fh, "70\n64\n"); /* shows layer is referenced by entities */
136   fprintf(fh, "62\n7\n"); /* color: kept the same used by SpeleoGen */
137   fprintf(fh, "6\nCONTINUOUS\n"); /* linetype */
138   /* Next Layer: Surface */
139   fprintf(fh, "0\nLAYER\n2\nSurface\n");
140   fprintf(fh, "70\n64\n"); /* shows layer is referenced by entities */
141   fprintf(fh, "62\n5\n"); /* color */
142   fprintf(fh, "6\nDASHED\n"); /* linetype */
143   /* Next Layer: SurfaceStations */
144   fprintf(fh, "0\nLAYER\n2\nSurfaceStations\n");
145   fprintf(fh, "70\n64\n"); /* shows layer is referenced by entities */
146   fprintf(fh, "62\n7\n"); /* color */
147   fprintf(fh, "6\nCONTINUOUS\n"); /* linetype */
148   /* Next Layer: SurfaceLabels */
149   fprintf(fh, "0\nLAYER\n2\nSurfaceLabels\n");
150   fprintf(fh, "70\n64\n"); /* shows layer is referenced by entities */
151   fprintf(fh, "62\n7\n"); /* color */
152   fprintf(fh, "6\nCONTINUOUS\n"); /* linetype */
153   if (grid > 0) {
154      /* Next Layer: Grid */
155      fprintf(fh, "0\nLAYER\n2\nGrid\n");
156      fprintf(fh, "70\n64\n"); /* shows layer is referenced by entities */
157      fprintf(fh, "62\n7\n"); /* color: kept the same used by SpeleoGen */
158      fprintf(fh, "6\nCONTINUOUS\n"); /* linetype */
159   }
160   fprintf(fh, "0\nENDTAB\n"
161               "0\nENDSEC\n");
162
163   fprintf(fh, "0\nSECTION\n"
164               "2\nENTITIES\n");
165
166   if (grid > 0) {
167      double x, y;
168      x = floor(min_x / grid) * grid + grid;
169      y = floor(min_y / grid) * grid + grid;
170#ifdef DEBUG_CAD3D
171      printf("x_min: %f  y_min: %f\n", x, y);
172#endif
173      while (x < max_x) {
174         /* horizontal line */
175         fprintf(fh, "0\nLINE\n");
176         fprintf(fh, "8\nGrid\n"); /* Layer */
177         fprintf(fh, "10\n%6.2f\n", x);
178         fprintf(fh, "20\n%6.2f\n", min_y);
179         fprintf(fh, "30\n0\n");
180         fprintf(fh, "11\n%6.2f\n", x);
181         fprintf(fh, "21\n%6.2f\n", max_y);
182         fprintf(fh, "31\n0\n");
183         x += grid;
184      }
185      while (y < max_y) {
186         /* vertical line */
187         fprintf(fh, "0\nLINE\n");
188         fprintf(fh, "8\nGrid\n"); /* Layer */
189         fprintf(fh, "10\n%6.2f\n", min_x);
190         fprintf(fh, "20\n%6.2f\n", y);
191         fprintf(fh, "30\n0\n");
192         fprintf(fh, "11\n%6.2f\n", max_x);
193         fprintf(fh, "21\n%6.2f\n", y);
194         fprintf(fh, "31\n0\n");
195         y += grid;
196      }
197   }
198}
199
200static void
201dxf_start_pass(int layer)
202{
203   (void)layer;
204}
205
206static void
207dxf_move(const img_point *p)
208{
209   (void)p; /* unused */
210}
211
212static void
213dxf_line(const img_point *p1, const img_point *p, bool fSurface)
214{
215   fprintf(fh, "0\nLINE\n");
216   fprintf(fh, fSurface ? "8\nSurface\n" : "8\nCentreLine\n"); /* Layer */
217   fprintf(fh, "10\n%6.2f\n", p1->x);
218   fprintf(fh, "20\n%6.2f\n", p1->y);
219   fprintf(fh, "30\n%6.2f\n", p1->z);
220   fprintf(fh, "11\n%6.2f\n", p->x);
221   fprintf(fh, "21\n%6.2f\n", p->y);
222   fprintf(fh, "31\n%6.2f\n", p->z);
223}
224
225static void
226dxf_label(const img_point *p, const char *s, bool fSurface)
227{
228   /* write station label to dxf file */
229   fprintf(fh, "0\nTEXT\n");
230   fprintf(fh, fSurface ? "8\nSurfaceLabels\n" : "8\nLabels\n"); /* Layer */
231   fprintf(fh, "10\n%6.2f\n", p->x);
232   fprintf(fh, "20\n%6.2f\n", p->y);
233   fprintf(fh, "30\n%6.2f\n", p->z);
234   fprintf(fh, "40\n%6.2f\n", text_height);
235   fprintf(fh, "1\n%s\n", s);
236}
237
238static void
239dxf_cross(const img_point *p, bool fSurface)
240{
241   /* write station marker to dxf file */
242   fprintf(fh, "0\nPOINT\n");
243   fprintf(fh, fSurface ? "8\nSurfaceStations\n" : "8\nStations\n"); /* Layer */
244   fprintf(fh, "10\n%6.2f\n", p->x);
245   fprintf(fh, "20\n%6.2f\n", p->y);
246   fprintf(fh, "30\n%6.2f\n", p->z);
247}
248
249static void
250dxf_footer(void)
251{
252   fprintf(fh, "000\nENDSEC\n");
253   fprintf(fh, "000\nEOF\n");
254}
255
256static void
257skencil_header(void)
258{
259   fprintf(fh, "##Sketch 1 2\n"); /* File format version */
260   fprintf(fh, "document()\n");
261   fprintf(fh, "layout((%.3f,%.3f),0)\n",
262           (max_x - min_x) * factor, (max_y - min_y) * factor);
263}
264
265static const char *layer_names[] = {
266   NULL,
267   "Legs",
268   "Stations",
269   NULL,
270   "Labels"
271};
272
273static void
274skencil_start_pass(int layer)
275{
276   fprintf(fh, "layer('%s',1,1,0,0,(0,0,0))\n", layer_names[layer]);
277}
278
279static void
280skencil_move(const img_point *p)
281{
282   fprintf(fh, "b()\n");
283   fprintf(fh, "bs(%.3f,%.3f,%.3f)\n", p->x * factor, p->y * factor, 0.0);
284}
285
286static void
287skencil_line(const img_point *p1, const img_point *p, bool fSurface)
288{
289   (void)fSurface; /* unused */
290   (void)p1; /* unused */
291   fprintf(fh, "bs(%.3f,%.3f,%.3f)\n", p->x * factor, p->y * factor, 0.0);
292}
293
294static void
295skencil_label(const img_point *p, const char *s, bool fSurface)
296{
297   (void)fSurface; /* unused */
298   fprintf(fh, "fp((0,0,0))\n");
299   fprintf(fh, "le()\n");
300   fprintf(fh, "Fn('Times-Roman')\n");
301   fprintf(fh, "Fs(5)\n");
302   fprintf(fh, "txt('");
303   while (*s) {
304      int ch = *s++;
305      if (ch == '\'' || ch == '\\') PUTC('\\', fh);
306      PUTC(ch, fh);
307   }
308   fprintf(fh, "',(%.3f,%.3f))\n", p->x * factor, p->y * factor);
309}
310
311static void
312skencil_cross(const img_point *p, bool fSurface)
313{
314   (void)fSurface; /* unused */
315   fprintf(fh, "b()\n");
316   fprintf(fh, "bs(%.3f,%.3f,%.3f)\n",
317           p->x * factor - marker_size, p->y * factor - marker_size, 0.0);
318   fprintf(fh, "bs(%.3f,%.3f,%.3f)\n",
319           p->x * factor + marker_size, p->y * factor + marker_size, 0.0);
320   fprintf(fh, "bn()\n");
321   fprintf(fh, "bs(%.3f,%.3f,%.3f)\n",
322           p->x * factor + marker_size, p->y * factor - marker_size, 0.0);
323   fprintf(fh, "bs(%.3f,%.3f,%.3f)\n",
324           p->x * factor - marker_size, p->y * factor + marker_size, 0.0);
325}
326
327static void
328skencil_footer(void)
329{
330   fprintf(fh, "guidelayer('Guide Lines',1,0,0,1,(0,0,1))\n");
331   if (grid) {
332      fprintf(fh, "grid((0,0,%.3f,%.3f),1,(0,0,1),'Grid')\n",
333              grid * factor, grid * factor);
334   }
335}
336
337typedef struct point {
338   img_point p;
339   const char *label;
340   struct point *next;
341} point;
342
343#define HTAB_SIZE 0x2000
344
345static point **htab;
346
347static void
348set_name_(const img_point *p, const char *s, int copy)
349{
350   int hash;
351   point *pt;
352   union {
353      char data[sizeof(int) * 3];
354      int x[3];
355   } u;
356
357   u.x[0] = (int)(p->x * 100);
358   u.x[1] = (int)(p->y * 100);
359   u.x[2] = (int)(p->z * 100);
360   hash = (hash_data(u.data, sizeof(int) * 3) & (HTAB_SIZE - 1));
361   for (pt = htab[hash]; pt; pt = pt->next) {
362      if (pt->p.x == p->x && pt->p.y == p->y && pt->p.z == p->z) {
363         /* already got name for these coordinates */
364         /* FIXME: what about multiple names for the same station? */
365         if (!copy)
366            osfree((char*)s);
367         return;
368      }
369   }
370
371   pt = osnew(point);
372   if (copy)
373      s = osstrdup(s);
374   pt->label = s;
375   pt->p = *p;
376   pt->next = htab[hash];
377   htab[hash] = pt;
378}
379
380static void
381set_name(const img_point *p, const char *s)
382{
383   set_name_(p, s, 0);
384}
385
386static void
387set_name_copy(const img_point *p, const char *s)
388{
389   set_name_(p, s, 1);
390}
391
392static const char *
393find_name(const img_point *p)
394{
395   int hash;
396   point *pt;
397   union {
398      char data[sizeof(int) * 3];
399      int x[3];
400   } u;
401   SVX_ASSERT(p);
402
403   u.x[0] = (int)(p->x * 100);
404   u.x[1] = (int)(p->y * 100);
405   u.x[2] = (int)(p->z * 100);
406   hash = (hash_data(u.data, sizeof(int) * 3) & (HTAB_SIZE - 1));
407   for (pt = htab[hash]; pt; pt = pt->next) {
408      if (pt->p.x == p->x && pt->p.y == p->y && pt->p.z == p->z)
409         return pt->label;
410   }
411   return "?";
412}
413
414static bool to_close = 0;
415static bool close_g = 0;
416
417static void
418svg_header(void)
419{
420   size_t i;
421   htab = osmalloc(HTAB_SIZE * ossizeof(point *));
422   for (i = 0; i < HTAB_SIZE; ++i) htab[i] = NULL;
423   fprintf(fh, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
424   fprintf(fh, "<svg width=\"%.3f%s\" height=\"%.3f%s\""
425               " viewBox=\"0 0 %0.3f %0.3f\">\n",
426           (max_x - min_x) * factor, unit, (max_y - min_y) * factor, unit,
427           (max_x - min_x) * factor, (max_y - min_y) * factor );
428   fprintf(fh, "<g transform=\"translate(%.3f %.3f)\">\n",
429           min_x * -factor, max_y * factor);
430   to_close = 0;
431   close_g = 0;
432}
433
434static void
435svg_start_pass(int layer)
436{
437   if (to_close) {
438      fprintf(fh, "\"/>\n");
439      to_close = 0;
440   }
441   if (close_g) {
442      fprintf(fh, "</g>\n");
443   }
444   close_g = 1;
445
446   fprintf(fh, "<g id=\"%s\"", layer_names[layer]);
447   if (layer & LEGS)
448      fprintf(fh, " style=\"stroke:black;fill:none;stroke-width:0.4\"");
449   else if (layer & STNS)
450      fprintf(fh, " style=\"stroke:black;fill:none;stroke-width:0.05\"");
451   else if (layer & LABELS)
452      fprintf(fh, " style=\"font-size:%.3f\"", text_height);
453   fprintf(fh, ">\n");
454}
455
456static void
457svg_move(const img_point *p)
458{
459   if (to_close) {
460      fprintf(fh, "\"/>\n");
461   }
462   fprintf(fh, "<path d=\"M%.3f %.3f", p->x * factor, p->y * -factor);
463   to_close = 1;
464}
465
466static void
467svg_line(const img_point *p1, const img_point *p, bool fSurface)
468{
469   (void)fSurface; /* unused */
470   (void)p1; /* unused */
471   fprintf(fh, "L%.3f %.3f", p->x * factor, p->y * -factor);
472   to_close = 1;
473}
474
475static void
476svg_label(const img_point *p, const char *s, bool fSurface)
477{
478   (void)fSurface; /* unused */
479   fprintf(fh, "<text transform=\"translate(%.3f %.3f)\">",
480           p->x * factor, p->y * -factor);
481   fputs(s, fh);
482   fputs("</text>\n", fh);
483   set_name_copy(p, s);
484}
485
486static void
487svg_cross(const img_point *p, bool fSurface)
488{
489   (void)fSurface; /* unused */
490   fprintf(fh, "<circle id=\"%s\" cx=\"%.3f\" cy=\"%.3f\" r=\"%.3f\"/>\n",
491           find_name(p), p->x * factor, p->y * -factor, marker_size * SQRT_2);
492   fprintf(fh, "<path d=\"M%.3f %.3fL%.3f %.3fM%.3f %.3fL%.3f %.3f\"/>\n",
493           p->x * factor - marker_size, p->y * -factor - marker_size,
494           p->x * factor + marker_size, p->y * -factor + marker_size,
495           p->x * factor + marker_size, p->y * -factor - marker_size,
496           p->x * factor - marker_size, p->y * -factor + marker_size);
497}
498
499static void
500svg_footer(void)
501{
502   if (to_close) {
503      fprintf(fh, "\"/>\n");
504      to_close = 0;
505   }
506   if (close_g) {
507      fprintf(fh, "</g>\n");
508   }
509   close_g = 1;
510   fprintf(fh, "</g>\n</svg>");
511}
512
513static void
514plt_header(void)
515{
516   size_t i;
517   htab = osmalloc(HTAB_SIZE * ossizeof(point *));
518   for (i = 0; i < HTAB_SIZE; ++i) htab[i] = NULL;
519   /* Survex is E, N, Alt - PLT file is N, E, Alt */
520   fprintf(fh, "Z %.3f %.3f %.3f %.3f %.3f %.3f\r\n",
521           min_y / METRES_PER_FOOT, max_y / METRES_PER_FOOT,
522           min_x / METRES_PER_FOOT, max_x / METRES_PER_FOOT,
523           min_z / METRES_PER_FOOT, max_z / METRES_PER_FOOT);
524   fprintf(fh, "N%s D 1 1 1 C%s\r\n", survey ? survey : "X", pimg->title);
525}
526
527static void
528plt_start_pass(int layer)
529{
530   (void)layer;
531}
532
533static void
534plt_move(const img_point *p)
535{
536   /* Survex is E, N, Alt - PLT file is N, E, Alt */
537   fprintf(fh, "M %.3f %.3f %.3f ",
538           p->y / METRES_PER_FOOT, p->x / METRES_PER_FOOT, p->z / METRES_PER_FOOT);
539   /* dummy passage dimensions are required to avoid compass bug */
540   fprintf(fh, "S%s P -9 -9 -9 -9\r\n", find_name(p));
541}
542
543static void
544plt_line(const img_point *p1, const img_point *p, bool fSurface)
545{
546   (void)fSurface; /* unused */
547   (void)p1; /* unused */
548   /* Survex is E, N, Alt - PLT file is N, E, Alt */
549   fprintf(fh, "D %.3f %.3f %.3f ",
550           p->y / METRES_PER_FOOT, p->x / METRES_PER_FOOT, p->z / METRES_PER_FOOT);
551   /* dummy passage dimensions are required to avoid compass bug */
552   fprintf(fh, "S%s P -9 -9 -9 -9\r\n", find_name(p));
553}
554
555static void
556plt_label(const img_point *p, const char *s, bool fSurface)
557{
558   const char * q;
559   char * escaped = NULL;
560   int elen;
561   (void)fSurface; /* unused */
562   /* PLT format can't handle spaces or control characters, so escape them
563    * like in URLs (an arbitrary choice of escaping, but at least a familiar
564    * one and % isn't likely to occur in station names).
565    */
566   for (q = s; *q; ++q) {
567      unsigned char ch = *q;
568      if (ch <= ' ' || ch == '%') {
569         s_cat_len(&escaped, &elen, s, q - s);
570         s_catchar(&escaped, &elen, '%');
571         s_catchar(&escaped, &elen, "0123456789abcdef"[ch >> 4]);
572         s_catchar(&escaped, &elen, "0123456789abcdef"[ch & 0x0f]);
573         s = q + 1;
574      }
575   }
576   if (escaped) {
577      s_cat_len(&escaped, &elen, s, q - s);
578      set_name(p, escaped);
579      return;
580   }
581   set_name_copy(p, s);
582}
583
584static void
585plt_cross(const img_point *p, bool fSurface)
586{
587   (void)fSurface; /* unused */
588   (void)p; /* unused */
589}
590
591static void
592plt_footer(void)
593{
594   /* Survex is E, N, Alt - PLT file is N, E, Alt */
595   fprintf(fh, "X %.3f %.3f %.3f %.3f %.3f %.3f\r\n",
596           min_y / METRES_PER_FOOT, max_y / METRES_PER_FOOT,
597           min_x / METRES_PER_FOOT, max_x / METRES_PER_FOOT,
598           min_z / METRES_PER_FOOT, max_z / METRES_PER_FOOT);
599   /* Yucky DOS "end of textfile" marker */
600   PUTC('\x1a', fh);
601}
602
603static int dxf_passes[] = { LEGS|STNS|LABELS, 0 };
604static int skencil_passes[] = { LEGS, STNS, LABELS, 0 };
605static int plt_passes[] = { LABELS, LEGS, 0 };
606static int svg_passes[] = { LEGS, LABELS, STNS, 0 };
607
608int
609main(int argc, char **argv)
610{
611   char *fnm_3d, *fnm_out;
612   unsigned char labels, crosses, legs;
613   int item;
614   int fSeenMove = 0;
615   img_point p, p1;
616   int elevation = 0;
617   double elev_angle = 0;
618   double s = 0, c = 0;
619   enum { FMT_DXF = 0, FMT_SK, FMT_PLT, FMT_SVG, FMT_AUTO } format;
620   static const char *extensions[] = { "dxf", "sk", "plt", "svg" };
621   int *pass;
622
623   void (*header)(void);
624   void (*start_pass)(int);
625   void (*move)(const img_point *);
626   void (*line)(const img_point *, const img_point *, bool);
627   void (*label)(const img_point *, const char *, bool);
628   void (*cross)(const img_point *, bool);
629   void (*footer)(void);
630   const char *mode = "w"; /* default to text output */
631
632   /* TRANSLATE */
633   static const struct option long_opts[] = {
634        /* const char *name; int has_arg (0 no_argument, 1 required, 2 options_*); int *flag; int val */
635        {"survey", required_argument, 0, 's'},
636        {"no-crosses", no_argument, 0, 'c'},
637        {"no-station-names", no_argument, 0, 'n'},
638        {"no-legs", no_argument, 0, 'l'},
639        {"grid", optional_argument, 0, 'g'},
640        {"text-height", required_argument, 0, 't'},
641        {"marker-size", required_argument, 0, 'm'},
642        {"elevation", required_argument, 0, 'e'},
643        {"reduction", required_argument, 0, 'r'},
644        {"dxf", no_argument, 0, 'D'},
645        {"skencil", no_argument, 0, 'S'},
646        {"plt", no_argument, 0, 'P'},
647        {"svg", no_argument, 0, 'V'},
648        {"help", no_argument, 0, HLP_HELP},
649        {"version", no_argument, 0, HLP_VERSION},
650        /* Old name for --skencil: */
651        {"sketch", no_argument, 0, 'S'},
652        {0,0,0,0}
653   };
654
655#define short_opts "s:cnlg::t:m:e:r:DSPV"
656
657   /* TRANSLATE */
658   static struct help_msg help[] = {
659        /*                      <-- */
660        {HLP_ENCODELONG(0),   /*only load the sub-survey with this prefix*/199, 0},
661        {HLP_ENCODELONG(1),   /*do not generate station markers*/100, 0},
662        {HLP_ENCODELONG(2),   /*do not generate station labels*/101, 0},
663        {HLP_ENCODELONG(3),   /*do not generate survey legs*/102, 0},
664        {HLP_ENCODELONG(4),   /*generate grid (default %sm)*/148, STRING(GRID_SPACING)},
665        {HLP_ENCODELONG(5),   /*station labels text height (default %s)*/149, STRING(TEXT_HEIGHT)},
666        {HLP_ENCODELONG(6),   /*station marker size (default %s)*/152, STRING(MARKER_SIZE)},
667        {HLP_ENCODELONG(7),   /*produce an elevation view*/103, 0},
668        {HLP_ENCODELONG(8),   /*factor to scale down by (default %s)*/155, "500"},
669        {HLP_ENCODELONG(9),   /*produce DXF output*/156, 0},
670        {HLP_ENCODELONG(10),  /*produce Skencil output*/158, 0},
671        {HLP_ENCODELONG(11),  /*produce Compass PLT output for Carto*/159, 0},
672        {HLP_ENCODELONG(12),  /*produce SVG output*/160, 0},
673        {0, 0, 0}
674   };
675
676   msg_init(argv);
677
678   /* Defaults */
679   crosses = 1;
680   labels = 1;
681   legs = 1;
682   grid = 0;
683   text_height = TEXT_HEIGHT;
684   marker_size = MARKER_SIZE;
685   format = FMT_AUTO;
686
687   cmdline_init(argc, argv, short_opts, long_opts, NULL, help, 1, 2);
688   while (1) {
689      int opt = cmdline_getopt();
690      if (opt == EOF) break;
691      switch (opt) {
692       case 'e': /* Elevation */
693         elevation = 1;
694         elev_angle = cmdline_double_arg();
695         break;
696       case 'c': /* Crosses */
697         crosses = 0;
698         break;
699       case 'n': /* Labels */
700         labels = 0;
701         break;
702       case 'l': /* Legs */
703         legs = 0;
704         break;
705       case 'g': /* Grid */
706         if (optarg) {
707            grid = cmdline_double_arg();
708         } else {
709            grid = (double)GRID_SPACING;
710         }
711         break;
712       case 'r': /* Reduction factor */
713         scale = cmdline_double_arg();
714         break;
715       case 't': /* Text height */
716         text_height = cmdline_double_arg();
717#ifdef DEBUG_CAD3D
718         printf("Text Height: “%s” input, converted to %6.2f\n", optarg, text_height);
719#endif
720         break;
721       case 'm': /* Marker size */
722         marker_size = cmdline_double_arg();
723#ifdef DEBUG_CAD3D
724         printf("Marker Size: “%s”, converted to %6.2f\n", optarg, marker_size);
725#endif
726         break;
727       case 'D':
728         format = FMT_DXF;
729         break;
730       case 'S':
731         format = FMT_SK;
732         break;
733       case 'P':
734         format = FMT_PLT;
735         break;
736       case 'V':
737         format = FMT_SVG;
738         break;
739       case 's':
740         survey = optarg;
741         break;
742#ifdef DEBUG_CAD3D
743       default:
744         printf("Internal Error: 'getopt' returned '%c' %d\n", opt, opt);
745#endif
746      }
747   }
748
749   fnm_3d = argv[optind++];
750   if (argv[optind]) {
751      fnm_out = argv[optind];
752      if (format == FMT_AUTO) {
753         size_t i;
754         size_t len = strlen(fnm_out);
755         format = FMT_DEFAULT;
756         for (i = 0; i < FMT_AUTO; ++i) {
757            size_t l = strlen(extensions[i]);
758            if (len > l + 1 && fnm_out[len - l - 1] == FNM_SEP_EXT &&
759                strcasecmp(fnm_out + len - l, extensions[i]) == 0) {
760               format = i;
761               break;
762            }
763         }
764      }
765   } else {
766      char *baseleaf = baseleaf_from_fnm(fnm_3d);
767      if (format == FMT_AUTO) format = FMT_DEFAULT;
768      /* note : memory allocated by fnm_out gets leaked in this case... */
769      fnm_out = add_ext(baseleaf, extensions[format]);
770      osfree(baseleaf);
771   }
772
773   switch (format) {
774    case FMT_DXF:
775      header = dxf_header;
776      start_pass = dxf_start_pass;
777      move = dxf_move;
778      line = dxf_line;
779      label = dxf_label;
780      cross = dxf_cross;
781      footer = dxf_footer;
782      pass = dxf_passes;
783      break;
784    case FMT_SK:
785      header = skencil_header;
786      start_pass = skencil_start_pass;
787      move = skencil_move;
788      line = skencil_line;
789      label = skencil_label;
790      cross = skencil_cross;
791      footer = skencil_footer;
792      pass = skencil_passes;
793      factor = POINTS_PER_MM * 1000.0 / scale;
794      mode = "wb"; /* Binary file output */
795      break;
796    case FMT_PLT:
797      header = plt_header;
798      start_pass = plt_start_pass;
799      move = plt_move;
800      line = plt_line;
801      label = plt_label;
802      cross = plt_cross;
803      footer = plt_footer;
804      pass = plt_passes;
805      mode = "wb"; /* Binary file output */
806      break;
807    case FMT_SVG:
808      header = svg_header;
809      start_pass = svg_start_pass;
810      move = svg_move;
811      line = svg_line;
812      label = svg_label;
813      cross = svg_cross;
814      footer = svg_footer;
815      pass = svg_passes;
816      factor = 1000.0 / scale;
817      mode = "wb"; /* Binary file output */
818      break;
819    default:
820      exit(1);
821   }
822
823   pimg = img_open_survey(fnm_3d, survey);
824   if (!pimg) fatalerror(img_error2msg(img_error()), fnm_3d);
825
826   fh = safe_fopen(fnm_out, mode);
827
828   if (elevation) {
829      s = sin(rad(elev_angle));
830      c = cos(rad(elev_angle));
831   }
832
833   /* Get drawing corners */
834   min_x = min_y = min_z = HUGE_VAL;
835   max_x = max_y = max_z = -HUGE_VAL;
836   do {
837      item = img_read_item(pimg, &p);
838
839      if (elevation) {
840         double xnew = p.x * c - p.y * s;
841         double znew = - p.x * s - p.y * c;
842         p.y = p.z;
843         p.z = znew;
844         p.x = xnew;
845      }
846
847      switch (item) {
848       case img_MOVE: case img_LINE: case img_LABEL:
849         if (p.x < min_x) min_x = p.x;
850         if (p.x > max_x) max_x = p.x;
851         if (p.y < min_y) min_y = p.y;
852         if (p.y > max_y) max_y = p.y;
853         if (p.z < min_z) min_z = p.z;
854         if (p.z > max_z) max_z = p.z;
855         break;
856      }
857   } while (item != img_STOP);
858
859   if (grid > 0) {
860      min_x -= grid / 2;
861      max_x += grid / 2;
862      min_y -= grid / 2;
863      max_y += grid / 2;
864   }
865
866   /* handle empty file gracefully */
867   if (min_x > max_x) {
868      min_x = min_y = min_z = 0;
869      max_x = max_y = max_z = 0;
870   }
871
872   /* Header */
873   header();
874
875   p1.x = p1.y = p1.z = 0; /* avoid compiler warning */
876
877   while (*pass) {
878      if (((*pass & LEGS) && legs) ||
879          ((*pass & STNS) && crosses) ||
880          ((*pass & LABELS) && labels)) {
881         if (!img_rewind(pimg)) {
882             fatalerror(img_error2msg(img_error()), fnm_3d);
883         }
884         start_pass(*pass);
885         do {
886            item = img_read_item(pimg, &p);
887
888            if (format == FMT_SK) {
889               p.x -= min_x;
890               p.y -= min_y;
891               p.z -= min_z;
892            }
893
894            if (elevation) {
895               double xnew = p.x * c - p.y * s;
896               double znew = - p.x * s - p.y * c;
897               p.y = p.z;
898               p.z = znew;
899               p.x = xnew;
900            }
901
902            switch (item) {
903             case img_BAD:
904               img_close(pimg);
905               fatalerror(/*Bad 3d image file “%s”*/106, fnm_3d);
906               break;
907             case img_LINE:
908#ifdef DEBUG_CAD3D
909               printf("line to %9.2f %9.2f %9.2f\n", p.x, p.y, p.z);
910#endif
911               if (!fSeenMove) {
912#ifdef DEBUG_CAD3D
913                  printf("Something is wrong -- img_LINE before any img_MOVE!\n");
914#endif
915                  img_close(pimg);
916                  fatalerror(/*Bad 3d image file “%s”*/106, fnm_3d);
917               }
918               if ((*pass & LEGS) && legs)
919                  line(&p1, &p, pimg->flags & img_FLAG_SURFACE);
920               p1 = p;
921               break;
922             case img_MOVE:
923#ifdef DEBUG_CAD3D
924               printf("move to %9.2f %9.2f %9.2f\n",x,y,z);
925#endif
926               if ((*pass & LEGS) && legs) move(&p);
927               fSeenMove = 1;
928               p1 = p;
929               break;
930             case img_LABEL:
931#ifdef DEBUG_CAD3D
932               printf("label “%s” at %9.2f %9.2f %9.2f\n",pimg->label,x,y,z);
933#endif
934               /* Use !UNDERGROUND as the criterion - we want stations where
935                * a surface and underground survey meet to be in the
936                * underground layer */
937               if ((*pass & LABELS) && labels)
938                  label(&p, pimg->label,
939                        !(pimg->flags & img_SFLAG_UNDERGROUND));
940               if ((*pass & STNS) && crosses)
941                  cross(&p, !(pimg->flags & img_SFLAG_UNDERGROUND));
942               break;
943#ifdef DEBUG_CAD3D
944             case img_STOP:
945               printf("stop\n");
946               break;
947             default:
948               printf("other info tag (code %d) ignored\n",item);
949#endif
950            }
951         } while (item != img_STOP);
952      }
953      pass++;
954   }
955   img_close(pimg);
956   footer();
957   safe_fclose(fh);
958   return 0;
959}
Note: See TracBrowser for help on using the repository browser.