File gpsbabel-20090809_r105.diff of Package gpsbabel
Index: smooth.c
===================================================================
--- smooth.c (revision 0)
+++ smooth.c (revision 106)
@@ -0,0 +1,299 @@
+/*
+
+ smooth: track smooth filter
+
+ Copyright (C) 2009 Stefan Dirsch, sndirsch@suse.de
+
+ 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 USA
+
+*/
+
+#include "defs.h"
+#include "filterdefs.h"
+#include "grtcirc.h"
+#include <ctype.h>
+
+#define MYNAME "smooth"
+
+#if FILTERS_ENABLED
+static char *opt_epsilon = NULL;
+static char *opt_debug = NULL;
+static int debug=0;
+static double epsilon=5;
+
+// Any arg in this list will appear in command line help and will be
+// populated for you.
+static
+arglist_t smooth_args[] = {
+ {"epsilon", &opt_epsilon, "Douglas-Peucker's epsilon (default: 5m)",
+ NULL, ARGTYPE_FLOAT, ARG_NOMINMAX},
+ {"debug", &opt_debug, "Enable Debug output (debug=1,...)",
+ NULL, ARGTYPE_INT, ARG_NOMINMAX},
+ ARG_TERMINATOR
+};
+
+struct mywaypoint {
+ waypoint *wpt;
+ int useit;
+};
+
+#define DBG dbgprintf
+
+static void
+dbgprintf(const int dlevel, const char *fmt, ...)
+{
+ va_list args;
+
+ if (debug >= dlevel) {
+ va_start(args, fmt);
+
+ printf("DEBUG%i: ", dlevel);
+ vprintf(fmt, args);
+ va_end(args);
+ }
+}
+
+/*******************************************************************************
+ * %%% global callbacks called by gpsbabel main process %%% *
+ *******************************************************************************/
+
+static void
+smooth_init(const char *args)
+{
+ /* Called before filter processing */
+
+ /* optional. If not needed, delete and replace entry in vecs with NULL */
+
+ /* This may be used to parse filter options, allocate memory, and do other
+ * housekeeping that should be done before filtering */
+
+ if (opt_debug)
+ debug=atoi(opt_debug);
+ DBG(1,"Debuglevel: %i\n", debug);
+
+ if (opt_epsilon)
+ epsilon=atof(opt_epsilon);
+}
+
+double distToLine(waypoint *linebegin, waypoint *lineend, waypoint *point)
+{
+ double a,b,c;
+
+ /* Hypotenuse / baseline */
+ c=radtometers(gcdist(RAD(linebegin->latitude),
+ RAD(linebegin->longitude),
+ RAD(lineend->latitude),
+ RAD(lineend->longitude)));
+ /* Kathetus a at begin of line / distance to begin of baseline */
+ a=radtometers(gcdist(RAD(linebegin->latitude),
+ RAD(linebegin->longitude),
+ RAD(point->latitude),
+ RAD(point->longitude)));
+ /* Kathetus b at end of line / distance to end of baseline */
+ b=radtometers(gcdist(RAD(lineend->latitude),
+ RAD(lineend->longitude),
+ RAD(point->latitude),
+ RAD(point->longitude)));
+
+ if (a >= c) {
+ /* shortest distance to baseline is distance to end of line */
+ return b;
+ } else {
+ if (b >= c) {
+ /* shortest distance to baseline is distance to begin of line */
+ return a;
+ } else {
+ /* calculate height in triangle (= orthogonal distance) */
+ return (b * sin( acos((b*b + c*c - a*a)/(2*b*c))));
+ }
+ }
+}
+
+void DouglasPeucker(struct mywaypoint* wptlist, int first, int last, float epsilon)
+{
+ int i,index=first;
+ double maxdist, dist;
+
+ DBG(2, "DouglasPeuker: first: %i, last: %i, epsilon: %f\n",
+ first+1, last+1, epsilon);
+
+ /* search for trackpoint with max distance to baseline */
+ maxdist=0;
+ for(i=first+1; i <= last-1; i++) {
+ dist=distToLine(wptlist[first].wpt,
+ wptlist[last].wpt,
+ wptlist[i].wpt);
+ DBG(4, "track point #%i: dist: %fm \n",i+1, dist);
+ if (dist > maxdist) {
+ maxdist = dist;
+ index=i;
+ }
+ }
+ DBG(3, "max dist: %fm (trackpoint #%i)\n", maxdist, index+1);
+
+ if ((maxdist > epsilon) && (index > first) && (index < last)) {
+ DBG(2, "Using trackpoint #%i \n",index+1);
+ /* mark it to be used */
+ wptlist[index].useit=1;
+ /* recursion on both remaining sections */
+ if ((index - first) > 1)
+ DouglasPeucker(wptlist, first, index, epsilon);
+ if ((last - index) > 1)
+ DouglasPeucker(wptlist, index, last, epsilon);
+ }
+}
+
+static void
+smooth_head(const route_head *track)
+{
+ queue *elem, *tmp;
+ long n,i, removed, dups;
+
+ struct mywaypoint *wptlist=NULL;
+
+ DBG(1,"BEGIN TRACK (%s)\n",track->rte_name);
+
+ /* Count number of trackpoints */
+ n=0;
+ QUEUE_FOR_EACH((queue *)&track->waypoint_list, elem, tmp) {
+ n++;
+ }
+ DBG(1, "Number of trackpoints: %i\n", n);
+
+ /* first remove duplicates */
+ dups=0;
+ QUEUE_FOR_EACH((queue *)&track->waypoint_list, elem, tmp) {
+ if (((((waypoint *)elem)->latitude) ==
+ ((waypoint *)elem->next)->latitude) &&
+ (((waypoint *)elem)->longitude ==
+ ((waypoint *)elem->next)->longitude)) {
+ dequeue(elem);
+ dups++;
+ }
+ }
+ DBG(2, "Number of trackpoints after removing duplicates: %i\n", n-dups);
+
+ /* nothing more to be done for this track */
+ if ((n-dups) <= 2) {
+ DBG(1, "%i (%f %) trackpoints removed\n", dups, (n != 0) ? 100* (float) dups/n : 0);
+ return;
+ }
+
+ n = n-dups;
+
+ /* it's easier and faster to work on an array, so let's reserve the required memory for it */
+ wptlist=(struct mywaypoint*) calloc(n, sizeof(struct mywaypoint));
+ if (wptlist == NULL) {
+ printf("calloc failed! Giving up.\n");
+ return;
+ }
+
+ /*
+ * initialize the array:
+ * pointers to trackpoints in the list
+ * besides the begin/end points mark the points not to be used
+ */
+ i=0;
+ QUEUE_FOR_EACH((queue *)&track->waypoint_list, elem, tmp) {
+ wptlist[i].wpt = (waypoint *) elem;
+ if (i == 0 || i == n-1) {
+ wptlist[i].useit=1;
+ } else {
+ wptlist[i].useit=0;
+ }
+ i++;
+ }
+
+ DBG(1, "Running Douglas-Peucker (epsilon: %f)\n", epsilon);
+
+ /* the algorithm working on an array :-) */
+ DouglasPeucker(wptlist, 0, n-1, epsilon);
+
+ /* remove the points, which have not been marked to be use by Douglas-Peucker */
+ i=0; removed=0;
+ QUEUE_FOR_EACH((queue *)&track->waypoint_list, elem, tmp) {
+ if (wptlist[i].useit == 0) {
+ DBG(4, "Removing trackpoint #%i\n", i+1);
+ dequeue(elem);
+ removed++;
+ }
+ i++;
+ }
+
+ DBG(1, "%i (%f %) trackpoints removed\n", removed+dups, 100* (float)(removed+dups)/(n+dups));
+
+ /* prevent memory leaks by this filter */
+ if (wptlist)
+ free(wptlist);
+}
+
+static void
+smooth_tail(const route_head *track)
+{
+ DBG(1,"END TRACK (%s)\n",track->rte_name);
+}
+
+static void
+smooth_trkpt(const waypoint *trkpt)
+{
+}
+
+static void
+smooth_process(void) /* this procedure must be present in vecs */
+{
+// Here is how you register callbacks for all waypoints, routes, tracks.
+// waypt_disp_all(waypt)
+// route_disp_all(head, tail, rtept);
+ track_disp_all(smooth_head, smooth_tail, smooth_trkpt);
+}
+
+static void
+smooth_deinit(void)
+{
+ /* called after filter processing */
+
+ /* optional. If not needed, delete and replace entry in vecs with NULL */
+
+ /* This should be used to clean up any memory allocations that are no longer
+ * needed after the filter terminates. */
+}
+
+static void
+smooth_exit(void)
+{
+ /* called on program exit */
+
+ /* optional. If not needed, delete and replace entry in vecs with NULL */
+
+ /* You should not need this for simple filters, but it may be used to
+ * clean up memory allocations that must persist from one invocation of
+ * your filter to the next (for example, the stack in the stack filter.)
+ * Note that this member will be called even if your filter has not been
+ * used, so it *cannot* assume that _init or _process has been called
+ * previously. */
+}
+
+/*******************************************************************************/
+
+filter_vecs_t smooth_vecs = {
+ smooth_init,
+ smooth_process,
+ smooth_deinit,
+ smooth_exit,
+ smooth_args
+};
+
+/*******************************************************************************/
+#endif // FILTERS_ENABLED
Index: srtm.c
===================================================================
--- srtm.c (revision 0)
+++ srtm.c (revision 106)
@@ -0,0 +1,459 @@
+/*
+
+ srtm: use SRTM data for altitude (replaces existing values)
+
+ Copyright (C) 2009 Stefan Dirsch, sndirsch@suse.de
+
+ 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 USA
+
+ */
+
+#include "defs.h"
+#include "filterdefs.h"
+#include <ctype.h>
+#include <byteswap.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#define MYNAME "srtm"
+
+#if FILTERS_ENABLED
+static char *opt_nearest=NULL;
+static char *opt_bilinear= NULL;
+static char *opt_maxdelta=NULL;
+static char *opt_roundtoint=NULL;
+static char *opt_delcache=NULL;
+static char *opt_debug = NULL;
+static int nearest=0;
+static int bilinear=1;
+static int maxdelta=0;
+static int round_to_int=0;
+static int debug=0;
+
+// Any arg in this list will appear in command line help and will be
+// populated for you.
+static
+arglist_t srtm_args[] = {
+ {"nearest", &opt_nearest, "Nearest neighbour",
+ NULL, ARGTYPE_BOOL | ARGTYPE_BEGIN_EXCL, ARG_NOMINMAX},
+ {"binlinear", &opt_bilinear, "Bilenear interpolation (default)",
+ NULL, ARGTYPE_BOOL | ARGTYPE_END_EXCL, ARG_NOMINMAX},
+ {"maxdelta", &opt_maxdelta, "Max. Delta in m (default: 0)",
+ NULL, ARGTYPE_INT, ARG_NOMINMAX},
+ {"round_to_int", &opt_roundtoint, "Round to integer",
+ NULL, ARGTYPE_BOOL, ARG_NOMINMAX},
+ {"delcache", &opt_delcache, "Remove SRTM data cache before",
+ NULL, ARGTYPE_BOOL, ARG_NOMINMAX},
+ {"debug", &opt_debug, "Enable Debug output (debug=1,...)",
+ NULL, ARGTYPE_INT, ARG_NOMINMAX},
+ ARG_TERMINATOR
+};
+
+#define DBG dbgprintf
+
+static void
+dbgprintf(const int dlevel, const char *fmt, ...)
+{
+ va_list args;
+
+ if (debug >= dlevel) {
+ va_start(args, fmt);
+
+ printf("DEBUG%i: ", dlevel);
+ vprintf(fmt, args);
+ va_end(args);
+ }
+}
+
+/*******************************************************************************
+* %%% global callbacks called by gpsbabel main process %%% *
+*******************************************************************************/
+
+static void
+srtm_init(const char *args)
+{
+ /* Called before filter processing */
+
+ /* optional. If not needed, delete and replace entry in vecs with NULL */
+
+ /* This may be used to parse filter options, allocate memory, and do other
+ * housekeeping that should be done before filtering */
+ DIR * dir;
+ char dirname[256], path[270];
+ struct dirent *direntry;
+
+ if (opt_debug)
+ debug=atoi(opt_debug);
+ DBG(1,"Debuglevel: %i\n", debug);
+
+ if (opt_maxdelta)
+ maxdelta=atoi(opt_maxdelta);
+
+ if (opt_nearest) {
+ DBG(1, "Nearest neighbour\n");
+ nearest=1;
+ bilinear=0;
+ } else {
+ DBG(1, "Using bilenear interpolation\n");
+ nearest=0;
+ bilinear=1;
+ }
+
+ if (opt_roundtoint) {
+ round_to_int=1;
+ } else {
+ round_to_int=0;
+ }
+
+ /* create cache dir for SRTM data files */
+ snprintf(dirname,sizeof(dirname), "%s/.gpsbabel",getenv("HOME"));
+ if ((dir=opendir(dirname)) == NULL) {
+ mkdir(dirname,0755);
+ }
+ closedir(dir);
+ snprintf(dirname,sizeof(dirname), "%s/.gpsbabel/srtm",getenv("HOME"));
+ if ((dir=opendir(dirname)) == NULL) {
+ DBG(2, "Creating cache dir '%s'\n", dirname);
+ mkdir(dirname,0755);
+ } else {
+ if (opt_delcache) {
+ DBG(2, "Removing SRTM-data cached files\n");
+ while((direntry=readdir(dir)) != NULL) {
+ if (strcmp(direntry->d_name,".") &&
+ strcmp(direntry->d_name,"..")) {
+ snprintf(path,sizeof(path),"%s/%s",dirname,direntry->d_name);
+ DBG(2, "%s\n", path);
+ unlink(path);
+ }
+ }
+ } else {
+ DBG(2, "Cache dir '%s' already exists.\n", dirname);
+ }
+ }
+ closedir(dir);
+}
+
+int download_and_extract_file(const char *filename, const char *path, int srtm1, const char * srtmsubdir)
+{
+ int i;
+ char url[128]="";
+ char command[512]="";
+ char zipfilename[260]="";
+ static char *continents[] = { "SRTM3/Africa",
+ "SRTM3/Australia" ,
+ "SRTM3/Eurasia" ,
+ "SRTM3/Islands",
+ "SRTM3/North_America",
+ "SRTM3/South_America",
+ NULL};
+ FILE *file;
+
+ snprintf(zipfilename,sizeof(zipfilename),"%s.zip",path);
+
+ if (srtm1) {
+ snprintf(url, sizeof(url), "http://dds.cr.usgs.gov/srtm/version2_1/" "%s" "%s" "%s",
+ srtmsubdir, filename, ".zip");
+
+ snprintf(command,sizeof(command), "curl -s %s -o %s; gunzip -d -S .zip %s%s",
+ url, zipfilename, zipfilename, "> /dev/null 2>&1");
+ DBG(2, "Running command: %s ...\n", command);
+ system(command);
+
+ if ((file=fopen(path,"r")) != NULL) {
+ fclose(file);
+ return 0;
+ }
+ } else {
+ for(i=0; continents[i]; i++) {
+ snprintf(url, sizeof(url), "http://dds.cr.usgs.gov/srtm/version2_1/" "%s/" "%s" "%s",
+ continents[i], filename, ".zip");
+
+ snprintf(command,sizeof(command), "curl -s %s -o %s; gunzip -d -S .zip %s%s",
+ url, zipfilename, zipfilename,"> /dev/null 2>&1");
+ DBG(2, "Running command: %s ...\n", command);
+ system(command);
+
+ if ((file=fopen(path,"r")) != NULL) {
+ fclose(file);
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static void
+srtm_head(const route_head *track)
+{
+ queue *elem, *tmp;
+ float lat, lon, alt, dlat, dlon, x, y, height;
+ int ilat, ilon, poslat_nearest, poslon_nearest, poswest, posnord;
+ long seekpos_nearest, seekpos_nordwest;
+ char filename[13]="", old_filename[13]="", path[256]="";
+ FILE *file=NULL;
+ short buf, height_nearest, height_nw, height_ne, height_sw, height_se;
+ int srtm1=0, open_failed=1, samplecount=1200, replace=0;
+ char srtmsubdir[17]="";
+
+ DBG(1,"BEGIN TRACK (%s)\n",track->rte_name);
+
+ QUEUE_FOR_EACH((queue *)&track->waypoint_list, elem, tmp) {
+ lat = ((waypoint *)elem)->latitude;
+ lon = ((waypoint *)elem)->longitude;
+ alt = ((waypoint *)elem)->altitude;
+
+ /* be on the safe side */
+ height = alt;
+
+ ilat=(int) floor(lat);
+ ilon=(int) floor(lon);
+
+ if (((ilon >= 172 && ilon <= 179) || (ilon >= -180 && ilon <= -130)) &&
+ (ilat <= 59 && ilat >= -5)) {
+ /* SRTM-1 Region 7 */
+ srtm1=1;
+ strcpy(srtmsubdir,"SRTM1/Region_07/");
+ } else if ((ilon >= -126 && ilon <= -112) && (ilat >= 38 && ilat <= 49)) {
+ /* SRTM-1 Region 1 */
+ srtm1=1;
+ strcpy(srtmsubdir,"SRTM1/Region_01/");
+ } else if ((ilon >= -111 && ilon <= -98) && (ilat >= 38 && ilat <= 49)) {
+ /* SRTM-1 Region 2 */
+ srtm1=1;
+ strcpy(srtmsubdir,"SRTM1/Region_02/");
+ } else if ((ilon >= -97 && ilon <= -84) && (ilat >= 38 && ilat <= 49)) {
+ /* SRTM-1 Region 3 */
+ srtm1=1;
+ strcpy(srtmsubdir,"SRTM1/Region_03/");
+ } else if ((ilon >= -123 && ilon <= -101) && (ilat >= 28 && ilat <= 37)) {
+ /* SRTM-1 Region 4 */
+ srtm1=1;
+ strcpy(srtmsubdir,"SRTM1/Region_04/");
+ } else if ((ilon >= 100 && ilon <= -84) && (ilat >= 25 && ilat <= 37)) {
+ /* SRTM-1 Region 5 */
+ srtm1=1;
+ strcpy(srtmsubdir,"SRTM1/Region_05/");
+ } else if ((ilon >= -83 && ilon <= -65) && (ilat >= 17 && ilat <= 47)) {
+ /* SRTM-1 Region 6 */
+ srtm1=1;
+ strcpy(srtmsubdir,"SRTM1/Region_06/");
+ } else {
+ /* rest of the world only SRTM-3 data */
+ srtm1=0;
+ /* later try subdirs SRTM3/{Africa,Australia,Eurasia,Islands,North_America,South_America} */
+ }
+
+ dlat=ilat+1-lat;
+ if (lon >= 0)
+ dlon=lon-ilon;
+ else
+ dlon=fabs(ilon-lon);
+
+ if (srtm1)
+ samplecount=3600;
+ else
+ samplecount=1200;
+
+ snprintf(filename,sizeof(filename), "%s" "%s%i" "%s" "%s%s%i" "%s",
+ lat >= 0 ? "N" : "S",
+ abs(ilat) <= 9 ? "0" : "", abs(ilat),
+ lon >=0 ? "E" : "W",
+ abs(ilon) <= 99 ? "0" : "", abs(ilon) <=9 ? "0" : "", abs(ilon),
+ ".hgt");
+ DBG(2, "\n");
+ DBG(2, "filename: %s\n", filename);
+
+ if (strcmp(filename,old_filename) != 0) {
+ if (file) {
+ DBG(2, "Closing file: %s\n", path);
+ fclose(file);
+ }
+ snprintf(path, sizeof(path), "%s/.gpsbabel/srtm/%s", getenv("HOME"),filename);
+ DBG(2, "Opening file: %s\n", path);
+ open_failed=1;
+ if ((file=fopen(path,"r")) == NULL) {
+ if (download_and_extract_file(filename, path, srtm1, srtmsubdir) == 0) {
+ /* download and extraction of the file succeeded */
+ if ((file=fopen(path,"r")) != NULL) {
+ open_failed=0;
+ }
+ }
+ } else {
+ /* file already in cache dir */
+ open_failed=0;
+ }
+ strcpy(old_filename,filename);
+ }
+
+ if (!open_failed) {
+ replace=0;
+ if (bilinear) {
+ posnord=samplecount*dlat;
+ poswest=samplecount*dlon;
+ seekpos_nordwest=(samplecount+1)*posnord*2 + poswest*2;
+
+ /* doesn't work well on exact SRTM data sample points; x/y should be 0, but it isn't :-( */
+ y=(dlat-(float)posnord/samplecount) * samplecount;
+ x=(dlon-(float)poswest/samplecount) * samplecount;
+
+ DBG(3, "lat: %f, lon: %f, dlat: %f, dlon: %f\n", lat, lon, dlat, dlon);
+ DBG(3, "poswest: %i, posnord: %i, seekpos_nordwest: %i\n", poswest, posnord, seekpos_nordwest);
+ DBG(3, "x: %f, y: %f\n", x,y);
+
+ /* north-west */
+ fseek(file, seekpos_nordwest, SEEK_SET);
+ fread(&buf, 2, 1, file);
+ height_nw=bswap_16(buf);
+ if (height_nw == -32768) {
+ DBG(2, "SRTM data void --> try again with nearest\n");
+ nearest=1;
+ } else {
+ /* north-east */
+ fread(&buf, 2, 1, file);
+ height_ne=bswap_16(buf);
+ if (height_ne == -32768) {
+ DBG(2, "SRTM data void --> try again with nearest\n");
+ nearest=1;
+ } else {
+ /* south-west */
+ fseek(file, samplecount*2-2, SEEK_CUR);
+ fread(&buf, 2, 1, file);
+ height_sw=bswap_16(buf);
+ if (height_sw == -32768) {
+ DBG(2, "SRTM data void --> try again with nearest\n");
+ nearest=1;
+ } else {
+ /* south-east */
+ fread(&buf, 2, 1, file);
+ height_se=bswap_16(buf);
+ if (height_se == -32768) {
+ DBG(2, "SRTM data void --> try again with nearest\n");
+ nearest=1;
+ } else {
+ /* bilinear interpolation - finally */
+ DBG(2, "height_nw: %i, height_ne: %i, height_sw: %i, height_se: %i\n",
+ height_nw, height_ne, height_sw, height_se);
+ height=(height_ne * x + height_nw * (1-x)) * (1-y) +
+ (height_se * x + height_sw * (1-x)) * y;
+ DBG(2, "height (bilinear): %f\n",height);
+ nearest=0;
+ replace=1;
+ }
+ }
+ }
+ }
+ }
+ if (nearest) {
+ poslon_nearest=samplecount*dlon+0.5;
+ poslat_nearest=samplecount*dlat+0.5;
+ seekpos_nearest=(samplecount+1)*2*poslat_nearest + poslon_nearest*2;
+
+ DBG(3, "lat: %f, lon: %f, dlat: %f, dlon: %f\n", lat, lon, dlat, dlon);
+ DBG(3, "poslat_nearest: %i, poslon_nearest: %i, seekpos_nearest: %i\n",
+ poslat_nearest, poslon_nearest, seekpos_nearest);
+
+ fseek(file, seekpos_nearest, SEEK_SET);
+ fread(&buf, 2, 1, file);
+ height_nearest=bswap_16(buf);
+ /* SRTM data voids are defined as a height of -32768 */
+ if (height_nearest != -32768) {
+ DBG(2, "SRTM data (nearest): 0x%x --> 0x%x (%i)\n",buf, height_nearest, height_nearest);
+ height = (float) height_nearest;
+ replace=1;
+ }
+ }
+
+ if (round_to_int) {
+ height = (float)((int)(height+0.5));
+ }
+
+ if (fabs(height-alt) > maxdelta && replace) {
+ DBG(2, "Altitude difference > maxdelta (%i)\n", maxdelta);
+ DBG(2, "Replacing existing altitude (%f) with SRTM data (%f)\n", alt, height);
+ ((waypoint *)elem)->altitude = (float) height;
+ } else {
+ DBG(2, "Altitude difference <= maxdelta (%i) or SRTM data void\n", maxdelta);
+ DBG(2, "Keeping existing altitude (%f)\n", alt);
+ }
+ } else {
+ printf("Warning: File \"%s\" not available. Continuing with next trackpoint.\n", filename);
+ }
+ }
+ if (file) {
+ DBG(2, "Closing file: %s\n", filename);
+ fclose(file);
+ }
+}
+
+static void
+srtm_tail(const route_head *track)
+{
+ DBG(1,"END TRACK (%s)\n",track->rte_name);
+}
+
+static void
+srtm_trkpt(const waypoint *trkpt)
+{
+}
+
+static void
+srtm_process(void) /* this procedure must be present in vecs */
+{
+// Here is how you register callbacks for all waypoints, routes, tracks.
+// waypt_disp_all(waypt)
+// route_disp_all(head, tail, rtept);
+ track_disp_all(srtm_head, srtm_tail, srtm_trkpt);
+}
+
+static void
+srtm_deinit(void)
+{
+ /* called after filter processing */
+
+ /* optional. If not needed, delete and replace entry in vecs with NULL */
+
+ /* This should be used to clean up any memory allocations that are no longer
+ * needed after the filter terminates. */
+}
+
+static void
+srtm_exit(void)
+{
+ /* called on program exit */
+
+ /* optional. If not needed, delete and replace entry in vecs with NULL */
+
+ /* You should not need this for simple filters, but it may be used to
+ * clean up memory allocations that must persist from one invocation of
+ * your filter to the next (for example, the stack in the stack filter.)
+ * Note that this member will be called even if your filter has not been
+ * used, so it *cannot* assume that _init or _process has been called
+ * previously. */
+}
+
+/*******************************************************************************/
+
+filter_vecs_t srtm_vecs = {
+ srtm_init,
+ srtm_process,
+ srtm_deinit,
+ srtm_exit,
+ srtm_args
+};
+
+/*******************************************************************************/
+#endif // FILTERS_ENABLED
Index: badpoints.c
===================================================================
--- badpoints.c (revision 0)
+++ badpoints.c (revision 106)
@@ -0,0 +1,624 @@
+/*
+
+ badpoints: remove bad points
+
+ Copyright (C) 2009 Stefan Dirsch, sndirsch@suse.de
+
+ 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 USA
+
+ */
+
+#include "defs.h"
+#include "filterdefs.h"
+#include "grtcirc.h"
+#include <ctype.h>
+
+#define MYNAME "badpoints"
+
+#if FILTERS_ENABLED
+static char *opt_speed = NULL;
+static char *opt_accel = NULL;
+static char *opt_3d = NULL;
+static char *opt_speedlimit = NULL;
+static char *opt_accelposlimit = NULL;
+static char *opt_accelneglimit = NULL;
+static char *opt_delfirstpoint = NULL;
+static char *opt_experimental = NULL;
+static char *opt_debug = NULL;
+static float speedlimit=20;
+/*
+ * default accel limits should be safe for pedestrians, cyclists and car
+ * drivers (http://de.wikipedia.org/wiki/Beschleunigung)
+ */
+static double accelposlimit=4;
+static double accelneglimit=-10.5;
+static int experimental=0;
+static int debug=0;
+
+// Any arg in this list will appear in command line help and will be
+// populated for you.
+static
+arglist_t badpoints_args[] = {
+ {"speed", &opt_speed, "Speed filter",
+ NULL, ARGTYPE_BOOL | ARGTYPE_BEGIN_EXCL, ARG_NOMINMAX},
+ {"accel", &opt_accel, "Acceleration filter (default)",
+ NULL, ARGTYPE_BOOL | ARGTYPE_END_EXCL, ARG_NOMINMAX},
+ {"3d", &opt_3d, "Calculations done in 3D (default: only 2D)",
+ NULL, ARGTYPE_BOOL, ARG_NOMINMAX},
+ {"speedlimit", &opt_speedlimit, "Speed limit in km/h (default: 20)",
+ NULL, ARGTYPE_FLOAT, ARG_NOMINMAX},
+ {"accelposlimit", &opt_accelposlimit, "Pos. acceleration limit in m/(s*s) (default: 4)",
+ NULL, ARGTYPE_FLOAT, ARG_NOMINMAX},
+ {"accelneglimit", &opt_accelneglimit, "Neg. acceleration limit in m/(s*s) (default: -10.5)",
+ NULL, ARGTYPE_FLOAT, ARG_NOMINMAX},
+ {"delfirstpoint", &opt_delfirstpoint, "Always remove first track point (accel filter)",
+ NULL, ARGTYPE_BOOL, ARG_NOMINMAX},
+ {"experimental", &opt_experimental, "Enable experimental filtering",
+ NULL, ARGTYPE_INT, ARG_NOMINMAX},
+ {"debug", &opt_debug, "Enable Debug output (debug=1,...)",
+ NULL, ARGTYPE_INT, ARG_NOMINMAX},
+ ARG_TERMINATOR
+};
+
+#define DBG dbgprintf
+
+static void
+dbgprintf(const int dlevel, const char *fmt, ...)
+{
+ va_list args;
+
+ if (debug >= dlevel) {
+ va_start(args, fmt);
+
+ printf("DEBUG%i: ", dlevel);
+ vprintf(fmt, args);
+ va_end(args);
+ }
+}
+
+#define EARTH_RAD 6378137.0
+
+double dist3d( double lat1, double lon1, double alt1,
+ double lat2, double lon2, double alt2)
+{
+ double gcdistance, distance3d, dx, dy, dz;
+
+ /* distance using great circle */
+ gcdistance=radtometers(gcdist(lat1, lon1, lat2, lon2));
+
+ if (opt_3d) {
+ /* convert spheric coordinates to kartesic coordinates
+ * due to easier distance calculation; for formula see
+ * http://de.wikipedia.org/wiki/Kugelkoordinaten#Andere_Konventionen
+ */
+ dx = EARTH_RAD * (cos(lat2) * cos(lon2) - cos(lat1) * cos(lon1)) ;
+ dy = EARTH_RAD * (cos(lat2) * sin(lon2) - cos(lat1) * sin(lon1)) ;
+ dz = (EARTH_RAD + alt1) * sin(lat1) - (EARTH_RAD + alt2) * sin(lat2);
+ distance3d = sqrt(dx*dx + dy*dy + dz*dz);
+
+ DBG(4,"gcdistance: %fm, distance3d: %fm\n", gcdistance,distance3d);
+
+ /* use 3d calculated distance if bigger than great circle distance */
+ if (distance3d > gcdistance)
+ return distance3d;
+ else
+ return gcdistance;
+ } else
+ return gcdistance;
+}
+
+/*
+ * make use of microseconds (by Dan Pidcock <dan.pidcock@googlemail.com>)
+ */
+double disttime(waypoint* wp1, waypoint *wp2)
+{
+ return labs((wp1->creation_time*1000000+wp1->microseconds) -
+ (wp2->creation_time*1000000+wp2->microseconds))/1000000.0;
+}
+
+/*
+ * use dedicated function for calculating speed (by Dan Pidcock <dan.pidcock@googlemail.com>))
+ */
+double distspeed(waypoint *wp1, waypoint *wp2)
+{
+ double dist=dist3d(RAD(wp1->latitude),
+ RAD(wp1->longitude),
+ RAD(wp1->altitude),
+ RAD(wp2->latitude),
+ RAD(wp2->longitude),
+ RAD(wp2->altitude));
+ double dt = disttime(wp1, wp2);
+
+ return dist/dt;
+}
+
+double gradient(waypoint *wp1, waypoint *wp2)
+{
+ double lon1, lon2, lat1, lat2, dx, dy;
+
+ lon1 = wp1->longitude;
+ lat1 = wp1->latitude;
+ lon2 = wp2->longitude;
+ lat2 = wp2->latitude;
+
+ dx = EARTH_RAD * (cos(lat2) * cos(lon2) - cos(lat1) * cos(lon1));
+ dy = EARTH_RAD * (cos(lat2) * sin(lon2) - cos(lat1) * sin(lon1));
+
+ return (dy/dx);
+}
+
+/*******************************************************************************
+* %%% global callbacks called by gpsbabel main process %%% *
+*******************************************************************************/
+
+static void
+badpoints_init(const char *args)
+{
+ /* Called before filter processing */
+
+ /* optional. If not needed, delete and replace entry in vecs with NULL */
+
+ /* This may be used to parse filter options, allocate memory, and do other
+ * housekeeping that should be done before filtering */
+
+ if (opt_debug)
+ debug=atoi(opt_debug);
+ DBG(1,"Debuglevel: %i\n", debug);
+
+ if (opt_speedlimit)
+ speedlimit=atof(opt_speedlimit);
+
+ if (opt_accelposlimit)
+ accelposlimit=atof(opt_accelposlimit);
+
+ if (opt_accelneglimit)
+ accelneglimit=atof(opt_accelneglimit);
+
+ if (opt_experimental)
+ experimental=1;
+}
+
+static void
+badpoints_head_speed(const route_head *track)
+{
+ queue *elem, *tmp;
+ int i,first,second;
+ double speed_current, speed_next, speed_prev_next;
+
+ DBG(3,"Speed limit: %f km/h\n", speedlimit);
+
+ /* use this one as a counter for current trackpoint number */
+ i=0;
+ /* we begin with the first trackpoint ... */
+ first=1;
+ /* ... not on the second */
+ second=0;
+
+ /* standard method to walk a through the double linked waypoint list
+ of a track */
+ QUEUE_FOR_EACH((queue *)&track->waypoint_list, elem, tmp) {
+ i++;
+ if (!first) {
+ /* always look behind */
+ speed_current=distspeed((waypoint *)elem, (waypoint *)elem->prev);
+ DBG(2,"\n");
+ DBG(2,"Observing trackpoint (#%i) of track %s ...\n",
+ i, track->rte_name);
+ DBG(3,"speed_current: %f km/h\n", speed_current*3.6);
+ /* second trackpoint is special */
+ if (second) {
+ /* remove points with same coords at the beginning */
+ if (((((waypoint *)elem)->latitude) ==
+ ((waypoint *)elem->prev)->latitude) &&
+ (((waypoint *)elem)->longitude ==
+ ((waypoint *)elem->prev)->longitude)) {
+ DBG(2,"*** Removing duplicate trackpoint (#%i) ***\n", i);
+ DBG(3,"lat: %f\n",((waypoint *)elem)->latitude);
+ DBG(3,"lon: %f\n",((waypoint *)elem)->longitude);
+ /* update timestamp */
+ ((waypoint *)elem->prev)->creation_time =
+ ((waypoint *)elem)->creation_time;
+ dequeue(elem);
+ continue;
+ }
+ /* also look ahead */
+ speed_next=distspeed((waypoint *)elem, (waypoint *)elem->next);
+ /* calculate speed between waypoint ahead and behind */
+ speed_prev_next=distspeed((waypoint *)elem->prev, (waypoint *)elem->next);
+ DBG(3,"speed_next: %f km/h\n", speed_next*3.6);
+ DBG(3,"speed_prev_next: %f km/h\n", speed_prev_next*3.6);
+ /* either first or second waypoint is wrong */
+ if (speed_current*3.6 > speedlimit) {
+ /* first (and third) is ok, second (=current) is wrong */
+ if ((speed_next*3.6 > speedlimit) &&
+ (speed_prev_next*3.6 <= speedlimit)) {
+ DBG(2,"*** Removing trackpoint (#%i) ***\n", i);
+ DBG(3,"lat: %f\n",((waypoint *)elem)->latitude);
+ DBG(3,"lon: %f\n",((waypoint *)elem)->longitude);
+ dequeue(elem);
+ } else {
+ /* first is wrong */
+ DBG(2,"*** Removing previous trackpoint (#%i) ***\n", i-1);
+ DBG(3,"lat: %f\n",((waypoint *)elem->prev)->latitude);
+ DBG(3,"lon: %f\n",((waypoint *)elem->prev)->longitude);
+ dequeue(elem->prev);
+ }
+ } else {
+ /* first and second are ok, go ahead to third one */
+ second=0;
+ }
+ } else {
+ /* current trackpoint is wrong */
+ if (speed_current*3.6 > speedlimit) {
+ DBG(2,"*** Removing trackpoint (#%i) ***\n", i);
+ DBG(3,"lat: %f\n",((waypoint *)elem)->latitude);
+ DBG(3,"lon: %f\n",((waypoint *)elem)->longitude);
+ dequeue(elem);
+ }
+ }
+ } else {
+ /* go ahead to second trackpoint */
+ first=0;
+ second=1;
+ }
+ }
+}
+
+static void
+badpoints_head_accel(const route_head *track)
+{
+ queue *elem, *tmp, *firstpoint;
+ int i, first, second, removed_head, extrapolated,j;
+ long time_prev_prev, time_prev, time_next;
+ double dist_prev_prev, dist_prev, dist_next;
+ double speed_prev, speed_current, speed_next, speed_current_lasttime;
+ double accel_current, accel_next, accel_current_next;
+ double gradient_change;
+
+ DBG(3,"Positive acceleration limit: %f m/(s*s)\n", accelposlimit);
+ DBG(3,"Negative acceleration limit: %f m/(s*s)\n", accelneglimit);
+
+ /*
+ * stupid: always remove first trackpoint (since we don't know its speed
+ * and thus can't calculate acceleration), but remember the speed at
+ * second point, which is used later as speed_prev to calculate
+ * acceleration between what is called later 'first' and 'second' point
+ *
+ * add it again later if the following track head is not removed
+ */
+ speed_current_lasttime=distspeed((waypoint *)(QUEUE_FIRST(&track->waypoint_list)),
+ (waypoint *)(QUEUE_FIRST(&track->waypoint_list)->next));
+ firstpoint=dequeue(QUEUE_FIRST((queue *)&track->waypoint_list));
+ DBG(2,"*** Removing trackpoint (#1) ***\n");
+ DBG(2,"*** Adding later again if following track head is not removed ***\n");
+ DBG(2,"*** and 'delfirstpoint' option is not set ***\n");
+ DBG(3,"lat: %f\n",((waypoint *)firstpoint)->latitude);
+ DBG(3,"lon: %f\n",((waypoint *)firstpoint)->longitude);
+ DBG(3,"speed at trackpoint #2: %f m/s\n", speed_current_lasttime);
+
+ /* use this one as a counter for current trackpoint number */
+ i=1;
+ /* we begin with the first trackpoint ... */
+ first=1;
+ /* ... not on the second */
+ second=0;
+ /* remember if we want to add firstpoint again */
+ removed_head=0;
+
+ /* standard method to walk through the double linked waypoint list
+ of a track */
+ QUEUE_FOR_EACH((queue *)&track->waypoint_list, elem, tmp) {
+ i++;
+ if (!first) {
+ /* always look behind */
+ dist_prev=dist3d(RAD(((waypoint *)elem)->latitude),
+ RAD(((waypoint *)elem)->longitude),
+ RAD(((waypoint *)elem)->altitude),
+ RAD(((waypoint *)elem->prev)->latitude),
+ RAD(((waypoint *)elem->prev)->longitude),
+ RAD(((waypoint *)elem->prev)->altitude));
+ time_prev=disttime((waypoint *)elem, (waypoint *)elem->prev);
+ speed_current=dist_prev / time_prev;
+ DBG(2,"\n");
+ DBG(2,"Observing trackpoint (#%i) of track %s ...\n", i,
+ track->rte_name);
+ DBG(3,"speed_current: %f m/s\n", speed_current);
+ /* second trackpoint is special */
+ if (second) {
+ /* remove points with same coords at the beginning */
+ if (((((waypoint *)elem)->latitude) ==
+ ((waypoint *)elem->prev)->latitude) &&
+ (((waypoint *)elem)->longitude ==
+ ((waypoint *)elem->prev)->longitude)) {
+ DBG(2,"*** Removing duplicate trackpoint (#%i) ***\n", i);
+ DBG(3,"lat: %f\n",((waypoint *)elem)->latitude);
+ DBG(3,"lon: %f\n",((waypoint *)elem)->longitude);
+ /* update timestamp */
+ ((waypoint *)elem->prev)->creation_time =
+ ((waypoint *)elem)->creation_time;
+ dequeue(elem);
+ /* we didn't move */
+ speed_current_lasttime=0;
+ continue;
+ }
+ speed_prev=speed_current_lasttime;
+ accel_current = (speed_current - speed_prev) / time_prev;
+ /* save speed_current to use it as speed_prev for the next run */
+ speed_current_lasttime=speed_current;
+ /* also look ahead */
+ dist_next=dist3d(RAD(((waypoint *)elem)->latitude),
+ RAD(((waypoint *)elem)->longitude),
+ RAD(((waypoint *)elem)->altitude),
+ RAD(((waypoint *)elem->next)->latitude),
+ RAD(((waypoint *)elem->next)->longitude),
+ RAD(((waypoint *)elem->next)->altitude));
+ time_next=disttime((waypoint *)elem->next, (waypoint *)elem);
+ speed_next=dist_next / time_next;
+ accel_next=(speed_next - speed_current) / time_next;
+ accel_current_next = (speed_next - speed_prev) / (time_prev + time_next);
+ DBG(3,"speed_prev: %f m/s\n", speed_prev);
+ DBG(3,"speed_next: %f m/s\n", speed_next);
+ DBG(3,"accel_current: %f m/(s*s)\n", accel_current);
+ DBG(3,"accel_next: %f m/(s*s)\n", accel_next);
+ DBG(3,"accel_current_next: %f m/(s*s)\n", accel_current_next);
+ /* either first or second waypoint is wrong */
+ if ((accel_current > accelposlimit) || (accel_current < accelneglimit)) {
+ /* first (and third) is ok, second (=current) is wrong */
+ if (((accel_next > accelposlimit) || (accel_next < accelneglimit)) &&
+ ((accel_current_next < accelposlimit) && (accel_current_next > accelneglimit))) {
+ DBG(2,"*** Removing trackpoint (#%i) ***\n", i);
+ DBG(3,"lat: %f\n",((waypoint *)elem)->latitude);
+ DBG(3,"lon: %f\n",((waypoint *)elem)->longitude);
+ dequeue(elem);
+ } else {
+ /* first is wrong */
+ DBG(2,"*** Removing previous trackpoint (#%i) ***\n",
+ i-1);
+ DBG(3,"lat: %f\n",((waypoint *)elem->prev)->latitude);
+ DBG(3,"lon: %f\n",((waypoint *)elem->prev)->longitude);
+ dequeue(elem->prev);
+ removed_head=1;
+ }
+ } else {
+ /* first and second are ok, go ahead to third one */
+ second=0;
+ }
+ } else {
+ /* look one more behind to calculate previous speed */
+ dist_prev_prev=dist3d(RAD(((waypoint *)elem->prev)->latitude),
+ RAD(((waypoint *)elem->prev)->longitude),
+ RAD(((waypoint *)elem->prev)->altitude),
+ RAD(((waypoint *)elem->prev->prev)->latitude),
+ RAD(((waypoint *)elem->prev->prev)->longitude),
+ RAD(((waypoint *)elem->prev->prev)->altitude));
+ time_prev_prev=disttime((waypoint *)elem->prev, (waypoint *)elem->prev->prev);
+ speed_prev=dist_prev_prev/time_prev_prev;
+ accel_current = (speed_current - speed_prev) / time_prev;
+ DBG(3,"speed_prev: %f m/s\n", speed_prev);
+ DBG(3,"accel_current: %f m/(s*s)\n", accel_current);
+ /* current trackpoint is wrong */
+ if ((accel_current > accelposlimit) || (accel_current < accelneglimit)) {
+ /*
+ * If the heading of the points before doesn't change significantly,
+ * let's assume they have been extrapolated by device and remove these
+ * instead of the "outlier"
+ */
+ if (experimental) {
+ extrapolated=0;
+ j=i;
+ while(elem->prev != &track->waypoint_list &&
+ elem->prev->prev != &track->waypoint_list &&
+ elem->prev->prev->prev != &track->waypoint_list) {
+ gradient_change=fabs(gradient((waypoint *)elem->prev, (waypoint *)elem->prev->prev)-
+ gradient((waypoint *)elem->prev->prev, (waypoint *)elem->prev->prev->prev))/
+ disttime((waypoint *)elem->prev, (waypoint *)elem->prev->prev->prev);
+ DBG(3, "gradient_change (#%i/#%i --> #%i/#%i): %f\n", j-3, j-2, j-2, j-1, gradient_change);
+ if (gradient_change < 0.001) {
+ DBG(2,"*** Removing (likely extrapolated) trackpoint (#%i) ***\n", j-1);
+ DBG(3,"lat: %f\n",((waypoint *)elem->prev)->latitude);
+ DBG(3,"lon: %f\n",((waypoint *)elem->prev)->longitude);
+ dequeue(elem->prev);
+ extrapolated=1;
+ j--;
+ } else {
+ /*
+ * If extrapolated points have been found likely a spline interpolation
+ * between "outlier" (=elem) and elem->prev would make sense here.
+ * if (extrapolated) { ... }
+ */
+ break;
+ }
+ }
+ }
+ /* if no extrapolated points have been found or experimental filtering not enabled */
+ if (!extrapolated || !experimental) {
+ DBG(2,"*** Removing trackpoint (#%i) ***\n", i);
+ DBG(3,"lat: %f\n",((waypoint *)elem)->latitude);
+ DBG(3,"lon: %f\n",((waypoint *)elem)->longitude);
+ dequeue(elem);
+ }
+ }
+ }
+ } else {
+ /* go ahead to second trackpoint */
+ first=0;
+ second=1;
+ }
+ }
+ /*
+ * add first trackpoint again if following point has not been removed and
+ * 'delfirstpoint' option is not set
+ */
+ if (!removed_head && !opt_delfirstpoint) {
+ DBG(2,"\n");
+ DBG(2,"*** Track head not removed and 'delfirstpoint' option not set ***\n");
+ DBG(2,"*** Adding trackpoint (#1) again ***\n");
+ ENQUEUE_HEAD((queue *)&track->waypoint_list, firstpoint);
+ DBG(3,"lat: %f\n",((waypoint *)firstpoint)->latitude);
+ DBG(3,"lon: %f\n",((waypoint *)firstpoint)->longitude);
+ }
+}
+
+static void
+badpoints_head(const route_head *track)
+{
+ queue *elem, *tmp;
+ int count=0;
+ float speed_prev, speed_current, accel, maxspeed=0, maxaccel=0, minaccel=0;
+ double gradient_change;
+ DBG(1,"BEGIN TRACK (%s)\n",track->rte_name);
+
+ /* count the number of trackpoints, maxspeed, maxaccel and minaccel before filtering */
+ if (debug >= 1) {
+ count=0;
+ maxspeed=0; maxaccel=0; minaccel=0;
+ DBG(2, "Trackpoints before filtering\n");
+ QUEUE_FOR_EACH((queue *)&track->waypoint_list, elem, tmp) {
+ DBG(2,"lat: %f, lon: %f, alt: %f\n", ((waypoint *)elem)->latitude,
+ ((waypoint *)elem)->longitude, ((waypoint *)elem)->altitude);
+ if (count >= 2 && debug >= 3) {
+ gradient_change=fabs(gradient((waypoint *)elem, (waypoint *)elem->prev)-
+ gradient((waypoint *)elem->prev, (waypoint *)elem->prev->prev))/
+ disttime((waypoint *)elem, (waypoint *)elem->prev->prev);
+ DBG(3,"gradient_change (#%i/#%i --> #%i/#%i): %f\n",
+ count-1, count, count, count+1, gradient_change);
+ }
+ if (count) {
+ speed_current=distspeed((waypoint *)elem, (waypoint *)elem->prev);
+ if (speed_current > maxspeed)
+ maxspeed = speed_current;
+ if (count >= 2) {
+ speed_prev=distspeed((waypoint *)elem->prev, (waypoint *)elem->prev->prev);
+ accel=(speed_current - speed_prev)/
+ disttime((waypoint *)elem, (waypoint *)elem->prev);
+ if (accel > maxaccel)
+ maxaccel = accel;
+ if (accel < minaccel)
+ minaccel = accel;
+ }
+ }
+ count++;
+ }
+ DBG(1,"%i waypoints before filtering\n", count);
+ DBG(3,"maxspeed before filtering: %f km/h\n", maxspeed * 3.6);
+ DBG(3,"maxaccel before filtering: %f m/(s*s)\n", maxaccel);
+ DBG(3,"minaccel before filtering: %f m/(s*s)\n", minaccel);
+ }
+
+ /* do the filtering */
+ if (opt_speed) {
+ DBG(1, "Using speed filter\n");
+ badpoints_head_speed(track);
+ } else {
+ DBG(1, "Using acceleration filter\n");
+ badpoints_head_accel(track);
+ }
+
+ /* count the number of trackpoints, maxspeed, maxaccel and minaccel after filtering */
+ if (debug >= 1) {
+ count = 0;
+ maxspeed=0; maxaccel=0; minaccel=0;
+ DBG(2, "Trackpoints after filtering\n");
+ QUEUE_FOR_EACH((queue *)&track->waypoint_list, elem, tmp) {
+ DBG(2,"lat: %f, lon: %f, alt: %f\n", ((waypoint *)elem)->latitude,
+ ((waypoint *)elem)->longitude, ((waypoint *)elem)->altitude);
+ if (count >= 2 && debug >= 3) {
+ gradient_change=fabs(gradient((waypoint *)elem, (waypoint *)elem->prev)-
+ gradient((waypoint *)elem->prev, (waypoint *)elem->prev->prev))/
+ disttime((waypoint *)elem, (waypoint *)elem->prev->prev);
+ DBG(3,"gradient_change (#%i/#%i --> #%i/#%i): %f\n",
+ count-1, count, count, count+1, gradient_change);
+ }
+ if (count) {
+ speed_current=distspeed((waypoint *)elem, (waypoint *)elem->prev);
+ if (speed_current > maxspeed)
+ maxspeed = speed_current;
+ if (count >= 2) {
+ speed_prev=distspeed((waypoint *)elem->prev, (waypoint *)elem->prev->prev);
+ accel=(speed_current - speed_prev)/
+ disttime((waypoint *)elem, (waypoint *)elem->prev);
+ if (accel > maxaccel)
+ maxaccel = accel;
+ if (accel < minaccel)
+ minaccel = accel;
+ }
+ }
+ count++;
+ }
+ DBG(1,"%i waypoints after filtering\n", count);
+ DBG(3,"maxspeed after filtering: %f km/h\n", maxspeed * 3.6);
+ DBG(3,"maxaccel after filtering: %f m/(s*s)\n", maxaccel);
+ DBG(3,"minaccel after filtering: %f m/(s*s)\n", minaccel);
+ }
+}
+
+static void
+badpoints_tail(const route_head *track)
+{
+ DBG(1,"END TRACK (%s)\n",track->rte_name);
+}
+
+static void
+badpoints_trkpt(const waypoint *trkpt)
+{
+}
+
+static void
+badpoints_process(void) /* this procedure must be present in vecs */
+{
+// Here is how you register callbacks for all waypoints, routes, tracks.
+// waypt_disp_all(waypt)
+// route_disp_all(head, tail, rtept);
+ track_disp_all(badpoints_head, badpoints_tail, badpoints_trkpt);
+}
+
+static void
+badpoints_deinit(void)
+{
+ /* called after filter processing */
+
+ /* optional. If not needed, delete and replace entry in vecs with NULL */
+
+ /* This should be used to clean up any memory allocations that are no longer
+ * needed after the filter terminates. */
+}
+
+static void
+badpoints_exit(void)
+{
+ /* called on program exit */
+
+ /* optional. If not needed, delete and replace entry in vecs with NULL */
+
+ /* You should not need this for simple filters, but it may be used to
+ * clean up memory allocations that must persist from one invocation of
+ * your filter to the next (for example, the stack in the stack filter.)
+ * Note that this member will be called even if your filter has not been
+ * used, so it *cannot* assume that _init or _process has been called
+ * previously. */
+}
+
+/*******************************************************************************/
+
+filter_vecs_t badpoints_vecs = {
+ badpoints_init,
+ badpoints_process,
+ badpoints_deinit,
+ badpoints_exit,
+ badpoints_args
+};
+
+/*******************************************************************************/
+#endif // FILTERS_ENABLED
Index: Makefile.in
===================================================================
--- Makefile.in (revision 1)
+++ Makefile.in (working copy)
@@ -67,7 +67,8 @@
FILTERS=position.o radius.o duplicate.o arcdist.o polygon.o smplrout.o \
reverse_route.o sort.o stackfilter.o trackfilter.o discard.o \
- nukedata.o interpolate.o transform.o height.o swapdata.o
+ nukedata.o interpolate.o transform.o height.o swapdata.o badpoints.o \
+ srtm.o smooth.o
JEEPS=jeeps/gpsapp.o jeeps/gpscom.o \
jeeps/gpsmath.o jeeps/gpsmem.o \
@@ -362,6 +363,9 @@
zlib/zlib.h zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h session.h
axim_gpb.o: axim_gpb.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \
zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h session.h
+badpoints.o: badpoints.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \
+ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h session.h filterdefs.h \
+ grtcirc.h
bcr.o: bcr.c defs.h config.h queue.h gbtypes.h zlib/zlib.h zlib/zconf.h \
gbfile.h cet.h cet_util.h inifile.h session.h csv_util.h \
garmin_tables.h
@@ -765,8 +769,14 @@
smplrout.o: smplrout.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \
zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h session.h filterdefs.h \
grtcirc.h
+smooth.o: smooth.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \
+ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h session.h filterdefs.h \
+ grtcirc.h
sort.o: sort.c defs.h config.h queue.h gbtypes.h zlib/zlib.h zlib/zconf.h \
gbfile.h cet.h cet_util.h inifile.h session.h filterdefs.h
+srtm.o: srtm.c defs.h config.h queue.h gbtypes.h zlib/zlib.h \
+ zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h session.h filterdefs.h \
+ grtcirc.h
stackfilter.o: stackfilter.c defs.h config.h queue.h gbtypes.h \
zlib/zlib.h zlib/zconf.h gbfile.h cet.h cet_util.h inifile.h session.h \
filterdefs.h
Index: filter_vecs.c
===================================================================
--- filter_vecs.c (revision 1)
+++ filter_vecs.c (working copy)
@@ -46,6 +46,9 @@
extern filter_vecs_t transform_vecs;
extern filter_vecs_t height_vecs;
extern filter_vecs_t swapdata_vecs;
+extern filter_vecs_t badpoints_vecs;
+extern filter_vecs_t srtm_vecs;
+extern filter_vecs_t smooth_vecs;
static
fl_vecs_t filter_vec_list[] = {
@@ -56,6 +59,11 @@
"Include Only Points Within Distance of Arc",
},
{
+ &badpoints_vecs,
+ "badpoints",
+ "Remove bad points",
+ },
+ {
&discard_vecs,
"discard",
"Remove unreliable points with high hdop or vdop"
@@ -96,6 +104,11 @@
"Simplify routes",
},
{
+ &smooth_vecs,
+ "smooth",
+ "Smooth tracks",
+ },
+ {
&sort_vecs,
"sort",
"Rearrange waypoints by resorting",
@@ -106,6 +119,11 @@
"Save and restore waypoint lists"
},
{
+ &srtm_vecs,
+ "srtm",
+ "use SRTM data for altitude (requires curl/gunzip)",
+ },
+ {
&reverse_route_vecs,
"reverse",
"Reverse stops within routes",