source: git/src/export.cc @ 9b5a5fd

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

src/: Hook up to pass "input_projection" from .aven config file
through to GPX export code.

  • Property mode set to 100644
File size: 39.6 KB
Line 
1/* export.cc
2 * Export to CAD-like formats (DXF, Skencil, SVG, EPS) and also Compass PLT.
3 */
4
5/* Copyright (C) 1994-2004,2005,2006,2008,2010,2011,2012,2013 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 "export.h"
30
31#include "wx.h"
32#include <wx/utils.h>
33#include "exportfilter.h"
34#include "gpx.h"
35#include "hpgl.h"
36#include "mainfrm.h"
37
38#include <float.h>
39#include <math.h>
40#include <stdio.h>
41#include <stdlib.h>
42#include <string.h>
43#include <time.h>
44
45#if defined(HAVE_GETPWUID) && !defined(__DJGPP__)
46# include <pwd.h>
47# include <sys/types.h>
48# include <unistd.h>
49#endif
50
51#include "cmdline.h"
52#include "debug.h"
53#include "filename.h"
54#include "hash.h"
55#include "img_hosted.h"
56#include "message.h"
57#include "useful.h"
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
64static const char *layer_name(int mask) {
65    switch (mask) {
66        case LEGS: case LEGS|SURF:
67            return "Legs";
68        case SURF:
69            return "Surface";
70        case STNS:
71            return "Stations";
72        case LABELS:
73            return "Labels";
74        case XSECT:
75            return "Cross-sections";
76        case WALL1: case WALL2: case WALLS:
77            return "Walls";
78        case PASG:
79            return "Passages";
80    }
81    return "";
82}
83
84/* bounds */
85static double min_x, min_y, min_z, max_x, max_y, max_z;
86
87static double text_height; /* for station labels */
88static double marker_size; /* for station markers */
89static double grid; /* grid spacing (or 0 for no grid) */
90static double scale = 500.0;
91static double factor;
92static const char *unit = "mm";
93const double SVG_MARGIN = 5.0; // In units of "unit".
94
95static const char *survey = NULL;
96
97const int *
98ExportFilter::passes() const
99{
100    static const int default_passes[] = { LEGS|SURF|STNS|LABELS, 0 };
101    return default_passes;
102}
103
104class DXF : public ExportFilter {
105    const char * to_close;
106    char pending[1024];
107
108  public:
109    DXF() : to_close(0) { pending[0] = '\0'; }
110    const int * passes() const;
111    bool fopen(const char *fnm_out);
112    void header(const char *);
113    void line(const img_point *, const img_point *, bool, bool);
114    void label(const img_point *, const char *, bool, int);
115    void cross(const img_point *, bool);
116    void xsect(const img_point *, double, double, double);
117    void wall(const img_point *, double, double);
118    void passage(const img_point *, double, double, double);
119    void tube_end();
120    void footer();
121};
122
123const int *
124DXF::passes() const
125{
126    static const int dxf_passes[] = {
127        PASG, XSECT, WALL1, WALL2, LEGS|SURF|STNS|LABELS, 0
128    };
129    return dxf_passes;
130}
131
132bool
133DXF::fopen(const char *fnm_out)
134{
135    // DXF gets written as text rather than binary.
136    fh = ::fopen(fnm_out, "w");
137    return (fh != NULL);
138}
139
140void
141DXF::header(const char *)
142{
143   fprintf(fh, "0\nSECTION\n"
144               "2\nHEADER\n");
145   fprintf(fh, "9\n$EXTMIN\n"); /* lower left corner of drawing */
146   fprintf(fh, "10\n%#-.6f\n", min_x); /* x */
147   fprintf(fh, "20\n%#-.6f\n", min_y); /* y */
148   fprintf(fh, "30\n%#-.6f\n", min_z); /* min z */
149   fprintf(fh, "9\n$EXTMAX\n"); /* upper right corner of drawing */
150   fprintf(fh, "10\n%#-.6f\n", max_x); /* x */
151   fprintf(fh, "20\n%#-.6f\n", max_y); /* y */
152   fprintf(fh, "30\n%#-.6f\n", max_z); /* max z */
153   fprintf(fh, "9\n$PDMODE\n70\n3\n"); /* marker style as CROSS */
154   fprintf(fh, "9\n$PDSIZE\n40\n%6.2f\n", marker_size); /* marker size */
155   fprintf(fh, "0\nENDSEC\n");
156
157   fprintf(fh, "0\nSECTION\n"
158               "2\nTABLES\n");
159   fprintf(fh, "0\nTABLE\n" /* Define CONTINUOUS and DASHED line types. */
160               "2\nLTYPE\n"
161               "70\n10\n"
162               "0\nLTYPE\n"
163               "2\nCONTINUOUS\n"
164               "70\n64\n"
165               "3\nContinuous\n"
166               "72\n65\n"
167               "73\n0\n"
168               "40\n0.0\n"
169               "0\nLTYPE\n"
170               "2\nDASHED\n"
171               "70\n64\n"
172               "3\nDashed\n"
173               "72\n65\n"
174               "73\n2\n"
175               "40\n2.5\n"
176               "49\n1.25\n"
177               "49\n-1.25\n"
178               "0\nENDTAB\n");
179   fprintf(fh, "0\nTABLE\n"
180               "2\nLAYER\n");
181   fprintf(fh, "70\n10\n"); /* max # off layers in this DXF file : 10 */
182   /* First Layer: CentreLine */
183   fprintf(fh, "0\nLAYER\n2\nCentreLine\n");
184   fprintf(fh, "70\n64\n"); /* shows layer is referenced by entities */
185   fprintf(fh, "62\n5\n"); /* color: kept the same used by SpeleoGen */
186   fprintf(fh, "6\nCONTINUOUS\n"); /* linetype */
187   /* Next Layer: Stations */
188   fprintf(fh, "0\nLAYER\n2\nStations\n");
189   fprintf(fh, "70\n64\n"); /* shows layer is referenced by entities */
190   fprintf(fh, "62\n7\n"); /* color: kept the same used by SpeleoGen */
191   fprintf(fh, "6\nCONTINUOUS\n"); /* linetype */
192   /* Next Layer: Labels */
193   fprintf(fh, "0\nLAYER\n2\nLabels\n");
194   fprintf(fh, "70\n64\n"); /* shows layer is referenced by entities */
195   fprintf(fh, "62\n7\n"); /* color: kept the same used by SpeleoGen */
196   fprintf(fh, "6\nCONTINUOUS\n"); /* linetype */
197   /* Next Layer: Surface */
198   fprintf(fh, "0\nLAYER\n2\nSurface\n");
199   fprintf(fh, "70\n64\n"); /* shows layer is referenced by entities */
200   fprintf(fh, "62\n5\n"); /* color */
201   fprintf(fh, "6\nDASHED\n"); /* linetype */
202   /* Next Layer: SurfaceStations */
203   fprintf(fh, "0\nLAYER\n2\nSurfaceStations\n");
204   fprintf(fh, "70\n64\n"); /* shows layer is referenced by entities */
205   fprintf(fh, "62\n7\n"); /* color */
206   fprintf(fh, "6\nCONTINUOUS\n"); /* linetype */
207   /* Next Layer: SurfaceLabels */
208   fprintf(fh, "0\nLAYER\n2\nSurfaceLabels\n");
209   fprintf(fh, "70\n64\n"); /* shows layer is referenced by entities */
210   fprintf(fh, "62\n7\n"); /* color */
211   fprintf(fh, "6\nCONTINUOUS\n"); /* linetype */
212   if (grid > 0) {
213      /* Next Layer: Grid */
214      fprintf(fh, "0\nLAYER\n2\nGrid\n");
215      fprintf(fh, "70\n64\n"); /* shows layer is referenced by entities */
216      fprintf(fh, "62\n7\n"); /* color: kept the same used by SpeleoGen */
217      fprintf(fh, "6\nCONTINUOUS\n"); /* linetype */
218   }
219   fprintf(fh, "0\nENDTAB\n"
220               "0\nENDSEC\n");
221
222   fprintf(fh, "0\nSECTION\n"
223               "2\nENTITIES\n");
224
225   if (grid > 0) {
226      double x, y;
227      x = floor(min_x / grid) * grid + grid;
228      y = floor(min_y / grid) * grid + grid;
229#ifdef DEBUG_CAD3D
230      printf("x_min: %f  y_min: %f\n", x, y);
231#endif
232      while (x < max_x) {
233         /* horizontal line */
234         fprintf(fh, "0\nLINE\n");
235         fprintf(fh, "8\nGrid\n"); /* Layer */
236         fprintf(fh, "10\n%6.2f\n", x);
237         fprintf(fh, "20\n%6.2f\n", min_y);
238         fprintf(fh, "30\n0\n");
239         fprintf(fh, "11\n%6.2f\n", x);
240         fprintf(fh, "21\n%6.2f\n", max_y);
241         fprintf(fh, "31\n0\n");
242         x += grid;
243      }
244      while (y < max_y) {
245         /* vertical line */
246         fprintf(fh, "0\nLINE\n");
247         fprintf(fh, "8\nGrid\n"); /* Layer */
248         fprintf(fh, "10\n%6.2f\n", min_x);
249         fprintf(fh, "20\n%6.2f\n", y);
250         fprintf(fh, "30\n0\n");
251         fprintf(fh, "11\n%6.2f\n", max_x);
252         fprintf(fh, "21\n%6.2f\n", y);
253         fprintf(fh, "31\n0\n");
254         y += grid;
255      }
256   }
257}
258
259void
260DXF::line(const img_point *p1, const img_point *p, bool fSurface, bool fPendingMove)
261{
262   fPendingMove = fPendingMove; /* unused */
263   fprintf(fh, "0\nLINE\n");
264   fprintf(fh, fSurface ? "8\nSurface\n" : "8\nCentreLine\n"); /* Layer */
265   fprintf(fh, "10\n%6.2f\n", p1->x);
266   fprintf(fh, "20\n%6.2f\n", p1->y);
267   fprintf(fh, "30\n%6.2f\n", p1->z);
268   fprintf(fh, "11\n%6.2f\n", p->x);
269   fprintf(fh, "21\n%6.2f\n", p->y);
270   fprintf(fh, "31\n%6.2f\n", p->z);
271}
272
273void
274DXF::label(const img_point *p, const char *s, bool fSurface, int)
275{
276   /* write station label to dxf file */
277   fprintf(fh, "0\nTEXT\n");
278   fprintf(fh, fSurface ? "8\nSurfaceLabels\n" : "8\nLabels\n"); /* Layer */
279   fprintf(fh, "10\n%6.2f\n", p->x);
280   fprintf(fh, "20\n%6.2f\n", p->y);
281   fprintf(fh, "30\n%6.2f\n", p->z);
282   fprintf(fh, "40\n%6.2f\n", text_height);
283   fprintf(fh, "1\n%s\n", s);
284}
285
286void
287DXF::cross(const img_point *p, bool fSurface)
288{
289   /* write station marker to dxf file */
290   fprintf(fh, "0\nPOINT\n");
291   fprintf(fh, fSurface ? "8\nSurfaceStations\n" : "8\nStations\n"); /* Layer */
292   fprintf(fh, "10\n%6.2f\n", p->x);
293   fprintf(fh, "20\n%6.2f\n", p->y);
294   fprintf(fh, "30\n%6.2f\n", p->z);
295}
296
297void
298DXF::xsect(const img_point *p, double angle, double d1, double d2)
299{
300   double s = sin(rad(angle));
301   double c = cos(rad(angle));
302   fprintf(fh, "0\nLINE\n");
303   fprintf(fh, "8\nCross-sections\n"); /* Layer */
304   fprintf(fh, "10\n%6.2f\n", p->x + c * d1);
305   fprintf(fh, "20\n%6.2f\n", p->y + s * d1);
306   fprintf(fh, "30\n%6.2f\n", p->z);
307   fprintf(fh, "11\n%6.2f\n", p->x - c * d2);
308   fprintf(fh, "21\n%6.2f\n", p->y - s * d2);
309   fprintf(fh, "31\n%6.2f\n", p->z);
310}
311
312void
313DXF::wall(const img_point *p, double angle, double d)
314{
315   if (!to_close) {
316       fprintf(fh, "0\nPOLYLINE\n");
317       fprintf(fh, "8\nWalls\n"); /* Layer */
318       fprintf(fh, "70\n0\n"); /* bit 0 == 0 => Open polyline */
319       to_close = "0\nSEQEND\n";
320   }
321   double s = sin(rad(angle));
322   double c = cos(rad(angle));
323   fprintf(fh, "0\nVERTEX\n");
324   fprintf(fh, "8\nWalls\n"); /* Layer */
325   fprintf(fh, "10\n%6.2f\n", p->x + c * d);
326   fprintf(fh, "20\n%6.2f\n", p->y + s * d);
327   fprintf(fh, "30\n%6.2f\n", p->z);
328}
329
330void
331DXF::passage(const img_point *p, double angle, double d1, double d2)
332{
333   fprintf(fh, "0\nSOLID\n");
334   fprintf(fh, "8\nPassages\n"); /* Layer */
335   double s = sin(rad(angle));
336   double c = cos(rad(angle));
337   double x1 = p->x + c * d1;
338   double y1 = p->y + s * d1;
339   double x2 = p->x - c * d2;
340   double y2 = p->y - s * d2;
341   if (*pending) {
342       fputs(pending, fh);
343       fprintf(fh, "12\n%6.2f\n22\n%6.2f\n32\n%6.2f\n"
344                   "13\n%6.2f\n23\n%6.2f\n33\n%6.2f\n",
345                   x1, y1, p->z,
346                   x2, y2, p->z);
347   }
348   sprintf(pending, "10\n%6.2f\n20\n%6.2f\n30\n%6.2f\n"
349                    "11\n%6.2f\n21\n%6.2f\n31\n%6.2f\n",
350                    x1, y1, p->z,
351                    x2, y2, p->z);
352}
353
354void
355DXF::tube_end()
356{
357   *pending = '\0';
358   if (to_close) {
359      fputs(to_close, fh);
360      to_close = NULL;
361   }
362}
363
364void
365DXF::footer()
366{
367   fprintf(fh, "000\nENDSEC\n");
368   fprintf(fh, "000\nEOF\n");
369}
370
371class Skencil : public ExportFilter {
372  public:
373    Skencil() { }
374    const int * passes() const;
375    void header(const char *);
376    void start_pass(int layer);
377    void line(const img_point *, const img_point *, bool, bool);
378    void label(const img_point *, const char *, bool, int);
379    void cross(const img_point *, bool);
380    void footer();
381};
382
383const int *
384Skencil::passes() const
385{
386    static const int skencil_passes[] = { LEGS|SURF, STNS, LABELS, 0 };
387    return skencil_passes;
388}
389
390void
391Skencil::header(const char *)
392{
393   fprintf(fh, "##Sketch 1 2\n"); /* File format version */
394   fprintf(fh, "document()\n");
395   fprintf(fh, "layout((%.3f,%.3f),0)\n",
396           (max_x - min_x) * factor, (max_y - min_y) * factor);
397}
398
399void
400Skencil::start_pass(int layer)
401{
402   fprintf(fh, "layer('%s',1,1,0,0,(0,0,0))\n", layer_name(layer));
403}
404
405void
406Skencil::line(const img_point *p1, const img_point *p, bool fSurface, bool fPendingMove)
407{
408   fSurface = fSurface; /* unused */
409   if (fPendingMove) {
410       fprintf(fh, "b()\n");
411       fprintf(fh, "bs(%.3f,%.3f,%.3f)\n", p1->x * factor, p1->y * factor, 0.0);
412   }
413   fprintf(fh, "bs(%.3f,%.3f,%.3f)\n", p->x * factor, p->y * factor, 0.0);
414}
415
416void
417Skencil::label(const img_point *p, const char *s, bool fSurface, int)
418{
419   fSurface = fSurface; /* unused */
420   fprintf(fh, "fp((0,0,0))\n");
421   fprintf(fh, "le()\n");
422   fprintf(fh, "Fn('Times-Roman')\n");
423   fprintf(fh, "Fs(5)\n");
424   fprintf(fh, "txt('");
425   while (*s) {
426      int ch = *s++;
427      if (ch == '\'' || ch == '\\') PUTC('\\', fh);
428      PUTC(ch, fh);
429   }
430   fprintf(fh, "',(%.3f,%.3f))\n", p->x * factor, p->y * factor);
431}
432
433void
434Skencil::cross(const img_point *p, bool fSurface)
435{
436   fSurface = fSurface; /* unused */
437   fprintf(fh, "b()\n");
438   fprintf(fh, "bs(%.3f,%.3f,%.3f)\n",
439           p->x * factor - marker_size, p->y * factor - marker_size, 0.0);
440   fprintf(fh, "bs(%.3f,%.3f,%.3f)\n",
441           p->x * factor + marker_size, p->y * factor + marker_size, 0.0);
442   fprintf(fh, "bn()\n");
443   fprintf(fh, "bs(%.3f,%.3f,%.3f)\n",
444           p->x * factor + marker_size, p->y * factor - marker_size, 0.0);
445   fprintf(fh, "bs(%.3f,%.3f,%.3f)\n",
446           p->x * factor - marker_size, p->y * factor + marker_size, 0.0);
447}
448
449void
450Skencil::footer(void)
451{
452   fprintf(fh, "guidelayer('Guide Lines',1,0,0,1,(0,0,1))\n");
453   if (grid) {
454      fprintf(fh, "grid((0,0,%.3f,%.3f),1,(0,0,1),'Grid')\n",
455              grid * factor, grid * factor);
456   }
457}
458
459typedef struct point {
460   img_point p;
461   const char *label;
462   struct point *next;
463} point;
464
465#define HTAB_SIZE 0x2000
466
467static point **htab;
468
469static void
470set_name(const img_point *p, const char *s)
471{
472   int hash;
473   point *pt;
474   union {
475      char data[sizeof(int) * 3];
476      int x[3];
477   } u;
478
479   u.x[0] = (int)(p->x * 100);
480   u.x[1] = (int)(p->y * 100);
481   u.x[2] = (int)(p->z * 100);
482   hash = (hash_data(u.data, sizeof(int) * 3) & (HTAB_SIZE - 1));
483   for (pt = htab[hash]; pt; pt = pt->next) {
484      if (pt->p.x == p->x && pt->p.y == p->y && pt->p.z == p->z) {
485         /* already got name for these coordinates */
486         /* FIXME: what about multiple names for the same station? */
487         return;
488      }
489   }
490
491   pt = osnew(point);
492   pt->label = osstrdup(s);
493   pt->p = *p;
494   pt->next = htab[hash];
495   htab[hash] = pt;
496
497   return;
498}
499
500static const char *
501find_name(const img_point *p)
502{
503   int hash;
504   point *pt;
505   union {
506      char data[sizeof(int) * 3];
507      int x[3];
508   } u;
509   SVX_ASSERT(p);
510
511   u.x[0] = (int)(p->x * 100);
512   u.x[1] = (int)(p->y * 100);
513   u.x[2] = (int)(p->z * 100);
514   hash = (hash_data(u.data, sizeof(int) * 3) & (HTAB_SIZE - 1));
515   for (pt = htab[hash]; pt; pt = pt->next) {
516      if (pt->p.x == p->x && pt->p.y == p->y && pt->p.z == p->z)
517         return pt->label;
518   }
519   return "?";
520}
521
522class SVG : public ExportFilter {
523    const char * to_close;
524    bool close_g;
525    char pending[1024];
526
527  public:
528    SVG() : to_close(NULL), close_g(false) { pending[0] = '\0'; }
529    const int * passes() const;
530    void header(const char *);
531    void start_pass(int layer);
532    void line(const img_point *, const img_point *, bool, bool);
533    void label(const img_point *, const char *, bool, int);
534    void cross(const img_point *, bool);
535    void xsect(const img_point *, double, double, double);
536    void wall(const img_point *, double, double);
537    void passage(const img_point *, double, double, double);
538    void tube_end();
539    void footer();
540};
541
542const int *
543SVG::passes() const
544{
545    static const int svg_passes[] = {
546        PASG, LEGS|SURF, XSECT, WALL1, WALL2, LABELS, STNS, 0
547    };
548    return svg_passes;
549}
550
551void
552SVG::header(const char *)
553{
554   size_t i;
555   htab = (point **)osmalloc(HTAB_SIZE * ossizeof(point *));
556   for (i = 0; i < HTAB_SIZE; ++i) htab[i] = NULL;
557   fprintf(fh, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
558   double width = (max_x - min_x) * factor + SVG_MARGIN * 2;
559   double height = (max_y - min_y) * factor + SVG_MARGIN * 2;
560   fprintf(fh, "<svg version=\"1.1\" baseProfile=\"full\"\n"
561               "xmlns=\"http://www.w3.org/2000/svg\"\n"
562               "xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
563               "xmlns:ev=\"http://www.w3.org/2001/xml-events\"\n"
564               "width=\"%.3f%s\" height=\"%.3f%s\"\n"
565               "viewBox=\"0 0 %0.3f %0.3f\">\n",
566           width, unit, height, unit, width, height);
567   fprintf(fh, "<g transform=\"translate(%.3f %.3f)\">\n",
568           SVG_MARGIN - min_x * factor, SVG_MARGIN + max_y * factor);
569   to_close = NULL;
570   close_g = false;
571}
572
573void
574SVG::start_pass(int layer)
575{
576   if (to_close) {
577      fputs(to_close, fh);
578      to_close = NULL;
579   }
580   if (close_g) {
581      fprintf(fh, "</g>\n");
582   }
583   fprintf(fh, "<g id=\"%s\"", layer_name(layer));
584   if (layer & LEGS)
585      fprintf(fh, " stroke=\"black\" fill=\"none\" stroke-width=\"0.4px\"");
586   else if (layer & STNS)
587      fprintf(fh, " stroke=\"black\" fill=\"none\" stroke-width=\"0.05px\"");
588   else if (layer & LABELS)
589      fprintf(fh, " font-size=\"%.3fem\"", text_height);
590   else if (layer & XSECT)
591      fprintf(fh, " stroke=\"grey\" fill=\"none\" stroke-width=\"0.1px\"");
592   else if (layer & WALLS)
593      fprintf(fh, " stroke=\"black\" fill=\"none\" stroke-width=\"0.1px\"");
594   else if (layer & PASG)
595      fprintf(fh, " stroke=\"none\" fill=\"peru\"");
596   fprintf(fh, ">\n");
597
598   close_g = true;
599}
600
601void
602SVG::line(const img_point *p1, const img_point *p, bool fSurface, bool fPendingMove)
603{
604   fSurface = fSurface; /* unused */
605   if (fPendingMove) {
606       if (to_close) {
607           fputs(to_close, fh);
608       }
609       fprintf(fh, "<path d=\"M%.3f %.3f", p1->x * factor, p1->y * -factor);
610   }
611   fprintf(fh, "L%.3f %.3f", p->x * factor, p->y * -factor);
612   to_close = "\"/>\n";
613}
614
615void
616SVG::label(const img_point *p, const char *s, bool fSurface, int)
617{
618   fSurface = fSurface; /* unused */
619   fprintf(fh, "<text transform=\"translate(%.3f %.3f)\">",
620           p->x * factor, p->y * -factor);
621   fputs(s, fh);
622   fputs("</text>\n", fh);
623   set_name(p, s);
624}
625
626void
627SVG::cross(const img_point *p, bool fSurface)
628{
629   fSurface = fSurface; /* unused */
630   fprintf(fh, "<circle id=\"%s\" cx=\"%.3f\" cy=\"%.3f\" r=\"%.3f\"/>\n",
631           find_name(p), p->x * factor, p->y * -factor, marker_size * SQRT_2);
632   fprintf(fh, "<path d=\"M%.3f %.3fL%.3f %.3fM%.3f %.3fL%.3f %.3f\"/>\n",
633           p->x * factor - marker_size, p->y * -factor - marker_size,
634           p->x * factor + marker_size, p->y * -factor + marker_size,
635           p->x * factor + marker_size, p->y * -factor - marker_size,
636           p->x * factor - marker_size, p->y * -factor + marker_size);
637}
638
639void
640SVG::xsect(const img_point *p, double angle, double d1, double d2)
641{
642   double s = sin(rad(angle));
643   double c = cos(rad(angle));
644   fprintf(fh, "<path d=\"M%.3f %.3fL%.3f %.3f\"/>\n",
645           (p->x + c * d1) * factor, (p->y + s * d1) * -factor,
646           (p->x - c * d2) * factor, (p->y - s * d2) * -factor);
647}
648
649void
650SVG::wall(const img_point *p, double angle, double d)
651{
652   if (!to_close) {
653       fprintf(fh, "<path d=\"M");
654       to_close = "\"/>\n";
655   } else {
656       fprintf(fh, "L");
657   }
658   double s = sin(rad(angle));
659   double c = cos(rad(angle));
660   fprintf(fh, "%.3f %.3f", (p->x + c * d) * factor, (p->y + s * d) * -factor);
661}
662
663void
664SVG::passage(const img_point *p, double angle, double d1, double d2)
665{
666   double s = sin(rad(angle));
667   double c = cos(rad(angle));
668   double x1 = (p->x + c * d1) * factor;
669   double y1 = (p->y + s * d1) * -factor;
670   double x2 = (p->x - c * d2) * factor;
671   double y2 = (p->y - s * d2) * -factor;
672   if (*pending) {
673       fputs(pending, fh);
674       fprintf(fh, "L%.3f %.3fL%.3f %.3fZ\"/>\n", x2, y2, x1, y1);
675   }
676   sprintf(pending, "<path d=\"M%.3f %.3fL%.3f %.3f", x1, y1, x2, y2);
677}
678
679void
680SVG::tube_end()
681{
682   *pending = '\0';
683   if (to_close) {
684      fputs(to_close, fh);
685      to_close = NULL;
686   }
687}
688
689void
690SVG::footer()
691{
692   if (to_close) {
693      fputs(to_close, fh);
694      to_close = NULL;
695   }
696   if (close_g) {
697      fprintf(fh, "</g>\n");
698      close_g = false;
699   }
700   fprintf(fh, "</g>\n</svg>\n");
701}
702
703class PLT : public ExportFilter {
704    string escaped;
705
706    const char * find_name_plt(const img_point *p);
707
708  public:
709    PLT() { }
710    const int * passes() const;
711    void header(const char *);
712    void line(const img_point *, const img_point *, bool, bool);
713    void label(const img_point *, const char *, bool, int);
714    void footer();
715};
716
717const int *
718PLT::passes() const
719{
720    static const int plt_passes[] = { LABELS, LEGS|SURF, 0 };
721    return plt_passes;
722}
723
724void
725PLT::header(const char *title)
726{
727   size_t i;
728   htab = (point **)osmalloc(HTAB_SIZE * ossizeof(point *));
729   for (i = 0; i < HTAB_SIZE; ++i) htab[i] = NULL;
730   /* Survex is E, N, Alt - PLT file is N, E, Alt */
731   fprintf(fh, "Z %.3f %.3f %.3f %.3f %.3f %.3f\r\n",
732           min_y / METRES_PER_FOOT, max_y / METRES_PER_FOOT,
733           min_x / METRES_PER_FOOT, max_x / METRES_PER_FOOT,
734           min_z / METRES_PER_FOOT, max_z / METRES_PER_FOOT);
735   fprintf(fh, "N%s D 1 1 1 C%s\r\n", survey ? survey : "X",
736           (title && title[0]) ? title : "X");
737}
738
739void
740PLT::line(const img_point *p1, const img_point *p, bool fSurface, bool fPendingMove)
741{
742   fSurface = fSurface; /* unused */
743   if (fPendingMove) {
744       /* Survex is E, N, Alt - PLT file is N, E, Alt */
745       fprintf(fh, "M %.3f %.3f %.3f ",
746               p1->y / METRES_PER_FOOT, p1->x / METRES_PER_FOOT, p1->z / METRES_PER_FOOT);
747       /* dummy passage dimensions are required to avoid compass bug */
748       fprintf(fh, "S%s P -9 -9 -9 -9\r\n", find_name_plt(p1));
749   }
750   /* Survex is E, N, Alt - PLT file is N, E, Alt */
751   fprintf(fh, "D %.3f %.3f %.3f ",
752           p->y / METRES_PER_FOOT, p->x / METRES_PER_FOOT, p->z / METRES_PER_FOOT);
753   /* dummy passage dimensions are required to avoid compass bug */
754   fprintf(fh, "S%s P -9 -9 -9 -9\r\n", find_name_plt(p));
755}
756
757const char *
758PLT::find_name_plt(const img_point *p)
759{
760    const char * s = find_name(p);
761    escaped.resize(0);
762
763    // PLT format can't handle spaces or control characters, so escape them
764    // like in URLs (an arbitrary choice of escaping, but at least a familiar
765    // one and % isn't likely to occur in station names).
766    const char * q;
767    for (q = s; *q; ++q) {
768        unsigned char ch = *q;
769        if (ch <= ' ' || ch == '%') {
770            escaped.append(s, q - s);
771            escaped += '%';
772            escaped += "0123456789abcdef"[ch >> 4];
773            escaped += "0123456789abcdef"[ch & 0x0f];
774            s = q + 1;
775        }
776    }
777    if (!escaped.empty()) {
778        escaped.append(s, q - s);
779        return escaped.c_str();
780    }
781    return s;
782}
783
784void
785PLT::label(const img_point *p, const char *s, bool fSurface, int)
786{
787   fSurface = fSurface; /* unused */
788   set_name(p, s);
789}
790
791void
792PLT::footer(void)
793{
794   /* Survex is E, N, Alt - PLT file is N, E, Alt */
795   fprintf(fh, "X %.3f %.3f %.3f %.3f %.3f %.3f\r\n",
796           min_y / METRES_PER_FOOT, max_y / METRES_PER_FOOT,
797           min_x / METRES_PER_FOOT, max_x / METRES_PER_FOOT,
798           min_z / METRES_PER_FOOT, max_z / METRES_PER_FOOT);
799   /* Yucky DOS "end of textfile" marker */
800   PUTC('\x1a', fh);
801}
802
803class EPS : public ExportFilter {
804  public:
805    EPS() { }
806    void header(const char *);
807    void line(const img_point *, const img_point *, bool, bool);
808    void label(const img_point *, const char *, bool, int);
809    void cross(const img_point *, bool);
810    void footer();
811};
812
813void
814EPS::header(const char *title)
815{
816   const char * fontname_labels = "helvetica"; // FIXME
817   int fontsize_labels = 10; // FIXME
818   fputs("%!PS-Adobe-2.0 EPSF-1.2\n", fh);
819   fputs("%%Creator: Survex "VERSION" EPS Output Filter\n", fh);
820
821   if (title && title[0]) fprintf(fh, "%%%%Title: %s\n", title);
822
823   char buf[64];
824   time_t now = time(NULL);
825   if (strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %Z\n", localtime(&now))) {
826      fputs("%%CreationDate: ", fh);
827      fputs(buf, fh);
828   }
829
830   string name;
831#if defined(HAVE_GETPWUID) && !defined(__DJGPP__)
832   struct passwd * ent = getpwuid(getuid());
833   if (ent && ent->pw_gecos[0]) name = ent->pw_gecos;
834#endif
835   if (name.empty()) {
836       name = ::wxGetUserName().mb_str();
837       if (name.empty()) {
838           name = ::wxGetUserId().mb_str();
839       }
840   }
841   if (!name.empty()) {
842       fprintf(fh, "%%%%For: %s\n", name.c_str());
843   }
844
845   fprintf(fh, "%%%%BoundingBox: %d %d %d %d\n",
846           int(floor(min_x * factor)), int(floor(min_y * factor)),
847           int(ceil(max_x * factor)), int(ceil(max_y * factor)));
848   fprintf(fh, "%%%%HiResBoundingBox: %.4f %.4f %.4f %.4f\n",
849           min_x * factor, min_y * factor, max_x * factor, max_y * factor);
850   fputs("%%LanguageLevel: 1\n"
851         "%%PageOrder: Ascend\n"
852         "%%Pages: 1\n"
853         "%%Orientation: Portrait\n", fh);
854
855   fprintf(fh, "%%%%DocumentFonts: %s\n", fontname_labels);
856
857   fputs("%%EndComments\n"
858         "%%Page 1 1\n"
859         "save countdictstack mark\n", fh);
860
861   /* this code adapted from a2ps */
862   fputs("%%BeginResource: encoding ISO88591Encoding\n"
863         "/ISO88591Encoding [\n", fh);
864   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
865   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
866   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
867   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
868   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
869   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
870   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
871   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
872   fputs(
873"/space /exclam /quotedbl /numbersign\n"
874"/dollar /percent /ampersand /quoteright\n"
875"/parenleft /parenright /asterisk /plus\n"
876"/comma /minus /period /slash\n"
877"/zero /one /two /three\n"
878"/four /five /six /seven\n"
879"/eight /nine /colon /semicolon\n"
880"/less /equal /greater /question\n"
881"/at /A /B /C /D /E /F /G\n"
882"/H /I /J /K /L /M /N /O\n"
883"/P /Q /R /S /T /U /V /W\n"
884"/X /Y /Z /bracketleft\n"
885"/backslash /bracketright /asciicircum /underscore\n"
886"/quoteleft /a /b /c /d /e /f /g\n"
887"/h /i /j /k /l /m /n /o\n"
888"/p /q /r /s /t /u /v /w\n"
889"/x /y /z /braceleft\n"
890"/bar /braceright /asciitilde /.notdef\n", fh);
891   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
892   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
893   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
894   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
895   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
896   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
897   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
898   fputs("/.notdef /.notdef /.notdef /.notdef\n", fh);
899   fputs(
900"/space /exclamdown /cent /sterling\n"
901"/currency /yen /brokenbar /section\n"
902"/dieresis /copyright /ordfeminine /guillemotleft\n"
903"/logicalnot /hyphen /registered /macron\n"
904"/degree /plusminus /twosuperior /threesuperior\n"
905"/acute /mu /paragraph /bullet\n"
906"/cedilla /onesuperior /ordmasculine /guillemotright\n"
907"/onequarter /onehalf /threequarters /questiondown\n"
908"/Agrave /Aacute /Acircumflex /Atilde\n"
909"/Adieresis /Aring /AE /Ccedilla\n"
910"/Egrave /Eacute /Ecircumflex /Edieresis\n"
911"/Igrave /Iacute /Icircumflex /Idieresis\n"
912"/Eth /Ntilde /Ograve /Oacute\n"
913"/Ocircumflex /Otilde /Odieresis /multiply\n"
914"/Oslash /Ugrave /Uacute /Ucircumflex\n"
915"/Udieresis /Yacute /Thorn /germandbls\n"
916"/agrave /aacute /acircumflex /atilde\n"
917"/adieresis /aring /ae /ccedilla\n"
918"/egrave /eacute /ecircumflex /edieresis\n"
919"/igrave /iacute /icircumflex /idieresis\n"
920"/eth /ntilde /ograve /oacute\n"
921"/ocircumflex /otilde /odieresis /divide\n"
922"/oslash /ugrave /uacute /ucircumflex\n"
923"/udieresis /yacute /thorn /ydieresis\n"
924"] def\n"
925"%%EndResource\n", fh);
926
927   /* this code adapted from a2ps */
928   fputs(
929"/reencode {\n" /* def */
930"dup length 5 add dict begin\n"
931"{\n" /* forall */
932"1 index /FID ne\n"
933"{ def }{ pop pop } ifelse\n"
934"} forall\n"
935"/Encoding exch def\n"
936
937/* Use the font's bounding box to determine the ascent, descent,
938 * and overall height; don't forget that these values have to be
939 * transformed using the font's matrix.
940 * We use `load' because sometimes BBox is executable, sometimes not.
941 * Since we need 4 numbers and not an array avoid BBox from being executed
942 */
943"/FontBBox load aload pop\n"
944"FontMatrix transform /Ascent exch def pop\n"
945"FontMatrix transform /Descent exch def pop\n"
946"/FontHeight Ascent Descent sub def\n"
947
948/* Define these in case they're not in the FontInfo (also, here
949 * they're easier to get to.
950 */
951"/UnderlinePosition 1 def\n"
952"/UnderlineThickness 1 def\n"
953
954/* Get the underline position and thickness if they're defined. */
955"currentdict /FontInfo known {\n"
956"FontInfo\n"
957
958"dup /UnderlinePosition known {\n"
959"dup /UnderlinePosition get\n"
960"0 exch FontMatrix transform exch pop\n"
961"/UnderlinePosition exch def\n"
962"} if\n"
963
964"dup /UnderlineThickness known {\n"
965"/UnderlineThickness get\n"
966"0 exch FontMatrix transform exch pop\n"
967"/UnderlineThickness exch def\n"
968"} if\n"
969
970"} if\n"
971"currentdict\n"
972"end\n"
973"} bind def\n", fh);
974
975   fprintf(fh, "/lab ISO88591Encoding /%s findfont reencode definefont pop\n",
976           fontname_labels);
977
978   fprintf(fh, "/lab findfont %d scalefont setfont\n", int(fontsize_labels));
979
980   fprintf(fh, "0.1 setlinewidth\n");
981
982#if 0
983   /* C<digit> changes colour */
984   /* FIXME: read from ini */
985   {
986      size_t i;
987      for (i = 0; i < sizeof(colour) / sizeof(colour[0]); ++i) {
988         fprintf(fh, "/C%u {stroke %.3f %.3f %.3f setrgbcolor} def\n", i,
989                 (double)(colour[i] & 0xff0000) / 0xff0000,
990                 (double)(colour[i] & 0xff00) / 0xff00,
991                 (double)(colour[i] & 0xff) / 0xff);
992      }
993   }
994   fputs("C0\n", fh);
995#endif
996
997   /* Postscript definition for drawing a cross */
998   fprintf(fh, "/X {stroke moveto %.2f %.2f rmoveto %.2f %.2f rlineto "
999           "%.2f 0 rmoveto %.2f %.2f rlineto %.2f %.2f rmoveto} def\n",
1000           -marker_size, -marker_size,  marker_size * 2, marker_size * 2,
1001           -marker_size * 2,  marker_size * 2, -marker_size * 2,
1002           -marker_size, marker_size );
1003
1004   /* define some functions to keep file short */
1005   fputs("/M {stroke moveto} def\n"
1006         "/L {lineto} def\n"
1007/*       "/R {rlineto} def\n" */
1008         "/S {show} def\n", fh);
1009
1010   fprintf(fh, "gsave %.8f dup scale\n", factor);
1011#if 0
1012   if (grid > 0) {
1013      double x, y;
1014      x = floor(min_x / grid) * grid + grid;
1015      y = floor(min_y / grid) * grid + grid;
1016#ifdef DEBUG_CAD3D
1017      printf("x_min: %f  y_min: %f\n", x, y);
1018#endif
1019      while (x < max_x) {
1020         /* horizontal line */
1021         fprintf(fh, "0\nLINE\n");
1022         fprintf(fh, "8\nGrid\n"); /* Layer */
1023         fprintf(fh, "10\n%6.2f\n", x);
1024         fprintf(fh, "20\n%6.2f\n", min_y);
1025         fprintf(fh, "30\n0\n");
1026         fprintf(fh, "11\n%6.2f\n", x);
1027         fprintf(fh, "21\n%6.2f\n", max_y);
1028         fprintf(fh, "31\n0\n");
1029         x += grid;
1030      }
1031      while (y < max_y) {
1032         /* vertical line */
1033         fprintf(fh, "0\nLINE\n");
1034         fprintf(fh, "8\nGrid\n"); /* Layer */
1035         fprintf(fh, "10\n%6.2f\n", min_x);
1036         fprintf(fh, "20\n%6.2f\n", y);
1037         fprintf(fh, "30\n0\n");
1038         fprintf(fh, "11\n%6.2f\n", max_x);
1039         fprintf(fh, "21\n%6.2f\n", y);
1040         fprintf(fh, "31\n0\n");
1041         y += grid;
1042      }
1043   }
1044#endif
1045}
1046
1047void
1048EPS::line(const img_point *p1, const img_point *p, bool fSurface, bool fPendingMove)
1049{
1050   fSurface = fSurface; /* unused */
1051   if (fPendingMove) {
1052       fprintf(fh, "%.2f %.2f M\n", p1->x, p1->y);
1053   }
1054   fprintf(fh, "%.2f %.2f L\n", p->x, p->y);
1055}
1056
1057void
1058EPS::label(const img_point *p, const char *s, bool /*fSurface*/, int)
1059{
1060   fprintf(fh, "%.2f %.2f M\n", p->x, p->y);
1061   PUTC('(', fh);
1062   while (*s) {
1063       unsigned char ch = *s++;
1064       switch (ch) {
1065           case '(': case ')': case '\\': /* need to escape these characters */
1066               PUTC('\\', fh);
1067               PUTC(ch, fh);
1068               break;
1069           default:
1070               PUTC(ch, fh);
1071               break;
1072       }
1073   }
1074   fputs(") S\n", fh);
1075}
1076
1077void
1078EPS::cross(const img_point *p, bool fSurface)
1079{
1080   fSurface = fSurface; /* unused */
1081   fprintf(fh, "%.2f %.2f X\n", p->x, p->y);
1082}
1083
1084void
1085EPS::footer(void)
1086{
1087   fputs("stroke showpage grestore\n"
1088         "%%Trailer\n"
1089         "cleartomark countdictstack exch sub { end } repeat restore\n"
1090         "%%EOF\n", fh);
1091}
1092
1093bool
1094Export(const wxString &fnm_out, const wxString &title, const MainFrm * mainfrm,
1095       double pan, double tilt, int show_mask, export_format format,
1096       const char * input_projection,
1097       double grid_, double text_height_, double marker_size_)
1098{
1099   int fPendingMove = 0;
1100   img_point p, p1;
1101   double s = 0, c = 0;
1102   const int *pass;
1103   bool elevation = (tilt == 0.0);
1104
1105   grid = grid_;
1106   text_height = text_height_;
1107   marker_size = marker_size_;
1108
1109#if 0 // FIXME: allow these to be set from aven somehow!
1110       case 'r': /* Reduction factor */
1111         scale = cmdline_double_arg();
1112         break;
1113       case 's':
1114         survey = optarg;
1115         break;
1116#endif
1117
1118   ExportFilter * filt;
1119   switch (format) {
1120       case FMT_DXF:
1121           filt = new DXF;
1122           break;
1123       case FMT_EPS:
1124           filt = new EPS;
1125           factor = POINTS_PER_MM * 1000.0 / scale;
1126           break;
1127       case FMT_GPX:
1128           filt = new GPX(input_projection);
1129           show_mask |= FULL_COORDS;
1130           break;
1131       case FMT_HPGL:
1132           filt = new HPGL;
1133           // factor = POINTS_PER_MM * 1000.0 / scale;
1134           break;
1135       case FMT_PLT:
1136           filt = new PLT;
1137           show_mask |= FULL_COORDS;
1138           break;
1139       case FMT_SK:
1140           filt = new Skencil;
1141           factor = POINTS_PER_MM * 1000.0 / scale;
1142           break;
1143       case FMT_SVG:
1144           filt = new SVG;
1145           factor = 1000.0 / scale;
1146           break;
1147       default:
1148           return false;
1149   }
1150
1151   // FIXME: This should really use fn_str() - currently we probably can't
1152   // save to a Unicode path on wxmsw.
1153   if (!filt->fopen(fnm_out.mb_str())) {
1154       delete filt;
1155       return false;
1156   }
1157
1158   if (elevation) {
1159      s = sin(rad(pan));
1160      c = cos(rad(pan));
1161   }
1162
1163   /* Get drawing corners */
1164   min_x = min_y = min_z = HUGE_VAL;
1165   max_x = max_y = max_z = -HUGE_VAL;
1166   list<traverse>::const_iterator trav = mainfrm->traverses_begin();
1167   list<traverse>::const_iterator tend = mainfrm->traverses_end();
1168   for ( ; trav != tend; ++trav) {
1169        vector<PointInfo>::const_iterator pos = trav->begin();
1170        vector<PointInfo>::const_iterator end = trav->end();
1171        for ( ; pos != end; ++pos) {
1172            p.x = pos->GetX();
1173            p.y = pos->GetY();
1174            p.z = pos->GetZ();
1175
1176            if (elevation) {
1177                double xnew = p.x * c - p.y * s;
1178                double znew = - p.x * s - p.y * c;
1179                p.y = p.z;
1180                p.z = znew;
1181                p.x = xnew;
1182            }
1183
1184            if (p.x < min_x) min_x = p.x;
1185            if (p.x > max_x) max_x = p.x;
1186            if (p.y < min_y) min_y = p.y;
1187            if (p.y > max_y) max_y = p.y;
1188            if (p.z < min_z) min_z = p.z;
1189            if (p.z > max_z) max_z = p.z;
1190        }
1191   }
1192   {
1193        list<LabelInfo*>::const_iterator pos = mainfrm->GetLabels();
1194        list<LabelInfo*>::const_iterator end = mainfrm->GetLabelsEnd();
1195        for ( ; pos != end; ++pos) {
1196            p.x = (*pos)->GetX();
1197            p.y = (*pos)->GetY();
1198            p.z = (*pos)->GetZ();
1199
1200            if (elevation) {
1201                double xnew = p.x * c - p.y * s;
1202                double znew = - p.x * s - p.y * c;
1203                p.y = p.z;
1204                p.z = znew;
1205                p.x = xnew;
1206            }
1207
1208            if (p.x < min_x) min_x = p.x;
1209            if (p.x > max_x) max_x = p.x;
1210            if (p.y < min_y) min_y = p.y;
1211            if (p.y > max_y) max_y = p.y;
1212            if (p.z < min_z) min_z = p.z;
1213            if (p.z > max_z) max_z = p.z;
1214        }
1215   }
1216
1217   if (grid > 0) {
1218      min_x -= grid / 2;
1219      max_x += grid / 2;
1220      min_y -= grid / 2;
1221      max_y += grid / 2;
1222   }
1223
1224   /* handle empty file gracefully */
1225   if (min_x > max_x) {
1226      min_x = min_y = min_z = 0;
1227      max_x = max_y = max_z = 0;
1228   }
1229
1230   double x_offset, y_offset, z_offset;
1231   if (show_mask & FULL_COORDS) {
1232       // Full coordinates.
1233       x_offset = mainfrm->GetOffset().GetX();
1234       y_offset = mainfrm->GetOffset().GetY();
1235       z_offset = mainfrm->GetOffset().GetZ();
1236   } else if (show_mask & CENTRED) {
1237       // Centred.
1238       x_offset = (min_x + max_x) * -0.5;
1239       y_offset = (min_y + max_y) * -0.5;
1240       z_offset = (min_z + max_z) * -0.5;
1241   } else {
1242       // Origin at lowest SW corner.
1243       x_offset = -min_x;
1244       y_offset = -min_y;
1245       z_offset = -min_z;
1246   }
1247   min_x += x_offset;
1248   max_x += x_offset;
1249   min_y += y_offset;
1250   max_y += y_offset;
1251   min_z += z_offset;
1252   max_z += z_offset;
1253
1254   /* Header */
1255   filt->header(title.mb_str());
1256
1257   p1.x = p1.y = p1.z = 0; /* avoid compiler warning */
1258
1259   for (pass = filt->passes(); *pass; ++pass) {
1260      int pass_mask = show_mask & *pass;
1261      if (!pass_mask)
1262          continue;
1263      filt->start_pass(*pass);
1264      if (pass_mask & LEGS) {
1265          trav = mainfrm->traverses_begin();
1266          tend = mainfrm->traverses_end();
1267          for ( ; trav != tend; ++trav) {
1268             assert(trav->size() > 1);
1269             vector<PointInfo>::const_iterator pos = trav->begin();
1270             vector<PointInfo>::const_iterator end = trav->end();
1271             for ( ; pos != end; ++pos) {
1272                 p.x = pos->GetX() + x_offset;
1273                 p.y = pos->GetY() + y_offset;
1274                 p.z = pos->GetZ() + z_offset;
1275                 if (elevation) {
1276                     double xnew = p.x * c - p.y * s;
1277                     double znew = - p.x * s - p.y * c;
1278                     p.y = p.z;
1279                     p.z = znew;
1280                     p.x = xnew;
1281                 }
1282
1283                 if (pos == trav->begin()) {
1284                     // First point is move...
1285#ifdef DEBUG_CAD3D
1286                     printf("move to %9.2f %9.2f %9.2f\n",x,y,z);
1287#endif
1288                     fPendingMove = 1;
1289                 } else {
1290#ifdef DEBUG_CAD3D
1291                     printf("line to %9.2f %9.2f %9.2f\n", p.x, p.y, p.z);
1292#endif
1293                     filt->line(&p1, &p, false, fPendingMove);
1294                     fPendingMove = 0;
1295                 }
1296                 p1 = p;
1297             }
1298         }
1299      }
1300      if (pass_mask & SURF) {
1301          trav = mainfrm->surface_traverses_begin();
1302          tend = mainfrm->surface_traverses_end();
1303          for ( ; trav != tend; ++trav) {
1304             assert(trav->size() > 1);
1305             vector<PointInfo>::const_iterator pos = trav->begin();
1306             vector<PointInfo>::const_iterator end = trav->end();
1307             for ( ; pos != end; ++pos) {
1308                 p.x = pos->GetX() + x_offset;
1309                 p.y = pos->GetY() + y_offset;
1310                 p.z = pos->GetZ() + z_offset;
1311
1312                 if (elevation) {
1313                     double xnew = p.x * c - p.y * s;
1314                     double znew = - p.x * s - p.y * c;
1315                     p.y = p.z;
1316                     p.z = znew;
1317                     p.x = xnew;
1318                 }
1319
1320                 if (pos == trav->begin()) {
1321                     // First point is move...
1322#ifdef DEBUG_CAD3D
1323                     printf("surface move to %9.2f %9.2f %9.2f\n",x,y,z);
1324#endif
1325                     fPendingMove = 1;
1326                 } else {
1327#ifdef DEBUG_CAD3D
1328                     printf("surface line to %9.2f %9.2f %9.2f\n", p.x, p.y, p.z);
1329#endif
1330                     filt->line(&p1, &p, true, fPendingMove);
1331                     fPendingMove = 0;
1332                 }
1333                 p1 = p;
1334             }
1335         }
1336      }
1337      if (pass_mask & (STNS|LABELS|ENTS|FIXES|EXPORTS)) {
1338          list<LabelInfo*>::const_iterator pos = mainfrm->GetLabels();
1339          list<LabelInfo*>::const_iterator end = mainfrm->GetLabelsEnd();
1340          for ( ; pos != end; ++pos) {
1341              p.x = (*pos)->GetX() + x_offset;
1342              p.y = (*pos)->GetY() + y_offset;
1343              p.z = (*pos)->GetZ() + z_offset;
1344
1345              if (elevation) {
1346                  double xnew = p.x * c - p.y * s;
1347                  double znew = - p.x * s - p.y * c;
1348                  p.y = p.z;
1349                  p.z = znew;
1350                  p.x = xnew;
1351              }
1352#ifdef DEBUG_CAD3D
1353              printf("label '%s' at %9.2f %9.2f %9.2f\n",(*pos)->GetText(),x,y,z);
1354#endif
1355              int type = 0;
1356              if ((pass_mask & ENTS) && (*pos)->IsEntrance()) {
1357                  type = ENTS;
1358              } else if ((pass_mask & FIXES) && (*pos)->IsFixedPt()) {
1359                  type = FIXES;
1360              } else if ((pass_mask & EXPORTS) && (*pos)->IsExportedPt())  {
1361                  type = EXPORTS;
1362              } else if (pass_mask & LABELS) {
1363                  type = LABELS;
1364              }
1365              if (type) {
1366                  const char * text = (*pos)->GetText().mb_str();
1367                  /* Use !UNDERGROUND as the criterion - we want stations where
1368                   * a surface and underground survey meet to be in the
1369                   * underground layer */
1370                  filt->label(&p, text, !(*pos)->IsUnderground(), type);
1371              }
1372              if (pass_mask & STNS)
1373                  filt->cross(&p, !(*pos)->IsUnderground());
1374          }
1375      }
1376      if (pass_mask & (XSECT|WALLS|PASG)) {
1377          list<vector<XSect> >::const_iterator tube = mainfrm->tubes_begin();
1378          list<vector<XSect> >::const_iterator tube_end = mainfrm->tubes_end();
1379          for ( ; tube != tube_end; ++tube) {
1380              vector<XSect>::const_iterator pos = tube->begin();
1381              vector<XSect>::const_iterator end = tube->end();
1382              for ( ; pos != end; ++pos) {
1383                  const XSect & xs = *pos;
1384                  p.x = xs.GetX() + x_offset;
1385                  p.y = xs.GetY() + y_offset;
1386                  p.z = xs.GetZ() + z_offset;
1387
1388                  if (elevation) {
1389                      double xnew = p.x * c - p.y * s;
1390                      double znew = - p.x * s - p.y * c;
1391                      p.y = p.z;
1392                      p.z = znew;
1393                      p.x = xnew;
1394                      if (pass_mask & XSECT)
1395                          filt->xsect(&p, 0, xs.GetU(), xs.GetD());
1396                      if (pass_mask & WALL1)
1397                          filt->wall(&p, 0, xs.GetU());
1398                      if (pass_mask & WALL2)
1399                          filt->wall(&p, 180, xs.GetD());
1400                      if (pass_mask & PASG)
1401                          filt->passage(&p, 0, xs.GetU(), xs.GetD());
1402                  } else {
1403                      if (pass_mask & XSECT)
1404                          filt->xsect(&p, xs.get_right_bearing() + 180, xs.GetL(), xs.GetR());
1405                      if (pass_mask & WALL1)
1406                          filt->wall(&p, xs.get_right_bearing() + 180, xs.GetL());
1407                      if (pass_mask & WALL2)
1408                          filt->wall(&p, xs.get_right_bearing(), xs.GetR());
1409                      if (pass_mask & PASG)
1410                          filt->passage(&p, xs.get_right_bearing() + 180, xs.GetL(), xs.GetR());
1411                  }
1412              }
1413              filt->tube_end();
1414          }
1415      }
1416   }
1417   filt->footer();
1418   delete filt;
1419   osfree(htab);
1420   htab = NULL;
1421   return true;
1422}
Note: See TracBrowser for help on using the repository browser.