source: git/src/cad3d.c @ a72ed95

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

lib/survex.pot,src/: Add more TRANSLATOR comments.

  • Property mode set to 100644
File size: 25.8 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_catlen(&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_catlen(&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        /* TRANSLATORS: "Skencil" is the name of a software package, so should not be
671         * translated. */
672        {HLP_ENCODELONG(10),  /*produce Skencil output*/158, 0},
673        /* TRANSLATORS: "Compass" and "Carto" are the names of software packages,
674         * so should not be translated. */
675        {HLP_ENCODELONG(11),  /*produce Compass PLT output for Carto*/159, 0},
676        {HLP_ENCODELONG(12),  /*produce SVG output*/160, 0},
677        {0, 0, 0}
678   };
679
680   msg_init(argv);
681
682   /* Defaults */
683   crosses = 1;
684   labels = 1;
685   legs = 1;
686   grid = 0;
687   text_height = TEXT_HEIGHT;
688   marker_size = MARKER_SIZE;
689   format = FMT_AUTO;
690
691   cmdline_init(argc, argv, short_opts, long_opts, NULL, help, 1, 2);
692   while (1) {
693      int opt = cmdline_getopt();
694      if (opt == EOF) break;
695      switch (opt) {
696       case 'e': /* Elevation */
697         elevation = 1;
698         elev_angle = cmdline_double_arg();
699         break;
700       case 'c': /* Crosses */
701         crosses = 0;
702         break;
703       case 'n': /* Labels */
704         labels = 0;
705         break;
706       case 'l': /* Legs */
707         legs = 0;
708         break;
709       case 'g': /* Grid */
710         if (optarg) {
711            grid = cmdline_double_arg();
712         } else {
713            grid = (double)GRID_SPACING;
714         }
715         break;
716       case 'r': /* Reduction factor */
717         scale = cmdline_double_arg();
718         break;
719       case 't': /* Text height */
720         text_height = cmdline_double_arg();
721#ifdef DEBUG_CAD3D
722         printf("Text Height: “%s” input, converted to %6.2f\n", optarg, text_height);
723#endif
724         break;
725       case 'm': /* Marker size */
726         marker_size = cmdline_double_arg();
727#ifdef DEBUG_CAD3D
728         printf("Marker Size: “%s”, converted to %6.2f\n", optarg, marker_size);
729#endif
730         break;
731       case 'D':
732         format = FMT_DXF;
733         break;
734       case 'S':
735         format = FMT_SK;
736         break;
737       case 'P':
738         format = FMT_PLT;
739         break;
740       case 'V':
741         format = FMT_SVG;
742         break;
743       case 's':
744         survey = optarg;
745         break;
746#ifdef DEBUG_CAD3D
747       default:
748         printf("Internal Error: 'getopt' returned '%c' %d\n", opt, opt);
749#endif
750      }
751   }
752
753   fnm_3d = argv[optind++];
754   if (argv[optind]) {
755      fnm_out = argv[optind];
756      if (format == FMT_AUTO) {
757         size_t i;
758         size_t len = strlen(fnm_out);
759         format = FMT_DEFAULT;
760         for (i = 0; i < FMT_AUTO; ++i) {
761            size_t l = strlen(extensions[i]);
762            if (len > l + 1 && fnm_out[len - l - 1] == FNM_SEP_EXT &&
763                strcasecmp(fnm_out + len - l, extensions[i]) == 0) {
764               format = i;
765               break;
766            }
767         }
768      }
769   } else {
770      char *baseleaf = baseleaf_from_fnm(fnm_3d);
771      if (format == FMT_AUTO) format = FMT_DEFAULT;
772      /* note : memory allocated by fnm_out gets leaked in this case... */
773      fnm_out = add_ext(baseleaf, extensions[format]);
774      osfree(baseleaf);
775   }
776
777   switch (format) {
778    case FMT_DXF:
779      header = dxf_header;
780      start_pass = dxf_start_pass;
781      move = dxf_move;
782      line = dxf_line;
783      label = dxf_label;
784      cross = dxf_cross;
785      footer = dxf_footer;
786      pass = dxf_passes;
787      break;
788    case FMT_SK:
789      header = skencil_header;
790      start_pass = skencil_start_pass;
791      move = skencil_move;
792      line = skencil_line;
793      label = skencil_label;
794      cross = skencil_cross;
795      footer = skencil_footer;
796      pass = skencil_passes;
797      factor = POINTS_PER_MM * 1000.0 / scale;
798      mode = "wb"; /* Binary file output */
799      break;
800    case FMT_PLT:
801      header = plt_header;
802      start_pass = plt_start_pass;
803      move = plt_move;
804      line = plt_line;
805      label = plt_label;
806      cross = plt_cross;
807      footer = plt_footer;
808      pass = plt_passes;
809      mode = "wb"; /* Binary file output */
810      break;
811    case FMT_SVG:
812      header = svg_header;
813      start_pass = svg_start_pass;
814      move = svg_move;
815      line = svg_line;
816      label = svg_label;
817      cross = svg_cross;
818      footer = svg_footer;
819      pass = svg_passes;
820      factor = 1000.0 / scale;
821      mode = "wb"; /* Binary file output */
822      break;
823    default:
824      exit(1);
825   }
826
827   pimg = img_open_survey(fnm_3d, survey);
828   if (!pimg) fatalerror(img_error2msg(img_error()), fnm_3d);
829
830   fh = safe_fopen(fnm_out, mode);
831
832   if (elevation) {
833      s = sin(rad(elev_angle));
834      c = cos(rad(elev_angle));
835   }
836
837   /* Get drawing corners */
838   min_x = min_y = min_z = HUGE_VAL;
839   max_x = max_y = max_z = -HUGE_VAL;
840   do {
841      item = img_read_item(pimg, &p);
842
843      if (elevation) {
844         double xnew = p.x * c - p.y * s;
845         double znew = - p.x * s - p.y * c;
846         p.y = p.z;
847         p.z = znew;
848         p.x = xnew;
849      }
850
851      switch (item) {
852       case img_MOVE: case img_LINE: case img_LABEL:
853         if (p.x < min_x) min_x = p.x;
854         if (p.x > max_x) max_x = p.x;
855         if (p.y < min_y) min_y = p.y;
856         if (p.y > max_y) max_y = p.y;
857         if (p.z < min_z) min_z = p.z;
858         if (p.z > max_z) max_z = p.z;
859         break;
860      }
861   } while (item != img_STOP);
862
863   if (grid > 0) {
864      min_x -= grid / 2;
865      max_x += grid / 2;
866      min_y -= grid / 2;
867      max_y += grid / 2;
868   }
869
870   /* handle empty file gracefully */
871   if (min_x > max_x) {
872      min_x = min_y = min_z = 0;
873      max_x = max_y = max_z = 0;
874   }
875
876   /* Header */
877   header();
878
879   p1.x = p1.y = p1.z = 0; /* avoid compiler warning */
880
881   while (*pass) {
882      if (((*pass & LEGS) && legs) ||
883          ((*pass & STNS) && crosses) ||
884          ((*pass & LABELS) && labels)) {
885         if (!img_rewind(pimg)) {
886             fatalerror(img_error2msg(img_error()), fnm_3d);
887         }
888         start_pass(*pass);
889         do {
890            item = img_read_item(pimg, &p);
891
892            if (format == FMT_SK) {
893               p.x -= min_x;
894               p.y -= min_y;
895               p.z -= min_z;
896            }
897
898            if (elevation) {
899               double xnew = p.x * c - p.y * s;
900               double znew = - p.x * s - p.y * c;
901               p.y = p.z;
902               p.z = znew;
903               p.x = xnew;
904            }
905
906            switch (item) {
907             case img_BAD:
908               img_close(pimg);
909               fatalerror(/*Bad 3d image file “%s”*/106, fnm_3d);
910               break;
911             case img_LINE:
912#ifdef DEBUG_CAD3D
913               printf("line to %9.2f %9.2f %9.2f\n", p.x, p.y, p.z);
914#endif
915               if (!fSeenMove) {
916#ifdef DEBUG_CAD3D
917                  printf("Something is wrong -- img_LINE before any img_MOVE!\n");
918#endif
919                  img_close(pimg);
920                  fatalerror(/*Bad 3d image file “%s”*/106, fnm_3d);
921               }
922               if ((*pass & LEGS) && legs)
923                  line(&p1, &p, pimg->flags & img_FLAG_SURFACE);
924               p1 = p;
925               break;
926             case img_MOVE:
927#ifdef DEBUG_CAD3D
928               printf("move to %9.2f %9.2f %9.2f\n",x,y,z);
929#endif
930               if ((*pass & LEGS) && legs) move(&p);
931               fSeenMove = 1;
932               p1 = p;
933               break;
934             case img_LABEL:
935#ifdef DEBUG_CAD3D
936               printf("label “%s” at %9.2f %9.2f %9.2f\n",pimg->label,x,y,z);
937#endif
938               /* Use !UNDERGROUND as the criterion - we want stations where
939                * a surface and underground survey meet to be in the
940                * underground layer */
941               if ((*pass & LABELS) && labels)
942                  label(&p, pimg->label,
943                        !(pimg->flags & img_SFLAG_UNDERGROUND));
944               if ((*pass & STNS) && crosses)
945                  cross(&p, !(pimg->flags & img_SFLAG_UNDERGROUND));
946               break;
947#ifdef DEBUG_CAD3D
948             case img_STOP:
949               printf("stop\n");
950               break;
951             default:
952               printf("other info tag (code %d) ignored\n", item);
953#endif
954            }
955         } while (item != img_STOP);
956      }
957      pass++;
958   }
959   img_close(pimg);
960   footer();
961   safe_fclose(fh);
962   return 0;
963}
Note: See TracBrowser for help on using the repository browser.