source: git/src/export.cc @ 6409cd0

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

src/export.cc: Fix to build with wx 2.9.2.

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

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