source: git/src/export.cc @ e24b7fb

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

lib/survex.pot,src/export.cc,src/export.h,src/printwx.cc: Add
"Origin in centre" and "Full coordinates" options to export

  • the latter fixes #10. GPX and PLT output force "full

coordinates".

  • Property mode set to 100644
File size: 39.5 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       double grid_, double text_height_, double marker_size_)
1097{
1098   int fPendingMove = 0;
1099   img_point p, p1;
1100   double s = 0, c = 0;
1101   const int *pass;
1102   bool elevation = (tilt == 0.0);
1103
1104   grid = grid_;
1105   text_height = text_height_;
1106   marker_size = marker_size_;
1107
1108#if 0 // FIXME: allow these to be set from aven somehow!
1109       case 'r': /* Reduction factor */
1110         scale = cmdline_double_arg();
1111         break;
1112       case 's':
1113         survey = optarg;
1114         break;
1115#endif
1116
1117   ExportFilter * filt;
1118   switch (format) {
1119       case FMT_DXF:
1120           filt = new DXF;
1121           break;
1122       case FMT_EPS:
1123           filt = new EPS;
1124           factor = POINTS_PER_MM * 1000.0 / scale;
1125           break;
1126       case FMT_GPX:
1127           filt = new GPX;
1128           show_mask |= FULL_COORDS;
1129           break;
1130       case FMT_HPGL:
1131           filt = new HPGL;
1132           // factor = POINTS_PER_MM * 1000.0 / scale;
1133           break;
1134       case FMT_PLT:
1135           filt = new PLT;
1136           show_mask |= FULL_COORDS;
1137           break;
1138       case FMT_SK:
1139           filt = new Skencil;
1140           factor = POINTS_PER_MM * 1000.0 / scale;
1141           break;
1142       case FMT_SVG:
1143           filt = new SVG;
1144           factor = 1000.0 / scale;
1145           break;
1146       default:
1147           return false;
1148   }
1149
1150   // FIXME: This should really use fn_str() - currently we probably can't
1151   // save to a Unicode path on wxmsw.
1152   if (!filt->fopen(fnm_out.mb_str())) {
1153       delete filt;
1154       return false;
1155   }
1156
1157   if (elevation) {
1158      s = sin(rad(pan));
1159      c = cos(rad(pan));
1160   }
1161
1162   /* Get drawing corners */
1163   min_x = min_y = min_z = HUGE_VAL;
1164   max_x = max_y = max_z = -HUGE_VAL;
1165   list<traverse>::const_iterator trav = mainfrm->traverses_begin();
1166   list<traverse>::const_iterator tend = mainfrm->traverses_end();
1167   for ( ; trav != tend; ++trav) {
1168        vector<PointInfo>::const_iterator pos = trav->begin();
1169        vector<PointInfo>::const_iterator end = trav->end();
1170        for ( ; pos != end; ++pos) {
1171            p.x = pos->GetX();
1172            p.y = pos->GetY();
1173            p.z = pos->GetZ();
1174
1175            if (elevation) {
1176                double xnew = p.x * c - p.y * s;
1177                double znew = - p.x * s - p.y * c;
1178                p.y = p.z;
1179                p.z = znew;
1180                p.x = xnew;
1181            }
1182
1183            if (p.x < min_x) min_x = p.x;
1184            if (p.x > max_x) max_x = p.x;
1185            if (p.y < min_y) min_y = p.y;
1186            if (p.y > max_y) max_y = p.y;
1187            if (p.z < min_z) min_z = p.z;
1188            if (p.z > max_z) max_z = p.z;
1189        }
1190   }
1191   {
1192        list<LabelInfo*>::const_iterator pos = mainfrm->GetLabels();
1193        list<LabelInfo*>::const_iterator end = mainfrm->GetLabelsEnd();
1194        for ( ; pos != end; ++pos) {
1195            p.x = (*pos)->GetX();
1196            p.y = (*pos)->GetY();
1197            p.z = (*pos)->GetZ();
1198
1199            if (elevation) {
1200                double xnew = p.x * c - p.y * s;
1201                double znew = - p.x * s - p.y * c;
1202                p.y = p.z;
1203                p.z = znew;
1204                p.x = xnew;
1205            }
1206
1207            if (p.x < min_x) min_x = p.x;
1208            if (p.x > max_x) max_x = p.x;
1209            if (p.y < min_y) min_y = p.y;
1210            if (p.y > max_y) max_y = p.y;
1211            if (p.z < min_z) min_z = p.z;
1212            if (p.z > max_z) max_z = p.z;
1213        }
1214   }
1215
1216   if (grid > 0) {
1217      min_x -= grid / 2;
1218      max_x += grid / 2;
1219      min_y -= grid / 2;
1220      max_y += grid / 2;
1221   }
1222
1223   /* handle empty file gracefully */
1224   if (min_x > max_x) {
1225      min_x = min_y = min_z = 0;
1226      max_x = max_y = max_z = 0;
1227   }
1228
1229   double x_offset, y_offset, z_offset;
1230   if (show_mask & FULL_COORDS) {
1231       // Full coordinates.
1232       x_offset = mainfrm->GetOffset().GetX();
1233       y_offset = mainfrm->GetOffset().GetY();
1234       z_offset = mainfrm->GetOffset().GetZ();
1235   } else if (show_mask & CENTRED) {
1236       // Centred.
1237       x_offset = (min_x + max_x) * -0.5;
1238       y_offset = (min_y + max_y) * -0.5;
1239       z_offset = (min_z + max_z) * -0.5;
1240   } else {
1241       // Origin at lowest SW corner.
1242       x_offset = -min_x;
1243       y_offset = -min_y;
1244       z_offset = -min_z;
1245   }
1246   min_x += x_offset;
1247   max_x += x_offset;
1248   min_y += y_offset;
1249   max_y += y_offset;
1250   min_z += z_offset;
1251   max_z += z_offset;
1252
1253   /* Header */
1254   filt->header(title.mb_str());
1255
1256   p1.x = p1.y = p1.z = 0; /* avoid compiler warning */
1257
1258   for (pass = filt->passes(); *pass; ++pass) {
1259      int pass_mask = show_mask & *pass;
1260      if (!pass_mask)
1261          continue;
1262      filt->start_pass(*pass);
1263      if (pass_mask & LEGS) {
1264          trav = mainfrm->traverses_begin();
1265          tend = mainfrm->traverses_end();
1266          for ( ; trav != tend; ++trav) {
1267             assert(trav->size() > 1);
1268             vector<PointInfo>::const_iterator pos = trav->begin();
1269             vector<PointInfo>::const_iterator end = trav->end();
1270             for ( ; pos != end; ++pos) {
1271                 p.x = pos->GetX() + x_offset;
1272                 p.y = pos->GetY() + y_offset;
1273                 p.z = pos->GetZ() + z_offset;
1274                 if (elevation) {
1275                     double xnew = p.x * c - p.y * s;
1276                     double znew = - p.x * s - p.y * c;
1277                     p.y = p.z;
1278                     p.z = znew;
1279                     p.x = xnew;
1280                 }
1281
1282                 if (pos == trav->begin()) {
1283                     // First point is move...
1284#ifdef DEBUG_CAD3D
1285                     printf("move to %9.2f %9.2f %9.2f\n",x,y,z);
1286#endif
1287                     fPendingMove = 1;
1288                 } else {
1289#ifdef DEBUG_CAD3D
1290                     printf("line to %9.2f %9.2f %9.2f\n", p.x, p.y, p.z);
1291#endif
1292                     filt->line(&p1, &p, false, fPendingMove);
1293                     fPendingMove = 0;
1294                 }
1295                 p1 = p;
1296             }
1297         }
1298      }
1299      if (pass_mask & SURF) {
1300          trav = mainfrm->surface_traverses_begin();
1301          tend = mainfrm->surface_traverses_end();
1302          for ( ; trav != tend; ++trav) {
1303             assert(trav->size() > 1);
1304             vector<PointInfo>::const_iterator pos = trav->begin();
1305             vector<PointInfo>::const_iterator end = trav->end();
1306             for ( ; pos != end; ++pos) {
1307                 p.x = pos->GetX() + x_offset;
1308                 p.y = pos->GetY() + y_offset;
1309                 p.z = pos->GetZ() + z_offset;
1310
1311                 if (elevation) {
1312                     double xnew = p.x * c - p.y * s;
1313                     double znew = - p.x * s - p.y * c;
1314                     p.y = p.z;
1315                     p.z = znew;
1316                     p.x = xnew;
1317                 }
1318
1319                 if (pos == trav->begin()) {
1320                     // First point is move...
1321#ifdef DEBUG_CAD3D
1322                     printf("surface move to %9.2f %9.2f %9.2f\n",x,y,z);
1323#endif
1324                     fPendingMove = 1;
1325                 } else {
1326#ifdef DEBUG_CAD3D
1327                     printf("surface line to %9.2f %9.2f %9.2f\n", p.x, p.y, p.z);
1328#endif
1329                     filt->line(&p1, &p, true, fPendingMove);
1330                     fPendingMove = 0;
1331                 }
1332                 p1 = p;
1333             }
1334         }
1335      }
1336      if (pass_mask & (STNS|LABELS|ENTS|FIXES|EXPORTS)) {
1337          list<LabelInfo*>::const_iterator pos = mainfrm->GetLabels();
1338          list<LabelInfo*>::const_iterator end = mainfrm->GetLabelsEnd();
1339          for ( ; pos != end; ++pos) {
1340              p.x = (*pos)->GetX() + x_offset;
1341              p.y = (*pos)->GetY() + y_offset;
1342              p.z = (*pos)->GetZ() + z_offset;
1343
1344              if (elevation) {
1345                  double xnew = p.x * c - p.y * s;
1346                  double znew = - p.x * s - p.y * c;
1347                  p.y = p.z;
1348                  p.z = znew;
1349                  p.x = xnew;
1350              }
1351#ifdef DEBUG_CAD3D
1352              printf("label '%s' at %9.2f %9.2f %9.2f\n",(*pos)->GetText(),x,y,z);
1353#endif
1354              int type = 0;
1355              if ((pass_mask & ENTS) && (*pos)->IsEntrance()) {
1356                  type = ENTS;
1357              } else if ((pass_mask & FIXES) && (*pos)->IsFixedPt()) {
1358                  type = FIXES;
1359              } else if ((pass_mask & EXPORTS) && (*pos)->IsExportedPt())  {
1360                  type = EXPORTS;
1361              } else if (pass_mask & LABELS) {
1362                  type = LABELS;
1363              }
1364              if (type) {
1365                  const char * text = (*pos)->GetText().mb_str();
1366                  /* Use !UNDERGROUND as the criterion - we want stations where
1367                   * a surface and underground survey meet to be in the
1368                   * underground layer */
1369                  filt->label(&p, text, !(*pos)->IsUnderground(), type);
1370              }
1371              if (pass_mask & STNS)
1372                  filt->cross(&p, !(*pos)->IsUnderground());
1373          }
1374      }
1375      if (pass_mask & (XSECT|WALLS|PASG)) {
1376          list<vector<XSect> >::const_iterator tube = mainfrm->tubes_begin();
1377          list<vector<XSect> >::const_iterator tube_end = mainfrm->tubes_end();
1378          for ( ; tube != tube_end; ++tube) {
1379              vector<XSect>::const_iterator pos = tube->begin();
1380              vector<XSect>::const_iterator end = tube->end();
1381              for ( ; pos != end; ++pos) {
1382                  const XSect & xs = *pos;
1383                  p.x = xs.GetX() + x_offset;
1384                  p.y = xs.GetY() + y_offset;
1385                  p.z = xs.GetZ() + z_offset;
1386
1387                  if (elevation) {
1388                      double xnew = p.x * c - p.y * s;
1389                      double znew = - p.x * s - p.y * c;
1390                      p.y = p.z;
1391                      p.z = znew;
1392                      p.x = xnew;
1393                      if (pass_mask & XSECT)
1394                          filt->xsect(&p, 0, xs.GetU(), xs.GetD());
1395                      if (pass_mask & WALL1)
1396                          filt->wall(&p, 0, xs.GetU());
1397                      if (pass_mask & WALL2)
1398                          filt->wall(&p, 180, xs.GetD());
1399                      if (pass_mask & PASG)
1400                          filt->passage(&p, 0, xs.GetU(), xs.GetD());
1401                  } else {
1402                      if (pass_mask & XSECT)
1403                          filt->xsect(&p, xs.get_right_bearing() + 180, xs.GetL(), xs.GetR());
1404                      if (pass_mask & WALL1)
1405                          filt->wall(&p, xs.get_right_bearing() + 180, xs.GetL());
1406                      if (pass_mask & WALL2)
1407                          filt->wall(&p, xs.get_right_bearing(), xs.GetR());
1408                      if (pass_mask & PASG)
1409                          filt->passage(&p, xs.get_right_bearing() + 180, xs.GetL(), xs.GetR());
1410                  }
1411              }
1412              filt->tube_end();
1413          }
1414      }
1415   }
1416   filt->footer();
1417   delete filt;
1418   osfree(htab);
1419   htab = NULL;
1420   return true;
1421}
Note: See TracBrowser for help on using the repository browser.