Routino SVN Repository Browser

Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino

ViewVC logotype

Contents of /trunk/src/nodes.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 303 - (show annotations) (download) (as text)
Sat Nov 14 19:39:20 2009 UTC (15 years, 4 months ago) by amb
File MIME type: text/x-csrc
File size: 14829 byte(s)
If a selected waypoint is not very close to an existing node then insert a fake
node in the segment that comes closest and use that instead.

1 /***************************************
2 $Header: /home/amb/CVS/routino/src/nodes.c,v 1.34 2009-11-14 19:39:19 amb Exp $
3
4 Node data type functions.
5
6 Part of the Routino routing software.
7 ******************/ /******************
8 This file Copyright 2008,2009 Andrew M. Bishop
9
10 This program is free software: you can redistribute it and/or modify
11 it under the terms of the GNU Affero General Public License as published by
12 the Free Software Foundation, either version 3 of the License, or
13 (at your option) any later version.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU Affero General Public License for more details.
19
20 You should have received a copy of the GNU Affero General Public License
21 along with this program. If not, see <http://www.gnu.org/licenses/>.
22 ***************************************/
23
24
25 #include <sys/types.h>
26 #include <stdlib.h>
27 #include <math.h>
28
29 #include "profiles.h"
30 #include "nodes.h"
31 #include "segments.h"
32 #include "ways.h"
33 #include "functions.h"
34
35
36 /*++++++++++++++++++++++++++++++++++++++
37 Load in a node list from a file.
38
39 Nodes* LoadNodeList Returns the node list.
40
41 const char *filename The name of the file to load.
42 ++++++++++++++++++++++++++++++++++++++*/
43
44 Nodes *LoadNodeList(const char *filename)
45 {
46 void *data;
47 Nodes *nodes;
48
49 nodes=(Nodes*)malloc(sizeof(Nodes));
50
51 data=MapFile(filename);
52
53 if(!data)
54 return(NULL);
55
56 /* Copy the Nodes structure from the loaded data */
57
58 *nodes=*((Nodes*)data);
59
60 /* Adjust the pointers in the Nodes structure. */
61
62 nodes->data=data;
63 nodes->offsets=(index_t*)(data+(off_t)nodes->offsets);
64 nodes->nodes=(Node*)(data+(off_t)nodes->nodes);
65
66 return(nodes);
67 }
68
69
70 /*++++++++++++++++++++++++++++++++++++++
71 Find the closest node given its latitude, longitude and optionally profile.
72
73 index_t FindClosestNode Returns the closest node.
74
75 Nodes* nodes The set of nodes to search.
76
77 Segments *segments The set of segments to use.
78
79 Ways *ways The set of ways to use.
80
81 double latitude The latitude to look for.
82
83 double longitude The longitude to look for.
84
85 distance_t distance The maximum distance to look.
86
87 Profile *profile The profile of the mode of transport (or NULL).
88
89 distance_t *bestdist Returns the distance to the best node.
90 ++++++++++++++++++++++++++++++++++++++*/
91
92 index_t FindClosestNode(Nodes* nodes,Segments *segments,Ways *ways,double latitude,double longitude,
93 distance_t distance,Profile *profile,distance_t *bestdist)
94 {
95 ll_bin_t latbin=latlong_to_bin(radians_to_latlong(latitude ))-nodes->latzero;
96 ll_bin_t lonbin=latlong_to_bin(radians_to_latlong(longitude))-nodes->lonzero;
97 int delta=0,count;
98 index_t i,bestn=NO_NODE;
99 distance_t bestd=INF_DISTANCE;
100
101 /* Start with the bin containing the location, then spiral outwards. */
102
103 do
104 {
105 int latb,lonb,llbin;
106
107 count=0;
108
109 for(latb=latbin-delta;latb<=latbin+delta;latb++)
110 {
111 if(latb<0 || latb>=nodes->latbins)
112 continue;
113
114 for(lonb=lonbin-delta;lonb<=lonbin+delta;lonb++)
115 {
116 if(lonb<0 || lonb>=nodes->lonbins)
117 continue;
118
119 if(abs(latb-latbin)<delta && abs(lonb-lonbin)<delta)
120 continue;
121
122 llbin=lonb*nodes->latbins+latb;
123
124 /* Check if this grid square has any hope of being close enough */
125
126 if(delta>0)
127 {
128 double lat1=latlong_to_radians(bin_to_latlong(nodes->latzero+latb));
129 double lon1=latlong_to_radians(bin_to_latlong(nodes->lonzero+lonb));
130 double lat2=latlong_to_radians(bin_to_latlong(nodes->latzero+latb+1));
131 double lon2=latlong_to_radians(bin_to_latlong(nodes->lonzero+lonb+1));
132
133 if(latb==latbin)
134 {
135 distance_t dist1=Distance(latitude,lon1,latitude,longitude);
136 distance_t dist2=Distance(latitude,lon2,latitude,longitude);
137
138 if(dist1>distance && dist2>distance)
139 continue;
140 }
141 else if(lonb==lonbin)
142 {
143 distance_t dist1=Distance(lat1,longitude,latitude,longitude);
144 distance_t dist2=Distance(lat2,longitude,latitude,longitude);
145
146 if(dist1>distance && dist2>distance)
147 continue;
148 }
149 else
150 {
151 distance_t dist1=Distance(lat1,lon1,latitude,longitude);
152 distance_t dist2=Distance(lat2,lon1,latitude,longitude);
153 distance_t dist3=Distance(lat2,lon2,latitude,longitude);
154 distance_t dist4=Distance(lat1,lon2,latitude,longitude);
155
156 if(dist1>distance && dist2>distance && dist3>distance && dist4>distance)
157 continue;
158 }
159 }
160
161 /* Check every node in this grid square. */
162
163 for(i=nodes->offsets[llbin];i<nodes->offsets[llbin+1];i++)
164 {
165 double lat=latlong_to_radians(bin_to_latlong(nodes->latzero+latb)+off_to_latlong(nodes->nodes[i].latoffset));
166 double lon=latlong_to_radians(bin_to_latlong(nodes->lonzero+lonb)+off_to_latlong(nodes->nodes[i].lonoffset));
167
168 distance_t dist=Distance(lat,lon,latitude,longitude);
169
170 if(dist<distance)
171 {
172 if(profile)
173 {
174 Segment *segment;
175
176 /* Decide if this is node is valid for the profile */
177
178 segment=FirstSegment(segments,nodes,i);
179
180 do
181 {
182 Way *way=LookupWay(ways,segment->way);
183
184 if(way->allow&profile->allow)
185 break;
186
187 segment=NextSegment(segments,segment,i);
188 }
189 while(segment);
190
191 if(!segment)
192 continue;
193 }
194
195 bestn=i; bestd=distance=dist;
196 }
197 }
198
199 count++;
200 }
201 }
202
203 delta++;
204 }
205 while(count);
206
207 *bestdist=bestd;
208
209 return(bestn);
210 }
211
212
213 /*++++++++++++++++++++++++++++++++++++++
214 Find the closest segment to a latitude, longitude and optionally profile.
215
216 Segment *FindClosestSegment Returns the closest segment.
217
218 Nodes* nodes The set of nodes to search.
219
220 Segments *segments The set of segments to use.
221
222 Ways *ways The set of ways to use.
223
224 double latitude The latitude to look for.
225
226 double longitude The longitude to look for.
227
228 distance_t distance The maximum distance to look.
229
230 Profile *profile The profile of the mode of transport (or NULL).
231
232 distance_t *bestdist Returns the distance to the best segment.
233
234 index_t *bestnode1 Returns the best node at one end.
235
236 index_t *bestnode2 Returns the best node at the other end.
237
238 distance_t *bestdist1 Returns the distance to the best node at one end.
239
240 distance_t *bestdist2 Returns the distance to the best node at the other end.
241 ++++++++++++++++++++++++++++++++++++++*/
242
243 Segment *FindClosestSegment(Nodes* nodes,Segments *segments,Ways *ways,double latitude,double longitude,
244 distance_t distance,Profile *profile, distance_t *bestdist,
245 index_t *bestnode1,index_t *bestnode2,distance_t *bestdist1,distance_t *bestdist2)
246 {
247 ll_bin_t latbin=latlong_to_bin(radians_to_latlong(latitude ))-nodes->latzero;
248 ll_bin_t lonbin=latlong_to_bin(radians_to_latlong(longitude))-nodes->lonzero;
249 int delta=0,count;
250 index_t i,bestn1=NO_NODE,bestn2=NO_NODE;
251 distance_t bestd=INF_DISTANCE,bestd1=INF_DISTANCE,bestd2=INF_DISTANCE;
252 Segment *bests=NULL;
253
254 /* Start with the bin containing the location, then spiral outwards. */
255
256 do
257 {
258 int latb,lonb,llbin;
259
260 count=0;
261
262 for(latb=latbin-delta;latb<=latbin+delta;latb++)
263 {
264 if(latb<0 || latb>=nodes->latbins)
265 continue;
266
267 for(lonb=lonbin-delta;lonb<=lonbin+delta;lonb++)
268 {
269 if(lonb<0 || lonb>=nodes->lonbins)
270 continue;
271
272 if(abs(latb-latbin)<delta && abs(lonb-lonbin)<delta)
273 continue;
274
275 llbin=lonb*nodes->latbins+latb;
276
277 /* Check if this grid square has any hope of being close enough */
278
279 if(delta>0)
280 {
281 double lat1=latlong_to_radians(bin_to_latlong(nodes->latzero+latb));
282 double lon1=latlong_to_radians(bin_to_latlong(nodes->lonzero+lonb));
283 double lat2=latlong_to_radians(bin_to_latlong(nodes->latzero+latb+1));
284 double lon2=latlong_to_radians(bin_to_latlong(nodes->lonzero+lonb+1));
285
286 if(latb==latbin)
287 {
288 distance_t dist1=Distance(latitude,lon1,latitude,longitude);
289 distance_t dist2=Distance(latitude,lon2,latitude,longitude);
290
291 if(dist1>distance && dist2>distance)
292 continue;
293 }
294 else if(lonb==lonbin)
295 {
296 distance_t dist1=Distance(lat1,longitude,latitude,longitude);
297 distance_t dist2=Distance(lat2,longitude,latitude,longitude);
298
299 if(dist1>distance && dist2>distance)
300 continue;
301 }
302 else
303 {
304 distance_t dist1=Distance(lat1,lon1,latitude,longitude);
305 distance_t dist2=Distance(lat2,lon1,latitude,longitude);
306 distance_t dist3=Distance(lat2,lon2,latitude,longitude);
307 distance_t dist4=Distance(lat1,lon2,latitude,longitude);
308
309 if(dist1>distance && dist2>distance && dist3>distance && dist4>distance)
310 continue;
311 }
312 }
313
314 /* Check every node in this grid square. */
315
316 for(i=nodes->offsets[llbin];i<nodes->offsets[llbin+1];i++)
317 {
318 double lat1=latlong_to_radians(bin_to_latlong(nodes->latzero+latb)+off_to_latlong(nodes->nodes[i].latoffset));
319 double lon1=latlong_to_radians(bin_to_latlong(nodes->lonzero+lonb)+off_to_latlong(nodes->nodes[i].lonoffset));
320 Segment *segment;
321 double dist1,dist2,dist3,dist3a,dist3b,distp;
322
323 dist1=Distance(lat1,lon1,latitude,longitude);
324
325 /* Check each segment for closeness and if valid for the profile */
326
327 segment=FirstSegment(segments,nodes,i);
328
329 do
330 {
331 if(IsNormalSegment(segment))
332 {
333 Way *way=NULL;
334
335 if(profile)
336 way=LookupWay(ways,segment->way);
337
338 if(!profile || way->allow&profile->allow)
339 {
340 double lat2,lon2;
341
342 GetLatLong(nodes,OtherNode(segment,i),&lat2,&lon2);
343
344 dist2=Distance(lat2,lon2,latitude,longitude);
345 dist3=Distance(lat1,lon1,lat2,lon2);
346
347 /* Use law of cosines (assume flat Earth) */
348
349 dist3a=(dist1*dist1-dist2*dist2+dist3*dist3)/(2*dist3);
350 dist3b=dist3-dist3a;
351
352 if(dist3a>=0 && dist3b>=0)
353 {
354 distp=sqrt(dist1*dist1-dist3a*dist3a);
355
356 if((distance_t)distp<bestd)
357 {
358 bests=segment;
359 bestn1=i;
360 bestn2=OtherNode(segment,i);
361 bestd1=(distance_t)dist3a;
362 bestd2=(distance_t)dist3b;
363 bestd=(distance_t)distp;
364 }
365 }
366 }
367 }
368
369 segment=NextSegment(segments,segment,i);
370 }
371 while(segment);
372 }
373
374 count++;
375 }
376 }
377
378 delta++;
379 }
380 while(count);
381
382 *bestdist=bestd;
383
384 *bestnode1=bestn1;
385 *bestnode2=bestn2;
386 *bestdist1=bestd1;
387 *bestdist2=bestd2;
388
389 return(bests);
390 }
391
392
393 /*++++++++++++++++++++++++++++++++++++++
394 Get the latitude and longitude associated with a node.
395
396 Nodes *nodes The set of nodes.
397
398 index_t index The node index.
399
400 double *latitude Returns the latitude.
401
402 double *longitude Returns the logitude.
403 ++++++++++++++++++++++++++++++++++++++*/
404
405 void GetLatLong(Nodes *nodes,index_t index,double *latitude,double *longitude)
406 {
407 Node *node=&nodes->nodes[index];
408 int latbin=-1,lonbin=-1;
409 int start,end,mid;
410
411 /* Binary search - search key closest below is required.
412 *
413 * # <- start | Check mid and move start or end if it doesn't match
414 * # |
415 * # | Since an inexact match is wanted we must set end=mid-1
416 * # <- mid | or start=mid because we know that mid doesn't match.
417 * # |
418 * # | Eventually either end=start or end=start+1 and one of
419 * # <- end | start or end is the wanted one.
420 */
421
422 /* Search for longitude */
423
424 start=0;
425 end=nodes->lonbins-1;
426
427 do
428 {
429 mid=(start+end)/2; /* Choose mid point */
430
431 if(nodes->offsets[nodes->latbins*mid]<index) /* Mid point is too low */
432 start=mid;
433 else if(nodes->offsets[nodes->latbins*mid]>index) /* Mid point is too high */
434 end=mid-1;
435 else /* Mid point is correct */
436 {lonbin=mid;break;}
437 }
438 while((end-start)>1);
439
440 if(lonbin==-1)
441 {
442 if(nodes->offsets[nodes->latbins*end]>index)
443 lonbin=start;
444 else
445 lonbin=end;
446 }
447
448 while(lonbin<nodes->lonbins && nodes->offsets[lonbin*nodes->latbins]==nodes->offsets[(lonbin+1)*nodes->latbins])
449 lonbin++;
450
451 /* Search for latitude */
452
453 start=0;
454 end=nodes->latbins-1;
455
456 do
457 {
458 mid=(start+end)/2; /* Choose mid point */
459
460 if(nodes->offsets[lonbin*nodes->latbins+mid]<index) /* Mid point is too low */
461 start=mid;
462 else if(nodes->offsets[lonbin*nodes->latbins+mid]>index) /* Mid point is too high */
463 end=mid-1;
464 else /* Mid point is correct */
465 {latbin=mid;break;}
466 }
467 while((end-start)>1);
468
469 if(latbin==-1)
470 {
471 if(nodes->offsets[lonbin*nodes->latbins+end]>index)
472 latbin=start;
473 else
474 latbin=end;
475 }
476
477 while(latbin<nodes->latbins && nodes->offsets[lonbin*nodes->latbins+latbin]==nodes->offsets[lonbin*nodes->latbins+latbin+1])
478 latbin++;
479
480 /* Return the values */
481
482 *latitude =latlong_to_radians(bin_to_latlong(nodes->latzero+latbin)+off_to_latlong(node->latoffset));
483 *longitude=latlong_to_radians(bin_to_latlong(nodes->lonzero+lonbin)+off_to_latlong(node->lonoffset));
484 }

Properties

Name Value
cvs:description Node data type.