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",
openSUSE Build Service is sponsored by