Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
home:sndirsch
gpsbabel
gpsbabel-20090809_r105.diff
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
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",
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor