From 1ca082d7cd3908f3ef30317444f3e506bc01927b Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sat, 5 Apr 2014 19:32:26 +0100 Subject: [PATCH] Enable exporting to GeoJSON file via the program togeojson. GPSBabel doesn't seem to support GeoJSON so have to use a specific program. togeojson is from https://github.com/mapbox/togeojson --- help/C/viking.xml | 24 +++++++++- po/POTFILES.in | 1 + src/Makefile.am | 1 + src/file.c | 11 ++++- src/file.h | 1 + src/geojson.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++ src/geojson.h | 35 ++++++++++++++ src/viktrwlayer.c | 23 +++++++++ 8 files changed, 211 insertions(+), 2 deletions(-) create mode 100644 src/geojson.c create mode 100644 src/geojson.h diff --git a/help/C/viking.xml b/help/C/viking.xml index 6929b25c..ddf095ab 100644 --- a/help/C/viking.xml +++ b/help/C/viking.xml @@ -755,8 +755,30 @@ You are probably better off expanding the waypoint list and directly start typin
Export Layer -The layer (all tracks, routes and waypoints) can be exported to a file GPX, GPSPoint, GPSMapper, Google's KML format or any other format supported by GPSbabel. +The layer (all tracks, routes and waypoints) can be exported to following file formats: + + + GPX + + + GPSPoint + + + GPSMapper + + + Google's KML + + + Any GPSBabel File Formats + + + GeoJSON. Via the program togeojson + This option will not be available if the program is not detected on your system. + See here for the installation method. + + Version1.1+: An individual track can be exported to a GPX file via the track menu. diff --git a/po/POTFILES.in b/po/POTFILES.in index 270edb96..1ba1e13c 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -8,6 +8,7 @@ src/curl_download.c src/dialog.c src/expedia.c src/geonamessearch.c +src/geojson.c src/globals.c src/google.c src/googlesearch.c diff --git a/src/Makefile.am b/src/Makefile.am index ba889689..a22c32a8 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -60,6 +60,7 @@ libviking_a_SOURCES = \ coords.c coords.h \ gpsmapper.c gpsmapper.h \ gpspoint.c gpspoint.h \ + geojson.c geojson.h \ dir.c dir.h \ file.c file.h \ fileutils.c fileutils.h \ diff --git a/src/file.c b/src/file.c index 49f35588..835f2ece 100644 --- a/src/file.c +++ b/src/file.c @@ -28,6 +28,7 @@ #include "jpg.h" #include "gpx.h" +#include "geojson.h" #include "babel.h" #include @@ -626,6 +627,9 @@ gchar *append_file_ext ( const gchar *filename, VikFileType_t type ) case FILE_TYPE_KML: ext = ".kml"; break; + case FILE_TYPE_GEOJSON: + ext = ".geojson"; + break; case FILE_TYPE_GPSMAPPER: case FILE_TYPE_GPSPOINT: default: @@ -797,6 +801,8 @@ gboolean a_file_export ( VikTrwLayer *vtl, const gchar *filename, VikFileType_t FILE *f = g_fopen ( filename, "w" ); if ( f ) { + gboolean result = TRUE; + if ( trk ) { switch ( file_type ) { case FILE_TYPE_GPX: @@ -818,6 +824,9 @@ gboolean a_file_export ( VikTrwLayer *vtl, const gchar *filename, VikFileType_t case FILE_TYPE_GPSPOINT: a_gpspoint_write_file ( vtl, f ); break; + case FILE_TYPE_GEOJSON: + result = a_geojson_write_file ( vtl, f ); + break; case FILE_TYPE_KML: fclose ( f ); f = NULL; @@ -840,7 +849,7 @@ gboolean a_file_export ( VikTrwLayer *vtl, const gchar *filename, VikFileType_t } fclose ( f ); f = NULL; - return TRUE; + return result; } return FALSE; } diff --git a/src/file.h b/src/file.h index 9d25f652..70fe1238 100644 --- a/src/file.h +++ b/src/file.h @@ -36,6 +36,7 @@ FILE_TYPE_GPSPOINT=1, FILE_TYPE_GPSMAPPER=2, FILE_TYPE_GPX=3, FILE_TYPE_KML=4, +FILE_TYPE_GEOJSON=5, } VikFileType_t; gboolean a_file_check_ext ( const gchar *filename, const gchar *fileext ); diff --git a/src/geojson.c b/src/geojson.c new file mode 100644 index 00000000..7a04b930 --- /dev/null +++ b/src/geojson.c @@ -0,0 +1,117 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ +/* + * viking -- GPS Data and Topo Analyzer, Explorer, and Manager + * + * Copyright (c) 2014, Rob Norris + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + * See http://geojson.org/ for the specification + * + */ + +#include "geojson.h" +#include "gpx.h" +#include "globals.h" +#include "vikwindow.h" + +#include +#include +#include + +/** + * Perform any cleanup actions once program has completed running + */ +static void my_watch ( GPid pid, + gint status, + gpointer user_data ) +{ + g_spawn_close_pid ( pid ); +} + +/** + * a_geojson_write_file: + * + * Returns TRUE if successfully written + */ +gboolean a_geojson_write_file ( VikTrwLayer *vtl, FILE *ff ) +{ + gboolean result = FALSE; + + gchar *tmp_filename = a_gpx_write_tmp_file ( vtl, NULL ); + if ( !tmp_filename ) + return result; + + GPid pid; + gint stdout; + + // geojson program should be on the $PATH + gchar **argv; + argv = g_new (gchar*, 5); + argv[0] = g_strdup (a_geojson_program_export()); + argv[1] = g_strdup ("-f"); + argv[2] = g_strdup ("gpx"); + argv[3] = g_strdup (tmp_filename); + argv[4] = NULL; + + GError *error = NULL; + // TODO: monitor stderr? + if (!g_spawn_async_with_pipes (NULL, argv, NULL, (GSpawnFlags) G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD, NULL, NULL, &pid, NULL, &stdout, NULL, &error)) { + + if ( IS_VIK_WINDOW ((VikWindow *)VIK_GTK_WINDOW_FROM_LAYER(vtl)) ) { + gchar* msg = g_strdup_printf ( _("%s command failed: %s"), argv[0], error->message ); + vik_window_statusbar_update ( (VikWindow*)VIK_GTK_WINDOW_FROM_LAYER(vtl), msg, VIK_STATUSBAR_INFO ); + g_free (msg); + } + else + g_warning ("Async command failed: %s", error->message); + + g_error_free(error); + } + else { + // Probably should use GIOChannels... + gchar line[512]; + FILE *fout = fdopen(stdout, "r"); + setvbuf(fout, NULL, _IONBF, 0); + + while (fgets(line, sizeof(line), fout)) { + fprintf ( ff, line ); + } + + fclose(fout); + + g_child_watch_add ( pid, (GChildWatchFunc) my_watch, NULL ); + result = TRUE; + } + + g_strfreev (argv); + + // Delete the temporary file + g_remove (tmp_filename); + g_free (tmp_filename); + + return result; +} + +// +// https://github.com/mapbox/togeojson +// +// https://www.npmjs.org/package/togeojson +// +// Tested with version 0.7.0 +const gchar* a_geojson_program_export ( void ) +{ + return "togeojson"; +} diff --git a/src/geojson.h b/src/geojson.h new file mode 100644 index 00000000..fdee6c83 --- /dev/null +++ b/src/geojson.h @@ -0,0 +1,35 @@ +/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */ +/* + * viking -- GPS Data and Topo Analyzer, Explorer, and Manager + * + * Copyright (c) 2014, Rob Norris + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef _VIKING_GEOJSON_H +#define _VIKING_GEOJSON_H + +#include "viktrwlayer.h" + +G_BEGIN_DECLS + +gboolean a_geojson_write_file ( VikTrwLayer *vtl, FILE *ff ); + +const gchar* a_geojson_program_export ( void ); + +G_END_DECLS + +#endif diff --git a/src/viktrwlayer.c b/src/viktrwlayer.c index b779ac46..e647d887 100644 --- a/src/viktrwlayer.c +++ b/src/viktrwlayer.c @@ -47,6 +47,7 @@ #include "thumbnails.h" #include "background.h" #include "gpx.h" +#include "geojson.h" #include "babel.h" #include "dem.h" #include "dems.h" @@ -775,6 +776,8 @@ VikLayerInterface vik_trw_layer_interface = { }; static gboolean have_diary_program = FALSE; +static gboolean have_geojson_export = FALSE; + // NB Only performed once per program run static void vik_trwlayer_class_init ( VikTrwLayerClass *klass ) @@ -811,6 +814,10 @@ static void vik_trwlayer_class_init ( VikTrwLayerClass *klass ) g_free ( stdout ); g_free ( stderr ); } + + if ( g_find_program_in_path ( a_geojson_program_export() ) ) { + have_geojson_export = TRUE; + } } GType vik_trw_layer_get_type () @@ -3379,6 +3386,15 @@ static void trw_layer_export_kml ( menu_array_layer values ) g_free ( auto_save_name ); } +static void trw_layer_export_geojson ( menu_array_layer values ) +{ + gchar *auto_save_name = append_file_ext ( vik_layer_get_name(VIK_LAYER(values[MA_VTL])), FILE_TYPE_GEOJSON ); + + vik_trw_layer_export ( VIK_TRW_LAYER (values[MA_VTL]), _("Export Layer"), auto_save_name, NULL, FILE_TYPE_GEOJSON ); + + g_free ( auto_save_name ); +} + static void trw_layer_export_babel ( gpointer layer_and_vlp[2] ) { const gchar *auto_save_name = vik_layer_get_name(VIK_LAYER(layer_and_vlp[0])); @@ -4031,6 +4047,13 @@ static void trw_layer_add_menu_items ( VikTrwLayer *vtl, GtkMenu *menu, gpointer gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item); gtk_widget_show ( item ); + if ( have_geojson_export ) { + item = gtk_menu_item_new_with_mnemonic ( _("Export as GEO_JSON...") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_geojson), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item); + gtk_widget_show ( item ); + } + item = gtk_menu_item_new_with_mnemonic ( _("Export via GPSbabel...") ); g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_export_babel), pass_along ); gtk_menu_shell_append (GTK_MENU_SHELL (export_submenu), item); -- 2.39.5