source: git/src/export.cc@ 18ff765

RELEASE/1.2 debug-ci debug-ci-sanitisers faster-cavernlog log-select main stereo stereo-2025 walls-data walls-data-hanging-as-warning warn-only-for-hanging-survey
Last change on this file since 18ff765 was 18ff765, checked in by Olly Betts <olly@…>, 11 years ago

src/export.cc,src/export.h,src/printwx.cc: For export formats where
scaling is supporting, aven now actually uses the scale specified in
the export dialog (previously it ignored this and used 1:500).

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