Check out the latest version of Routino: svn co http://routino.org/svn/trunk routino
Contents of /trunk/src/nodesx.c
Parent Directory
|
Revision Log
Revision 212 -
(show annotations)
(download)
(as text)
Wed Jul 1 18:23:26 2009 UTC (15 years, 8 months ago) by amb
File MIME type: text/x-csrc
File size: 14908 byte(s)
Wed Jul 1 18:23:26 2009 UTC (15 years, 8 months ago) by amb
File MIME type: text/x-csrc
File size: 14908 byte(s)
Remove the Node structure from the NodeX structure to save memory.
1 | /*************************************** |
2 | $Header: /home/amb/CVS/routino/src/nodesx.c,v 1.18 2009-07-01 18:23:26 amb Exp $ |
3 | |
4 | Extented 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 <assert.h> |
26 | #include <stdlib.h> |
27 | #include <string.h> |
28 | #include <stdio.h> |
29 | #include <math.h> |
30 | |
31 | #include "types.h" |
32 | #include "functions.h" |
33 | #include "nodesx.h" |
34 | #include "segmentsx.h" |
35 | #include "waysx.h" |
36 | |
37 | |
38 | /* Constants */ |
39 | |
40 | /*+ The array size increment for nodes - expect ~8,000,000 nodes. +*/ |
41 | #define INCREMENT_NODES 1024*1024 |
42 | |
43 | |
44 | /* Functions */ |
45 | |
46 | static int sort_by_id(NodeX **a,NodeX **b); |
47 | static int sort_by_lat_long(NodeX **a,NodeX **b); |
48 | |
49 | |
50 | /*++++++++++++++++++++++++++++++++++++++ |
51 | Allocate a new node list. |
52 | |
53 | NodesX *NewNodeList Returns the node list. |
54 | ++++++++++++++++++++++++++++++++++++++*/ |
55 | |
56 | NodesX *NewNodeList(void) |
57 | { |
58 | NodesX *nodesx; |
59 | |
60 | nodesx=(NodesX*)malloc(sizeof(NodesX)); |
61 | |
62 | nodesx->alloced=INCREMENT_NODES; |
63 | nodesx->xnumber=0; |
64 | nodesx->sorted=0; |
65 | |
66 | nodesx->xdata=(NodeX*)malloc(nodesx->alloced*sizeof(NodeX)); |
67 | nodesx->gdata=NULL; |
68 | nodesx->idata=NULL; |
69 | |
70 | nodesx->ndata=NULL; |
71 | |
72 | return(nodesx); |
73 | } |
74 | |
75 | |
76 | /*++++++++++++++++++++++++++++++++++++++ |
77 | Save the node list to a file. |
78 | |
79 | NodesX* nodesx The set of nodes to save. |
80 | |
81 | const char *filename The name of the file to save. |
82 | ++++++++++++++++++++++++++++++++++++++*/ |
83 | |
84 | void SaveNodeList(NodesX* nodesx,const char *filename) |
85 | { |
86 | int i; |
87 | int fd; |
88 | Nodes *nodes=calloc(1,sizeof(Nodes)); |
89 | index_t *offsets; |
90 | int32_t lat_min,lat_max,lon_min,lon_max; |
91 | int latbins,lonbins,latlonbin; |
92 | |
93 | assert(nodesx->sorted); /* Must be sorted */ |
94 | |
95 | /* Work out the offsets */ |
96 | |
97 | lat_min=lat_long_to_bin(nodesx->lat_min); |
98 | lon_min=lat_long_to_bin(nodesx->lon_min); |
99 | lat_max=lat_long_to_bin(nodesx->lat_max); |
100 | lon_max=lat_long_to_bin(nodesx->lon_max); |
101 | |
102 | latbins=(lat_max-lat_min)+1; |
103 | lonbins=(lon_max-lon_min)+1; |
104 | |
105 | offsets=malloc((latbins*lonbins+1)*sizeof(index_t)); |
106 | |
107 | latlonbin=0; |
108 | |
109 | for(i=0;i<nodesx->number;i++) |
110 | { |
111 | int32_t latbin=lat_long_to_bin(nodesx->gdata[i]->latitude )-lat_min; |
112 | int32_t lonbin=lat_long_to_bin(nodesx->gdata[i]->longitude)-lon_min; |
113 | int llbin=lonbin*latbins+latbin; |
114 | |
115 | for(;latlonbin<=llbin;latlonbin++) |
116 | offsets[latlonbin]=i; |
117 | } |
118 | |
119 | for(;latlonbin<=(latbins*lonbins);latlonbin++) |
120 | offsets[latlonbin]=nodesx->number; |
121 | |
122 | /* Fill in a Nodes structure with the offset of the real data in the file after |
123 | the Node structure itself. */ |
124 | |
125 | nodes->number=nodesx->number; |
126 | |
127 | nodes->latbins=latbins; |
128 | nodes->lonbins=lonbins; |
129 | |
130 | nodes->latzero=lat_min; |
131 | nodes->lonzero=lon_min; |
132 | |
133 | nodes->data=NULL; |
134 | nodes->offsets=(void*)sizeof(Nodes); |
135 | nodes->nodes=(void*)sizeof(Nodes)+(latbins*lonbins+1)*sizeof(index_t); |
136 | |
137 | /* Write out the Nodes structure and then the real data. */ |
138 | |
139 | fd=OpenFile(filename); |
140 | |
141 | WriteFile(fd,nodes,sizeof(Nodes)); |
142 | |
143 | WriteFile(fd,offsets,(latbins*lonbins+1)*sizeof(index_t)); |
144 | |
145 | for(i=0;i<nodes->number;i++) |
146 | { |
147 | NodeX **nodex=FindNodeX(nodesx,nodesx->gdata[i]->id); |
148 | Node *node =&nodesx->ndata[nodex-nodesx->idata]; |
149 | |
150 | WriteFile(fd,node,sizeof(Node)); |
151 | |
152 | if(!((i+1)%10000)) |
153 | { |
154 | printf("\rWriting Nodes: Nodes=%d",i+1); |
155 | fflush(stdout); |
156 | } |
157 | } |
158 | |
159 | printf("\rWrote Nodes: Nodes=%d \n",nodes->number); |
160 | fflush(stdout); |
161 | |
162 | CloseFile(fd); |
163 | |
164 | /* Free the fake Nodes */ |
165 | |
166 | free(nodes); |
167 | free(offsets); |
168 | } |
169 | |
170 | |
171 | /*++++++++++++++++++++++++++++++++++++++ |
172 | Find a particular node. |
173 | |
174 | NodeX **FindNodeX Returns a pointer to the extended node with the specified id. |
175 | |
176 | NodesX* nodesx The set of nodes to process. |
177 | |
178 | node_t id The node id to look for. |
179 | ++++++++++++++++++++++++++++++++++++++*/ |
180 | |
181 | NodeX **FindNodeX(NodesX* nodesx,node_t id) |
182 | { |
183 | int start=0; |
184 | int end=nodesx->number-1; |
185 | int mid; |
186 | |
187 | assert(nodesx->sorted); /* Must be sorted */ |
188 | |
189 | /* Binary search - search key exact match only is required. |
190 | * |
191 | * # <- start | Check mid and move start or end if it doesn't match |
192 | * # | |
193 | * # | Since an exact match is wanted we can set end=mid-1 |
194 | * # <- mid | or start=mid+1 because we know that mid doesn't match. |
195 | * # | |
196 | * # | Eventually either end=start or end=start+1 and one of |
197 | * # <- end | start or end is the wanted one. |
198 | */ |
199 | |
200 | if(end<start) /* There are no nodes */ |
201 | return(NULL); |
202 | else if(id<nodesx->idata[start]->id) /* Check key is not before start */ |
203 | return(NULL); |
204 | else if(id>nodesx->idata[end]->id) /* Check key is not after end */ |
205 | return(NULL); |
206 | else |
207 | { |
208 | do |
209 | { |
210 | mid=(start+end)/2; /* Choose mid point */ |
211 | |
212 | if(nodesx->idata[mid]->id<id) /* Mid point is too low */ |
213 | start=mid+1; |
214 | else if(nodesx->idata[mid]->id>id) /* Mid point is too high */ |
215 | end=mid-1; |
216 | else /* Mid point is correct */ |
217 | return(&nodesx->idata[mid]); |
218 | } |
219 | while((end-start)>1); |
220 | |
221 | if(nodesx->idata[start]->id==id) /* Start is correct */ |
222 | return(&nodesx->idata[start]); |
223 | |
224 | if(nodesx->idata[end]->id==id) /* End is correct */ |
225 | return(&nodesx->idata[end]); |
226 | } |
227 | |
228 | return(NULL); |
229 | } |
230 | |
231 | |
232 | /*++++++++++++++++++++++++++++++++++++++ |
233 | Append a node to a newly created node list (unsorted). |
234 | |
235 | NodesX* nodesx The set of nodes to process. |
236 | |
237 | node_t id The node identification. |
238 | |
239 | float latitude The latitude of the node. |
240 | |
241 | float longitude The longitude of the node. |
242 | ++++++++++++++++++++++++++++++++++++++*/ |
243 | |
244 | void AppendNode(NodesX* nodesx,node_t id,float latitude,float longitude) |
245 | { |
246 | /* Check that the array has enough space. */ |
247 | |
248 | if(nodesx->xnumber==nodesx->alloced) |
249 | { |
250 | nodesx->alloced+=INCREMENT_NODES; |
251 | |
252 | nodesx->xdata=(NodeX*)realloc((void*)nodesx->xdata,nodesx->alloced*sizeof(NodeX)); |
253 | } |
254 | |
255 | /* Insert the node */ |
256 | |
257 | nodesx->xdata[nodesx->xnumber].id=id; |
258 | nodesx->xdata[nodesx->xnumber].super=0; |
259 | nodesx->xdata[nodesx->xnumber].latitude =floorf(latitude *LAT_LONG_SCALE)/LAT_LONG_SCALE; |
260 | nodesx->xdata[nodesx->xnumber].longitude=floorf(longitude*LAT_LONG_SCALE)/LAT_LONG_SCALE; |
261 | |
262 | nodesx->xnumber++; |
263 | |
264 | nodesx->sorted=0; |
265 | } |
266 | |
267 | |
268 | /*++++++++++++++++++++++++++++++++++++++ |
269 | Sort the node list. |
270 | |
271 | NodesX* nodesx The set of nodes to process. |
272 | ++++++++++++++++++++++++++++++++++++++*/ |
273 | |
274 | void SortNodeList(NodesX* nodesx) |
275 | { |
276 | int i; |
277 | int duplicate; |
278 | |
279 | printf("Sorting Nodes"); fflush(stdout); |
280 | |
281 | /* Allocate the arrays of pointers */ |
282 | |
283 | if(nodesx->idata) |
284 | nodesx->idata=realloc(nodesx->idata,nodesx->xnumber*sizeof(NodeX*)); |
285 | else |
286 | nodesx->idata=malloc(nodesx->xnumber*sizeof(NodeX*)); |
287 | |
288 | sort_again: |
289 | |
290 | nodesx->number=0; |
291 | |
292 | for(i=0;i<nodesx->xnumber;i++) |
293 | if(nodesx->xdata[i].id!=NO_NODE) |
294 | { |
295 | nodesx->idata[nodesx->number]=&nodesx->xdata[i]; |
296 | nodesx->number++; |
297 | } |
298 | |
299 | nodesx->sorted=1; |
300 | |
301 | /* Sort by id */ |
302 | |
303 | qsort(nodesx->idata,nodesx->number,sizeof(NodeX*),(int (*)(const void*,const void*))sort_by_id); |
304 | |
305 | duplicate=0; |
306 | |
307 | for(i=1;i<nodesx->number;i++) |
308 | { |
309 | if(nodesx->idata[i]->id==nodesx->idata[i-1]->id && |
310 | nodesx->idata[i]->id!=NO_NODE) |
311 | { |
312 | nodesx->idata[i-1]->id=NO_NODE; |
313 | duplicate++; |
314 | } |
315 | } |
316 | |
317 | if(duplicate) |
318 | { |
319 | printf(" - %d duplicates found; trying again.\nSorting Nodes",duplicate); fflush(stdout); |
320 | goto sort_again; |
321 | } |
322 | |
323 | printf("\rSorted Nodes \n"); fflush(stdout); |
324 | } |
325 | |
326 | |
327 | /*++++++++++++++++++++++++++++++++++++++ |
328 | Sort the nodes into id order. |
329 | |
330 | int sort_by_id Returns the comparison of the id fields. |
331 | |
332 | NodeX **a The first Node. |
333 | |
334 | NodeX **b The second Node. |
335 | ++++++++++++++++++++++++++++++++++++++*/ |
336 | |
337 | static int sort_by_id(NodeX **a,NodeX **b) |
338 | { |
339 | node_t a_id=(*a)->id; |
340 | node_t b_id=(*b)->id; |
341 | |
342 | if(a_id<b_id) |
343 | return(-1); |
344 | else if(a_id>b_id) |
345 | return(1); |
346 | else |
347 | return(0); |
348 | } |
349 | |
350 | |
351 | /*++++++++++++++++++++++++++++++++++++++ |
352 | Sort the node list geographically. |
353 | |
354 | NodesX* nodesx The set of nodes to process. |
355 | ++++++++++++++++++++++++++++++++++++++*/ |
356 | |
357 | void SortNodeListGeographically(NodesX* nodesx) |
358 | { |
359 | int i; |
360 | |
361 | assert(nodesx->sorted); /* Must be sorted */ |
362 | |
363 | printf("Sorting Nodes Geographically"); fflush(stdout); |
364 | |
365 | /* Sort geographically */ |
366 | |
367 | nodesx->gdata=(NodeX**)malloc(nodesx->number*sizeof(NodeX*)); |
368 | |
369 | for(i=0;i<nodesx->number;i++) |
370 | nodesx->gdata[i]=nodesx->idata[i]; |
371 | |
372 | qsort(nodesx->gdata,nodesx->number,sizeof(NodeX*),(int (*)(const void*,const void*))sort_by_lat_long); |
373 | |
374 | /* Work out the range of data */ |
375 | |
376 | nodesx->lat_min=2; |
377 | nodesx->lat_max=-2; |
378 | nodesx->lon_min=4; |
379 | nodesx->lon_max=-4; |
380 | |
381 | for(i=0;i<nodesx->number;i++) |
382 | { |
383 | if(nodesx->idata[i]->latitude<nodesx->lat_min) |
384 | nodesx->lat_min=nodesx->idata[i]->latitude; |
385 | if(nodesx->idata[i]->latitude>nodesx->lat_max) |
386 | nodesx->lat_max=nodesx->idata[i]->latitude; |
387 | if(nodesx->idata[i]->longitude<nodesx->lon_min) |
388 | nodesx->lon_min=nodesx->idata[i]->longitude; |
389 | if(nodesx->idata[i]->longitude>nodesx->lon_max) |
390 | nodesx->lon_max=nodesx->idata[i]->longitude; |
391 | } |
392 | |
393 | printf("\rSorted Nodes Geographically\n"); fflush(stdout); |
394 | } |
395 | |
396 | |
397 | /*++++++++++++++++++++++++++++++++++++++ |
398 | Sort the nodes into latitude and longitude order. |
399 | |
400 | int sort_by_lat_long Returns the comparison of the latitude and longitude fields. |
401 | |
402 | NodeX **a The first Node. |
403 | |
404 | NodeX **b The second Node. |
405 | ++++++++++++++++++++++++++++++++++++++*/ |
406 | |
407 | static int sort_by_lat_long(NodeX **a,NodeX **b) |
408 | { |
409 | int32_t a_lon=lat_long_to_bin((*a)->longitude); |
410 | int32_t b_lon=lat_long_to_bin((*b)->longitude); |
411 | |
412 | if(a_lon<b_lon) |
413 | return(-1); |
414 | else if(a_lon>b_lon) |
415 | return(1); |
416 | else |
417 | { |
418 | int32_t a_lat=lat_long_to_bin((*a)->latitude); |
419 | int32_t b_lat=lat_long_to_bin((*b)->latitude); |
420 | |
421 | if(a_lat<b_lat) |
422 | return(-1); |
423 | else if(a_lat>b_lat) |
424 | return(1); |
425 | else |
426 | return(0); |
427 | } |
428 | } |
429 | |
430 | |
431 | /*++++++++++++++++++++++++++++++++++++++ |
432 | Remove any nodes that are not part of a highway. |
433 | |
434 | NodesX *nodesx The complete node list. |
435 | |
436 | SegmentsX *segmentsx The list of segments. |
437 | ++++++++++++++++++++++++++++++++++++++*/ |
438 | |
439 | void RemoveNonHighwayNodes(NodesX *nodesx,SegmentsX *segmentsx) |
440 | { |
441 | int i; |
442 | int highway=0,nothighway=0; |
443 | |
444 | for(i=0;i<nodesx->xnumber;i++) |
445 | { |
446 | if(FindFirstSegmentX(segmentsx,nodesx->xdata[i].id)) |
447 | highway++; |
448 | else |
449 | { |
450 | nodesx->xdata[i].id=NO_NODE; |
451 | nothighway++; |
452 | } |
453 | |
454 | if(!((i+1)%10000)) |
455 | { |
456 | printf("\rChecking: Nodes=%d Highway=%d not-Highway=%d",i+1,highway,nothighway); |
457 | fflush(stdout); |
458 | } |
459 | } |
460 | |
461 | printf("\rChecked: Nodes=%d Highway=%d not-Highway=%d \n",nodesx->xnumber,highway,nothighway); |
462 | fflush(stdout); |
463 | } |
464 | |
465 | |
466 | /*++++++++++++++++++++++++++++++++++++++ |
467 | Create the real node data. |
468 | |
469 | NodesX *nodesx The set of nodes to use. |
470 | |
471 | int iteration The final super-node iteration. |
472 | ++++++++++++++++++++++++++++++++++++++*/ |
473 | |
474 | void CreateRealNodes(NodesX *nodesx,int iteration) |
475 | { |
476 | int i; |
477 | |
478 | assert(nodesx->sorted); /* Must be sorted */ |
479 | |
480 | /* Allocate the memory */ |
481 | |
482 | nodesx->ndata=(Node*)malloc(nodesx->number*sizeof(Node)); |
483 | |
484 | /* Loop through and allocate. */ |
485 | |
486 | for(i=0;i<nodesx->number;i++) |
487 | { |
488 | int32_t lat=(int32_t)(nodesx->idata[i]->latitude *LAT_LONG_SCALE); |
489 | int32_t lon=(int32_t)(nodesx->idata[i]->longitude*LAT_LONG_SCALE); |
490 | |
491 | nodesx->ndata[i].latoffset=lat%LAT_LONG_BIN; |
492 | nodesx->ndata[i].lonoffset=lon%LAT_LONG_BIN; |
493 | |
494 | nodesx->ndata[i].firstseg=SEGMENT(NO_SEGMENT); |
495 | |
496 | if(nodesx->idata[i]->super==iteration) |
497 | nodesx->ndata[i].firstseg|=NODE_SUPER; |
498 | |
499 | if(!((i+1)%10000)) |
500 | { |
501 | printf("\rCreating Real Nodes: Nodes=%d",i+1); |
502 | fflush(stdout); |
503 | } |
504 | } |
505 | |
506 | printf("\rCreating Real Nodes: Nodes=%d \n",nodesx->number); |
507 | fflush(stdout); |
508 | } |
509 | |
510 | |
511 | /*++++++++++++++++++++++++++++++++++++++ |
512 | Assign the segment indexes to the nodes. |
513 | |
514 | NodesX *nodesx The list of nodes to process. |
515 | |
516 | SegmentsX* segmentsx The set of segments to use. |
517 | ++++++++++++++++++++++++++++++++++++++*/ |
518 | |
519 | void IndexNodes(NodesX *nodesx,SegmentsX *segmentsx) |
520 | { |
521 | int i; |
522 | |
523 | assert(nodesx->sorted); /* Must be sorted */ |
524 | assert(segmentsx->sorted); /* Must be sorted */ |
525 | assert(segmentsx->sdata); /* Must have real segments */ |
526 | |
527 | /* Index the nodes */ |
528 | |
529 | for(i=0;i<segmentsx->number;i++) |
530 | { |
531 | NodeX **nodex1=FindNodeX(nodesx,segmentsx->ndata[i]->node1); |
532 | NodeX **nodex2=FindNodeX(nodesx,segmentsx->ndata[i]->node2); |
533 | Node *node1=&nodesx->ndata[nodex1-nodesx->idata]; |
534 | Node *node2=&nodesx->ndata[nodex2-nodesx->idata]; |
535 | |
536 | /* Check node1 */ |
537 | |
538 | if(SEGMENT(node1->firstseg)==SEGMENT(NO_SEGMENT)) |
539 | { |
540 | node1->firstseg^=SEGMENT(NO_SEGMENT); |
541 | node1->firstseg|=i; |
542 | } |
543 | else |
544 | { |
545 | index_t index=SEGMENT(node1->firstseg); |
546 | |
547 | do |
548 | { |
549 | if(segmentsx->ndata[index]->node1==segmentsx->ndata[i]->node1) |
550 | { |
551 | index++; |
552 | |
553 | if(index>=segmentsx->number || segmentsx->ndata[index]->node1!=segmentsx->ndata[i]->node1) |
554 | break; |
555 | } |
556 | else |
557 | { |
558 | if(segmentsx->sdata[index].next2==NO_NODE) |
559 | { |
560 | segmentsx->sdata[index].next2=i; |
561 | break; |
562 | } |
563 | else |
564 | index=segmentsx->sdata[index].next2; |
565 | } |
566 | } |
567 | while(1); |
568 | } |
569 | |
570 | /* Check node2 */ |
571 | |
572 | if(SEGMENT(node2->firstseg)==SEGMENT(NO_SEGMENT)) |
573 | { |
574 | node2->firstseg^=SEGMENT(NO_SEGMENT); |
575 | node2->firstseg|=i; |
576 | } |
577 | else |
578 | { |
579 | index_t index=SEGMENT(node2->firstseg); |
580 | |
581 | do |
582 | { |
583 | if(segmentsx->ndata[index]->node1==segmentsx->ndata[i]->node2) |
584 | { |
585 | index++; |
586 | |
587 | if(index>=segmentsx->number || segmentsx->ndata[index]->node1!=segmentsx->ndata[i]->node2) |
588 | break; |
589 | } |
590 | else |
591 | { |
592 | if(segmentsx->sdata[index].next2==NO_NODE) |
593 | { |
594 | segmentsx->sdata[index].next2=i; |
595 | break; |
596 | } |
597 | else |
598 | index=segmentsx->sdata[index].next2; |
599 | } |
600 | } |
601 | while(1); |
602 | } |
603 | |
604 | if(!((i+1)%10000)) |
605 | { |
606 | printf("\rIndexing Segments: Segments=%d",i+1); |
607 | fflush(stdout); |
608 | } |
609 | } |
610 | |
611 | printf("\rIndexed Segments: Segments=%d \n",segmentsx->number); |
612 | fflush(stdout); |
613 | } |
Properties
Name | Value |
---|---|
cvs:description | Extended nodes functions. |