64 const gchar **attribute_names,
const gchar **attribute_values,
65 gpointer ueer_data, GError **
error);
67 gpointer user_data, GError **
error);
68static void _gpx_parser_text(GMarkupParseContext *context,
const gchar *text, gsize text_len,
69 gpointer user_data, GError **
error);
79 return g_date_time_compare(pa->
time, pb->
time);
93 GMarkupParseContext *ctx = NULL;
97 GMappedFile *gpxmf = g_mapped_file_new(filename,
FALSE, &err);
100 gchar *gpxmf_content = g_mapped_file_get_contents(gpxmf);
101 const gint gpxmf_size = g_mapped_file_get_length(gpxmf);
108 if(gpxmf_content[0] ==
'\xef' && gpxmf_content[1] ==
'\xbb' && gpxmf_content[2] ==
'\xbf')
112 ctx = g_markup_parse_context_new(&
_gpx_parser, 0, gpx, NULL);
113 g_markup_parse_context_parse(ctx, gpxmf_content + bom_offset, gpxmf_size - bom_offset, &err);
117 g_markup_parse_context_free(ctx);
118 g_mapped_file_unref(gpxmf);
128 fprintf(stderr,
"dt_gpx_new: %s\n", err->message);
132 if(ctx) g_markup_parse_context_free(ctx);
136 if(gpxmf) g_mapped_file_unref(gpxmf);
149 g_date_time_unref(trkpt->
time);
178 for(GList *item = gpx->
trkpts; item; item = g_list_next(item))
184 const gint cmp = g_date_time_compare(timestamp, tp->
time);
185 if((
IS_NULL_PTR(item->next) && cmp >= 0) || (cmp <= 0))
195 const gint cmp_n = g_date_time_compare(timestamp, tp_next->
time);
196 if(item->next && cmp_n <= 0)
198 GTimeSpan seg_diff = g_date_time_difference(tp_next->
time, tp->
time);
199 GTimeSpan diff = g_date_time_difference(timestamp, tp->
time);
200 if(seg_diff == 0 || diff == 0)
215 const double lat2 = tp_next->
latitude;
220 const double f = (
double)diff / (
double)seg_diff;
226 lon = lon1 + (lon2 - lon1) *
f;
227 lat = lat1 + (lat2 - lat1) *
f;
276 const gchar **attribute_names,
const gchar **attribute_values,
277 gpointer user_data, GError **
error)
284 if(strcmp(element_name,
"trk") == 0)
292 if(strcmp(element_name,
"trkpt") == 0)
296 fprintf(stderr,
"broken GPX file, new trkpt element before the previous ended.\n");
300 const gchar **attribute_name = attribute_names;
301 const gchar **attribute_value = attribute_values;
316 while(*attribute_name)
318 if(strcmp(*attribute_name,
"lon") == 0)
320 else if(strcmp(*attribute_name,
"lat") == 0)
330 fprintf(stderr,
"broken GPX file, failed to get lon/lat attribute values for trkpt\n");
335 fprintf(stderr,
"broken GPX file, trkpt element doesn't have lon/lat attributes\n");
339 else if(strcmp(element_name,
"time") == 0)
345 else if(strcmp(element_name,
"ele") == 0)
351 else if(strcmp(element_name,
"name") == 0)
355 else if(strcmp(element_name,
"trkseg") == 0)
369 fprintf(stderr,
"broken GPX file, element '%s' found outside of trkpt.\n", element_name);
380 if(strcmp(element_name,
"trk") == 0)
384 else if(strcmp(element_name,
"trkpt") == 0)
394 else if(strcmp(element_name,
"trkseg") == 0)
404void _gpx_parser_text(GMarkupParseContext *context,
const gchar *text, gsize text_len, gpointer user_data,
426 fprintf(stderr,
"broken GPX file, failed to pars is8601 time '%s' for trackpoint\n", text);
452 GList *ts = g_list_nth(gpx->
trksegs, segid);
457 for(GList *tp = tps; tp; tp = g_list_next(tp))
460 if(tpd->
segid != segid)
return pts;
464 pts = g_list_prepend(pts,
p);
474 double lat2,
double lon2,
477 const double lat_rad_1 = lat1 *
M_PI / 180;
478 const double lat_rad_2 = lat2 *
M_PI / 180;
479 const double lon_rad_1 = lon1 *
M_PI / 180;
480 const double lon_rad_2 = lon2 *
M_PI / 180;
481 const double delta_lat_rad = lat_rad_2 - lat_rad_1;
482 const double delta_lon_rad = lon_rad_2 - lon_rad_1;
483 const double sin_delta_lat_rad = sin(delta_lat_rad / 2);
484 const double sin_delta_lon_rad = sin(delta_lon_rad / 2);
486 const double a = sin_delta_lat_rad * sin_delta_lat_rad +
487 cos(lat_rad_1) * cos(lat_rad_2) *
488 sin_delta_lon_rad * sin_delta_lon_rad;
489 *
delta = 2 * atan2(sqrt(a), sqrt(1 - a));
495 const double lat2,
const double lon2,
497 const gboolean first_time,
501 static double lat_rad_1;
502 static double sin_lat_rad_1;
503 static double cos_lat_rad_1;
504 static double lat_rad_2;
505 static double sin_lat_rad_2;
506 static double cos_lat_rad_2;
507 static double lon_rad_1;
508 static double sin_lon_rad_1;
509 static double cos_lon_rad_1;
510 static double lon_rad_2;
511 static double sin_lon_rad_2;
512 static double cos_lon_rad_2;
513 static double sin_delta;
517 lat_rad_1 = lat1 *
M_PI / 180;
518 sin_lat_rad_1 = sin(lat_rad_1);
519 cos_lat_rad_1 = cos(lat_rad_1);
520 lat_rad_2 = lat2 *
M_PI / 180;
521 sin_lat_rad_2 = sin(lat_rad_2);
522 cos_lat_rad_2 = cos(lat_rad_2);
523 lon_rad_1 = lon1 *
M_PI / 180;
524 sin_lon_rad_1 = sin(lon_rad_1);
525 cos_lon_rad_1 = cos(lon_rad_1);
526 lon_rad_2 = lon2 *
M_PI / 180;
527 sin_lon_rad_2 = sin(lon_rad_2);
528 cos_lon_rad_2 = cos(lon_rad_2);
529 sin_delta = sin(
delta);
532 const double a = sin((1 -
f) *
delta) / sin_delta;
533 const double b = sin(
f *
delta) / sin_delta;
534 const double x = a * cos_lat_rad_1 * cos_lon_rad_1 + b * cos_lat_rad_2 * cos_lon_rad_2;
535 const double y = a * cos_lat_rad_1 * sin_lon_rad_1 + b * cos_lat_rad_2 * sin_lon_rad_2;
536 const double z = a * sin_lat_rad_1 + b * sin_lat_rad_2;
537 const double lat_rad = atan2(z, sqrt(
x *
x + y * y));
538 const double lon_rad = atan2(y,
x);
static void error(char *msg)
static gboolean g_list_shorter_than(const GList *list, unsigned len)
void dt_gpx_destroy(struct dt_gpx_t *gpx)
GList * dt_gpx_get_trkpts(struct dt_gpx_t *gpx, const guint segid)
static gint _sort_track(gconstpointer a, gconstpointer b)
static void _gpx_parser_text(GMarkupParseContext *context, const gchar *text, gsize text_len, gpointer user_data, GError **error)
static GMarkupParser _gpx_parser
void _track_seg_free(dt_gpx_track_segment_t *trkseg)
static void _gpx_parser_end_element(GMarkupParseContext *context, const gchar *element_name, gpointer user_data, GError **error)
gboolean dt_gpx_get_location(struct dt_gpx_t *gpx, GDateTime *timestamp, dt_image_geoloc_t *geoloc)
@ GPX_PARSER_ELEMENT_NAME
@ GPX_PARSER_ELEMENT_TRKPT
@ GPX_PARSER_ELEMENT_NONE
@ GPX_PARSER_ELEMENT_TIME
static gint _sort_segment(gconstpointer a, gconstpointer b)
dt_gpx_t * dt_gpx_new(const gchar *filename)
void _track_pts_free(dt_gpx_track_point_t *trkpt)
void dt_gpx_geodesic_intermediate_point(const double lat1, const double lon1, const double lat2, const double lon2, const double delta, const gboolean first_time, double f, double *lat, double *lon)
GList * dt_gpx_get_trkseg(struct dt_gpx_t *gpx)
static void _gpx_parser_start_element(GMarkupParseContext *ctx, const gchar *element_name, const gchar **attribute_names, const gchar **attribute_values, gpointer ueer_data, GError **error)
void dt_gpx_geodesic_distance(double lat1, double lon1, double lat2, double lon2, double *d, double *delta)
#define DT_MINIMUM_ANGULAR_DELTA_FOR_GEODESIC
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
gboolean invalid_track_point
_gpx_parser_element_t current_parser_element
dt_gpx_track_point_t * current_track_point
dt_gpx_track_point_t * trkpt
typedef double((*spd)(unsigned long int wavelength, double TempK))