2 * Converts a .3d file to CAD-like formats (DXF, Skencil, SVG) and also Compass
5 * Also useful as an example of how to use the img code in your own programs
8 /* Copyright (C) 1994-2004,2008,2010,2011,2013,2014 Olly Betts
9 * Copyright (C) 2004 John Pybus (SVG Output code)
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 2 of the License, or
14 * (at your option) any later version.
16 * This program is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
21 * You should have received a copy of the GNU General Public License
22 * along with this program; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
26 /* #define DEBUG_CAD3D */
42 #include "img_hosted.h"
47 /* default values - can be overridden with --text-height and --marker-size
49 #define TEXT_HEIGHT 0.6
50 #define MARKER_SIZE 0.8
52 #define GRID_SPACING 100
54 #define POINTS_PER_INCH 72.0
55 #define POINTS_PER_MM (POINTS_PER_INCH / MM_PER_INCH)
57 #define SQRT_2 1.41421356237309504880168872420969
64 #define FMT_DEFAULT FMT_DXF
69 static double min_x
, min_y
, min_z
, max_x
, max_y
, max_z
;
71 static double text_height
; /* for station labels */
72 static double marker_size
; /* for station markers */
73 static double grid
; /* grid spacing (or 0 for no grid) */
74 static double scale
= 500.0;
76 static const char *unit
= "mm";
79 static const char *survey
= NULL
;
84 fprintf(fh
, "0\nSECTION\n"
86 fprintf(fh
, "9\n$EXTMIN\n"); /* lower left corner of drawing */
87 fprintf(fh
, "10\n%#-.6f\n", min_x
); /* x */
88 fprintf(fh
, "20\n%#-.6f\n", min_y
); /* y */
89 fprintf(fh
, "30\n%#-.6f\n", min_z
); /* min z */
90 fprintf(fh
, "9\n$EXTMAX\n"); /* upper right corner of drawing */
91 fprintf(fh
, "10\n%#-.6f\n", max_x
); /* x */
92 fprintf(fh
, "20\n%#-.6f\n", max_y
); /* y */
93 fprintf(fh
, "30\n%#-.6f\n", max_z
); /* max z */
94 fprintf(fh
, "9\n$PDMODE\n70\n3\n"); /* marker style as CROSS */
95 fprintf(fh
, "9\n$PDSIZE\n40\n%6.2f\n", marker_size
); /* marker size */
96 fprintf(fh
, "0\nENDSEC\n");
98 fprintf(fh
, "0\nSECTION\n"
100 fprintf(fh
, "0\nTABLE\n" /* Define CONTINUOUS and DASHED line types. */
120 fprintf(fh
, "0\nTABLE\n"
122 fprintf(fh
, "70\n10\n"); /* max # off layers in this DXF file : 10 */
123 /* First Layer: CentreLine */
124 fprintf(fh
, "0\nLAYER\n2\nCentreLine\n");
125 fprintf(fh
, "70\n64\n"); /* shows layer is referenced by entities */
126 fprintf(fh
, "62\n5\n"); /* color: kept the same used by SpeleoGen */
127 fprintf(fh
, "6\nCONTINUOUS\n"); /* linetype */
128 /* Next Layer: Stations */
129 fprintf(fh
, "0\nLAYER\n2\nStations\n");
130 fprintf(fh
, "70\n64\n"); /* shows layer is referenced by entities */
131 fprintf(fh
, "62\n7\n"); /* color: kept the same used by SpeleoGen */
132 fprintf(fh
, "6\nCONTINUOUS\n"); /* linetype */
133 /* Next Layer: Labels */
134 fprintf(fh
, "0\nLAYER\n2\nLabels\n");
135 fprintf(fh
, "70\n64\n"); /* shows layer is referenced by entities */
136 fprintf(fh
, "62\n7\n"); /* color: kept the same used by SpeleoGen */
137 fprintf(fh
, "6\nCONTINUOUS\n"); /* linetype */
138 /* Next Layer: Surface */
139 fprintf(fh
, "0\nLAYER\n2\nSurface\n");
140 fprintf(fh
, "70\n64\n"); /* shows layer is referenced by entities */
141 fprintf(fh
, "62\n5\n"); /* color */
142 fprintf(fh
, "6\nDASHED\n"); /* linetype */
143 /* Next Layer: SurfaceStations */
144 fprintf(fh
, "0\nLAYER\n2\nSurfaceStations\n");
145 fprintf(fh
, "70\n64\n"); /* shows layer is referenced by entities */
146 fprintf(fh
, "62\n7\n"); /* color */
147 fprintf(fh
, "6\nCONTINUOUS\n"); /* linetype */
148 /* Next Layer: SurfaceLabels */
149 fprintf(fh
, "0\nLAYER\n2\nSurfaceLabels\n");
150 fprintf(fh
, "70\n64\n"); /* shows layer is referenced by entities */
151 fprintf(fh
, "62\n7\n"); /* color */
152 fprintf(fh
, "6\nCONTINUOUS\n"); /* linetype */
154 /* Next Layer: Grid */
155 fprintf(fh
, "0\nLAYER\n2\nGrid\n");
156 fprintf(fh
, "70\n64\n"); /* shows layer is referenced by entities */
157 fprintf(fh
, "62\n7\n"); /* color: kept the same used by SpeleoGen */
158 fprintf(fh
, "6\nCONTINUOUS\n"); /* linetype */
160 fprintf(fh
, "0\nENDTAB\n"
163 fprintf(fh
, "0\nSECTION\n"
168 x
= floor(min_x
/ grid
) * grid
+ grid
;
169 y
= floor(min_y
/ grid
) * grid
+ grid
;
171 printf("x_min: %f y_min: %f\n", x
, y
);
174 /* horizontal line */
175 fprintf(fh
, "0\nLINE\n");
176 fprintf(fh
, "8\nGrid\n"); /* Layer */
177 fprintf(fh
, "10\n%6.2f\n", x
);
178 fprintf(fh
, "20\n%6.2f\n", min_y
);
179 fprintf(fh
, "30\n0\n");
180 fprintf(fh
, "11\n%6.2f\n", x
);
181 fprintf(fh
, "21\n%6.2f\n", max_y
);
182 fprintf(fh
, "31\n0\n");
187 fprintf(fh
, "0\nLINE\n");
188 fprintf(fh
, "8\nGrid\n"); /* Layer */
189 fprintf(fh
, "10\n%6.2f\n", min_x
);
190 fprintf(fh
, "20\n%6.2f\n", y
);
191 fprintf(fh
, "30\n0\n");
192 fprintf(fh
, "11\n%6.2f\n", max_x
);
193 fprintf(fh
, "21\n%6.2f\n", y
);
194 fprintf(fh
, "31\n0\n");
201 dxf_start_pass(int layer
)
207 dxf_move(const img_point
*p
)
209 (void)p
; /* unused */
213 dxf_line(const img_point
*p1
, const img_point
*p
, bool fSurface
)
215 fprintf(fh
, "0\nLINE\n");
216 fprintf(fh
, fSurface
? "8\nSurface\n" : "8\nCentreLine\n"); /* Layer */
217 fprintf(fh
, "10\n%6.2f\n", p1
->x
);
218 fprintf(fh
, "20\n%6.2f\n", p1
->y
);
219 fprintf(fh
, "30\n%6.2f\n", p1
->z
);
220 fprintf(fh
, "11\n%6.2f\n", p
->x
);
221 fprintf(fh
, "21\n%6.2f\n", p
->y
);
222 fprintf(fh
, "31\n%6.2f\n", p
->z
);
226 dxf_label(const img_point
*p
, const char *s
, bool fSurface
)
228 /* write station label to dxf file */
229 fprintf(fh
, "0\nTEXT\n");
230 fprintf(fh
, fSurface
? "8\nSurfaceLabels\n" : "8\nLabels\n"); /* Layer */
231 fprintf(fh
, "10\n%6.2f\n", p
->x
);
232 fprintf(fh
, "20\n%6.2f\n", p
->y
);
233 fprintf(fh
, "30\n%6.2f\n", p
->z
);
234 fprintf(fh
, "40\n%6.2f\n", text_height
);
235 fprintf(fh
, "1\n%s\n", s
);
239 dxf_cross(const img_point
*p
, bool fSurface
)
241 /* write station marker to dxf file */
242 fprintf(fh
, "0\nPOINT\n");
243 fprintf(fh
, fSurface
? "8\nSurfaceStations\n" : "8\nStations\n"); /* Layer */
244 fprintf(fh
, "10\n%6.2f\n", p
->x
);
245 fprintf(fh
, "20\n%6.2f\n", p
->y
);
246 fprintf(fh
, "30\n%6.2f\n", p
->z
);
252 fprintf(fh
, "000\nENDSEC\n");
253 fprintf(fh
, "000\nEOF\n");
259 fprintf(fh
, "##Sketch 1 2\n"); /* File format version */
260 fprintf(fh
, "document()\n");
261 fprintf(fh
, "layout((%.3f,%.3f),0)\n",
262 (max_x
- min_x
) * factor
, (max_y
- min_y
) * factor
);
265 static const char *layer_names
[] = {
274 skencil_start_pass(int layer
)
276 fprintf(fh
, "layer('%s',1,1,0,0,(0,0,0))\n", layer_names
[layer
]);
280 skencil_move(const img_point
*p
)
282 fprintf(fh
, "b()\n");
283 fprintf(fh
, "bs(%.3f,%.3f,%.3f)\n", p
->x
* factor
, p
->y
* factor
, 0.0);
287 skencil_line(const img_point
*p1
, const img_point
*p
, bool fSurface
)
289 (void)fSurface
; /* unused */
290 (void)p1
; /* unused */
291 fprintf(fh
, "bs(%.3f,%.3f,%.3f)\n", p
->x
* factor
, p
->y
* factor
, 0.0);
295 skencil_label(const img_point
*p
, const char *s
, bool fSurface
)
297 (void)fSurface
; /* unused */
298 fprintf(fh
, "fp((0,0,0))\n");
299 fprintf(fh
, "le()\n");
300 fprintf(fh
, "Fn('Times-Roman')\n");
301 fprintf(fh
, "Fs(5)\n");
302 fprintf(fh
, "txt('");
305 if (ch
== '\'' || ch
== '\\') PUTC('\\', fh
);
308 fprintf(fh
, "',(%.3f,%.3f))\n", p
->x
* factor
, p
->y
* factor
);
312 skencil_cross(const img_point
*p
, bool fSurface
)
314 (void)fSurface
; /* unused */
315 fprintf(fh
, "b()\n");
316 fprintf(fh
, "bs(%.3f,%.3f,%.3f)\n",
317 p
->x
* factor
- marker_size
, p
->y
* factor
- marker_size
, 0.0);
318 fprintf(fh
, "bs(%.3f,%.3f,%.3f)\n",
319 p
->x
* factor
+ marker_size
, p
->y
* factor
+ marker_size
, 0.0);
320 fprintf(fh
, "bn()\n");
321 fprintf(fh
, "bs(%.3f,%.3f,%.3f)\n",
322 p
->x
* factor
+ marker_size
, p
->y
* factor
- marker_size
, 0.0);
323 fprintf(fh
, "bs(%.3f,%.3f,%.3f)\n",
324 p
->x
* factor
- marker_size
, p
->y
* factor
+ marker_size
, 0.0);
330 fprintf(fh
, "guidelayer('Guide Lines',1,0,0,1,(0,0,1))\n");
332 fprintf(fh
, "grid((0,0,%.3f,%.3f),1,(0,0,1),'Grid')\n",
333 grid
* factor
, grid
* factor
);
337 typedef struct point
{
343 #define HTAB_SIZE 0x2000
348 set_name_(const img_point
*p
, const char *s
, int copy
)
353 char data
[sizeof(int) * 3];
357 u
.x
[0] = (int)(p
->x
* 100);
358 u
.x
[1] = (int)(p
->y
* 100);
359 u
.x
[2] = (int)(p
->z
* 100);
360 hash
= (hash_data(u
.data
, sizeof(int) * 3) & (HTAB_SIZE
- 1));
361 for (pt
= htab
[hash
]; pt
; pt
= pt
->next
) {
362 if (pt
->p
.x
== p
->x
&& pt
->p
.y
== p
->y
&& pt
->p
.z
== p
->z
) {
363 /* already got name for these coordinates */
364 /* FIXME: what about multiple names for the same station? */
376 pt
->next
= htab
[hash
];
381 set_name(const img_point
*p
, const char *s
)
387 set_name_copy(const img_point
*p
, const char *s
)
393 find_name(const img_point
*p
)
398 char data
[sizeof(int) * 3];
403 u
.x
[0] = (int)(p
->x
* 100);
404 u
.x
[1] = (int)(p
->y
* 100);
405 u
.x
[2] = (int)(p
->z
* 100);
406 hash
= (hash_data(u
.data
, sizeof(int) * 3) & (HTAB_SIZE
- 1));
407 for (pt
= htab
[hash
]; pt
; pt
= pt
->next
) {
408 if (pt
->p
.x
== p
->x
&& pt
->p
.y
== p
->y
&& pt
->p
.z
== p
->z
)
414 static bool to_close
= 0;
415 static bool close_g
= 0;
421 htab
= osmalloc(HTAB_SIZE
* ossizeof(point
*));
422 for (i
= 0; i
< HTAB_SIZE
; ++i
) htab
[i
] = NULL
;
423 fprintf(fh
, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
424 fprintf(fh
, "<svg width=\"%.3f%s\" height=\"%.3f%s\""
425 " viewBox=\"0 0 %0.3f %0.3f\">\n",
426 (max_x
- min_x
) * factor
, unit
, (max_y
- min_y
) * factor
, unit
,
427 (max_x
- min_x
) * factor
, (max_y
- min_y
) * factor
);
428 fprintf(fh
, "<g transform=\"translate(%.3f %.3f)\">\n",
429 min_x
* -factor
, max_y
* factor
);
435 svg_start_pass(int layer
)
438 fprintf(fh
, "\"/>\n");
442 fprintf(fh
, "</g>\n");
446 fprintf(fh
, "<g id=\"%s\"", layer_names
[layer
]);
448 fprintf(fh
, " style=\"stroke:black;fill:none;stroke-width:0.4\"");
449 else if (layer
& STNS
)
450 fprintf(fh
, " style=\"stroke:black;fill:none;stroke-width:0.05\"");
451 else if (layer
& LABELS
)
452 fprintf(fh
, " style=\"font-size:%.3f\"", text_height
);
457 svg_move(const img_point
*p
)
460 fprintf(fh
, "\"/>\n");
462 fprintf(fh
, "<path d=\"M%.3f %.3f", p
->x
* factor
, p
->y
* -factor
);
467 svg_line(const img_point
*p1
, const img_point
*p
, bool fSurface
)
469 (void)fSurface
; /* unused */
470 (void)p1
; /* unused */
471 fprintf(fh
, "L%.3f %.3f", p
->x
* factor
, p
->y
* -factor
);
476 svg_label(const img_point
*p
, const char *s
, bool fSurface
)
478 (void)fSurface
; /* unused */
479 fprintf(fh
, "<text transform=\"translate(%.3f %.3f)\">",
480 p
->x
* factor
, p
->y
* -factor
);
482 fputs("</text>\n", fh
);
487 svg_cross(const img_point
*p
, bool fSurface
)
489 (void)fSurface
; /* unused */
490 fprintf(fh
, "<circle id=\"%s\" cx=\"%.3f\" cy=\"%.3f\" r=\"%.3f\"/>\n",
491 find_name(p
), p
->x
* factor
, p
->y
* -factor
, marker_size
* SQRT_2
);
492 fprintf(fh
, "<path d=\"M%.3f %.3fL%.3f %.3fM%.3f %.3fL%.3f %.3f\"/>\n",
493 p
->x
* factor
- marker_size
, p
->y
* -factor
- marker_size
,
494 p
->x
* factor
+ marker_size
, p
->y
* -factor
+ marker_size
,
495 p
->x
* factor
+ marker_size
, p
->y
* -factor
- marker_size
,
496 p
->x
* factor
- marker_size
, p
->y
* -factor
+ marker_size
);
503 fprintf(fh
, "\"/>\n");
507 fprintf(fh
, "</g>\n");
510 fprintf(fh
, "</g>\n</svg>");
517 htab
= osmalloc(HTAB_SIZE
* ossizeof(point
*));
518 for (i
= 0; i
< HTAB_SIZE
; ++i
) htab
[i
] = NULL
;
519 /* Survex is E, N, Alt - PLT file is N, E, Alt */
520 fprintf(fh
, "Z %.3f %.3f %.3f %.3f %.3f %.3f\r\n",
521 min_y
/ METRES_PER_FOOT
, max_y
/ METRES_PER_FOOT
,
522 min_x
/ METRES_PER_FOOT
, max_x
/ METRES_PER_FOOT
,
523 min_z
/ METRES_PER_FOOT
, max_z
/ METRES_PER_FOOT
);
524 fprintf(fh
, "N%s D 1 1 1 C%s\r\n", survey
? survey
: "X", pimg
->title
);
528 plt_start_pass(int layer
)
534 plt_move(const img_point
*p
)
536 /* Survex is E, N, Alt - PLT file is N, E, Alt */
537 fprintf(fh
, "M %.3f %.3f %.3f ",
538 p
->y
/ METRES_PER_FOOT
, p
->x
/ METRES_PER_FOOT
, p
->z
/ METRES_PER_FOOT
);
539 /* dummy passage dimensions are required to avoid compass bug */
540 fprintf(fh
, "S%s P -9 -9 -9 -9\r\n", find_name(p
));
544 plt_line(const img_point
*p1
, const img_point
*p
, bool fSurface
)
546 (void)fSurface
; /* unused */
547 (void)p1
; /* unused */
548 /* Survex is E, N, Alt - PLT file is N, E, Alt */
549 fprintf(fh
, "D %.3f %.3f %.3f ",
550 p
->y
/ METRES_PER_FOOT
, p
->x
/ METRES_PER_FOOT
, p
->z
/ METRES_PER_FOOT
);
551 /* dummy passage dimensions are required to avoid compass bug */
552 fprintf(fh
, "S%s P -9 -9 -9 -9\r\n", find_name(p
));
556 plt_label(const img_point
*p
, const char *s
, bool fSurface
)
559 char * escaped
= NULL
;
561 (void)fSurface
; /* unused */
562 /* PLT format can't handle spaces or control characters, so escape them
563 * like in URLs (an arbitrary choice of escaping, but at least a familiar
564 * one and % isn't likely to occur in station names).
566 for (q
= s
; *q
; ++q
) {
567 unsigned char ch
= *q
;
568 if (ch
<= ' ' || ch
== '%') {
569 s_catlen(&escaped
, &elen
, s
, q
- s
);
570 s_catchar(&escaped
, &elen
, '%');
571 s_catchar(&escaped
, &elen
, "0123456789abcdef"[ch
>> 4]);
572 s_catchar(&escaped
, &elen
, "0123456789abcdef"[ch
& 0x0f]);
577 s_catlen(&escaped
, &elen
, s
, q
- s
);
578 set_name(p
, escaped
);
585 plt_cross(const img_point
*p
, bool fSurface
)
587 (void)fSurface
; /* unused */
588 (void)p
; /* unused */
594 /* Survex is E, N, Alt - PLT file is N, E, Alt */
595 fprintf(fh
, "X %.3f %.3f %.3f %.3f %.3f %.3f\r\n",
596 min_y
/ METRES_PER_FOOT
, max_y
/ METRES_PER_FOOT
,
597 min_x
/ METRES_PER_FOOT
, max_x
/ METRES_PER_FOOT
,
598 min_z
/ METRES_PER_FOOT
, max_z
/ METRES_PER_FOOT
);
599 /* Yucky DOS "end of textfile" marker */
603 static int dxf_passes
[] = { LEGS
|STNS
|LABELS
, 0 };
604 static int skencil_passes
[] = { LEGS
, STNS
, LABELS
, 0 };
605 static int plt_passes
[] = { LABELS
, LEGS
, 0 };
606 static int svg_passes
[] = { LEGS
, LABELS
, STNS
, 0 };
609 main(int argc
, char **argv
)
611 char *fnm_3d
, *fnm_out
;
612 unsigned char labels
, crosses
, legs
;
617 double elev_angle
= 0;
619 enum { FMT_DXF
= 0, FMT_SK
, FMT_PLT
, FMT_SVG
, FMT_AUTO
} format
;
620 static const char *extensions
[] = { "dxf", "sk", "plt", "svg" };
623 void (*header
)(void);
624 void (*start_pass
)(int);
625 void (*move
)(const img_point
*);
626 void (*line
)(const img_point
*, const img_point
*, bool);
627 void (*label
)(const img_point
*, const char *, bool);
628 void (*cross
)(const img_point
*, bool);
629 void (*footer
)(void);
630 const char *mode
= "w"; /* default to text output */
633 static const struct option long_opts
[] = {
634 /* const char *name; int has_arg (0 no_argument, 1 required, 2 options_*); int *flag; int val */
635 {"survey", required_argument
, 0, 's'},
636 {"no-crosses", no_argument
, 0, 'c'},
637 {"no-station-names", no_argument
, 0, 'n'},
638 {"no-legs", no_argument
, 0, 'l'},
639 {"grid", optional_argument
, 0, 'g'},
640 {"text-height", required_argument
, 0, 't'},
641 {"marker-size", required_argument
, 0, 'm'},
642 {"elevation", required_argument
, 0, 'e'},
643 {"reduction", required_argument
, 0, 'r'},
644 {"dxf", no_argument
, 0, 'D'},
645 {"skencil", no_argument
, 0, 'S'},
646 {"plt", no_argument
, 0, 'P'},
647 {"svg", no_argument
, 0, 'V'},
648 {"help", no_argument
, 0, HLP_HELP
},
649 {"version", no_argument
, 0, HLP_VERSION
},
650 /* Old name for --skencil: */
651 {"sketch", no_argument
, 0, 'S'},
655 #define short_opts "s:cnlg::t:m:e:r:DSPV"
658 static struct help_msg help
[] = {
660 {HLP_ENCODELONG(0), /*only load the sub-survey with this prefix*/199, 0},
661 {HLP_ENCODELONG(1), /*do not generate station markers*/100, 0},
662 {HLP_ENCODELONG(2), /*do not generate station labels*/101, 0},
663 {HLP_ENCODELONG(3), /*do not generate survey legs*/102, 0},
664 {HLP_ENCODELONG(4), /*generate grid (default %sm)*/148, STRING(GRID_SPACING
)},
665 {HLP_ENCODELONG(5), /*station labels text height (default %s)*/149, STRING(TEXT_HEIGHT
)},
666 {HLP_ENCODELONG(6), /*station marker size (default %s)*/152, STRING(MARKER_SIZE
)},
667 {HLP_ENCODELONG(7), /*produce an elevation view*/103, 0},
668 {HLP_ENCODELONG(8), /*factor to scale down by (default %s)*/155, "500"},
669 {HLP_ENCODELONG(9), /*produce DXF output*/156, 0},
670 /* TRANSLATORS: "Skencil" is the name of a software package, so should not be
672 {HLP_ENCODELONG(10), /*produce Skencil output*/158, 0},
673 /* TRANSLATORS: "Compass" and "Carto" are the names of software packages,
674 * so should not be translated. */
675 {HLP_ENCODELONG(11), /*produce Compass PLT output for Carto*/159, 0},
676 {HLP_ENCODELONG(12), /*produce SVG output*/160, 0},
687 text_height
= TEXT_HEIGHT
;
688 marker_size
= MARKER_SIZE
;
691 cmdline_init(argc
, argv
, short_opts
, long_opts
, NULL
, help
, 1, 2);
693 int opt
= cmdline_getopt();
694 if (opt
== EOF
) break;
696 case 'e': /* Elevation */
698 elev_angle
= cmdline_double_arg();
700 case 'c': /* Crosses */
703 case 'n': /* Labels */
711 grid
= cmdline_double_arg();
713 grid
= (double)GRID_SPACING
;
716 case 'r': /* Reduction factor */
717 scale
= cmdline_double_arg();
719 case 't': /* Text height */
720 text_height
= cmdline_double_arg();
722 printf("Text Height: “%s” input, converted to %6.2f\n", optarg
, text_height
);
725 case 'm': /* Marker size */
726 marker_size
= cmdline_double_arg();
728 printf("Marker Size: “%s”, converted to %6.2f\n", optarg
, marker_size
);
748 printf("Internal Error: 'getopt' returned '%c' %d\n", opt
, opt
);
753 fnm_3d
= argv
[optind
++];
755 fnm_out
= argv
[optind
];
756 if (format
== FMT_AUTO
) {
758 size_t len
= strlen(fnm_out
);
759 format
= FMT_DEFAULT
;
760 for (i
= 0; i
< FMT_AUTO
; ++i
) {
761 size_t l
= strlen(extensions
[i
]);
762 if (len
> l
+ 1 && fnm_out
[len
- l
- 1] == FNM_SEP_EXT
&&
763 strcasecmp(fnm_out
+ len
- l
, extensions
[i
]) == 0) {
770 char *baseleaf
= baseleaf_from_fnm(fnm_3d
);
771 if (format
== FMT_AUTO
) format
= FMT_DEFAULT
;
772 /* note : memory allocated by fnm_out gets leaked in this case... */
773 fnm_out
= add_ext(baseleaf
, extensions
[format
]);
780 start_pass
= dxf_start_pass
;
789 header
= skencil_header
;
790 start_pass
= skencil_start_pass
;
793 label
= skencil_label
;
794 cross
= skencil_cross
;
795 footer
= skencil_footer
;
796 pass
= skencil_passes
;
797 factor
= POINTS_PER_MM
* 1000.0 / scale
;
798 mode
= "wb"; /* Binary file output */
802 start_pass
= plt_start_pass
;
809 mode
= "wb"; /* Binary file output */
813 start_pass
= svg_start_pass
;
820 factor
= 1000.0 / scale
;
821 mode
= "wb"; /* Binary file output */
827 pimg
= img_open_survey(fnm_3d
, survey
);
828 if (!pimg
) fatalerror(img_error2msg(img_error()), fnm_3d
);
830 fh
= safe_fopen(fnm_out
, mode
);
833 s
= sin(rad(elev_angle
));
834 c
= cos(rad(elev_angle
));
837 /* Get drawing corners */
838 min_x
= min_y
= min_z
= HUGE_VAL
;
839 max_x
= max_y
= max_z
= -HUGE_VAL
;
841 item
= img_read_item(pimg
, &p
);
844 double xnew
= p
.x
* c
- p
.y
* s
;
845 double znew
= - p
.x
* s
- p
.y
* c
;
852 case img_MOVE
: case img_LINE
: case img_LABEL
:
853 if (p
.x
< min_x
) min_x
= p
.x
;
854 if (p
.x
> max_x
) max_x
= p
.x
;
855 if (p
.y
< min_y
) min_y
= p
.y
;
856 if (p
.y
> max_y
) max_y
= p
.y
;
857 if (p
.z
< min_z
) min_z
= p
.z
;
858 if (p
.z
> max_z
) max_z
= p
.z
;
861 } while (item
!= img_STOP
);
870 /* handle empty file gracefully */
872 min_x
= min_y
= min_z
= 0;
873 max_x
= max_y
= max_z
= 0;
879 p1
.x
= p1
.y
= p1
.z
= 0; /* avoid compiler warning */
882 if (((*pass
& LEGS
) && legs
) ||
883 ((*pass
& STNS
) && crosses
) ||
884 ((*pass
& LABELS
) && labels
)) {
885 if (!img_rewind(pimg
)) {
886 fatalerror(img_error2msg(img_error()), fnm_3d
);
890 item
= img_read_item(pimg
, &p
);
892 if (format
== FMT_SK
) {
899 double xnew
= p
.x
* c
- p
.y
* s
;
900 double znew
= - p
.x
* s
- p
.y
* c
;
909 fatalerror(/*Bad 3d image file “%s”*/106, fnm_3d
);
913 printf("line to %9.2f %9.2f %9.2f\n", p
.x
, p
.y
, p
.z
);
917 printf("Something is wrong -- img_LINE before any img_MOVE!\n");
920 fatalerror(/*Bad 3d image file “%s”*/106, fnm_3d
);
922 if ((*pass
& LEGS
) && legs
)
923 line(&p1
, &p
, pimg
->flags
& img_FLAG_SURFACE
);
928 printf("move to %9.2f %9.2f %9.2f\n",x
,y
,z
);
930 if ((*pass
& LEGS
) && legs
) move(&p
);
936 printf("label “%s” at %9.2f %9.2f %9.2f\n",pimg
->label
,x
,y
,z
);
938 /* Use !UNDERGROUND as the criterion - we want stations where
939 * a surface and underground survey meet to be in the
940 * underground layer */
941 if ((*pass
& LABELS
) && labels
)
942 label(&p
, pimg
->label
,
943 !(pimg
->flags
& img_SFLAG_UNDERGROUND
));
944 if ((*pass
& STNS
) && crosses
)
945 cross(&p
, !(pimg
->flags
& img_SFLAG_UNDERGROUND
));
952 printf("other info tag (code %d) ignored\n", item
);
955 } while (item
!= img_STOP
);