1 /* 2 Support for Google Earth & Keyhole "kml" format. 3 4 Copyright (C) 2005-2013 Robert Lipe, robertlipe+source@gpsbabel.org 5 Updates by Andrew Kirmse, akirmse at google.com 6 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. 11 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. 16 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 21 */ 22 #ifndef KML_H_INCLUDED_ 23 #define KML_H_INCLUDED_ 24 25 #include <tuple> // for tuple, make_tuple, tie 26 27 #include <QtCore/QList> // for QList 28 #include <QtCore/QString> // for QString, QStringLiteral, operator+, operator!= 29 #include <QtCore/QVector> // for QVector 30 #include <QtCore/QXmlStreamAttributes> // for QXmlStreamAttributes 31 32 #include "defs.h" 33 #include "format.h" 34 #include "src/core/datetime.h" // for DateTime 35 #include "src/core/file.h" // for File 36 #include "src/core/xmlstreamwriter.h" // for XmlStreamWriter 37 #include "xmlgeneric.h" // for cb_cdata, cb_end, cb_start, xg_callback, xg_string, xg_cb_type, xml_deinit, xml_ignore_tags, xml_init, xml_read, xg_tag_mapping 38 39 40 class KmlFormat : public Format 41 { 42 public: get_args()43 QVector<arglist_t>* get_args() override 44 { 45 return &kml_args; 46 } 47 get_type()48 ff_type get_type() const override 49 { 50 return ff_type_file; 51 } 52 get_cap()53 QVector<ff_cap> get_cap() const override 54 { 55 return FF_CAP_RW_ALL; 56 } 57 get_encode()58 QString get_encode() const override 59 { 60 return CET_CHARSET_UTF8; 61 } 62 get_fixed_encode()63 int get_fixed_encode() const override 64 { 65 return 1; 66 } 67 68 void rd_init(const QString& fname) override; 69 void read() override; 70 void rd_deinit() override; 71 void wr_init(const QString& fname) override; 72 void write() override; 73 void wr_deinit() override; 74 void wr_position_init(const QString& fname) override; 75 void wr_position(Waypoint* wpt) override; 76 void wr_position_deinit() override; 77 78 private: 79 /* Types */ 80 81 enum kml_point_type { 82 kmlpt_unknown, 83 kmlpt_waypoint, 84 kmlpt_track, 85 kmlpt_route, 86 kmlpt_multitrack, 87 kmlpt_other 88 }; 89 90 // Helper to write gx:SimpleList, iterating over a route queue and writing out. 91 92 enum wp_field { 93 fld_cadence, 94 fld_depth, 95 fld_heartrate, 96 fld_temperature, 97 fld_power 98 }; 99 100 /* Constants */ 101 static constexpr const char* default_precision = "6"; 102 static constexpr int kml_color_limit = 204; /* allowed range [0,255] */ 103 104 // Multitrack ids to correlate Schema to SchemaData 105 static constexpr const char* kmt_heartrate = "heartrate"; 106 static constexpr const char* kmt_cadence = "cadence"; 107 static constexpr const char* kmt_temperature = "temperature"; 108 static constexpr const char* kmt_depth = "depth"; 109 static constexpr const char* kmt_power = "power"; 110 111 /* Member Functions */ 112 113 void kml_init_color_sequencer(unsigned int steps_per_rev); 114 void kml_step_color(); 115 void wpt_s(const QString& args, const QXmlStreamAttributes* attrs); 116 void wpt_e(const QString& args, const QXmlStreamAttributes* attrs); 117 void wpt_name(const QString& args, const QXmlStreamAttributes* attrs); 118 void wpt_desc(const QString& args, const QXmlStreamAttributes* attrs); 119 void wpt_coord(const QString& args, const QXmlStreamAttributes* attrs); 120 void wpt_icon(const QString& args, const QXmlStreamAttributes* attrs); 121 void trk_coord(const QString& args, const QXmlStreamAttributes* attrs); 122 void wpt_time(const QString& args, const QXmlStreamAttributes* attrs); 123 void wpt_ts_begin(const QString& args, const QXmlStreamAttributes* attrs); 124 void wpt_ts_end(const QString& args, const QXmlStreamAttributes* attrs); 125 void gx_trk_s(const QString& args, const QXmlStreamAttributes* attrs); 126 void gx_trk_e(const QString& args, const QXmlStreamAttributes* attrs); 127 void gx_trk_when(const QString& args, const QXmlStreamAttributes* attrs); 128 void gx_trk_coord(const QString& args, const QXmlStreamAttributes* attrs); 129 void kml_output_linestyle(char* color, int width) const; 130 void kml_write_bitmap_style_(const QString& style, const QString& bitmap, int highlighted, int force_heading) const; 131 void kml_write_bitmap_style(kml_point_type pt_type, const QString& bitmap, const QString& customstyle) const; 132 void kml_output_timestamp(const Waypoint* waypointp) const; 133 static void kml_td(gpsbabel::XmlStreamWriter& hwriter, const QString& boldData, const QString& data); 134 static void kml_td(gpsbabel::XmlStreamWriter& hwriter, const QString& data); 135 void kml_output_trkdescription(const route_head* header, const computed_trkdata* td) const; 136 void kml_output_header(const route_head* header, const computed_trkdata* td) const; 137 int kml_altitude_known(const Waypoint* waypoint) const; 138 void kml_write_coordinates(const Waypoint* waypointp) const; 139 void kml_output_lookat(const Waypoint* waypointp) const; 140 void kml_output_positioning(bool tessellate) const; 141 void kml_output_description(const Waypoint* pt) const; 142 void kml_recompute_time_bounds(const Waypoint* waypointp); 143 void kml_add_to_bounds(const Waypoint* waypointp); 144 void kml_output_point(const Waypoint* waypointp, kml_point_type pt_type) const; 145 void kml_output_tailer(const route_head* header); 146 static void kml_gc_all_tabs_text(QString& cdataStr); 147 void kml_gc_make_balloonstyletext() const; 148 void kml_gc_make_balloonstyle() const; 149 static QString kml_lookup_gc_icon(const Waypoint* waypointp); 150 static const char* kml_lookup_gc_container(const Waypoint* waypointp); 151 static QString kml_gc_mkstar(int rating); 152 QString kml_geocache_get_logs(const Waypoint* wpt) const; 153 void kml_write_data_element(const QString& name, const QString& value) const; 154 void kml_write_data_element(const QString& name, int value) const; 155 void kml_write_data_element(const QString& name, double value) const; 156 void kml_write_cdata_element(const QString& name, const QString& value) const; 157 void kml_geocache_pr(const Waypoint* waypointp) const; 158 void kml_waypt_pr(const Waypoint* waypointp) const; 159 void kml_track_hdr(const route_head* header) const; 160 void kml_track_disp(const Waypoint* waypointp) const; 161 void kml_track_tlr(const route_head* header); 162 void kml_mt_simple_array(const route_head* header, const char* name, wp_field member) const; 163 static int track_has_time(const route_head* header); 164 void write_as_linestring(const route_head* header); 165 void kml_mt_hdr(const route_head* header); 166 void kml_mt_tlr(const route_head* header) const; 167 void kml_route_hdr(const route_head* header) const; 168 void kml_route_disp(const Waypoint* waypointp) const; 169 void kml_route_tlr(const route_head* header); 170 void kml_write_AbstractView(); 171 void kml_mt_array_schema(const char* field_name, const char* display_name, const char* type) const; 172 static QString kml_get_posn_icon(int freshness); 173 174 /* Data Members */ 175 176 // options 177 char* opt_deficon{nullptr}; 178 char* opt_export_lines{nullptr}; 179 char* opt_export_points{nullptr}; 180 char* opt_export_track{nullptr}; 181 char* opt_line_width{nullptr}; 182 char* opt_line_color{nullptr}; 183 char* opt_floating{nullptr}; 184 char* opt_extrude{nullptr}; 185 char* opt_trackdata{nullptr}; 186 char* opt_trackdirection{nullptr}; 187 char* opt_units{nullptr}; 188 char* opt_labels{nullptr}; 189 char* opt_max_position_points{nullptr}; 190 char* opt_rotate_colors{nullptr}; 191 char* opt_precision{nullptr}; 192 193 int export_lines{}; 194 int export_points{}; 195 int export_track{}; 196 int floating{}; 197 int extrude{}; 198 int trackdata{}; 199 int trackdirection{}; 200 int max_position_points{}; 201 int rotate_colors{}; 202 int line_width{}; 203 int html_encrypt{}; 204 int precision{}; 205 206 Waypoint* wpt_tmp{nullptr}; 207 bool wpt_tmp_queued{false}; 208 QString posnfilename; 209 QString posnfilenametmp; 210 211 route_head* gx_trk_head{nullptr}; 212 QList<gpsbabel::DateTime>* gx_trk_times{nullptr}; 213 QList<std::tuple<int, double, double, double>>* gx_trk_coords{nullptr}; 214 215 gpsbabel::File* oqfile{nullptr}; 216 gpsbabel::XmlStreamWriter* writer{nullptr}; 217 218 int realtime_positioning{}; 219 bounds kml_bounds{}; 220 gpsbabel::DateTime kml_time_max; 221 gpsbabel::DateTime kml_time_min; 222 223 QVector<arglist_t> kml_args = { 224 {"deficon", &opt_deficon, "Default icon name", nullptr, ARGTYPE_STRING, ARG_NOMINMAX, nullptr }, 225 { 226 "lines", &opt_export_lines, 227 "Export linestrings for tracks and routes", 228 "1", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr, 229 }, 230 { 231 "points", &opt_export_points, 232 "Export placemarks for tracks and routes", 233 "1", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr 234 }, 235 { 236 "line_width", &opt_line_width, 237 "Width of lines, in pixels", 238 "6", ARGTYPE_INT, ARG_NOMINMAX, nullptr 239 }, 240 { 241 "line_color", &opt_line_color, 242 "Line color, specified in hex AABBGGRR", 243 "99ffac59", ARGTYPE_STRING, ARG_NOMINMAX, nullptr 244 }, 245 { 246 "floating", &opt_floating, 247 "Altitudes are absolute and not clamped to ground", 248 "0", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr 249 }, 250 { 251 "extrude", &opt_extrude, 252 "Draw extrusion line from trackpoint to ground", 253 "0", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr 254 }, 255 { 256 "track", &opt_export_track, 257 "Write KML track (default = 0)", 258 "0", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr 259 }, 260 { 261 "trackdata", &opt_trackdata, 262 "Include extended data for trackpoints (default = 1)", 263 "1", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr 264 }, 265 { 266 "trackdirection", &opt_trackdirection, 267 "Indicate direction of travel in track icons (default = 0)", 268 "0", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr 269 }, 270 { 271 "units", &opt_units, 272 "Units used when writing comments ('s'tatute, 'm'etric,' 'n'autical, 'a'viation)", 273 "s", ARGTYPE_STRING, ARG_NOMINMAX, nullptr 274 }, 275 { 276 "labels", &opt_labels, 277 "Display labels on track and routepoints (default = 1)", 278 "1", ARGTYPE_BOOL, ARG_NOMINMAX, nullptr 279 }, 280 { 281 "max_position_points", &opt_max_position_points, 282 "Retain at most this number of position points (0 = unlimited)", 283 "0", ARGTYPE_INT, ARG_NOMINMAX, nullptr 284 }, 285 { 286 "rotate_colors", &opt_rotate_colors, 287 "Rotate colors for tracks and routes (default automatic)", 288 nullptr, ARGTYPE_FLOAT, "0", "360", nullptr 289 }, 290 { 291 "prec", &opt_precision, 292 "Precision of coordinates, number of decimals", 293 default_precision, ARGTYPE_INT, ARG_NOMINMAX, nullptr 294 }, 295 }; 296 297 struct { 298 float seq{0.0f}; 299 float step{0.0f}; 300 gb_color color; 301 } kml_color_sequencer; 302 303 QList<xg_functor_map_entry<KmlFormat>> kml_map = { 304 {&KmlFormat::wpt_s, cb_start, "/Placemark"}, 305 {&KmlFormat::wpt_e, cb_end, "/Placemark"}, 306 {&KmlFormat::wpt_name, cb_cdata, "/Placemark/name"}, 307 {&KmlFormat::wpt_desc, cb_cdata, "/Placemark/description"}, 308 {&KmlFormat::wpt_ts_begin, cb_cdata,"/Placemark/TimeSpan/begin"}, 309 {&KmlFormat::wpt_ts_end, cb_cdata, "/Placemark/TimeSpan/end"}, 310 {&KmlFormat::wpt_time, cb_cdata, "/Placemark/TimeStamp/when"}, 311 // Alias for above used in KML 2.0 312 {&KmlFormat::wpt_time, cb_cdata, "/Placemark/TimeInstant/timePosition"}, 313 {&KmlFormat::wpt_coord, cb_cdata, "/Placemark/Point/coordinates"}, 314 {&KmlFormat::wpt_icon, cb_cdata, "/Placemark/Style/Icon/href"}, 315 {&KmlFormat::trk_coord, cb_cdata, "/Placemark/MultiGeometry/LineString/coordinates"}, 316 {&KmlFormat::trk_coord, cb_cdata, "/Placemark/GeometryCollection/LineString/coordinates"}, 317 {&KmlFormat::trk_coord, cb_cdata, "/Placemark/Polygon/outerBoundaryIs/LinearRing/coordinates"}, 318 {&KmlFormat::trk_coord, cb_cdata, "/Placemark/LineString/coordinates"}, 319 {&KmlFormat::gx_trk_s, cb_start, "/Placemark/*gx:Track"}, 320 {&KmlFormat::gx_trk_e, cb_end, "/Placemark/*gx:Track"}, 321 {&KmlFormat::gx_trk_when, cb_cdata, "/Placemark/*gx:Track/when"}, 322 {&KmlFormat::gx_trk_coord, cb_cdata, "/Placemark/*gx:Track/gx:coord"}, 323 {&KmlFormat::gx_trk_s, cb_start, "/Placemark/Track"}, // KML 2.3 324 {&KmlFormat::gx_trk_e, cb_end, "/Placemark/Track"}, // KML 2.3 325 {&KmlFormat::gx_trk_when, cb_cdata, "/Placemark/Track/when"}, // KML 2.3 326 {&KmlFormat::gx_trk_coord, cb_cdata, "/Placemark/Track/coord"}, // KML 2.3 327 {&KmlFormat::gx_trk_s, cb_start, "/Placemark/MultiTrack/Track"}, // KML 2.3 328 {&KmlFormat::gx_trk_e, cb_end, "/Placemark/MultiTrack/Track"}, // KML 2.3 329 {&KmlFormat::gx_trk_when, cb_cdata, "/Placemark/MultiTrack/Track/when"}, // KML 2.3 330 {&KmlFormat::gx_trk_coord, cb_cdata, "/Placemark/MultiTrack/Track/coord"} // KML 2.3 331 }; 332 333 static const char* kml_tags_to_ignore[]; 334 static const char* kml_tags_to_skip[]; 335 336 // The TimeSpan/begin and TimeSpan/end DateTimes: 337 gpsbabel::DateTime wpt_timespan_begin, wpt_timespan_end; 338 339 static const QString map_templates[]; 340 341 route_head* posn_trk_head{nullptr}; 342 }; 343 344 #endif // KML_H_INCLUDED_ 345