source: git/src/cad3d.c @ caeff4a

RELEASE/1.2debug-cidebug-ci-sanitisersstereowalls-datawalls-data-hanging-as-warning
Last change on this file since caeff4a was caeff4a, checked in by Olly Betts <olly@…>, 11 years ago

src/cad3d.c: Make --marker-size work for Skencil and SVG output.

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