source: git/src/export.cc @ 5624403

RELEASE/1.2debug-cidebug-ci-sanitisersfaster-cavernloglog-selectstereostereo-2025walls-datawalls-data-hanging-as-warningwarn-only-for-hanging-survey
Last change on this file since 5624403 was fc68ad5, checked in by Olly Betts <olly@…>, 13 years ago

src/: Implement exporting of passages (ticket#4) for SVG. Currently
it is always on (I'll update the Export dialog shortly).

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