source: git/src/gpx.cc @ f10cf8f

RELEASE/1.2debug-cidebug-ci-sanitisersstereowalls-datawalls-data-hanging-as-warning
Last change on this file since f10cf8f was f10cf8f, checked in by Olly Betts <olly@…>, 10 years ago

src/: Pass the numeric datestamp to ExportFilter::header(), and use
it to set a timestamp in exported GPX files.

  • Property mode set to 100644
File size: 4.8 KB
RevLine 
[4734106]1/* gpx.cc
2 * Export from Aven as GPX.
3 */
4/* Copyright (C) 2012 Olaf Kähler
[f10cf8f]5 * Copyright (C) 2012,2013,2014 Olly Betts
[4734106]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 St, Fifth Floor, Boston, MA  02110-1301 USA
20 */
21
22#ifdef HAVE_CONFIG_H
23# include <config.h>
24#endif
25
26#include "gpx.h"
27
[fdea415]28#include "export.h" // For LABELS, etc
29
[4734106]30#include <stdio.h>
31#include <string>
[f10cf8f]32#include <time.h>
[4734106]33#include <math.h>
34
35#include "useful.h"
36#include <proj_api.h>
37
38#include "aven.h"
39#include "message.h"
40
41using namespace std;
42
43#define WGS84_DATUM_STRING "+proj=longlat +ellps=WGS84 +datum=WGS84"
44
[fdea415]45static void
46html_escape(FILE *fh, const char *s)
47{
48    while (*s) {
49        switch (*s) {
50            case '<':
51                fputs("&lt;", fh);
52                break;
53            case '>':
54                fputs("&gt;", fh);
55                break;
56            case '&':
57                fputs("&amp;", fh);
58                break;
59            default:
60                PUTC(*s, fh);
61        }
62        ++s;
63    }
64}
65
[9b5a5fd]66GPX::GPX(const char * input_datum)
[a6dddd1]67    : pj_input(NULL), pj_output(NULL), in_trkseg(false)
[4734106]68{
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);
72        wxGetApp().ReportError(m);
73        return;
74    }
75    if (!(pj_output = pj_init_plus(WGS84_DATUM_STRING))) {
76        wxString m = wmsg(/*Failed to initialise output coordinate system “%s”*/288);
77        m = wxString::Format(m.c_str(), WGS84_DATUM_STRING);
78        wxGetApp().ReportError(m);
79        return;
80    }
81}
82
83GPX::~GPX()
84{
85    if (pj_input)
86        pj_free(pj_input);
87    if (pj_output)
88        pj_free(pj_output);
89}
90
[fdea415]91const int *
92GPX::passes() const
93{
[a6dddd1]94    static const int default_passes[] = { LABELS|ENTS|FIXES|EXPORTS, LEGS|SURF, 0 };
[fdea415]95    return default_passes;
96}
97
[4734106]98/* Initialise GPX routines. */
[f10cf8f]99void GPX::header(const char * title, const char *, time_t datestamp_numeric)
[4734106]100{
[79137712]101    fputs(
[4734106]102"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"
[fdea415]103"<gpx version=\"1.0\" creator=\""PACKAGE_STRING" (aven) - http://survex.com/\""
[4734106]104" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\""
105" xmlns=\"http://www.topografix.com/GPX/1/0\""
106" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/0"
[79137712]107" http://www.topografix.com/GPX/1/0/gpx.xsd\">\n", fh);
[6a1c384]108    if (title) {
109        fputs("<name>", fh);
110        html_escape(fh, title);
111        fputs("</name>\n", fh);
112    }
[f10cf8f]113    if (datestamp_numeric != time_t(-1)) {
114        struct tm * tm = gmtime(&datestamp_numeric);
115        if (tm) {
116            char buf[32];
117            if (strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%SZ", tm)) {
118                fputs("<time>", fh);
119                fputs(buf, fh);
120                fputs("</time>\n", fh);
121            }
122        }
123    }
[fdea415]124    // FIXME: optional in GPX, but perhaps useful:
125    // <bounds minlat="..." minlon="..." maxlat="..." maxlon="..." />
126    // NB Not necessarily the same as the bounds in survex coords translated
127    // to WGS85 lat+long...
[4734106]128}
129
130void
[a6dddd1]131GPX::line(const img_point *p1, const img_point *p, bool /*fSurface*/, bool fPendingMove)
[4734106]132{
[a6dddd1]133    if (fPendingMove) {
134        if (in_trkseg) {
135            fputs("</trkseg><trkseg>\n", fh);
136        } else {
137            fputs("<trk><trkseg>\n", fh);
138            in_trkseg = true;
139        }
140        double X = p1->x, Y = p1->y, Z = p1->z;
141        pj_transform(pj_input, pj_output, 1, 1, &X, &Y, &Z);
142        X = deg(X);
143        Y = deg(Y);
144        // %.8f is at worst just over 1mm.
145        fprintf(fh, "<trkpt lon=\"%.8f\" lat=\"%.8f\"><ele>%.2f</ele></trkpt>\n", X, Y, Z);
146    }
147    double X = p->x, Y = p->y, Z = p->z;
148    pj_transform(pj_input, pj_output, 1, 1, &X, &Y, &Z);
149    X = deg(X);
150    Y = deg(Y);
151    // %.8f is at worst just over 1mm.
152    fprintf(fh, "<trkpt lon=\"%.8f\" lat=\"%.8f\"><ele>%.2f</ele></trkpt>\n", X, Y, Z);
[4734106]153}
154
155void
[fdea415]156GPX::label(const img_point *p, const char *s, bool /*fSurface*/, int type)
[4734106]157{
158    double X = p->x, Y = p->y, Z = p->z;
159    pj_transform(pj_input, pj_output, 1, 1, &X, &Y, &Z);
160    X = deg(X);
161    Y = deg(Y);
162    // %.8f is at worst just over 1mm.
163    fprintf(fh, "<wpt lon=\"%.8f\" lat=\"%.8f\"><ele>%.2f</ele><name>", X, Y, Z);
[fdea415]164    html_escape(fh, s);
165    fputs("</name>", fh);
166    // Add a "pin" symbol with colour matching what aven shows.
167    switch (type) {
168        case FIXES:
169            fputs("<sym>Pin, Red</sym>", fh);
170            break;
171        case EXPORTS:
172            fputs("<sym>Pin, Blue</sym>", fh);
173            break;
174        case ENTS:
175            fputs("<sym>Pin, Green</sym>", fh);
176            break;
[4734106]177    }
[fdea415]178    fputs("</wpt>\n", fh);
[4734106]179}
180
181void
182GPX::footer()
183{
[a6dddd1]184    if (in_trkseg)
185        fputs("</trkseg></trk>\n", fh);
186    fputs("</gpx>\n", fh);
[4734106]187}
Note: See TracBrowser for help on using the repository browser.