source: git/src/cad3d.c @ ecff0b8a

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

lib/codes.po,src/cad3d.c: Tweak wording of a message. Remove
"unused" messages which have actually just been adapted slightly,
add back a removed unused message, and mark an unused message as
unused.
`

git-svn-id: file:///home/survex-svn/survex/trunk@3748 4b37db11-9a0c-4f06-9ece-9ab7cdaee568

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