source: git/src/export.cc @ 0fa7aac

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

src/: Remove unused parameter names.

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