2 * Export to CAD-like formats (DXF, Skencil, SVG, EPS) and also Compass PLT.
5 /* Copyright (C) 1994-2004,2005,2006,2008,2010,2011,2012,2013,2014,2015,2016 Olly Betts
6 * Copyright (C) 2004 John Pybus (SVG Output code)
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.
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.
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
23 /* #define DEBUG_CAD3D */
33 #include "exportfilter.h"
49 #if defined(HAVE_GETPWUID) && !defined(__DJGPP__)
51 # include <sys/types.h>
62 #include "img_hosted.h"
66 #define POINTS_PER_INCH 72.0
67 #define POINTS_PER_MM (POINTS_PER_INCH / MM_PER_INCH)
69 #define SQRT_2 1.41421356237309504880168872420969
72 html_escape(FILE *fh
, const char *s
)
92 // Used by Skencil and SVG.
93 static const char *layer_name(int mask
) {
95 case LEGS
: case LEGS
|SURF
:
104 return "Cross-sections";
105 case WALL1
: case WALL2
: case WALLS
:
113 static double marker_size
; /* for station markers */
114 static double grid
; /* grid spacing (or 0 for no grid) */
117 ExportFilter::passes() const
119 static const int default_passes
[] = { LEGS
|SURF
|STNS
|LABELS
, 0 };
120 return default_passes
;
123 class DXF
: public ExportFilter
{
124 const char * to_close
;
125 /* for station labels */
130 explicit DXF(double text_height_
)
131 : to_close(0), text_height(text_height_
) { pending
[0] = '\0'; }
132 const int * passes() const;
133 bool fopen(const wxString
& fnm_out
);
134 void header(const char *, const char *, time_t,
135 double min_x
, double min_y
, double min_z
,
136 double max_x
, double max_y
, double max_z
);
137 void line(const img_point
*, const img_point
*, unsigned, bool);
138 void label(const img_point
*, const char *, bool, int);
139 void cross(const img_point
*, bool);
140 void xsect(const img_point
*, double, double, double);
141 void wall(const img_point
*, double, double);
142 void passage(const img_point
*, double, double, double);
150 static const int dxf_passes
[] = {
151 PASG
, XSECT
, WALL1
, WALL2
, LEGS
|SURF
|STNS
|LABELS
, 0
157 DXF::fopen(const wxString
& fnm_out
)
159 // DXF gets written as text rather than binary.
160 fh
= wxFopen(fnm_out
.fn_str(), wxT("w"));
165 DXF::header(const char *, const char *, time_t,
166 double min_x
, double min_y
, double min_z
,
167 double max_x
, double max_y
, double max_z
)
169 fprintf(fh
, "0\nSECTION\n"
171 fprintf(fh
, "9\n$EXTMIN\n"); /* lower left corner of drawing */
172 fprintf(fh
, "10\n%#-.6f\n", min_x
); /* x */
173 fprintf(fh
, "20\n%#-.6f\n", min_y
); /* y */
174 fprintf(fh
, "30\n%#-.6f\n", min_z
); /* min z */
175 fprintf(fh
, "9\n$EXTMAX\n"); /* upper right corner of drawing */
176 fprintf(fh
, "10\n%#-.6f\n", max_x
); /* x */
177 fprintf(fh
, "20\n%#-.6f\n", max_y
); /* y */
178 fprintf(fh
, "30\n%#-.6f\n", max_z
); /* max z */
179 fprintf(fh
, "9\n$PDMODE\n70\n3\n"); /* marker style as CROSS */
180 fprintf(fh
, "9\n$PDSIZE\n40\n%6.2f\n", marker_size
); /* marker size */
181 fprintf(fh
, "0\nENDSEC\n");
183 fprintf(fh
, "0\nSECTION\n"
185 fprintf(fh
, "0\nTABLE\n" /* Define CONTINUOUS and DASHED line types. */
205 fprintf(fh
, "0\nTABLE\n"
207 fprintf(fh
, "70\n10\n"); /* max # off layers in this DXF file : 10 */
208 /* First Layer: CentreLine */
209 fprintf(fh
, "0\nLAYER\n2\nCentreLine\n");
210 fprintf(fh
, "70\n64\n"); /* shows layer is referenced by entities */
211 fprintf(fh
, "62\n5\n"); /* color: kept the same used by SpeleoGen */
212 fprintf(fh
, "6\nCONTINUOUS\n"); /* linetype */
213 /* Next Layer: Stations */
214 fprintf(fh
, "0\nLAYER\n2\nStations\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: Labels */
219 fprintf(fh
, "0\nLAYER\n2\nLabels\n");
220 fprintf(fh
, "70\n64\n"); /* shows layer is referenced by entities */
221 fprintf(fh
, "62\n7\n"); /* color: kept the same used by SpeleoGen */
222 fprintf(fh
, "6\nCONTINUOUS\n"); /* linetype */
223 /* Next Layer: Surface */
224 fprintf(fh
, "0\nLAYER\n2\nSurface\n");
225 fprintf(fh
, "70\n64\n"); /* shows layer is referenced by entities */
226 fprintf(fh
, "62\n5\n"); /* color */
227 fprintf(fh
, "6\nDASHED\n"); /* linetype */
228 /* Next Layer: SurfaceStations */
229 fprintf(fh
, "0\nLAYER\n2\nSurfaceStations\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 /* Next Layer: SurfaceLabels */
234 fprintf(fh
, "0\nLAYER\n2\nSurfaceLabels\n");
235 fprintf(fh
, "70\n64\n"); /* shows layer is referenced by entities */
236 fprintf(fh
, "62\n7\n"); /* color */
237 fprintf(fh
, "6\nCONTINUOUS\n"); /* linetype */
239 /* Next Layer: Grid */
240 fprintf(fh
, "0\nLAYER\n2\nGrid\n");
241 fprintf(fh
, "70\n64\n"); /* shows layer is referenced by entities */
242 fprintf(fh
, "62\n7\n"); /* color: kept the same used by SpeleoGen */
243 fprintf(fh
, "6\nCONTINUOUS\n"); /* linetype */
245 fprintf(fh
, "0\nENDTAB\n"
248 fprintf(fh
, "0\nSECTION\n"
253 x
= floor(min_x
/ grid
) * grid
+ grid
;
254 y
= floor(min_y
/ grid
) * grid
+ grid
;
256 printf("x_min: %f y_min: %f\n", x
, y
);
259 /* horizontal line */
260 fprintf(fh
, "0\nLINE\n");
261 fprintf(fh
, "8\nGrid\n"); /* Layer */
262 fprintf(fh
, "10\n%6.2f\n", x
);
263 fprintf(fh
, "20\n%6.2f\n", min_y
);
264 fprintf(fh
, "30\n0\n");
265 fprintf(fh
, "11\n%6.2f\n", x
);
266 fprintf(fh
, "21\n%6.2f\n", max_y
);
267 fprintf(fh
, "31\n0\n");
272 fprintf(fh
, "0\nLINE\n");
273 fprintf(fh
, "8\nGrid\n"); /* Layer */
274 fprintf(fh
, "10\n%6.2f\n", min_x
);
275 fprintf(fh
, "20\n%6.2f\n", y
);
276 fprintf(fh
, "30\n0\n");
277 fprintf(fh
, "11\n%6.2f\n", max_x
);
278 fprintf(fh
, "21\n%6.2f\n", y
);
279 fprintf(fh
, "31\n0\n");
286 DXF::line(const img_point
*p1
, const img_point
*p
, unsigned flags
, bool fPendingMove
)
288 bool fSurface
= (flags
& SURF
);
289 (void)fPendingMove
; /* unused */
290 fprintf(fh
, "0\nLINE\n");
291 fprintf(fh
, fSurface
? "8\nSurface\n" : "8\nCentreLine\n"); /* Layer */
292 fprintf(fh
, "10\n%6.2f\n", p1
->x
);
293 fprintf(fh
, "20\n%6.2f\n", p1
->y
);
294 fprintf(fh
, "30\n%6.2f\n", p1
->z
);
295 fprintf(fh
, "11\n%6.2f\n", p
->x
);
296 fprintf(fh
, "21\n%6.2f\n", p
->y
);
297 fprintf(fh
, "31\n%6.2f\n", p
->z
);
301 DXF::label(const img_point
*p
, const char *s
, bool fSurface
, int)
303 /* write station label to dxf file */
304 fprintf(fh
, "0\nTEXT\n");
305 fprintf(fh
, fSurface
? "8\nSurfaceLabels\n" : "8\nLabels\n"); /* Layer */
306 fprintf(fh
, "10\n%6.2f\n", p
->x
);
307 fprintf(fh
, "20\n%6.2f\n", p
->y
);
308 fprintf(fh
, "30\n%6.2f\n", p
->z
);
309 fprintf(fh
, "40\n%6.2f\n", text_height
);
310 fprintf(fh
, "1\n%s\n", s
);
314 DXF::cross(const img_point
*p
, bool fSurface
)
316 /* write station marker to dxf file */
317 fprintf(fh
, "0\nPOINT\n");
318 fprintf(fh
, fSurface
? "8\nSurfaceStations\n" : "8\nStations\n"); /* Layer */
319 fprintf(fh
, "10\n%6.2f\n", p
->x
);
320 fprintf(fh
, "20\n%6.2f\n", p
->y
);
321 fprintf(fh
, "30\n%6.2f\n", p
->z
);
325 DXF::xsect(const img_point
*p
, double angle
, double d1
, double d2
)
327 double s
= sin(rad(angle
));
328 double c
= cos(rad(angle
));
329 fprintf(fh
, "0\nLINE\n");
330 fprintf(fh
, "8\nCross-sections\n"); /* Layer */
331 fprintf(fh
, "10\n%6.2f\n", p
->x
+ c
* d1
);
332 fprintf(fh
, "20\n%6.2f\n", p
->y
+ s
* d1
);
333 fprintf(fh
, "30\n%6.2f\n", p
->z
);
334 fprintf(fh
, "11\n%6.2f\n", p
->x
- c
* d2
);
335 fprintf(fh
, "21\n%6.2f\n", p
->y
- s
* d2
);
336 fprintf(fh
, "31\n%6.2f\n", p
->z
);
340 DXF::wall(const img_point
*p
, double angle
, double d
)
343 fprintf(fh
, "0\nPOLYLINE\n");
344 fprintf(fh
, "8\nWalls\n"); /* Layer */
345 fprintf(fh
, "70\n0\n"); /* bit 0 == 0 => Open polyline */
346 to_close
= "0\nSEQEND\n";
348 double s
= sin(rad(angle
));
349 double c
= cos(rad(angle
));
350 fprintf(fh
, "0\nVERTEX\n");
351 fprintf(fh
, "8\nWalls\n"); /* Layer */
352 fprintf(fh
, "10\n%6.2f\n", p
->x
+ c
* d
);
353 fprintf(fh
, "20\n%6.2f\n", p
->y
+ s
* d
);
354 fprintf(fh
, "30\n%6.2f\n", p
->z
);
358 DXF::passage(const img_point
*p
, double angle
, double d1
, double d2
)
360 fprintf(fh
, "0\nSOLID\n");
361 fprintf(fh
, "8\nPassages\n"); /* Layer */
362 double s
= sin(rad(angle
));
363 double c
= cos(rad(angle
));
364 double x1
= p
->x
+ c
* d1
;
365 double y1
= p
->y
+ s
* d1
;
366 double x2
= p
->x
- c
* d2
;
367 double y2
= p
->y
- s
* d2
;
370 fprintf(fh
, "12\n%6.2f\n22\n%6.2f\n32\n%6.2f\n"
371 "13\n%6.2f\n23\n%6.2f\n33\n%6.2f\n",
375 sprintf(pending
, "10\n%6.2f\n20\n%6.2f\n30\n%6.2f\n"
376 "11\n%6.2f\n21\n%6.2f\n31\n%6.2f\n",
394 fprintf(fh
, "000\nENDSEC\n");
395 fprintf(fh
, "000\nEOF\n");
398 class Skencil
: public ExportFilter
{
401 explicit Skencil(double scale
)
402 : factor(POINTS_PER_MM
* 1000.0 / scale
) { }
403 const int * passes() const;
404 void header(const char *, const char *, time_t,
405 double min_x
, double min_y
, double min_z
,
406 double max_x
, double max_y
, double max_z
);
407 void start_pass(int layer
);
408 void line(const img_point
*, const img_point
*, unsigned, bool);
409 void label(const img_point
*, const char *, bool, int);
410 void cross(const img_point
*, bool);
415 Skencil::passes() const
417 static const int skencil_passes
[] = { LEGS
|SURF
, STNS
, LABELS
, 0 };
418 return skencil_passes
;
422 Skencil::header(const char *, const char *, time_t,
423 double min_x
, double min_y
, double /*min_z*/,
424 double max_x
, double max_y
, double /*max_z*/)
426 fprintf(fh
, "##Sketch 1 2\n"); /* File format version */
427 fprintf(fh
, "document()\n");
428 fprintf(fh
, "layout((%.3f,%.3f),0)\n",
429 (max_x
- min_x
) * factor
, (max_y
- min_y
) * factor
);
433 Skencil::start_pass(int layer
)
435 fprintf(fh
, "layer('%s',1,1,0,0,(0,0,0))\n", layer_name(layer
));
439 Skencil::line(const img_point
*p1
, const img_point
*p
, unsigned flags
, bool fPendingMove
)
441 (void)flags
; /* unused */
443 fprintf(fh
, "b()\n");
444 fprintf(fh
, "bs(%.3f,%.3f,%.3f)\n", p1
->x
* factor
, p1
->y
* factor
, 0.0);
446 fprintf(fh
, "bs(%.3f,%.3f,%.3f)\n", p
->x
* factor
, p
->y
* factor
, 0.0);
450 Skencil::label(const img_point
*p
, const char *s
, bool fSurface
, int)
452 (void)fSurface
; /* unused */
453 fprintf(fh
, "fp((0,0,0))\n");
454 fprintf(fh
, "le()\n");
455 fprintf(fh
, "Fn('Times-Roman')\n");
456 fprintf(fh
, "Fs(5)\n");
457 fprintf(fh
, "txt('");
460 if (ch
== '\'' || ch
== '\\') PUTC('\\', fh
);
463 fprintf(fh
, "',(%.3f,%.3f))\n", p
->x
* factor
, p
->y
* factor
);
467 Skencil::cross(const img_point
*p
, bool fSurface
)
469 (void)fSurface
; /* unused */
470 fprintf(fh
, "b()\n");
471 fprintf(fh
, "bs(%.3f,%.3f,%.3f)\n",
472 p
->x
* factor
- marker_size
, p
->y
* factor
- marker_size
, 0.0);
473 fprintf(fh
, "bs(%.3f,%.3f,%.3f)\n",
474 p
->x
* factor
+ marker_size
, p
->y
* factor
+ marker_size
, 0.0);
475 fprintf(fh
, "bn()\n");
476 fprintf(fh
, "bs(%.3f,%.3f,%.3f)\n",
477 p
->x
* factor
+ marker_size
, p
->y
* factor
- marker_size
, 0.0);
478 fprintf(fh
, "bs(%.3f,%.3f,%.3f)\n",
479 p
->x
* factor
- marker_size
, p
->y
* factor
+ marker_size
, 0.0);
483 Skencil::footer(void)
485 fprintf(fh
, "guidelayer('Guide Lines',1,0,0,1,(0,0,1))\n");
487 fprintf(fh
, "grid((0,0,%.3f,%.3f),1,(0,0,1),'Grid')\n",
488 grid
* factor
, grid
* factor
);
492 typedef struct point
{
498 #define HTAB_SIZE 0x2000
503 set_name(const img_point
*p
, const char *s
)
508 char data
[sizeof(int) * 3];
512 u
.x
[0] = (int)(p
->x
* 100);
513 u
.x
[1] = (int)(p
->y
* 100);
514 u
.x
[2] = (int)(p
->z
* 100);
515 hash
= (hash_data(u
.data
, sizeof(int) * 3) & (HTAB_SIZE
- 1));
516 for (pt
= htab
[hash
]; pt
; pt
= pt
->next
) {
517 if (pt
->p
.x
== p
->x
&& pt
->p
.y
== p
->y
&& pt
->p
.z
== p
->z
) {
518 /* already got name for these coordinates */
519 /* FIXME: what about multiple names for the same station? */
525 pt
->label
= osstrdup(s
);
527 pt
->next
= htab
[hash
];
534 find_name(const img_point
*p
)
539 char data
[sizeof(int) * 3];
544 u
.x
[0] = (int)(p
->x
* 100);
545 u
.x
[1] = (int)(p
->y
* 100);
546 u
.x
[2] = (int)(p
->z
* 100);
547 hash
= (hash_data(u
.data
, sizeof(int) * 3) & (HTAB_SIZE
- 1));
548 for (pt
= htab
[hash
]; pt
; pt
= pt
->next
) {
549 if (pt
->p
.x
== p
->x
&& pt
->p
.y
== p
->y
&& pt
->p
.z
== p
->z
)
555 class SVG
: public ExportFilter
{
556 const char * to_close
;
559 /* for station labels */
564 SVG(double scale
, double text_height_
)
567 factor(1000.0 / scale
),
568 text_height(text_height_
) {
571 const int * passes() const;
572 void header(const char *, const char *, time_t,
573 double min_x
, double min_y
, double min_z
,
574 double max_x
, double max_y
, double max_z
);
575 void start_pass(int layer
);
576 void line(const img_point
*, const img_point
*, unsigned, bool);
577 void label(const img_point
*, const char *, bool, int);
578 void cross(const img_point
*, bool);
579 void xsect(const img_point
*, double, double, double);
580 void wall(const img_point
*, double, double);
581 void passage(const img_point
*, double, double, double);
589 static const int svg_passes
[] = {
590 PASG
, LEGS
|SURF
, XSECT
, WALL1
, WALL2
, LABELS
, STNS
, 0
596 SVG::header(const char * title
, const char *, time_t,
597 double min_x
, double min_y
, double /*min_z*/,
598 double max_x
, double max_y
, double /*max_z*/)
600 const char *unit
= "mm";
601 const double SVG_MARGIN
= 5.0; // In units of "unit".
602 htab
= (point
**)osmalloc(HTAB_SIZE
* ossizeof(point
*));
603 for (size_t i
= 0; i
< HTAB_SIZE
; ++i
) htab
[i
] = NULL
;
604 fprintf(fh
, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
605 double width
= (max_x
- min_x
) * factor
+ SVG_MARGIN
* 2;
606 double height
= (max_y
- min_y
) * factor
+ SVG_MARGIN
* 2;
607 fprintf(fh
, "<svg version=\"1.1\" baseProfile=\"full\"\n"
608 "xmlns=\"http://www.w3.org/2000/svg\"\n"
609 "xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n"
610 "xmlns:ev=\"http://www.w3.org/2001/xml-events\"\n"
611 "width=\"%.3f%s\" height=\"%.3f%s\"\n"
612 "viewBox=\"0 0 %0.3f %0.3f\">\n",
613 width
, unit
, height
, unit
, width
, height
);
614 if (title
&& title
[0]) {
615 fputs("<title>", fh
);
616 html_escape(fh
, title
);
617 fputs("</title>\n", fh
);
619 fprintf(fh
, "<g transform=\"translate(%.3f %.3f)\">\n",
620 SVG_MARGIN
- min_x
* factor
, SVG_MARGIN
+ max_y
* factor
);
626 SVG::start_pass(int layer
)
633 fprintf(fh
, "</g>\n");
635 fprintf(fh
, "<g id=\"%s\"", layer_name(layer
));
637 fprintf(fh
, " stroke=\"black\" fill=\"none\" stroke-width=\"0.4px\"");
638 else if (layer
& STNS
)
639 fprintf(fh
, " stroke=\"black\" fill=\"none\" stroke-width=\"0.05px\"");
640 else if (layer
& LABELS
)
641 fprintf(fh
, " font-size=\"%.3fem\"", text_height
);
642 else if (layer
& XSECT
)
643 fprintf(fh
, " stroke=\"grey\" fill=\"none\" stroke-width=\"0.1px\"");
644 else if (layer
& WALLS
)
645 fprintf(fh
, " stroke=\"black\" fill=\"none\" stroke-width=\"0.1px\"");
646 else if (layer
& PASG
)
647 fprintf(fh
, " stroke=\"none\" fill=\"peru\"");
654 SVG::line(const img_point
*p1
, const img_point
*p
, unsigned flags
, bool fPendingMove
)
656 bool splay
= (flags
& SPLAYS
);
661 fprintf(fh
, "<path ");
662 if (splay
) fprintf(fh
, "stroke=\"grey\" stroke-width=\"0.1px\" ");
663 fprintf(fh
, "d=\"M%.3f %.3f", p1
->x
* factor
, p1
->y
* -factor
);
665 fprintf(fh
, "L%.3f %.3f", p
->x
* factor
, p
->y
* -factor
);
670 SVG::label(const img_point
*p
, const char *s
, bool fSurface
, int)
672 (void)fSurface
; /* unused */
673 fprintf(fh
, "<text transform=\"translate(%.3f %.3f)\">",
674 p
->x
* factor
, p
->y
* -factor
);
676 fputs("</text>\n", fh
);
681 SVG::cross(const img_point
*p
, bool fSurface
)
683 (void)fSurface
; /* unused */
684 fprintf(fh
, "<circle id=\"%s\" cx=\"%.3f\" cy=\"%.3f\" r=\"%.3f\"/>\n",
685 find_name(p
), p
->x
* factor
, p
->y
* -factor
, marker_size
* SQRT_2
);
686 fprintf(fh
, "<path d=\"M%.3f %.3fL%.3f %.3fM%.3f %.3fL%.3f %.3f\"/>\n",
687 p
->x
* factor
- marker_size
, p
->y
* -factor
- marker_size
,
688 p
->x
* factor
+ marker_size
, p
->y
* -factor
+ marker_size
,
689 p
->x
* factor
+ marker_size
, p
->y
* -factor
- marker_size
,
690 p
->x
* factor
- marker_size
, p
->y
* -factor
+ marker_size
);
694 SVG::xsect(const img_point
*p
, double angle
, double d1
, double d2
)
696 double s
= sin(rad(angle
));
697 double c
= cos(rad(angle
));
698 fprintf(fh
, "<path d=\"M%.3f %.3fL%.3f %.3f\"/>\n",
699 (p
->x
+ c
* d1
) * factor
, (p
->y
+ s
* d1
) * -factor
,
700 (p
->x
- c
* d2
) * factor
, (p
->y
- s
* d2
) * -factor
);
704 SVG::wall(const img_point
*p
, double angle
, double d
)
707 fprintf(fh
, "<path d=\"M");
712 double s
= sin(rad(angle
));
713 double c
= cos(rad(angle
));
714 fprintf(fh
, "%.3f %.3f", (p
->x
+ c
* d
) * factor
, (p
->y
+ s
* d
) * -factor
);
718 SVG::passage(const img_point
*p
, double angle
, double d1
, double d2
)
720 double s
= sin(rad(angle
));
721 double c
= cos(rad(angle
));
722 double x1
= (p
->x
+ c
* d1
) * factor
;
723 double y1
= (p
->y
+ s
* d1
) * -factor
;
724 double x2
= (p
->x
- c
* d2
) * factor
;
725 double y2
= (p
->y
- s
* d2
) * -factor
;
728 fprintf(fh
, "L%.3f %.3fL%.3f %.3fZ\"/>\n", x2
, y2
, x1
, y1
);
730 sprintf(pending
, "<path d=\"M%.3f %.3fL%.3f %.3f", x1
, y1
, x2
, y2
);
751 fprintf(fh
, "</g>\n");
754 fprintf(fh
, "</g>\n</svg>\n");
757 class PLT
: public ExportFilter
{
760 const char * find_name_plt(const img_point
*p
);
762 double min_N
, max_N
, min_E
, max_E
, min_A
, max_A
;
766 const int * passes() const;
767 void header(const char *, const char *, time_t,
768 double min_x
, double min_y
, double min_z
,
769 double max_x
, double max_y
, double max_z
);
770 void line(const img_point
*, const img_point
*, unsigned, bool);
771 void label(const img_point
*, const char *, bool, int);
778 static const int plt_passes
[] = { LABELS
, LEGS
|SURF
, 0 };
783 PLT::header(const char *title
, const char *, time_t,
784 double min_x
, double min_y
, double min_z
,
785 double max_x
, double max_y
, double max_z
)
787 // FIXME: allow survey to be set from aven somehow!
788 const char *survey
= NULL
;
789 htab
= (point
**)osmalloc(HTAB_SIZE
* ossizeof(point
*));
790 for (size_t i
= 0; i
< HTAB_SIZE
; ++i
) htab
[i
] = NULL
;
791 /* Survex is E, N, Alt - PLT file is N, E, Alt */
792 min_N
= min_y
/ METRES_PER_FOOT
;
793 max_N
= max_y
/ METRES_PER_FOOT
;
794 min_E
= min_x
/ METRES_PER_FOOT
;
795 max_E
= max_x
/ METRES_PER_FOOT
;
796 min_A
= min_z
/ METRES_PER_FOOT
;
797 max_A
= max_z
/ METRES_PER_FOOT
;
798 fprintf(fh
, "Z %.3f %.3f %.3f %.3f %.3f %.3f\r\n",
799 min_N
, max_N
, min_E
, max_E
, min_A
, max_A
);
800 fprintf(fh
, "N%s D 1 1 1 C%s\r\n", survey
? survey
: "X",
801 (title
&& title
[0]) ? title
: "X");
805 PLT::line(const img_point
*p1
, const img_point
*p
, unsigned flags
, bool fPendingMove
)
807 (void)flags
; /* unused */
809 /* Survex is E, N, Alt - PLT file is N, E, Alt */
810 fprintf(fh
, "M %.3f %.3f %.3f ",
811 p1
->y
/ METRES_PER_FOOT
, p1
->x
/ METRES_PER_FOOT
, p1
->z
/ METRES_PER_FOOT
);
812 /* dummy passage dimensions are required to avoid compass bug */
813 fprintf(fh
, "S%s P -9 -9 -9 -9\r\n", find_name_plt(p1
));
815 /* Survex is E, N, Alt - PLT file is N, E, Alt */
816 fprintf(fh
, "D %.3f %.3f %.3f ",
817 p
->y
/ METRES_PER_FOOT
, p
->x
/ METRES_PER_FOOT
, p
->z
/ METRES_PER_FOOT
);
818 /* dummy passage dimensions are required to avoid compass bug */
819 fprintf(fh
, "S%s P -9 -9 -9 -9\r\n", find_name_plt(p
));
823 PLT::find_name_plt(const img_point
*p
)
825 const char * s
= find_name(p
);
828 // PLT format can't handle spaces or control characters, so escape them
829 // like in URLs (an arbitrary choice of escaping, but at least a familiar
830 // one and % isn't likely to occur in station names).
832 for (q
= s
; *q
; ++q
) {
833 unsigned char ch
= *q
;
834 if (ch
<= ' ' || ch
== '%') {
835 escaped
.append(s
, q
- s
);
837 escaped
+= "0123456789abcdef"[ch
>> 4];
838 escaped
+= "0123456789abcdef"[ch
& 0x0f];
842 if (!escaped
.empty()) {
843 escaped
.append(s
, q
- s
);
844 return escaped
.c_str();
850 PLT::label(const img_point
*p
, const char *s
, bool fSurface
, int)
852 (void)fSurface
; /* unused */
859 /* Survex is E, N, Alt - PLT file is N, E, Alt */
860 fprintf(fh
, "X %.3f %.3f %.3f %.3f %.3f %.3f\r\n",
861 min_N
, max_N
, min_E
, max_E
, min_A
, max_A
);
862 /* Yucky DOS "end of textfile" marker */
866 class EPS
: public ExportFilter
{
869 vector
<pair
<double, double> > psg
;
871 explicit EPS(double scale
)
872 : factor(POINTS_PER_MM
* 1000.0 / scale
) { }
873 const int * passes() const;
874 void header(const char *, const char *, time_t,
875 double min_x
, double min_y
, double min_z
,
876 double max_x
, double max_y
, double max_z
);
877 void start_pass(int layer
);
878 void line(const img_point
*, const img_point
*, unsigned, bool);
879 void label(const img_point
*, const char *, bool, int);
880 void cross(const img_point
*, bool);
881 void xsect(const img_point
*, double, double, double);
882 void wall(const img_point
*, double, double);
883 void passage(const img_point
*, double, double, double);
891 static const int eps_passes
[] = {
892 PASG
, XSECT
, WALL1
, WALL2
, LEGS
|SURF
|STNS
|LABELS
, 0
898 EPS::header(const char *title
, const char *, time_t,
899 double min_x
, double min_y
, double /*min_z*/,
900 double max_x
, double max_y
, double /*max_z*/)
902 const char * fontname_labels
= "helvetica"; // FIXME
903 int fontsize_labels
= 10; // FIXME
904 fputs("%!PS-Adobe-2.0 EPSF-1.2\n", fh
);
905 fputs("%%Creator: Survex " VERSION
" EPS Export Filter\n", fh
);
907 if (title
&& title
[0])
908 fprintf(fh
, "%%%%Title: %s\n", title
);
911 time_t now
= time(NULL
);
912 if (strftime(buf
, sizeof(buf
), "%Y-%m-%d %H:%M:%S %Z\n", localtime(&now
))) {
913 fputs("%%CreationDate: ", fh
);
918 #if defined(HAVE_GETPWUID) && !defined(__DJGPP__)
919 struct passwd
* ent
= getpwuid(getuid());
920 if (ent
&& ent
->pw_gecos
[0]) name
= ent
->pw_gecos
;
923 name
= ::wxGetUserName().mb_str();
925 name
= ::wxGetUserId().mb_str();
929 fprintf(fh
, "%%%%For: %s\n", name
.c_str());
932 fprintf(fh
, "%%%%BoundingBox: %d %d %d %d\n",
933 int(floor(min_x
* factor
)), int(floor(min_y
* factor
)),
934 int(ceil(max_x
* factor
)), int(ceil(max_y
* factor
)));
935 fprintf(fh
, "%%%%HiResBoundingBox: %.4f %.4f %.4f %.4f\n",
936 min_x
* factor
, min_y
* factor
, max_x
* factor
, max_y
* factor
);
937 fputs("%%LanguageLevel: 1\n"
938 "%%PageOrder: Ascend\n"
940 "%%Orientation: Portrait\n", fh
);
942 fprintf(fh
, "%%%%DocumentFonts: %s\n", fontname_labels
);
944 fputs("%%EndComments\n"
946 "save countdictstack mark\n", fh
);
948 /* this code adapted from a2ps */
949 fputs("%%BeginResource: encoding ISO88591Encoding\n"
950 "/ISO88591Encoding [\n", fh
);
951 fputs("/.notdef /.notdef /.notdef /.notdef\n", fh
);
952 fputs("/.notdef /.notdef /.notdef /.notdef\n", fh
);
953 fputs("/.notdef /.notdef /.notdef /.notdef\n", fh
);
954 fputs("/.notdef /.notdef /.notdef /.notdef\n", fh
);
955 fputs("/.notdef /.notdef /.notdef /.notdef\n", fh
);
956 fputs("/.notdef /.notdef /.notdef /.notdef\n", fh
);
957 fputs("/.notdef /.notdef /.notdef /.notdef\n", fh
);
958 fputs("/.notdef /.notdef /.notdef /.notdef\n", fh
);
960 "/space /exclam /quotedbl /numbersign\n"
961 "/dollar /percent /ampersand /quoteright\n"
962 "/parenleft /parenright /asterisk /plus\n"
963 "/comma /minus /period /slash\n"
964 "/zero /one /two /three\n"
965 "/four /five /six /seven\n"
966 "/eight /nine /colon /semicolon\n"
967 "/less /equal /greater /question\n"
968 "/at /A /B /C /D /E /F /G\n"
969 "/H /I /J /K /L /M /N /O\n"
970 "/P /Q /R /S /T /U /V /W\n"
971 "/X /Y /Z /bracketleft\n"
972 "/backslash /bracketright /asciicircum /underscore\n"
973 "/quoteleft /a /b /c /d /e /f /g\n"
974 "/h /i /j /k /l /m /n /o\n"
975 "/p /q /r /s /t /u /v /w\n"
976 "/x /y /z /braceleft\n"
977 "/bar /braceright /asciitilde /.notdef\n", fh
);
978 fputs("/.notdef /.notdef /.notdef /.notdef\n", fh
);
979 fputs("/.notdef /.notdef /.notdef /.notdef\n", fh
);
980 fputs("/.notdef /.notdef /.notdef /.notdef\n", fh
);
981 fputs("/.notdef /.notdef /.notdef /.notdef\n", fh
);
982 fputs("/.notdef /.notdef /.notdef /.notdef\n", fh
);
983 fputs("/.notdef /.notdef /.notdef /.notdef\n", fh
);
984 fputs("/.notdef /.notdef /.notdef /.notdef\n", fh
);
985 fputs("/.notdef /.notdef /.notdef /.notdef\n", fh
);
987 "/space /exclamdown /cent /sterling\n"
988 "/currency /yen /brokenbar /section\n"
989 "/dieresis /copyright /ordfeminine /guillemotleft\n"
990 "/logicalnot /hyphen /registered /macron\n"
991 "/degree /plusminus /twosuperior /threesuperior\n"
992 "/acute /mu /paragraph /bullet\n"
993 "/cedilla /onesuperior /ordmasculine /guillemotright\n"
994 "/onequarter /onehalf /threequarters /questiondown\n"
995 "/Agrave /Aacute /Acircumflex /Atilde\n"
996 "/Adieresis /Aring /AE /Ccedilla\n"
997 "/Egrave /Eacute /Ecircumflex /Edieresis\n"
998 "/Igrave /Iacute /Icircumflex /Idieresis\n"
999 "/Eth /Ntilde /Ograve /Oacute\n"
1000 "/Ocircumflex /Otilde /Odieresis /multiply\n"
1001 "/Oslash /Ugrave /Uacute /Ucircumflex\n"
1002 "/Udieresis /Yacute /Thorn /germandbls\n"
1003 "/agrave /aacute /acircumflex /atilde\n"
1004 "/adieresis /aring /ae /ccedilla\n"
1005 "/egrave /eacute /ecircumflex /edieresis\n"
1006 "/igrave /iacute /icircumflex /idieresis\n"
1007 "/eth /ntilde /ograve /oacute\n"
1008 "/ocircumflex /otilde /odieresis /divide\n"
1009 "/oslash /ugrave /uacute /ucircumflex\n"
1010 "/udieresis /yacute /thorn /ydieresis\n"
1012 "%%EndResource\n", fh
);
1014 /* this code adapted from a2ps */
1016 "/reencode {\n" /* def */
1017 "dup length 5 add dict begin\n"
1020 "{ def }{ pop pop } ifelse\n"
1022 "/Encoding exch def\n"
1024 /* Use the font's bounding box to determine the ascent, descent,
1025 * and overall height; don't forget that these values have to be
1026 * transformed using the font's matrix.
1027 * We use `load' because sometimes BBox is executable, sometimes not.
1028 * Since we need 4 numbers and not an array avoid BBox from being executed
1030 "/FontBBox load aload pop\n"
1031 "FontMatrix transform /Ascent exch def pop\n"
1032 "FontMatrix transform /Descent exch def pop\n"
1033 "/FontHeight Ascent Descent sub def\n"
1035 /* Define these in case they're not in the FontInfo (also, here
1036 * they're easier to get to.
1038 "/UnderlinePosition 1 def\n"
1039 "/UnderlineThickness 1 def\n"
1041 /* Get the underline position and thickness if they're defined. */
1042 "currentdict /FontInfo known {\n"
1045 "dup /UnderlinePosition known {\n"
1046 "dup /UnderlinePosition get\n"
1047 "0 exch FontMatrix transform exch pop\n"
1048 "/UnderlinePosition exch def\n"
1051 "dup /UnderlineThickness known {\n"
1052 "/UnderlineThickness get\n"
1053 "0 exch FontMatrix transform exch pop\n"
1054 "/UnderlineThickness exch def\n"
1060 "} bind def\n", fh
);
1062 fprintf(fh
, "/lab ISO88591Encoding /%s findfont reencode definefont pop\n",
1065 fprintf(fh
, "/lab findfont %d scalefont setfont\n", int(fontsize_labels
));
1068 /* C<digit> changes colour */
1069 /* FIXME: read from ini */
1072 for (i
= 0; i
< sizeof(colour
) / sizeof(colour
[0]); ++i
) {
1073 fprintf(fh
, "/C%u {stroke %.3f %.3f %.3f setrgbcolor} def\n", i
,
1074 (double)(colour
[i
] & 0xff0000) / 0xff0000,
1075 (double)(colour
[i
] & 0xff00) / 0xff00,
1076 (double)(colour
[i
] & 0xff) / 0xff);
1082 /* Postscript definition for drawing a cross */
1083 fprintf(fh
, "/X {stroke moveto %.2f %.2f rmoveto %.2f %.2f rlineto "
1084 "%.2f 0 rmoveto %.2f %.2f rlineto %.2f %.2f rmoveto} def\n",
1085 -marker_size
, -marker_size
, marker_size
* 2, marker_size
* 2,
1086 -marker_size
* 2, marker_size
* 2, -marker_size
* 2,
1087 -marker_size
, marker_size
);
1089 /* define some functions to keep file short */
1090 fputs("/M {stroke moveto} def\n"
1091 "/P {stroke newpath moveto} def\n"
1092 "/F {closepath gsave 0.8 setgray fill grestore} def\n"
1094 "/R {rlineto} def\n"
1095 "/S {show} def\n", fh
);
1097 fprintf(fh
, "gsave %.8f dup scale\n", factor
);
1101 x
= floor(min_x
/ grid
) * grid
+ grid
;
1102 y
= floor(min_y
/ grid
) * grid
+ grid
;
1104 printf("x_min: %f y_min: %f\n", x
, y
);
1107 /* horizontal line */
1108 fprintf(fh
, "0\nLINE\n");
1109 fprintf(fh
, "8\nGrid\n"); /* Layer */
1110 fprintf(fh
, "10\n%6.2f\n", x
);
1111 fprintf(fh
, "20\n%6.2f\n", min_y
);
1112 fprintf(fh
, "30\n0\n");
1113 fprintf(fh
, "11\n%6.2f\n", x
);
1114 fprintf(fh
, "21\n%6.2f\n", max_y
);
1115 fprintf(fh
, "31\n0\n");
1120 fprintf(fh
, "0\nLINE\n");
1121 fprintf(fh
, "8\nGrid\n"); /* Layer */
1122 fprintf(fh
, "10\n%6.2f\n", min_x
);
1123 fprintf(fh
, "20\n%6.2f\n", y
);
1124 fprintf(fh
, "30\n0\n");
1125 fprintf(fh
, "11\n%6.2f\n", max_x
);
1126 fprintf(fh
, "21\n%6.2f\n", y
);
1127 fprintf(fh
, "31\n0\n");
1135 EPS::start_pass(int layer
)
1139 case LEGS
|SURF
|STNS
|LABELS
:
1140 fprintf(fh
, "0.1 setlinewidth\n");
1142 case PASG
: case XSECT
: case WALL1
: case WALL2
:
1143 fprintf(fh
, "0.01 setlinewidth\n");
1149 EPS::line(const img_point
*p1
, const img_point
*p
, unsigned flags
, bool fPendingMove
)
1151 (void)flags
; /* unused */
1153 fprintf(fh
, "%.2f %.2f M\n", p1
->x
, p1
->y
);
1155 fprintf(fh
, "%.2f %.2f L\n", p
->x
, p
->y
);
1159 EPS::label(const img_point
*p
, const char *s
, bool /*fSurface*/, int)
1161 fprintf(fh
, "%.2f %.2f M\n", p
->x
, p
->y
);
1164 unsigned char ch
= *s
++;
1166 case '(': case ')': case '\\': /* need to escape these characters */
1179 EPS::cross(const img_point
*p
, bool fSurface
)
1181 (void)fSurface
; /* unused */
1182 fprintf(fh
, "%.2f %.2f X\n", p
->x
, p
->y
);
1186 EPS::xsect(const img_point
*p
, double angle
, double d1
, double d2
)
1188 double s
= sin(rad(angle
));
1189 double c
= cos(rad(angle
));
1190 fprintf(fh
, "%.2f %.2f M %.2f %.2f R\n",
1191 p
->x
- c
* d2
, p
->y
- s
* d2
,
1192 c
* (d1
+ d2
), s
* (d1
+ d2
));
1196 EPS::wall(const img_point
*p
, double angle
, double d
)
1198 double s
= sin(rad(angle
));
1199 double c
= cos(rad(angle
));
1200 fprintf(fh
, "%.2f %.2f %c\n", p
->x
+ c
* d
, p
->y
+ s
* d
, first
? 'M' : 'L');
1205 EPS::passage(const img_point
*p
, double angle
, double d1
, double d2
)
1207 double s
= sin(rad(angle
));
1208 double c
= cos(rad(angle
));
1209 double x1
= p
->x
+ c
* d1
;
1210 double y1
= p
->y
+ s
* d1
;
1211 double x2
= p
->x
- c
* d2
;
1212 double y2
= p
->y
- s
* d2
;
1213 fprintf(fh
, "%.2f %.2f %c\n", x1
, y1
, first
? 'P' : 'L');
1215 psg
.push_back(make_pair(x2
, y2
));
1222 vector
<pair
<double, double> >::const_reverse_iterator i
;
1223 for (i
= psg
.rbegin(); i
!= psg
.rend(); ++i
) {
1224 fprintf(fh
, "%.2f %.2f L\n", i
->first
, i
->second
);
1234 fputs("stroke showpage grestore\n"
1236 "cleartomark countdictstack exch sub { end } repeat restore\n"
1240 class UseNumericCLocale
{
1241 char * current_locale
;
1244 UseNumericCLocale() {
1245 current_locale
= osstrdup(setlocale(LC_NUMERIC
, NULL
));
1246 setlocale(LC_NUMERIC
, "C");
1249 ~UseNumericCLocale() {
1250 setlocale(LC_NUMERIC
, current_locale
);
1251 osfree(current_locale
);
1256 transform_point(const Point
& pos
, const Vector3
* pre_offset
,
1257 double COS
, double SIN
, double COST
, double SINT
,
1260 double x
= pos
.GetX();
1261 double y
= pos
.GetY();
1262 double z
= pos
.GetZ();
1264 x
+= pre_offset
->GetX();
1265 y
+= pre_offset
->GetY();
1266 z
+= pre_offset
->GetZ();
1268 p
->x
= x
* COS
- y
* SIN
;
1269 double tmp
= x
* SIN
+ y
* COS
;
1270 p
->y
= z
* COST
- tmp
* SINT
;
1271 p
->z
= z
* SINT
+ tmp
* COST
;
1275 Export(const wxString
&fnm_out
, const wxString
&title
,
1276 const wxString
&datestamp
, time_t datestamp_numeric
,
1277 const MainFrm
* mainfrm
,
1278 double pan
, double tilt
, int show_mask
, export_format format
,
1279 const char * input_projection
,
1280 double grid_
, double text_height
, double marker_size_
,
1283 UseNumericCLocale dummy
;
1284 int fPendingMove
= 0;
1287 double SIN
= sin(rad(pan
));
1288 double COS
= cos(rad(pan
));
1289 double SINT
= sin(rad(tilt
));
1290 double COST
= cos(rad(tilt
));
1293 marker_size
= marker_size_
;
1295 ExportFilter
* filt
;
1298 filt
= new DXF(text_height
);
1301 filt
= new EPS(scale
);
1304 filt
= new GPX(input_projection
);
1305 show_mask
|= FULL_COORDS
;
1309 // factor = POINTS_PER_MM * 1000.0 / scale;
1315 filt
= new KML(input_projection
);
1316 show_mask
|= FULL_COORDS
;
1320 show_mask
|= FULL_COORDS
;
1323 filt
= new POS(mainfrm
->GetSeparator());
1324 show_mask
|= FULL_COORDS
;
1327 filt
= new Skencil(scale
);
1330 filt
= new SVG(scale
, text_height
);
1336 if (!filt
->fopen(fnm_out
)) {
1341 const Vector3
* pre_offset
= NULL
;
1342 if (show_mask
& FULL_COORDS
) {
1343 pre_offset
= &mainfrm
->GetOffset();
1346 /* Get bounding box */
1347 double min_x
, min_y
, min_z
, max_x
, max_y
, max_z
;
1348 min_x
= min_y
= min_z
= HUGE_VAL
;
1349 max_x
= max_y
= max_z
= -HUGE_VAL
;
1350 list
<traverse
>::const_iterator trav
= mainfrm
->traverses_begin();
1351 list
<traverse
>::const_iterator tend
= mainfrm
->traverses_end();
1352 for ( ; trav
!= tend
; ++trav
) {
1353 if (trav
->isSplay
&& (show_mask
& SPLAYS
) == 0) {
1356 vector
<PointInfo
>::const_iterator pos
= trav
->begin();
1357 vector
<PointInfo
>::const_iterator end
= trav
->end();
1358 for ( ; pos
!= end
; ++pos
) {
1359 transform_point(*pos
, pre_offset
, COS
, SIN
, COST
, SINT
, &p
);
1361 if (p
.x
< min_x
) min_x
= p
.x
;
1362 if (p
.x
> max_x
) max_x
= p
.x
;
1363 if (p
.y
< min_y
) min_y
= p
.y
;
1364 if (p
.y
> max_y
) max_y
= p
.y
;
1365 if (p
.z
< min_z
) min_z
= p
.z
;
1366 if (p
.z
> max_z
) max_z
= p
.z
;
1370 list
<LabelInfo
*>::const_iterator pos
= mainfrm
->GetLabels();
1371 list
<LabelInfo
*>::const_iterator end
= mainfrm
->GetLabelsEnd();
1372 for ( ; pos
!= end
; ++pos
) {
1373 transform_point(**pos
, pre_offset
, COS
, SIN
, COST
, SINT
, &p
);
1375 if (p
.x
< min_x
) min_x
= p
.x
;
1376 if (p
.x
> max_x
) max_x
= p
.x
;
1377 if (p
.y
< min_y
) min_y
= p
.y
;
1378 if (p
.y
> max_y
) max_y
= p
.y
;
1379 if (p
.z
< min_z
) min_z
= p
.z
;
1380 if (p
.z
> max_z
) max_z
= p
.z
;
1391 /* handle empty file gracefully */
1392 if (min_x
> max_x
) {
1393 min_x
= min_y
= min_z
= 0;
1394 max_x
= max_y
= max_z
= 0;
1397 double x_offset
, y_offset
, z_offset
;
1398 if (show_mask
& FULL_COORDS
) {
1399 // Full coordinates - offset is applied before rotations.
1400 x_offset
= y_offset
= z_offset
= 0.0;
1401 } else if (show_mask
& CENTRED
) {
1403 x_offset
= (min_x
+ max_x
) * -0.5;
1404 y_offset
= (min_y
+ max_y
) * -0.5;
1405 z_offset
= (min_z
+ max_z
) * -0.5;
1407 // Origin at lowest SW corner.
1420 filt
->header(title
.utf8_str(), datestamp
.utf8_str(), datestamp_numeric
,
1421 min_x
, min_y
, min_z
, max_x
, max_y
, max_z
);
1423 p1
.x
= p1
.y
= p1
.z
= 0; /* avoid compiler warning */
1425 for (pass
= filt
->passes(); *pass
; ++pass
) {
1426 int pass_mask
= show_mask
& *pass
;
1429 filt
->start_pass(*pass
);
1430 if (pass_mask
& LEGS
) {
1431 trav
= mainfrm
->traverses_begin();
1432 tend
= mainfrm
->traverses_end();
1433 for ( ; trav
!= tend
; ++trav
) {
1435 if (trav
->isSplay
) {
1436 if ((show_mask
& SPLAYS
) == 0) {
1441 assert(trav
->size() > 1);
1442 vector
<PointInfo
>::const_iterator pos
= trav
->begin();
1443 vector
<PointInfo
>::const_iterator end
= trav
->end();
1444 for ( ; pos
!= end
; ++pos
) {
1445 transform_point(*pos
, pre_offset
, COS
, SIN
, COST
, SINT
, &p
);
1450 if (pos
== trav
->begin()) {
1451 // First point is move...
1453 printf("move to %9.2f %9.2f %9.2f\n",x
,y
,z
);
1458 printf("line to %9.2f %9.2f %9.2f\n", p
.x
, p
.y
, p
.z
);
1460 filt
->line(&p1
, &p
, flags
, fPendingMove
);
1467 if (pass_mask
& SURF
) {
1468 trav
= mainfrm
->surface_traverses_begin();
1469 tend
= mainfrm
->surface_traverses_end();
1470 for ( ; trav
!= tend
; ++trav
) {
1472 if (trav
->isSplay
) {
1473 if ((show_mask
& SPLAYS
) == 0) {
1476 flags
= SURF
|SPLAYS
;
1478 assert(trav
->size() > 1);
1479 vector
<PointInfo
>::const_iterator pos
= trav
->begin();
1480 vector
<PointInfo
>::const_iterator end
= trav
->end();
1481 for ( ; pos
!= end
; ++pos
) {
1482 transform_point(*pos
, pre_offset
, COS
, SIN
, COST
, SINT
, &p
);
1487 if (pos
== trav
->begin()) {
1488 // First point is move...
1490 printf("surface move to %9.2f %9.2f %9.2f\n",x
,y
,z
);
1495 printf("surface line to %9.2f %9.2f %9.2f\n", p
.x
, p
.y
, p
.z
);
1497 filt
->line(&p1
, &p
, flags
, fPendingMove
);
1504 if (pass_mask
& (STNS
|LABELS
|ENTS
|FIXES
|EXPORTS
)) {
1505 list
<LabelInfo
*>::const_iterator pos
= mainfrm
->GetLabels();
1506 list
<LabelInfo
*>::const_iterator end
= mainfrm
->GetLabelsEnd();
1507 for ( ; pos
!= end
; ++pos
) {
1508 transform_point(**pos
, pre_offset
, COS
, SIN
, COST
, SINT
, &p
);
1514 printf("label '%s' at %9.2f %9.2f %9.2f\n",(*pos
)->GetText(),x
,y
,z
);
1517 if ((pass_mask
& ENTS
) && (*pos
)->IsEntrance()) {
1519 } else if ((pass_mask
& FIXES
) && (*pos
)->IsFixedPt()) {
1521 } else if ((pass_mask
& EXPORTS
) && (*pos
)->IsExportedPt()) {
1523 } else if (pass_mask
& LABELS
) {
1526 /* Use !UNDERGROUND as the criterion - we want stations where a
1527 * surface and underground survey meet to be in the underground
1529 bool f_surface
= !(*pos
)->IsUnderground();
1531 const wxString
& text
= (*pos
)->GetText();
1532 filt
->label(&p
, text
.utf8_str(), f_surface
, type
);
1534 if (pass_mask
& STNS
)
1535 filt
->cross(&p
, f_surface
);
1538 if (pass_mask
& (XSECT
|WALLS
|PASG
)) {
1539 bool elevation
= (tilt
== 0.0);
1540 list
<vector
<XSect
> >::const_iterator tube
= mainfrm
->tubes_begin();
1541 list
<vector
<XSect
> >::const_iterator tube_end
= mainfrm
->tubes_end();
1542 for ( ; tube
!= tube_end
; ++tube
) {
1543 vector
<XSect
>::const_iterator pos
= tube
->begin();
1544 vector
<XSect
>::const_iterator end
= tube
->end();
1545 for ( ; pos
!= end
; ++pos
) {
1546 const XSect
& xs
= *pos
;
1547 transform_point(xs
, pre_offset
, COS
, SIN
, COST
, SINT
, &p
);
1553 if (pass_mask
& XSECT
)
1554 filt
->xsect(&p
, 90, xs
.GetU(), xs
.GetD());
1555 if (pass_mask
& WALL1
)
1556 filt
->wall(&p
, 90, xs
.GetU());
1557 if (pass_mask
& WALL2
)
1558 filt
->wall(&p
, 270, xs
.GetD());
1559 if (pass_mask
& PASG
)
1560 filt
->passage(&p
, 90, xs
.GetU(), xs
.GetD());
1562 // Should only be enabled in plan or elevation mode.
1563 double angle
= pan
+ xs
.get_right_bearing();
1564 if (pass_mask
& XSECT
)
1565 filt
->xsect(&p
, angle
+ 180, xs
.GetL(), xs
.GetR());
1566 if (pass_mask
& WALL1
)
1567 filt
->wall(&p
, angle
+ 180, xs
.GetL());
1568 if (pass_mask
& WALL2
)
1569 filt
->wall(&p
, angle
, xs
.GetR());
1570 if (pass_mask
& PASG
)
1571 filt
->passage(&p
, angle
+ 180, xs
.GetL(), xs
.GetR());