2 * Export from Aven as KML.
4 /* Copyright (C) 2012 Olaf Kähler
5 * Copyright (C) 2012,2013,2014,2015,2016,2017,2018,2019 Olly Betts
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 #include "export.h" // For LABELS, etc
35 #define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H 1
43 #define WGS84_DATUM_STRING "+proj=longlat +ellps=WGS84 +datum=WGS84"
46 html_escape(FILE *fh
, const char *s
)
66 KML::KML(const char * input_datum
, bool clamp_to_ground_
)
67 : clamp_to_ground(clamp_to_ground_
)
69 if (!(pj_input
= pj_init_plus(input_datum
))) {
70 wxString m
= wmsg(/*Failed to initialise input coordinate system “%s”*/287);
71 m
= wxString::Format(m
.c_str(), input_datum
);
74 if (!(pj_output
= pj_init_plus(WGS84_DATUM_STRING
))) {
75 wxString m
= wmsg(/*Failed to initialise output coordinate system “%s”*/288);
76 m
= wxString::Format(m
.c_str(), WGS84_DATUM_STRING
);
92 static const int default_passes
[] = {
93 PASG
, XSECT
, WALL1
, WALL2
, LEGS
|SURF
, LABELS
|ENTS
|FIXES
|EXPORTS
, 0
95 return default_passes
;
98 /* Initialise KML routines. */
99 void KML::header(const char * title
, const char *, time_t,
100 double, double, double, double, double, double)
103 "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
104 "<kml xmlns=\"http://www.opengis.net/kml/2.2\">\n", fh
);
105 fputs("<Document><name>", fh
);
106 html_escape(fh
, title
);
107 fputs("</name>\n", fh
);
108 // Set up styles for the icons to reduce the file size.
109 fputs("<Style id=\"fix\"><IconStyle>"
110 "<Icon><href>http://maps.google.com/mapfiles/kml/paddle/red-blank.png</href></Icon>"
111 "</IconStyle></Style>\n", fh
);
112 fputs("<Style id=\"exp\"><IconStyle>"
113 "<Icon><href>http://maps.google.com/mapfiles/kml/paddle/blu-blank.png</href></Icon>"
114 "</IconStyle></Style>\n", fh
);
115 fputs("<Style id=\"ent\"><IconStyle>"
116 "<Icon><href>http://maps.google.com/mapfiles/kml/paddle/grn-blank.png</href></Icon>"
117 "</IconStyle></Style>\n", fh
);
118 // FIXME: does KML allow bounds?
119 // NB Lat+long bounds are not necessarily the same as the bounds in survex
120 // coords translated to WGS84 lat+long...
127 fputs("</coordinates></LineString></MultiGeometry></Placemark>\n", fh
);
128 in_linestring
= false;
133 KML::line(const img_point
*p1
, const img_point
*p
, unsigned /*flags*/, bool fPendingMove
)
136 if (!in_linestring
) {
137 in_linestring
= true;
138 fputs("<Placemark><MultiGeometry>\n", fh
);
140 fputs("</coordinates></LineString>\n", fh
);
142 if (clamp_to_ground
) {
143 fputs("<LineString><coordinates>\n", fh
);
145 fputs("<LineString><altitudeMode>absolute</altitudeMode><coordinates>\n", fh
);
147 double X
= p1
->x
, Y
= p1
->y
, Z
= p1
->z
;
148 pj_transform(pj_input
, pj_output
, 1, 1, &X
, &Y
, &Z
);
151 // %.8f is at worst just over 1mm.
152 fprintf(fh
, "%.8f,%.8f,%.2f\n", X
, Y
, Z
);
154 double X
= p
->x
, Y
= p
->y
, Z
= p
->z
;
155 pj_transform(pj_input
, pj_output
, 1, 1, &X
, &Y
, &Z
);
158 // %.8f is at worst just over 1mm.
159 fprintf(fh
, "%.8f,%.8f,%.2f\n", X
, Y
, Z
);
163 KML::xsect(const img_point
*p
, double angle
, double d1
, double d2
)
165 double s
= sin(rad(angle
));
166 double c
= cos(rad(angle
));
168 double x1
= p
->x
+ s
* d1
;
169 double y1
= p
->y
+ c
* d1
;
171 pj_transform(pj_input
, pj_output
, 1, 1, &x1
, &y1
, &z1
);
175 double x2
= p
->x
- s
* d2
;
176 double y2
= p
->y
- c
* d2
;
178 pj_transform(pj_input
, pj_output
, 1, 1, &x2
, &y2
, &z2
);
182 if (clamp_to_ground
) {
183 fputs("<Placemark><name></name><LineString><coordinates>", fh
);
185 fputs("<Placemark><name></name><LineString><altitudeMode>absolute</altitudeMode><coordinates>", fh
);
187 fprintf(fh
, "%.8f,%.8f,%.2f %.8f,%.8f,%.2f", x1
, y1
, z1
, x2
, y2
, z2
);
188 fputs("</coordinates></LineString></Placemark>\n", fh
);
192 KML::wall(const img_point
*p
, double angle
, double d
)
194 double s
= sin(rad(angle
));
195 double c
= cos(rad(angle
));
197 double x
= p
->x
+ s
* d
;
198 double y
= p
->y
+ c
* d
;
200 pj_transform(pj_input
, pj_output
, 1, 1, &x
, &y
, &z
);
205 if (clamp_to_ground
) {
206 fputs("<Placemark><name></name><LineString><coordinates>", fh
);
208 fputs("<Placemark><name></name><LineString><altitudeMode>absolute</altitudeMode><coordinates>", fh
);
212 fprintf(fh
, "%.8f,%.8f,%.2f\n", x
, y
, z
);
216 KML::passage(const img_point
*p
, double angle
, double d1
, double d2
)
218 double s
= sin(rad(angle
));
219 double c
= cos(rad(angle
));
221 double x1
= p
->x
+ s
* d1
;
222 double y1
= p
->y
+ c
* d1
;
224 pj_transform(pj_input
, pj_output
, 1, 1, &x1
, &y1
, &z1
);
228 double x2
= p
->x
- s
* d2
;
229 double y2
= p
->y
- c
* d2
;
231 pj_transform(pj_input
, pj_output
, 1, 1, &x2
, &y2
, &z2
);
235 // Define each passage as a multigeometry comprising of one quadrilateral
236 // per section. This prevents invalid geometry (such as self-intersecting
237 // polygons) being created.
241 fputs("<Placemark><name></name><MultiGeometry>\n", fh
);
243 if (clamp_to_ground
) {
245 "<outerBoundaryIs><LinearRing><coordinates>\n", fh
);
247 fputs("<Polygon><altitudeMode>absolute</altitudeMode>"
248 "<outerBoundaryIs><LinearRing><coordinates>\n", fh
);
251 // Draw anti-clockwise around the ring.
252 fprintf(fh
, "%.8f,%.8f,%.2f\n", v2
.GetX(), v2
.GetY(), v2
.GetZ());
253 fprintf(fh
, "%.8f,%.8f,%.2f\n", v1
.GetX(), v1
.GetY(), v1
.GetZ());
255 fprintf(fh
, "%.8f,%.8f,%.2f\n", x1
, y1
, z1
);
256 fprintf(fh
, "%.8f,%.8f,%.2f\n", x2
, y2
, z2
);
259 fprintf(fh
, "%.8f,%.8f,%.2f\n", v2
.GetX(), v2
.GetY(), v2
.GetZ());
261 fputs("</coordinates></LinearRing></outerBoundaryIs>"
265 v2
= Vector3(x2
, y2
, z2
);
266 v1
= Vector3(x1
, y1
, z1
);
273 fputs("</MultiGeometry></Placemark>\n", fh
);
277 fputs("</coordinates></LineString></Placemark>\n", fh
);
283 KML::label(const img_point
*p
, const char *s
, bool /*fSurface*/, int type
)
285 double X
= p
->x
, Y
= p
->y
, Z
= p
->z
;
286 pj_transform(pj_input
, pj_output
, 1, 1, &X
, &Y
, &Z
);
289 // %.8f is at worst just over 1mm.
290 fprintf(fh
, "<Placemark><Point><coordinates>%.8f,%.8f,%.2f</coordinates></Point><name>", X
, Y
, Z
);
292 fputs("</name>", fh
);
293 // Add a "pin" symbol with colour matching what aven shows.
296 fputs("<styleUrl>#fix</styleUrl>", fh
);
299 fputs("<styleUrl>#exp</styleUrl>", fh
);
302 fputs("<styleUrl>#ent</styleUrl>", fh
);
305 fputs("</Placemark>\n", fh
);
312 fputs("</coordinates></LineString></MultiGeometry></Placemark>\n", fh
);
313 fputs("</Document></kml>\n", fh
);