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