source: git/src/cad3d.c @ 53496ab3

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

src/: Use cast to void rather than assignment to self to suppress
unused parameter warnings, as clang warns about the latter.

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