source: git/src/export.cc @ e7f613a

RELEASE/1.0
Last change on this file since e7f613a was b95ba56, checked in by Olly Betts <olly@…>, 14 years ago

Backport change from 1.1.13:
NEWS,src/cad3d.c,src/export.cc: Fix export to SVG when a label
contains a '%' character.

git-svn-id: file:///home/survex-svn/survex/branches/1.0@3459 4b37db11-9a0c-4f06-9ece-9ab7cdaee568

  • Property mode set to 100644
File size: 32.5 KB
Line 
1/* export.cc
2 * Export to CAD-like formats (DXF, Sketch, SVG, EPS) and also Compass PLT.
3 */
4
5/* Copyright (C) 1994-2004,2005,2008 Olly Betts
6 * Copyright (C) 2004 John Pybus (SVG Output code)
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21 */
22
23/* #define DEBUG_CAD3D */
24
25#ifdef HAVE_CONFIG_H
26#include <config.h>
27#endif
28
29#include "wx.h"
30#include <wx/utils.h>
31#include "mainfrm.h"
32
33#include <float.h>
34#include <math.h>
35#include <stdio.h>
36#include <stdlib.h>
37#include <string.h>
38
39#if defined(HAVE_GETPWUID) && !defined(__DJGPP__)
40# include <pwd.h>
41# include <sys/types.h>
42# include <unistd.h>
43#endif
44
45#include "cmdline.h"
46#include "debug.h"
47#include "filename.h"
48#include "hash.h"
49#include "img.h"
50#include "message.h"
51#include "useful.h"
52
53/* default values - can be overridden with --htext and --msize respectively */
54#define TEXT_HEIGHT     0.6
55#define MARKER_SIZE     0.8
56
57#define GRID_SPACING    100
58
59#define POINTS_PER_INCH 72.0
60#define POINTS_PER_MM (POINTS_PER_INCH / MM_PER_INCH)
61
62#define SQRT_2          1.41421356237309504880168872420969
63
64#define LEGS 1
65#define STNS 4
66#define LABELS 8
67
68/* default to DXF */
69#define FMT_DEFAULT FMT_DXF
70
71static FILE *fh;
72
73/* bounds */
74static double min_x, min_y, min_z, max_x, max_y, max_z;
75
76static double text_height; /* for station labels */
77static double marker_size; /* for station markers */
78static double grid; /* grid spacing (or 0 for no grid) */
79static double scale = 500.0;
80static double factor;
81static const char *unit = "mm";
82
83static const char *survey = NULL;
84
85static void
86dxf_header(const char *)
87{
88   fprintf(fh, "0\nSECTION\n"
89               "2\nHEADER\n");
90   fprintf(fh, "9\n$EXTMIN\n"); /* lower left corner of drawing */
91   fprintf(fh, "10\n%#-.6f\n", min_x); /* x */
92   fprintf(fh, "20\n%#-.6f\n", min_y); /* y */
93   fprintf(fh, "30\n%#-.6f\n", min_z); /* min z */
94   fprintf(fh, "9\n$EXTMAX\n"); /* upper right corner of drawing */
95   fprintf(fh, "10\n%#-.6f\n", max_x); /* x */
96   fprintf(fh, "20\n%#-.6f\n", max_y); /* y */
97   fprintf(fh, "30\n%#-.6f\n", max_z); /* max z */
98   fprintf(fh, "9\n$PDMODE\n70\n3\n"); /* marker style as CROSS */
99   fprintf(fh, "9\n$PDSIZE\n40\n%6.2f\n", marker_size); /* marker size */
100   fprintf(fh, "0\nENDSEC\n");
101
102   fprintf(fh, "0\nSECTION\n"
103               "2\nTABLES\n");
104   fprintf(fh, "0\nTABLE\n" /* Define CONTINUOUS and DASHED line types. */
105               "2\nLTYPE\n"
106               "70\n10\n"
107               "0\nLTYPE\n"
108               "2\nCONTINUOUS\n"
109               "70\n64\n"
110               "3\nContinuous\n"
111               "72\n65\n"
112               "73\n0\n"
113               "40\n0.0\n"
114               "0\nLTYPE\n"
115               "2\nDASHED\n"
116               "70\n64\n"
117               "3\nDashed\n"
118               "72\n65\n"
119               "73\n2\n"
120               "40\n2.5\n"
121               "49\n1.25\n"
122               "49\n-1.25\n"
123               "0\nENDTAB\n");
124   fprintf(fh, "0\nTABLE\n"
125               "2\nLAYER\n");
126   fprintf(fh, "70\n10\n"); /* max # off layers in this DXF file : 10 */
127   /* First Layer: CentreLine */
128   fprintf(fh, "0\nLAYER\n2\nCentreLine\n");
129   fprintf(fh, "70\n64\n"); /* shows layer is referenced by entities */
130   fprintf(fh, "62\n5\n"); /* color: kept the same used by SpeleoGen */
131   fprintf(fh, "6\nCONTINUOUS\n"); /* linetype */
132   /* Next Layer: Stations */
133   fprintf(fh, "0\nLAYER\n2\nStations\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: Labels */
138   fprintf(fh, "0\nLAYER\n2\nLabels\n");
139   fprintf(fh, "70\n64\n"); /* shows layer is referenced by entities */
140   fprintf(fh, "62\n7\n"); /* color: kept the same used by SpeleoGen */
141   fprintf(fh, "6\nCONTINUOUS\n"); /* linetype */
142   /* Next Layer: Surface */
143   fprintf(fh, "0\nLAYER\n2\nSurface\n");
144   fprintf(fh, "70\n64\n"); /* shows layer is referenced by entities */
145   fprintf(fh, "62\n5\n"); /* color */
146   fprintf(fh, "6\nDASHED\n"); /* linetype */
147   /* Next Layer: SurfaceStations */
148   fprintf(fh, "0\nLAYER\n2\nSurfaceStations\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   /* Next Layer: SurfaceLabels */
153   fprintf(fh, "0\nLAYER\n2\nSurfaceLabels\n");
154   fprintf(fh, "70\n64\n"); /* shows layer is referenced by entities */
155   fprintf(fh, "62\n7\n"); /* color */
156   fprintf(fh, "6\nCONTINUOUS\n"); /* linetype */
157   if (grid > 0) {
158      /* Next Layer: Grid */
159      fprintf(fh, "0\nLAYER\n2\nGrid\n");
160      fprintf(fh, "70\n64\n"); /* shows layer is referenced by entities */
161      fprintf(fh, "62\n7\n"); /* color: kept the same used by SpeleoGen */
162      fprintf(fh, "6\nCONTINUOUS\n"); /* linetype */
163   }
164   fprintf(fh, "0\nENDTAB\n"
165               "0\nENDSEC\n");
166
167   fprintf(fh, "0\nSECTION\n"
168               "2\nENTITIES\n");
169
170   if (grid > 0) {
171      double x, y;
172      x = floor(min_x / grid) * grid + grid;
173      y = floor(min_y / grid) * grid + grid;
174#ifdef DEBUG_CAD3D
175      printf("x_min: %f  y_min: %f\n", x, y);
176#endif
177      while (x < max_x) {
178         /* horizontal line */
179         fprintf(fh, "0\nLINE\n");
180         fprintf(fh, "8\nGrid\n"); /* Layer */
181         fprintf(fh, "10\n%6.2f\n", x);
182         fprintf(fh, "20\n%6.2f\n", min_y);
183         fprintf(fh, "30\n0\n");
184         fprintf(fh, "11\n%6.2f\n", x);
185         fprintf(fh, "21\n%6.2f\n", max_y);
186         fprintf(fh, "31\n0\n");
187         x += grid;
188      }
189      while (y < max_y) {
190         /* vertical line */
191         fprintf(fh, "0\nLINE\n");
192         fprintf(fh, "8\nGrid\n"); /* Layer */
193         fprintf(fh, "10\n%6.2f\n", min_x);
194         fprintf(fh, "20\n%6.2f\n", y);
195         fprintf(fh, "30\n0\n");
196         fprintf(fh, "11\n%6.2f\n", max_x);
197         fprintf(fh, "21\n%6.2f\n", y);
198         fprintf(fh, "31\n0\n");
199         y += grid;
200      }
201   }
202}
203
204static void
205dxf_start_pass(int layer)
206{
207   layer = layer;
208}
209
210static void
211dxf_line(const img_point *p1, const img_point *p, bool fSurface, bool fPendingMove)
212{
213   fPendingMove = fPendingMove; /* unused */
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
256sketch_header(const char *)
257{
258   fprintf(fh, "##Sketch 1 2\n"); /* Sketch file 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
273sketch_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
279sketch_line(const img_point *p1, const img_point *p, bool fSurface, bool fPendingMove)
280{
281   fSurface = fSurface; /* unused */
282   if (fPendingMove) {
283       fprintf(fh, "b()\n");
284       fprintf(fh, "bs(%.3f,%.3f,%.3f)\n", p1->x * factor, p1->y * factor, 0.0);
285   }
286   fprintf(fh, "bs(%.3f,%.3f,%.3f)\n", p->x * factor, p->y * factor, 0.0);
287}
288
289static void
290sketch_label(const img_point *p, const char *s, bool fSurface)
291{
292   fSurface = fSurface; /* unused */
293   fprintf(fh, "fp((0,0,0))\n");
294   fprintf(fh, "le()\n");
295   fprintf(fh, "Fn('Times-Roman')\n");
296   fprintf(fh, "Fs(5)\n");
297   fprintf(fh, "txt('");
298   while (*s) {
299      int ch = *s++;
300      if (ch == '\'' || ch == '\\') putc('\\', fh);
301      putc(ch, fh);
302   }
303   fprintf(fh, "',(%.3f,%.3f))\n", p->x * factor, p->y * factor);
304}
305
306static void
307sketch_cross(const img_point *p, bool fSurface)
308{
309   fSurface = fSurface; /* unused */
310   fprintf(fh, "b()\n");
311   fprintf(fh, "bs(%.3f,%.3f,%.3f)\n",
312           p->x * factor - MARKER_SIZE, p->y * factor - MARKER_SIZE, 0.0);
313   fprintf(fh, "bs(%.3f,%.3f,%.3f)\n",
314           p->x * factor + MARKER_SIZE, p->y * factor + MARKER_SIZE, 0.0);
315   fprintf(fh, "bn()\n");
316   fprintf(fh, "bs(%.3f,%.3f,%.3f)\n",
317           p->x * factor + MARKER_SIZE, p->y * factor - MARKER_SIZE, 0.0);
318   fprintf(fh, "bs(%.3f,%.3f,%.3f)\n",
319           p->x * factor - MARKER_SIZE, p->y * factor + MARKER_SIZE, 0.0);
320}
321
322static void
323sketch_footer(void)
324{
325   fprintf(fh, "guidelayer('Guide Lines',1,0,0,1,(0,0,1))\n");
326   if (grid) {
327      fprintf(fh, "grid((0,0,%.3f,%.3f),1,(0,0,1),'Grid')\n",
328              grid * factor, grid * factor);
329   }
330}
331
332typedef struct point {
333   img_point p;
334   const char *label;
335   struct point *next;
336} point;
337
338#define HTAB_SIZE 0x2000
339
340static point **htab;
341
342static void
343set_name(const img_point *p, const char *s)
344{
345   int hash;
346   point *pt;
347   union {
348      char data[sizeof(int) * 3];
349      int x[3];
350   } u;
351
352   u.x[0] = (int)(p->x * 100);
353   u.x[1] = (int)(p->y * 100);
354   u.x[2] = (int)(p->z * 100);
355   hash = (hash_data(u.data, sizeof(int) * 3) & (HTAB_SIZE - 1));
356   for (pt = htab[hash]; pt; pt = pt->next) {
357      if (pt->p.x == p->x && pt->p.y == p->y && pt->p.z == p->z) {
358         /* already got name for these coordinates */
359         /* FIXME: what about multiple names for the same station? */
360         return;
361      }
362   }
363
364   pt = osnew(point);
365   pt->label = osstrdup(s);
366   pt->p = *p;
367   pt->next = htab[hash];
368   htab[hash] = pt;
369
370   return;
371}
372
373static const char *
374find_name(const img_point *p)
375{
376   int hash;
377   point *pt;
378   union {
379      char data[sizeof(int) * 3];
380      int x[3];
381   } u;
382   SVX_ASSERT(p);
383
384   u.x[0] = (int)(p->x * 100);
385   u.x[1] = (int)(p->y * 100);
386   u.x[2] = (int)(p->z * 100);
387   hash = (hash_data(u.data, sizeof(int) * 3) & (HTAB_SIZE - 1));
388   for (pt = htab[hash]; pt; pt = pt->next) {
389      if (pt->p.x == p->x && pt->p.y == p->y && pt->p.z == p->z)
390         return pt->label;
391   }
392   return "?";
393}
394
395static bool to_close = 0;
396static bool close_g = 0;
397
398static void
399svg_header(const char *)
400{
401   size_t i;
402   htab = (point **)osmalloc(HTAB_SIZE * ossizeof(point *));
403   for (i = 0; i < HTAB_SIZE; ++i) htab[i] = NULL;
404   fprintf(fh, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
405   fprintf(fh, "<svg width=\"%.3f%s\" height=\"%.3f%s\""
406               " viewBox=\"0 0 %0.3f %0.3f\">\n",
407           (max_x - min_x) * factor, unit, (max_y - min_y) * factor, unit,
408           (max_x - min_x) * factor, (max_y - min_y) * factor );
409   fprintf(fh, "<g transform=\"translate(%.3f %.3f)\">\n",
410           min_x * -factor, max_y * factor);
411   to_close = 0;
412   close_g = 0;
413}
414
415static void
416svg_start_pass(int layer)
417{
418   if (to_close) {
419      fprintf(fh, "\"/>\n");
420      to_close = 0;
421   }
422   if (close_g) {
423      fprintf(fh, "</g>\n");
424   }
425   close_g = 1;
426
427   fprintf(fh, "<g id=\"%s\"", layer_names[layer]);
428   if (layer & LEGS)
429      fprintf(fh, " style=\"stroke:black;fill:none;stroke-width:0.4\"");
430   else if (layer & STNS)
431      fprintf(fh, " style=\"stroke:black;fill:none;stroke-width:0.05\"");
432   else if (layer & LABELS)
433      fprintf(fh, " style=\"font-size:%.3f\"", text_height);
434   fprintf(fh, ">\n");
435}
436
437static void
438svg_line(const img_point *p1, const img_point *p, bool fSurface, bool fPendingMove)
439{
440   fSurface = fSurface; /* unused */
441   if (fPendingMove) {
442       if (to_close) {
443           fprintf(fh, "\"/>\n");
444       }
445       fprintf(fh, "<path d=\"M%.3f %.3f", p1->x * factor, p1->y * -factor);
446   }
447   fprintf(fh, "L%.3f %.3f", p->x * factor, p->y * -factor);
448   to_close = 1;
449}
450
451static void
452svg_label(const img_point *p, const char *s, bool fSurface)
453{
454   fSurface = fSurface; /* unused */
455   fprintf(fh, "<text transform=\"translate(%.3f %.3f)\">",
456           p->x * factor, p->y * -factor);
457   fputs(s, fh);
458   fputs("</text>\n", fh);
459   set_name(p, s);
460}
461
462static void
463svg_cross(const img_point *p, bool fSurface)
464{
465   fSurface = fSurface; /* unused */
466   fprintf(fh, "<circle id=\"%s\" cx=\"%.3f\" cy=\"%.3f\" r=\"%.3f\"/>\n",
467           find_name(p), p->x * factor, p->y * -factor, MARKER_SIZE * SQRT_2);
468   fprintf(fh, "<path d=\"M%.3f %.3fL%.3f %.3fM%.3f %.3fL%.3f %.3f\"/>\n",
469           p->x * factor - MARKER_SIZE, p->y * -factor - MARKER_SIZE,
470           p->x * factor + MARKER_SIZE, p->y * -factor + MARKER_SIZE,
471           p->x * factor + MARKER_SIZE, p->y * -factor - MARKER_SIZE,
472           p->x * factor - MARKER_SIZE, p->y * -factor + MARKER_SIZE );
473}
474
475static void
476svg_footer(void)
477{
478   if (to_close) {
479      fprintf(fh, "\"/>\n");
480      to_close = 0;
481   }
482   if (close_g) {
483      fprintf(fh, "</g>\n");
484   }
485   close_g = 1;
486   fprintf(fh, "</g>\n</svg>");
487}
488
489static void
490plt_header(const char *title)
491{
492   size_t i;
493   htab = (point **)osmalloc(HTAB_SIZE * ossizeof(point *));
494   for (i = 0; i < HTAB_SIZE; ++i) htab[i] = NULL;
495   /* Survex is E, N, Alt - PLT file is N, E, Alt */
496   fprintf(fh, "Z %.3f %.3f %.3f %.3f %.3f %.3f\r\n",
497           min_y / METRES_PER_FOOT, max_y / METRES_PER_FOOT,
498           min_x / METRES_PER_FOOT, max_x / METRES_PER_FOOT,
499           min_z / METRES_PER_FOOT, max_z / METRES_PER_FOOT);
500   fprintf(fh, "N%s D 1 1 1 C%s\r\n", survey ? survey : "X",
501           (title && title[0]) ? title : "X");
502}
503
504static void
505plt_start_pass(int layer)
506{
507   layer = layer;
508}
509
510static void
511plt_line(const img_point *p1, const img_point *p, bool fSurface, bool fPendingMove)
512{
513   fSurface = fSurface; /* unused */
514   if (fPendingMove) {
515       /* Survex is E, N, Alt - PLT file is N, E, Alt */
516       fprintf(fh, "M %.3f %.3f %.3f ",
517               p1->y / METRES_PER_FOOT, p1->x / METRES_PER_FOOT, p1->z / METRES_PER_FOOT);
518       /* dummy passage dimensions are required to avoid compass bug */
519       fprintf(fh, "S%s P -9 -9 -9 -9\r\n", find_name(p1));
520   }
521   /* Survex is E, N, Alt - PLT file is N, E, Alt */
522   fprintf(fh, "D %.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_label(const img_point *p, const char *s, bool fSurface)
530{
531   fSurface = fSurface; /* unused */
532   /* FIXME: also ctrl characters - ought to remap them, not give up */
533   if (strchr(s, ' ')) {
534      fprintf(stderr, "PLT format can't cope with spaces in station names\n");
535      exit(1);
536   }
537   set_name(p, s);
538}
539
540static void
541plt_cross(const img_point *p, bool fSurface)
542{
543   fSurface = fSurface; /* unused */
544   p = p; /* unused */
545}
546
547static void
548plt_footer(void)
549{
550   /* Survex is E, N, Alt - PLT file is N, E, Alt */
551   fprintf(fh, "X %.3f %.3f %.3f %.3f %.3f %.3f\r\n",
552           min_y / METRES_PER_FOOT, max_y / METRES_PER_FOOT,
553           min_x / METRES_PER_FOOT, max_x / METRES_PER_FOOT,
554           min_z / METRES_PER_FOOT, max_z / METRES_PER_FOOT);
555   /* Yucky DOS "end of textfile" marker */
556   putc('\x1a', fh);
557}
558
559static void
560eps_header(const char *title)
561{
562   const char * fontname_labels = "helvetica"; // FIXME
563   int fontsize_labels = 10; // FIXME
564   fputs("%!PS-Adobe-2.0 EPSF-1.2\n", fh);
565   fputs("%%Creator: Survex "VERSION" EPS Output Filter\n", fh);
566
567   if (title && title[0]) fprintf(fh, "%%%%Title: %s\n", title);
568
569   char buf[64];
570   time_t now = time(NULL);
571   if (strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %Z\n", localtime(&now))) {
572      fputs("%%CreationDate: ", fh);
573      fputs(buf, fh);
574   }
575
576   wxString name;
577#if defined(HAVE_GETPWUID) && !defined(__DJGPP__)
578   struct passwd * ent = getpwuid(getuid());
579   if (ent && ent->pw_gecos[0]) name = ent->pw_gecos;
580#endif
581   if (name.empty()) {
582       name = ::wxGetUserName();
583       if (name.empty()) {
584           name = ::wxGetUserId();
585       }
586   }
587   if (name) {
588      fprintf(fh, "%%%%For: %s\n", name.c_str());
589   }
590
591   fprintf(fh, "%%%%BoundingBox: %d %d %d %d\n",
592           int(floor(min_x * factor)), int(floor(min_y * factor)),
593           int(ceil(max_x * factor)), int(ceil(max_y * factor)));
594   fprintf(fh, "%%%%HiResBoundingBox: %.4f %.4f %.4f %.4f\n",
595           min_x * factor, min_y * factor, max_x * factor, max_y * factor);
596   fputs("%%LanguageLevel: 1\n"
597         "%%PageOrder: Ascend\n"
598         "%%Pages: 1\n"
599         "%%Orientation: Portrait\n", fh);
600
601   fprintf(fh, "%%%%DocumentFonts: %s\n", fontname_labels);
602
603   fputs("%%EndComments\n"
604         "%%Page 1 1\n"
605         "save countdictstack mark\n", fh);
606
607   /* this code adapted from a2ps */
608   fputs("%%BeginResource: encoding ISO88591Encoding\n"
609         "/ISO88591Encoding [\n", fh);
610   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
611   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
612   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
613   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
614   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
615   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
616   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
617   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
618   fputs(
619"/space /exclam /quotedbl /numbersign\n"
620"/dollar /percent /ampersand /quoteright\n"
621"/parenleft /parenright /asterisk /plus\n"
622"/comma /minus /period /slash\n"
623"/zero /one /two /three\n"
624"/four /five /six /seven\n"
625"/eight /nine /colon /semicolon\n"
626"/less /equal /greater /question\n"
627"/at /A /B /C /D /E /F /G\n"
628"/H /I /J /K /L /M /N /O\n"
629"/P /Q /R /S /T /U /V /W\n"
630"/X /Y /Z /bracketleft\n"
631"/backslash /bracketright /asciicircum /underscore\n"
632"/quoteleft /a /b /c /d /e /f /g\n"
633"/h /i /j /k /l /m /n /o\n"
634"/p /q /r /s /t /u /v /w\n"
635"/x /y /z /braceleft\n"
636"/bar /braceright /asciitilde /.notdef\n", fh);
637   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
638   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
639   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
640   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
641   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
642   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
643   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
644   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
645   fputs(
646"/space /exclamdown /cent /sterling\n"
647"/currency /yen /brokenbar /section\n"
648"/dieresis /copyright /ordfeminine /guillemotleft\n"
649"/logicalnot /hyphen /registered /macron\n"
650"/degree /plusminus /twosuperior /threesuperior\n"
651"/acute /mu /paragraph /bullet\n"
652"/cedilla /onesuperior /ordmasculine /guillemotright\n"
653"/onequarter /onehalf /threequarters /questiondown\n"
654"/Agrave /Aacute /Acircumflex /Atilde\n"
655"/Adieresis /Aring /AE /Ccedilla\n"
656"/Egrave /Eacute /Ecircumflex /Edieresis\n"
657"/Igrave /Iacute /Icircumflex /Idieresis\n"
658"/Eth /Ntilde /Ograve /Oacute\n"
659"/Ocircumflex /Otilde /Odieresis /multiply\n"
660"/Oslash /Ugrave /Uacute /Ucircumflex\n"
661"/Udieresis /Yacute /Thorn /germandbls\n"
662"/agrave /aacute /acircumflex /atilde\n"
663"/adieresis /aring /ae /ccedilla\n"
664"/egrave /eacute /ecircumflex /edieresis\n"
665"/igrave /iacute /icircumflex /idieresis\n"
666"/eth /ntilde /ograve /oacute\n"
667"/ocircumflex /otilde /odieresis /divide\n"
668"/oslash /ugrave /uacute /ucircumflex\n"
669"/udieresis /yacute /thorn /ydieresis\n"
670"] def\n"
671"%%EndResource\n", fh);
672
673   /* this code adapted from a2ps */
674   fputs(
675"/reencode {\n" /* def */
676"dup length 5 add dict begin\n"
677"{\n" /* forall */
678"1 index /FID ne\n"
679"{ def }{ pop pop } ifelse\n"
680"} forall\n"
681"/Encoding exch def\n"
682
683/* Use the font's bounding box to determine the ascent, descent,
684 * and overall height; don't forget that these values have to be
685 * transformed using the font's matrix.
686 * We use `load' because sometimes BBox is executable, sometimes not.
687 * Since we need 4 numbers and not an array avoid BBox from being executed
688 */
689"/FontBBox load aload pop\n"
690"FontMatrix transform /Ascent exch def pop\n"
691"FontMatrix transform /Descent exch def pop\n"
692"/FontHeight Ascent Descent sub def\n"
693
694/* Define these in case they're not in the FontInfo (also, here
695 * they're easier to get to.
696 */
697"/UnderlinePosition 1 def\n"
698"/UnderlineThickness 1 def\n"
699
700/* Get the underline position and thickness if they're defined. */
701"currentdict /FontInfo known {\n"
702"FontInfo\n"
703
704"dup /UnderlinePosition known {\n"
705"dup /UnderlinePosition get\n"
706"0 exch FontMatrix transform exch pop\n"
707"/UnderlinePosition exch def\n"
708"} if\n"
709
710"dup /UnderlineThickness known {\n"
711"/UnderlineThickness get\n"
712"0 exch FontMatrix transform exch pop\n"
713"/UnderlineThickness exch def\n"
714"} if\n"
715
716"} if\n"
717"currentdict\n"
718"end\n"
719"} bind def\n", fh);
720
721   fprintf(fh, "/lab ISO88591Encoding /%s findfont reencode definefont pop\n",
722           fontname_labels);
723
724   fprintf(fh, "/lab findfont %d scalefont setfont\n", int(fontsize_labels));
725
726   fprintf(fh, "0.1 setlinewidth\n");
727
728#if 0
729   /* C<digit> changes colour */
730   /* FIXME: read from ini */
731   {
732      size_t i;
733      for (i = 0; i < sizeof(colour) / sizeof(colour[0]); ++i) {
734         fprintf(fh, "/C%u {stroke %.3f %.3f %.3f setrgbcolor} def\n", i,
735                 (double)(colour[i] & 0xff0000) / 0xff0000,
736                 (double)(colour[i] & 0xff00) / 0xff00,
737                 (double)(colour[i] & 0xff) / 0xff);
738      }
739   }
740   fputs("C0\n", fh);
741#endif
742
743   /* Postscript definition for drawing a cross */
744   fprintf(fh, "/X {stroke moveto %.2f %.2f rmoveto %.2f %.2f rlineto "
745           "%.2f 0 rmoveto %.2f %.2f rlineto %.2f %.2f rmoveto} def\n",
746           -marker_size, -marker_size,  marker_size * 2, marker_size * 2,
747           -marker_size * 2,  marker_size * 2, -marker_size * 2,
748           -marker_size, marker_size );
749
750   /* define some functions to keep file short */
751   fputs("/M {stroke moveto} def\n"
752         "/L {lineto} def\n"
753/*       "/R {rlineto} def\n" */
754         "/S {show} def\n", fh);
755
756   fprintf(fh, "gsave %.8f dup scale\n", factor);
757#if 0
758   if (grid > 0) {
759      double x, y;
760      x = floor(min_x / grid) * grid + grid;
761      y = floor(min_y / grid) * grid + grid;
762#ifdef DEBUG_CAD3D
763      printf("x_min: %f  y_min: %f\n", x, y);
764#endif
765      while (x < max_x) {
766         /* horizontal line */
767         fprintf(fh, "0\nLINE\n");
768         fprintf(fh, "8\nGrid\n"); /* Layer */
769         fprintf(fh, "10\n%6.2f\n", x);
770         fprintf(fh, "20\n%6.2f\n", min_y);
771         fprintf(fh, "30\n0\n");
772         fprintf(fh, "11\n%6.2f\n", x);
773         fprintf(fh, "21\n%6.2f\n", max_y);
774         fprintf(fh, "31\n0\n");
775         x += grid;
776      }
777      while (y < max_y) {
778         /* vertical line */
779         fprintf(fh, "0\nLINE\n");
780         fprintf(fh, "8\nGrid\n"); /* Layer */
781         fprintf(fh, "10\n%6.2f\n", min_x);
782         fprintf(fh, "20\n%6.2f\n", y);
783         fprintf(fh, "30\n0\n");
784         fprintf(fh, "11\n%6.2f\n", max_x);
785         fprintf(fh, "21\n%6.2f\n", y);
786         fprintf(fh, "31\n0\n");
787         y += grid;
788      }
789   }
790#endif
791}
792
793static void
794eps_start_pass(int layer)
795{
796   layer = layer;
797}
798
799static void
800eps_line(const img_point *p1, const img_point *p, bool fSurface, bool fPendingMove)
801{
802   fSurface = fSurface; /* unused */
803   if (fPendingMove) {
804       fprintf(fh, "%.2f %.2f M\n", p1->x, p1->y);
805   }
806   fprintf(fh, "%.2f %.2f L\n", p->x, p->y);
807}
808
809static void
810eps_label(const img_point *p, const char *s, bool fSurface)
811{
812   fprintf(fh, "%.2f %.2f M\n", p->x, p->y);
813   putc('(', fh);
814   while (*s) {
815       unsigned char ch = *s++;
816       switch (ch) {
817           case '(': case ')': case '\\': /* need to escape these characters */
818               putc('\\', fh);
819               putc(ch, fh);
820               break;
821           default:
822               putc(ch, fh);
823               break;
824       }
825   }
826   fputs(") S\n", fh);
827}
828
829static void
830eps_cross(const img_point *p, bool fSurface)
831{
832   fSurface = fSurface; /* unused */
833   fprintf(fh, "%.2f %.2f X\n", p->x, p->y);
834}
835
836static void
837eps_footer(void)
838{
839   fputs("stroke showpage grestore\n"
840         "%%Trailer\n"
841         "cleartomark countdictstack exch sub { end } repeat restore\n"
842         "%%EOF\n", fh);
843}
844
845static int dxf_passes[] = { LEGS|STNS|LABELS, 0 };
846static int sketch_passes[] = { LEGS, STNS, LABELS, 0 };
847static int plt_passes[] = { LABELS, LEGS, 0 };
848static int svg_passes[] = { LEGS, LABELS, STNS, 0 };
849static int eps_passes[] = { LEGS|STNS|LABELS, 0 };
850
851typedef enum {
852    FMT_DXF = 0, FMT_SVG, FMT_SKETCH, FMT_PLT, FMT_EPS, FMT_ENDMARKER
853} export_format;
854static const char *extensions[] = { "dxf", "svg", "sk", "plt", "eps" };
855
856bool
857Export(const wxString &fnm_out, const wxString &title, const MainFrm * mainfrm,
858       double pan, double tilt, bool labels, bool crosses, bool legs,
859       bool surface)
860{
861   int fSeenMove = 0;
862   int fPendingMove = 0;
863   img_point p, p1;
864   double s = 0, c = 0;
865   export_format format = FMT_DXF;
866   int *pass;
867   bool elevation = (tilt == 90.0);
868   double elev_angle = pan;
869
870   void (*header)(const char *);
871   void (*start_pass)(int);
872   void (*line)(const img_point *, const img_point *, bool, bool);
873   void (*label)(const img_point *, const char *, bool);
874   void (*cross)(const img_point *, bool);
875   void (*footer)(void);
876   const char *mode = "w"; /* default to text output */
877
878   /* Defaults */
879   grid = 0;
880   text_height = TEXT_HEIGHT;
881   marker_size = MARKER_SIZE;
882#if 0
883   cmdline_init(argc, argv, short_opts, long_opts, NULL, help, 1, 2);
884   while (1) {
885      int opt = cmdline_getopt();
886      if (opt == EOF) break;
887      switch (opt) {
888       case 'e': /* Elevation */
889         elevation = 1;
890         elev_angle = cmdline_double_arg();
891         break;
892       case 'c': /* Crosses */
893         crosses = 0;
894         break;
895       case 'n': /* Labels */
896         labels = 0;
897         break;
898       case 'l': /* Legs */
899         legs = 0;
900         break;
901       case 'g': /* Grid */
902         if (optarg) {
903            grid = cmdline_double_arg();
904         } else {
905            grid = (double)GRID_SPACING;
906         }
907         break;
908       case 'r': /* Reduction factor */
909         scale = cmdline_double_arg();
910         break;
911       case 't': /* Text height */
912         text_height = cmdline_double_arg();
913#ifdef DEBUG_CAD3D
914         printf("Text Height: `%s' input, converted to %6.2f\n", optarg, text_height);
915#endif
916         break;
917       case 'm': /* Marker size */
918         marker_size = cmdline_double_arg();
919#ifdef DEBUG_CAD3D
920         printf("Marker Size: `%s', converted to %6.2f\n", optarg, marker_size);
921#endif
922         break;
923       case 'D':
924         format = FMT_DXF;
925         break;
926       case 'S':
927         format = FMT_SKETCH;
928         break;
929       case 'P':
930         format = FMT_PLT;
931         break;
932       case 'V':
933         format = FMT_SVG;
934         break;
935       case 's':
936         survey = optarg;
937         break;
938#ifdef DEBUG_CAD3D
939       default:
940         printf("Internal Error: 'getopt' returned '%c' %d\n", opt, opt);
941#endif
942      }
943   }
944#endif
945
946   {
947      size_t i;
948      size_t len = fnm_out.length();
949      for (i = 0; i < FMT_ENDMARKER; ++i) {
950         size_t l = strlen(extensions[i]);
951         if (len > l + 1 && fnm_out[len - l - 1] == FNM_SEP_EXT &&
952             strcasecmp(fnm_out.c_str() + len - l, extensions[i]) == 0) {
953            format = export_format(i);
954            break;
955         }
956      }
957   }
958   switch (format) {
959    case FMT_DXF:
960      header = dxf_header;
961      start_pass = dxf_start_pass;
962      line = dxf_line;
963      label = dxf_label;
964      cross = dxf_cross;
965      footer = dxf_footer;
966      pass = dxf_passes;
967      break;
968    case FMT_SKETCH:
969      header = sketch_header;
970      start_pass = sketch_start_pass;
971      line = sketch_line;
972      label = sketch_label;
973      cross = sketch_cross;
974      footer = sketch_footer;
975      pass = sketch_passes;
976      factor = POINTS_PER_MM * 1000.0 / scale;
977      mode = "wb"; /* Binary file output */
978      break;
979    case FMT_PLT:
980      header = plt_header;
981      start_pass = plt_start_pass;
982      line = plt_line;
983      label = plt_label;
984      cross = plt_cross;
985      footer = plt_footer;
986      pass = plt_passes;
987      mode = "wb"; /* Binary file output */
988      break;
989    case FMT_SVG:
990      header = svg_header;
991      start_pass = svg_start_pass;
992      line = svg_line;
993      label = svg_label;
994      cross = svg_cross;
995      footer = svg_footer;
996      pass = svg_passes;
997      factor = 1000.0 / scale;
998      mode = "wb"; /* Binary file output */
999      break;
1000    case FMT_EPS:
1001      header = eps_header;
1002      start_pass = eps_start_pass;
1003      line = eps_line;
1004      label = eps_label;
1005      cross = eps_cross;
1006      footer = eps_footer;
1007      pass = eps_passes;
1008      factor = POINTS_PER_MM * 1000.0 / scale;
1009      mode = "wb"; /* Binary file output */
1010      break;
1011    default:
1012      exit(1);
1013   }
1014
1015   fh = fopen(fnm_out.c_str(), mode);
1016   if (!fh) return false;
1017
1018   if (elevation) {
1019      s = sin(rad(elev_angle));
1020      c = cos(rad(elev_angle));
1021   }
1022
1023   /* Get drawing corners */
1024   min_x = min_y = min_z = HUGE_VAL;
1025   max_x = max_y = max_z = -HUGE_VAL;
1026   for (int band = 0; band < mainfrm->GetNumDepthBands(); ++band) {
1027        list<PointInfo*>::const_iterator pos = mainfrm->GetPoints(band);
1028        list<PointInfo*>::const_iterator end = mainfrm->GetPointsEnd(band);
1029        for ( ; pos != end; ++pos) {
1030            p.x = (*pos)->GetX();
1031            p.y = (*pos)->GetY();
1032            p.z = (*pos)->GetZ();
1033
1034            if (elevation) {
1035                double xnew = p.x * c - p.y * s;
1036                double znew = - p.x * s - p.y * c;
1037                p.y = p.z;
1038                p.z = znew;
1039                p.x = xnew;
1040            }
1041
1042            if (p.x < min_x) min_x = p.x;
1043            if (p.x > max_x) max_x = p.x;
1044            if (p.y < min_y) min_y = p.y;
1045            if (p.y > max_y) max_y = p.y;
1046            if (p.z < min_z) min_z = p.z;
1047            if (p.z > max_z) max_z = p.z;
1048        }
1049   }
1050   {
1051        list<LabelInfo*>::const_iterator pos = mainfrm->GetLabels();
1052        list<LabelInfo*>::const_iterator end = mainfrm->GetLabelsEnd();
1053        for ( ; pos != end; ++pos) {
1054            p.x = (*pos)->GetX();
1055            p.y = (*pos)->GetY();
1056            p.z = (*pos)->GetZ();
1057
1058            if (elevation) {
1059                double xnew = p.x * c - p.y * s;
1060                double znew = - p.x * s - p.y * c;
1061                p.y = p.z;
1062                p.z = znew;
1063                p.x = xnew;
1064            }
1065
1066            if (p.x < min_x) min_x = p.x;
1067            if (p.x > max_x) max_x = p.x;
1068            if (p.y < min_y) min_y = p.y;
1069            if (p.y > max_y) max_y = p.y;
1070            if (p.z < min_z) min_z = p.z;
1071            if (p.z > max_z) max_z = p.z;
1072        }
1073   }
1074
1075   if (grid > 0) {
1076      min_x -= grid / 2;
1077      max_x += grid / 2;
1078      min_y -= grid / 2;
1079      max_y += grid / 2;
1080   }
1081
1082   /* handle empty file gracefully */
1083   if (min_x > max_x) {
1084      min_x = min_y = min_z = 0;
1085      max_x = max_y = max_z = 0;
1086   }
1087
1088   /* Header */
1089   header(title.c_str());
1090
1091   p1.x = p1.y = p1.z = 0; /* avoid compiler warning */
1092
1093   for ( ; *pass; ++pass) {
1094      bool legs_this_pass = ((*pass & LEGS) && legs);
1095      bool crosses_this_pass = ((*pass & STNS) && crosses);
1096      bool labels_this_pass = ((*pass & LABELS) && labels);
1097      if (!(legs_this_pass || crosses_this_pass || labels_this_pass))
1098          continue;
1099      start_pass(*pass);
1100      if (legs_this_pass) {
1101         for (int band = 0; band < mainfrm->GetNumDepthBands(); ++band) {
1102             list<PointInfo*>::const_iterator pos = mainfrm->GetPoints(band);
1103             list<PointInfo*>::const_iterator end = mainfrm->GetPointsEnd(band);
1104             for ( ; pos != end; ++pos) {
1105                 p.x = (*pos)->GetX();
1106                 p.y = (*pos)->GetY();
1107                 p.z = (*pos)->GetZ();
1108
1109                 if (format == FMT_SKETCH) {
1110                     p.x -= min_x;
1111                     p.y -= min_y;
1112                     p.z -= min_z;
1113                 }
1114
1115                 if (elevation) {
1116                     double xnew = p.x * c - p.y * s;
1117                     double znew = - p.x * s - p.y * c;
1118                     p.y = p.z;
1119                     p.z = znew;
1120                     p.x = xnew;
1121                 }
1122
1123                 if (!(*pos)->IsLine()) {
1124#ifdef DEBUG_CAD3D
1125                     printf("move to %9.2f %9.2f %9.2f\n",x,y,z);
1126#endif
1127                     fPendingMove = 1;
1128                     fSeenMove = 1;
1129                 } else {
1130#ifdef DEBUG_CAD3D
1131                     printf("line to %9.2f %9.2f %9.2f\n", p.x, p.y, p.z);
1132#endif
1133                     if (!fSeenMove) {
1134                         p1 = p;
1135                         fPendingMove = 1;
1136                         fSeenMove = 1;
1137                     }
1138                     if (surface || !(*pos)->IsSurface()) {
1139                         line(&p1, &p, (*pos)->IsSurface(), fPendingMove);
1140                         fPendingMove = 0;
1141                     } else {
1142                         fPendingMove = 1;
1143                     }
1144                 }
1145                 p1 = p;
1146             }
1147         }
1148      }
1149      if (crosses_this_pass || labels_this_pass) {
1150        list<LabelInfo*>::const_iterator pos = mainfrm->GetLabels();
1151        list<LabelInfo*>::const_iterator end = mainfrm->GetLabelsEnd();
1152        for ( ; pos != end; ++pos) {
1153            p.x = (*pos)->GetX();
1154            p.y = (*pos)->GetY();
1155            p.z = (*pos)->GetZ();
1156
1157            if (format == FMT_SKETCH) {
1158               p.x -= min_x;
1159               p.y -= min_y;
1160               p.z -= min_z;
1161            }
1162
1163            if (elevation) {
1164                double xnew = p.x * c - p.y * s;
1165                double znew = - p.x * s - p.y * c;
1166                p.y = p.z;
1167                p.z = znew;
1168                p.x = xnew;
1169            }
1170#ifdef DEBUG_CAD3D
1171            printf("label '%s' at %9.2f %9.2f %9.2f\n",(*pos)->GetText(),x,y,z);
1172#endif
1173            /* Use !UNDERGROUND as the criterion - we want stations where
1174             * a surface and underground survey meet to be in the
1175             * underground layer */
1176            if (labels_this_pass)
1177                label(&p, (*pos)->GetText(), !(*pos)->IsUnderground());
1178            if (crosses_this_pass)
1179                cross(&p, !(*pos)->IsUnderground());
1180        }
1181      }
1182   }
1183   footer();
1184   safe_fclose(fh);
1185   osfree(htab);
1186   htab = NULL;
1187   return true;
1188}
Note: See TracBrowser for help on using the repository browser.