You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

xol.cc 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. /*
  2. Support for Swiss Map # (.xol) format
  3. Copyright (C) 2007 Olaf Klein, o.b.klein@gpsbabel.org
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2 of the License, or
  7. (at your option) any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
  15. */
  16. #include "defs.h"
  17. #include "xmlgeneric.h"
  18. #include "jeeps/gpsmath.h"
  19. #include "garmin_tables.h"
  20. #include "src/core/file.h"
  21. #include "src/core/xmlstreamwriter.h"
  22. #include <QtCore/QXmlStreamWriter>
  23. #include <QtCore/QXmlStreamAttributes>
  24. static Waypoint* wpt;
  25. static route_head* trk;
  26. static bounds all_bounds;
  27. static short_handle short_h;
  28. static gpsbabel::File* oqfile;
  29. static gpsbabel::XmlStreamWriter* writer;
  30. static arglist_t xol_args[] = {ARG_TERMINATOR};
  31. #define MYNAME "xol"
  32. static xg_callback xol_shape, xol_shape_end;
  33. static xg_callback xol_waypt, xol_overlay;
  34. #define XOL "/overlays/overlay"
  35. static xg_tag_mapping xol_map[] = {
  36. { xol_overlay, cb_start, XOL },
  37. { xol_shape, cb_start, XOL "/shapes/*shape" },
  38. { xol_shape_end, cb_end, XOL "/shapes/*shape" },
  39. { xol_waypt, cb_start, XOL "/shapes/shape/*points/point" },
  40. { NULL, (xg_cb_type)0, NULL} };
  41. static void xol_overlay(xg_string args, const QXmlStreamAttributes* attrv) {
  42. if (attrv->hasAttribute("version")) {
  43. if (attrv->value("version") != "1.0") {
  44. fatal(MYNAME ": Unsupported version %s.\n",
  45. qPrintable(attrv->value("version").toString()));
  46. }
  47. }
  48. }
  49. static void xol_shape(xg_string args, const QXmlStreamAttributes* attrv) {
  50. if (attrv->hasAttribute("type")) {
  51. if (attrv->value("type") == "waypoint") {
  52. wpt = new Waypoint;
  53. } else if (attrv->value("type") == "polyline") {
  54. trk = route_head_alloc();
  55. track_add_head(trk);
  56. }
  57. }
  58. if (attrv->hasAttribute("name")) {
  59. if (wpt) {
  60. wpt->shortname = attrv->value("name").toString();
  61. } else if (trk) {
  62. trk->rte_name = attrv->value("name").toString();
  63. }
  64. }
  65. if (wpt) {
  66. if (attrv->hasAttribute("comment")) {
  67. wpt->notes = attrv->value("comment").toString();
  68. }
  69. if (attrv->hasAttribute("alt")) {
  70. wpt->altitude = attrv->value("alt").toString().toDouble();
  71. }
  72. if (attrv->hasAttribute("timestamp")) {
  73. wpt->creation_time = xml_parse_time(
  74. attrv->value("timestamp").toString().toUtf8().constData());
  75. }
  76. if (attrv->hasAttribute("icon")) {
  77. wpt->icon_descr = attrv->value("icon").toString();
  78. }
  79. }
  80. }
  81. static void xol_shape_end(xg_string args, const QXmlStreamAttributes*) {
  82. if (wpt) {
  83. if (trk) {
  84. track_add_wpt(trk, wpt);
  85. } else {
  86. waypt_add(wpt);
  87. }
  88. wpt = NULL;
  89. } else if (trk) {
  90. if (trk->rte_waypt_ct == 0) {
  91. track_del_head(trk);
  92. }
  93. trk = NULL;
  94. }
  95. }
  96. static void xol_waypt(xg_string args, const QXmlStreamAttributes* attrv) {
  97. int x = 0, y = 0;
  98. if (attrv->hasAttribute("y")) {
  99. y = attrv->value("y").toString().toInt();
  100. }
  101. if (attrv->hasAttribute("x")) {
  102. x = attrv->value("x").toString().toInt();
  103. }
  104. GPS_Math_Swiss_EN_To_WGS84(x, y, &wpt->latitude, &wpt->longitude);
  105. }
  106. static void xol_rd_init(const QString& fname) {
  107. trk = NULL;
  108. wpt = NULL;
  109. xml_init(fname, xol_map, NULL);
  110. }
  111. static void xol_read(void) { xml_read(); }
  112. static void xol_rd_deinit(void) { xml_deinit(); }
  113. /* writer */
  114. static void xol_fatal_outside(const Waypoint* wpt) {
  115. fatal(MYNAME ": %s (%s) is outside of convertable area \"%s\"!\n",
  116. wpt->shortname.isEmpty() ? "Waypoint" : qPrintable(wpt->shortname),
  117. pretty_deg_format(wpt->latitude, wpt->longitude, 'd', NULL, 0),
  118. gt_get_mps_grid_longname(grid_swiss, MYNAME));
  119. }
  120. static void xol_waypt_bound_calc(const Waypoint* wpt) {
  121. waypt_add_to_bounds(&all_bounds, wpt);
  122. }
  123. static void xol_wr_init(const QString& fname) {
  124. oqfile = new gpsbabel::File(fname);
  125. oqfile->open(QIODevice::WriteOnly | QIODevice::Text);
  126. writer = new gpsbabel::XmlStreamWriter(oqfile);
  127. writer->setAutoFormattingIndent(2);
  128. writer->writeStartDocument();
  129. waypt_init_bounds(&all_bounds);
  130. short_h = mkshort_new_handle();
  131. setshort_length(short_h, 1024); /* ??? */
  132. setshort_badchars(short_h, "\r\n\t");
  133. setshort_mustupper(short_h, 0);
  134. setshort_mustuniq(short_h, 1);
  135. setshort_whitespace_ok(short_h, 1);
  136. setshort_repeating_whitespace_ok(short_h, 1);
  137. setshort_defname(short_h, "Waypoint");
  138. }
  139. static void xol_wr_deinit(void) {
  140. mkshort_del_handle(&short_h);
  141. writer->writeEndDocument();
  142. delete writer;
  143. writer = NULL;
  144. oqfile->close();
  145. delete oqfile;
  146. oqfile = NULL;
  147. }
  148. static void xol_waypt_disp_cb(const Waypoint* wpt) {
  149. double x, y;
  150. QString name = wpt->shortname;
  151. if (name.isEmpty() || global_opts.synthesize_shortnames) {
  152. name = mkshort_from_wpt(short_h, wpt);
  153. } else {
  154. name = mkshort(short_h, name);
  155. }
  156. if (!GPS_Math_WGS84_To_Swiss_EN(wpt->latitude, wpt->longitude, &x, &y)) {
  157. xol_fatal_outside(wpt);
  158. }
  159. writer->writeStartElement("shape");
  160. writer->writeAttribute("type", "waypoint");
  161. writer->writeAttribute("name", name);
  162. writer->writeAttribute("comment", wpt->notes);
  163. writer->writeAttribute("icon", wpt->icon_descr);
  164. if (wpt->creation_time.isValid()) {
  165. writer->writeAttribute("timestamp", wpt->CreationTimeXML());
  166. }
  167. if (wpt->altitude != unknown_alt) {
  168. writer->writeAttribute("alt", QString::number(wpt->altitude, 'f', 6));
  169. }
  170. writer->writeStartElement("points");
  171. writer->writeStartElement("point");
  172. writer->writeAttribute("x", QString::number(x));
  173. writer->writeAttribute("y", QString::number(y));
  174. writer->writeEndElement(); // point
  175. writer->writeEndElement(); // points
  176. writer->writeEndElement(); // shape
  177. }
  178. static void xol_track_hdr_disp_cb(const route_head* trk) {
  179. writer->writeStartElement("shape");
  180. writer->writeAttribute("type", "polyline");
  181. writer->writeAttribute("lineSize", "3");
  182. writer->writeAttribute("lineColor", "#e60000");
  183. writer->writeAttribute("lineStyle", "solid");
  184. writer->writeStartElement("waypoints");
  185. }
  186. static void xol_track_tlr_disp_cb(const route_head* trk) {
  187. writer->writeEndElement(); // waypoints
  188. writer->writeEndElement(); // shape
  189. }
  190. static void xol_trkpt_disp_cb(const Waypoint* wpt) {
  191. double x, y;
  192. if (!GPS_Math_WGS84_To_Swiss_EN(wpt->latitude, wpt->longitude, &x, &y)) {
  193. xol_fatal_outside(wpt);
  194. }
  195. writer->writeStartElement("shape");
  196. writer->writeAttribute("type", "waypoint");
  197. if (wpt->creation_time.isValid()) {
  198. writer->writeAttribute("timestamp", wpt->CreationTimeXML());
  199. }
  200. if (wpt->altitude != unknown_alt) {
  201. writer->writeAttribute("alt", QString::number(wpt->altitude, 'f'));
  202. }
  203. writer->writeStartElement("points");
  204. writer->writeStartElement("point");
  205. writer->writeAttribute("x", QString::number(x));
  206. writer->writeAttribute("y", QString::number(y));
  207. writer->writeEndElement(); // point
  208. writer->writeEndElement(); // points
  209. writer->writeEndElement(); // shape
  210. }
  211. static void xol_write(void) {
  212. double x, y;
  213. waypt_disp_all(xol_waypt_bound_calc);
  214. track_disp_all(NULL, NULL, xol_waypt_bound_calc);
  215. if (!waypt_bounds_valid(&all_bounds)) {
  216. fatal(MYNAME ": No data available!\n");
  217. }
  218. if (!GPS_Math_WGS84_To_Swiss_EN((all_bounds.min_lat + all_bounds.max_lat) / 2,
  219. (all_bounds.min_lon + all_bounds.max_lon) / 2,
  220. &x, &y)) {
  221. fatal(MYNAME
  222. ": At least one point is outside of convertable area \"%s\"!\n",
  223. gt_get_mps_grid_longname(grid_swiss, MYNAME));
  224. }
  225. writer->setAutoFormatting(true);
  226. writer->writeStartElement("overlays");
  227. writer->writeStartElement("overlay");
  228. writer->writeAttribute("version", "1.0");
  229. writer->writeStartElement("center");
  230. writer->writeAttribute("x", QString::number(x));
  231. writer->writeAttribute("y", QString::number(y));
  232. writer->writeEndElement(); // center
  233. writer->writeStartElement("shapes");
  234. waypt_disp_all(xol_waypt_disp_cb);
  235. track_disp_all(xol_track_hdr_disp_cb, xol_track_tlr_disp_cb,
  236. xol_trkpt_disp_cb);
  237. writer->writeEndElement(); // shapes
  238. writer->writeEndElement(); // overlay
  239. }
  240. ff_vecs_t xol_vecs = {ff_type_file,
  241. {(ff_cap)(ff_cap_read | ff_cap_write), /* waypoints */
  242. (ff_cap)(ff_cap_read | ff_cap_write), /* tracks */
  243. ff_cap_none}, /* routes */
  244. xol_rd_init,
  245. xol_wr_init,
  246. xol_rd_deinit,
  247. xol_wr_deinit,
  248. xol_read,
  249. xol_write,
  250. NULL,
  251. xol_args,
  252. CET_CHARSET_UTF8,
  253. 0};