1 /*
2     Distance Between Points Filter(s)
3 
4     Copyright (C) 2002 Robert Lipe, robertlipe@usa.net
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111 USA
19 
20  */
21 #include "defs.h"
22 #include "filterdefs.h"
23 #include "grtcirc.h"
24 
25 #if FILTERS_ENABLED
26 
27 #ifndef M_PI
28 #  define M_PI 3.14159265358979323846
29 #endif
30 
31 static route_head *cur_rte = NULL;
32 
33 static double pos_dist;
34 static double max_diff_time;
35 static char *distopt = NULL;
36 static char *timeopt = NULL;
37 static char *purge_duplicates = NULL;
38 static int check_time;
39 
40 typedef struct {
41   double distance;
42 } extra_data;
43 
44 static
45 arglist_t position_args[] = {
46   {
47     "distance", &distopt, "Maximum positional distance",
48     NULL, ARGTYPE_FLOAT | ARGTYPE_REQUIRED, ARG_NOMINMAX
49   },
50   {
51     "all", &purge_duplicates,
52     "Suppress all points close to other points",
53     NULL, ARGTYPE_BOOL, ARG_NOMINMAX
54   },
55   {
56     "time", &timeopt, "Maximum time in seconds beetween two points",
57     NULL, ARGTYPE_FLOAT | ARGTYPE_REQUIRED, ARG_NOMINMAX
58   },
59   ARG_TERMINATOR
60 };
61 
62 static double
gc_distance(double lat1,double lon1,double lat2,double lon2)63 gc_distance(double lat1, double lon1, double lat2, double lon2)
64 {
65   return gcdist(
66            RAD(lat1),
67            RAD(lon1),
68            RAD(lat2),
69            RAD(lon2)
70          );
71 }
72 
73 /* tear through a waypoint queue, processing points by distance */
74 static void
position_runqueue(queue * q,int nelems,int qtype)75 position_runqueue(queue *q, int nelems, int qtype)
76 {
77   queue * elem, * tmp;
78   waypoint ** comp;
79   int * qlist;
80   double dist, diff_time;
81   int i = 0, j, anyitem;
82 
83   comp = (waypoint **) xcalloc(nelems, sizeof(*comp));
84   qlist = (int *) xcalloc(nelems, sizeof(*qlist));
85 
86   QUEUE_FOR_EACH(q, elem, tmp) {
87     comp[i] = (waypoint *)elem;
88     qlist[i] = 0;
89     i++;
90   }
91 
92   for (i = 0 ; i < nelems ; i++) {
93     anyitem = 0;
94 
95     if (!qlist[i]) {
96       for (j = i + 1 ; j < nelems ; j++) {
97         if (!qlist[j]) {
98           dist = gc_distance(comp[j]->latitude,
99                              comp[j]->longitude,
100                              comp[i]->latitude,
101                              comp[i]->longitude);
102 
103           /* convert radians to integer feet */
104           dist = (int)(5280*radtomiles(dist));
105           diff_time = fabs(waypt_time(comp[i]) - waypt_time(comp[j]));
106 
107           if (dist <= pos_dist) {
108             if (check_time && diff_time >= max_diff_time) {
109               continue;
110             }
111 
112             qlist[j] = 1;
113             switch (qtype) {
114             case wptdata:
115               waypt_del(comp[j]);
116               waypt_free(comp[j]);
117               break;
118             case trkdata:
119               track_del_wpt(cur_rte, comp[j]);
120               break;
121             case rtedata:
122               route_del_wpt(cur_rte, comp[j]);
123               break;
124             default:
125               break;
126             }
127             anyitem = 1;
128           }
129         }
130       }
131 
132       if (anyitem && !!purge_duplicates) {
133         switch (qtype) {
134         case wptdata:
135           waypt_del(comp[i]);
136           break;
137         case trkdata:
138           track_del_wpt(cur_rte, comp[i]);
139           break;
140         case rtedata:
141           route_del_wpt(cur_rte, comp[i]);
142           break;
143         default:
144           break;
145         }
146         waypt_free(comp[i]);
147       }
148     }
149   }
150 
151   if (comp) {
152     xfree(comp);
153   }
154 
155   if (qlist) {
156     xfree(qlist);
157   }
158 }
159 
160 static void
position_process_route(const route_head * rh)161 position_process_route(const route_head * rh)
162 {
163   int i = rh->rte_waypt_ct;
164 
165   if (i) {
166     cur_rte = (route_head *)rh;
167     position_runqueue((queue *)&rh->waypoint_list, i, rtedata);
168     cur_rte = NULL;
169   }
170 
171 }
172 
173 static void
position_noop_w(const waypoint * w)174 position_noop_w(const waypoint *w)
175 {
176 }
177 
178 static void
position_noop_t(const route_head * h)179 position_noop_t(const route_head *h)
180 {
181 }
182 
position_process(void)183 void position_process(void)
184 {
185   int i = waypt_count();
186 
187   if (i) {
188     position_runqueue(&waypt_head, i, wptdata);
189   }
190 
191   route_disp_all(position_process_route, position_noop_t, position_noop_w);
192   track_disp_all(position_process_route, position_noop_t, position_noop_w);
193 }
194 
195 void
position_init(const char * args)196 position_init(const char *args)
197 {
198   char *fm;
199 
200   pos_dist = 0;
201   max_diff_time = 0;
202   check_time = 0;
203 
204   if (distopt) {
205     pos_dist = strtod(distopt, &fm);
206 
207     if ((*fm == 'm') || (*fm == 'M')) {
208       /* distance is meters */
209       pos_dist *= 3.2802;
210     }
211   }
212 
213   if (timeopt) {
214     check_time = 1;
215     max_diff_time = strtod(timeopt, &fm);
216   }
217 }
218 
219 void
position_deinit(void)220 position_deinit(void)
221 {
222 }
223 
224 filter_vecs_t position_vecs = {
225   position_init,
226   position_process,
227   position_deinit,
228   NULL,
229   position_args
230 };
231 
232 #endif // FILTERS_ENABLED
233