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/routino.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2188 - (show annotations) (download) (as text)
Thu Aug 29 17:36:39 2024 UTC (6 months, 2 weeks ago) by amb
File MIME type: text/x-csrc
File size: 22363 byte(s)
Swap the order of arguments to calloc() function (new gcc warning).

1 /***************************************
2 Routino library functions file.
3
4 Part of the Routino routing software.
5 ******************/ /******************
6 This file Copyright 2015-2017, 2019, 2020, 2024 Andrew M. Bishop
7
8 This program is free software: you can redistribute it and/or modify
9 it under the terms of the GNU Affero General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Affero General Public License for more details.
17
18 You should have received a copy of the GNU Affero General Public License
19 along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ***************************************/
21
22 #include <stdlib.h>
23
24 #include "routino.h"
25
26 #include "types.h"
27 #include "nodes.h"
28 #include "segments.h"
29 #include "ways.h"
30 #include "relations.h"
31
32 #include "fakes.h"
33 #include "results.h"
34 #include "functions.h"
35 #include "profiles.h"
36 #include "translations.h"
37
38 #include "version.h"
39
40
41 /* Global variables */
42
43 /*+ Contains the libroutino API version number. +*/
44 DLL_PUBLIC const int Routino_APIVersion=ROUTINO_API_VERSION;
45
46 /*+ Contains the Routino version number. +*/
47 DLL_PUBLIC const char *Routino_Version=ROUTINO_VERSION;
48
49 /*+ Contains the error number of the most recent Routino function (one of the ROUTINO_ERROR_* values). +*/
50 DLL_PUBLIC int Routino_errno=ROUTINO_ERROR_NONE;
51
52 /*+ The function to be called to report on the routing progress. +*/
53 Routino_ProgressFunc progress_func=NULL;
54
55 /*+ The current state of the routing progress. +*/
56 double progress_value=0;
57
58 /*+ Set when the progress callback returns false in the routing function. +*/
59 int progress_abort=0;
60
61 /*+ The option to calculate the quickest route insted of the shortest. +*/
62 extern int option_quickest;
63
64 /*+ The options to select the format of the file output. +*/
65 extern int option_file_html,option_file_gpx_track,option_file_gpx_route,option_file_text,option_file_text_all,option_file_stdout;
66
67 /*+ The options to select the format of the linked list output. +*/
68 extern int option_list_html,option_list_html_all,option_list_text,option_list_text_all;
69
70
71 /* Static variables */
72
73 static distance_t distmax=km_to_distance(1);
74
75
76 /* Local types */
77
78 struct _Routino_Database
79 {
80 Nodes *nodes;
81 Segments *segments;
82 Ways *ways;
83 Relations *relations;
84 };
85
86 struct _Routino_Waypoint
87 {
88 index_t segment;
89 index_t node1,node2;
90 distance_t dist1,dist2;
91 };
92
93
94 /*++++++++++++++++++++++++++++++++++++++
95 Check the version of the library used by the caller against the library version
96
97 int Routino_Check_API_Version Returns ROUTINO_ERROR_NONE if OK or ROUTINO_ERROR_WRONG_VERSION if there is an error.
98
99 int caller_version The version of the API used in the caller.
100
101 This function should not be called directly, use the macro Routino_CheckAPIVersion() which takes no arguments.
102 ++++++++++++++++++++++++++++++++++++++*/
103
104 DLL_PUBLIC int Routino_Check_API_Version(int caller_version)
105 {
106 if(caller_version==Routino_APIVersion)
107 return(ROUTINO_ERROR_NONE);
108 else
109 return(ROUTINO_ERROR_WRONG_API_VERSION);
110 }
111
112
113 /*++++++++++++++++++++++++++++++++++++++
114 Load a database of files for Routino to use for routing.
115
116 Routino_Database *Routino_LoadDatabase Returns a pointer to the database.
117
118 const char *dirname The pathname of the directory containing the database files.
119
120 const char *prefix The prefix of the database files.
121 ++++++++++++++++++++++++++++++++++++++*/
122
123 DLL_PUBLIC Routino_Database *Routino_LoadDatabase(const char *dirname,const char *prefix)
124 {
125 char *nodes_filename;
126 char *segments_filename;
127 char *ways_filename;
128 char *relations_filename;
129 Routino_Database *database=NULL;
130
131 nodes_filename =FileName(dirname,prefix,"nodes.mem");
132 segments_filename =FileName(dirname,prefix,"segments.mem");
133 ways_filename =FileName(dirname,prefix,"ways.mem");
134 relations_filename=FileName(dirname,prefix,"relations.mem");
135
136 if(!ExistsFile(nodes_filename) || !ExistsFile(segments_filename) || !ExistsFile(ways_filename) || !ExistsFile(relations_filename))
137 {
138 Routino_errno=ROUTINO_ERROR_NO_DATABASE_FILES;
139 return(NULL);
140 }
141 else
142 {
143 database=calloc(1,sizeof(Routino_Database));
144
145 database->nodes =LoadNodeList (nodes_filename);
146 database->segments =LoadSegmentList (segments_filename);
147 database->ways =LoadWayList (ways_filename);
148 database->relations=LoadRelationList(relations_filename);
149 }
150
151 free(nodes_filename);
152 free(segments_filename);
153 free(ways_filename);
154 free(relations_filename);
155
156 if(!database->nodes || !database->segments || !database->ways || !database->relations)
157 {
158 Routino_UnloadDatabase(database);
159 database=NULL;
160
161 Routino_errno=ROUTINO_ERROR_BAD_DATABASE_FILES;
162 }
163
164 if(database)
165 {
166 Routino_errno=ROUTINO_ERROR_NONE;
167 return(database);
168 }
169 else
170 return(NULL);
171 }
172
173
174 /*++++++++++++++++++++++++++++++++++++++
175 Close the database files that were opened by a call to Routino_LoadDatabase().
176
177 Routino_Database *database The database to close.
178 ++++++++++++++++++++++++++++++++++++++*/
179
180 DLL_PUBLIC void Routino_UnloadDatabase(Routino_Database *database)
181 {
182 if(!database)
183 Routino_errno=ROUTINO_ERROR_NO_DATABASE;
184 else
185 {
186 if(database->nodes) DestroyNodeList (database->nodes);
187 if(database->segments) DestroySegmentList (database->segments);
188 if(database->ways) DestroyWayList (database->ways);
189 if(database->relations) DestroyRelationList(database->relations);
190
191 free(database);
192
193 Routino_errno=ROUTINO_ERROR_NONE;
194 }
195 }
196
197
198 /*++++++++++++++++++++++++++++++++++++++
199 Parse a Routino XML file containing profiles, must be called before selecting a profile.
200
201 int Routino_ParseXMLProfiles Returns non-zero in case of an error or zero if there was no error.
202
203 const char *filename The full pathname of the file to read.
204 ++++++++++++++++++++++++++++++++++++++*/
205
206 DLL_PUBLIC int Routino_ParseXMLProfiles(const char *filename)
207 {
208 int retval;
209
210 retval=ParseXMLProfiles(filename,NULL,1);
211
212 if(retval==1)
213 retval=ROUTINO_ERROR_NO_PROFILES_XML;
214 else if(retval==2)
215 retval=ROUTINO_ERROR_BAD_PROFILES_XML;
216
217 Routino_errno=retval;
218 return(retval);
219 }
220
221
222 /*++++++++++++++++++++++++++++++++++++++
223 Return a list of the profile names that have been loaded from the XML file.
224
225 char **Routino_GetProfileNames Returns a NULL terminated list of strings - all allocated.
226 ++++++++++++++++++++++++++++++++++++++*/
227
228 DLL_PUBLIC char **Routino_GetProfileNames(void)
229 {
230 Routino_errno=ROUTINO_ERROR_NONE;
231
232 return(GetProfileNames());
233 }
234
235
236 /*++++++++++++++++++++++++++++++++++++++
237 Select a specific routing profile from the set of Routino profiles that have been loaded from the XML file or NULL in case of an error.
238
239 Routino_Profile *Routino_GetProfile Returns a pointer to an internal data structure - do not free.
240
241 const char *name The name of the profile to select.
242 ++++++++++++++++++++++++++++++++++++++*/
243
244 DLL_PUBLIC Routino_Profile *Routino_GetProfile(const char *name)
245 {
246 Profile *profile=GetProfile(name);
247
248 if(profile)
249 Routino_errno=ROUTINO_ERROR_NONE;
250 else
251 Routino_errno=ROUTINO_ERROR_NO_SUCH_PROFILE;
252
253 return(profile);
254 }
255
256
257 /*++++++++++++++++++++++++++++++++++++++
258 Free the internal memory that was allocated for the Routino profiles loaded from the XML file.
259 ++++++++++++++++++++++++++++++++++++++*/
260
261 DLL_PUBLIC void Routino_FreeXMLProfiles(void)
262 {
263 Routino_errno=ROUTINO_ERROR_NONE;
264
265 FreeXMLProfiles();
266 }
267
268
269 /*++++++++++++++++++++++++++++++++++++++
270 Parse a Routino XML file containing translations, must be called before selecting a translation.
271
272 int Routino_ParseXMLTranslations Returns non-zero in case of an error or zero if there was no error.
273
274 const char *filename The full pathname of the file to read.
275 ++++++++++++++++++++++++++++++++++++++*/
276
277 DLL_PUBLIC int Routino_ParseXMLTranslations(const char *filename)
278 {
279 int retval;
280
281 retval=ParseXMLTranslations(filename,NULL,1);
282
283 if(retval==1)
284 retval=ROUTINO_ERROR_NO_TRANSLATIONS_XML;
285 else if(retval==2)
286 retval=ROUTINO_ERROR_BAD_TRANSLATIONS_XML;
287
288 Routino_errno=retval;
289 return(retval);
290 }
291
292
293 /*++++++++++++++++++++++++++++++++++++++
294 Return a list of the translation languages that have been loaded from the XML file.
295
296 char **Routino_GetTranslationLanguages Returns a NULL terminated list of strings - all allocated.
297 ++++++++++++++++++++++++++++++++++++++*/
298
299 DLL_PUBLIC char **Routino_GetTranslationLanguages(void)
300 {
301 Routino_errno=ROUTINO_ERROR_NONE;
302
303 return(GetTranslationLanguages());
304 }
305
306
307 /*++++++++++++++++++++++++++++++++++++++
308 Return a list of the full names of the translation languages that have been loaded from the XML file.
309
310 char **Routino_GetTranslationLanguageFullNames Returns a NULL terminated list of strings - all allocated.
311 ++++++++++++++++++++++++++++++++++++++*/
312
313 DLL_PUBLIC char **Routino_GetTranslationLanguageFullNames(void)
314 {
315 Routino_errno=ROUTINO_ERROR_NONE;
316
317 return(GetTranslationLanguageFullNames());
318 }
319
320
321 /*++++++++++++++++++++++++++++++++++++++
322 Select a specific translation from the set of Routino translations that have been loaded from the XML file or NULL in case of an error.
323
324 Routino_Translation *Routino_GetTranslation Returns a pointer to an internal data structure - do not free.
325
326 const char *language The language to select (as a country code, e.g. 'en', 'de') or an empty string for the first in the file or NULL for the built-in English version.
327 ++++++++++++++++++++++++++++++++++++++*/
328
329 DLL_PUBLIC Routino_Translation *Routino_GetTranslation(const char *language)
330 {
331 Translation *translation=GetTranslation(language);
332
333 if(translation)
334 Routino_errno=ROUTINO_ERROR_NONE;
335 else
336 Routino_errno=ROUTINO_ERROR_NO_SUCH_TRANSLATION;
337
338 return(translation);
339 }
340
341
342 /*++++++++++++++++++++++++++++++++++++++
343 Free the internal memory that was allocated for the Routino translations loaded from the XML file.
344 ++++++++++++++++++++++++++++++++++++++*/
345
346 DLL_PUBLIC void Routino_FreeXMLTranslations(void)
347 {
348 Routino_errno=ROUTINO_ERROR_NONE;
349
350 FreeXMLTranslations();
351 }
352
353
354 /*++++++++++++++++++++++++++++++++++++++
355 Create a fully formed Routino Profile from a Routino User Profile.
356
357 Routino_Profile *Routino_CreateProfileFromUserProfile Returns an allocated Routino Profile.
358
359 Routino_UserProfile *profile The user specified profile to convert (not modified by this).
360 ++++++++++++++++++++++++++++++++++++++*/
361
362 DLL_PUBLIC Routino_Profile *Routino_CreateProfileFromUserProfile(Routino_UserProfile *profile)
363 {
364 Routino_Profile *rprofile=calloc(1,sizeof(Routino_Profile));
365 int i;
366
367 Routino_errno=ROUTINO_ERROR_NONE;
368
369 if(!profile)
370 {
371 Routino_errno=ROUTINO_ERROR_NO_PROFILE;
372 free(rprofile);
373 return(NULL);
374 }
375
376 if(profile->transport<=0 || profile->transport>=Transport_Count)
377 Routino_errno=ROUTINO_ERROR_BAD_USER_PROFILE;
378 else
379 rprofile->transport=profile->transport;
380
381 for(i=1;i<Highway_Count;i++)
382 {
383 if(profile->highway[i]<0 || profile->highway[i]>1)
384 Routino_errno=ROUTINO_ERROR_BAD_USER_PROFILE;
385 else
386 rprofile->highway[i]=profile->highway[i];
387
388 if(profile->speed[i]<=0)
389 Routino_errno=ROUTINO_ERROR_BAD_USER_PROFILE;
390 else
391 rprofile->speed[i]=kph_to_speed(profile->speed[i]);
392 }
393
394 for(i=1;i<Property_Count;i++)
395 {
396 if(profile->props[i]<0 || profile->props[i]>1)
397 Routino_errno=ROUTINO_ERROR_BAD_USER_PROFILE;
398 else
399 rprofile->props[i]=profile->props[i];
400 }
401
402 if(profile->weight<=0)
403 Routino_errno=ROUTINO_ERROR_BAD_USER_PROFILE;
404 else
405 rprofile->weight=tonnes_to_weight(profile->weight);
406
407 if(profile->height<=0)
408 Routino_errno=ROUTINO_ERROR_BAD_USER_PROFILE;
409 else
410 rprofile->height=metres_to_height(profile->height);
411
412 if(profile->width<=0)
413 Routino_errno=ROUTINO_ERROR_BAD_USER_PROFILE;
414 else
415 rprofile->width=metres_to_width(profile->width);
416
417 if(profile->length<=0)
418 Routino_errno=ROUTINO_ERROR_BAD_USER_PROFILE;
419 else
420 rprofile->length=metres_to_length(profile->length);
421
422 if(Routino_errno==ROUTINO_ERROR_NONE)
423 return(rprofile);
424
425 free(rprofile);
426 return(NULL);
427 }
428
429
430 /*++++++++++++++++++++++++++++++++++++++
431 Create a Routino User Profile from a Routino Profile loaded from an XML file.
432
433 Routino_UserProfile *Routino_CreateUserProfileFromProfile Returns an allocated Routino User Profile.
434
435 Routino_Profile *profile The Routino Profile to convert (not modified by this).
436 ++++++++++++++++++++++++++++++++++++++*/
437
438 DLL_PUBLIC Routino_UserProfile *Routino_CreateUserProfileFromProfile(Routino_Profile *profile)
439 {
440 Routino_UserProfile *uprofile=calloc(1,sizeof(Routino_UserProfile));
441 int i;
442
443 Routino_errno=ROUTINO_ERROR_NONE;
444
445 if(!profile)
446 {
447 Routino_errno=ROUTINO_ERROR_NO_PROFILE;
448 free(uprofile);
449 return(NULL);
450 }
451
452 uprofile->transport=profile->transport;
453
454 for(i=1;i<Highway_Count;i++)
455 {
456 uprofile->highway[i]=profile->highway[i];
457
458 uprofile->speed[i]=speed_to_kph(profile->speed[i]);
459 }
460
461 for(i=1;i<Property_Count;i++)
462 uprofile->props[i]=profile->props[i];
463
464 uprofile->weight=weight_to_tonnes(profile->weight);
465
466 uprofile->height=height_to_metres(profile->height);
467
468 uprofile->width=width_to_metres(profile->width);
469
470 uprofile->length=length_to_metres(profile->length);
471
472 return(uprofile);
473 }
474
475
476 /*++++++++++++++++++++++++++++++++++++++
477 Validates that a selected routing profile is valid for use with the selected routing database.
478
479 int Routino_ValidateProfile Returns zero if OK or something else in case of an error.
480
481 Routino_Database *database The Routino database to use.
482
483 Routino_Profile *profile The Routino profile to validate.
484 ++++++++++++++++++++++++++++++++++++++*/
485
486 DLL_PUBLIC int Routino_ValidateProfile(Routino_Database *database,Routino_Profile *profile)
487 {
488 Routino_errno=ROUTINO_ERROR_NONE;
489
490 if(!database)
491 {
492 Routino_errno=ROUTINO_ERROR_NO_DATABASE;
493 return Routino_errno;
494 }
495
496 if(!profile)
497 {
498 Routino_errno=ROUTINO_ERROR_NO_PROFILE;
499 return Routino_errno;
500 }
501
502 if(UpdateProfile(profile,database->ways))
503 Routino_errno=ROUTINO_ERROR_PROFILE_DATABASE_ERR;
504
505 return(Routino_errno);
506 }
507
508
509 /*++++++++++++++++++++++++++++++++++++++
510 Finds the nearest point in the database to the specified latitude and longitude.
511
512 Routino_Waypoint *Routino_FindWaypoint Returns a pointer to a newly allocated Routino waypoint or NULL if none could be found.
513
514 Routino_Database *database The Routino database to use.
515
516 Routino_Profile *profile The Routino profile to use.
517
518 double latitude The latitude in degrees of the point.
519
520 double longitude The longitude in degrees of the point.
521 ++++++++++++++++++++++++++++++++++++++*/
522
523 DLL_PUBLIC Routino_Waypoint *Routino_FindWaypoint(Routino_Database *database,Routino_Profile *profile,double latitude,double longitude)
524 {
525 distance_t dist;
526 Routino_Waypoint *waypoint;
527
528 if(!database)
529 {
530 Routino_errno=ROUTINO_ERROR_NO_DATABASE;
531 return(NULL);
532 }
533
534 if(!profile)
535 {
536 Routino_errno=ROUTINO_ERROR_NO_PROFILE;
537 return(NULL);
538 }
539
540 if(!profile->transports)
541 {
542 Routino_errno=ROUTINO_ERROR_NOTVALID_PROFILE;
543 return(NULL);
544 }
545
546 waypoint=calloc(1,sizeof(Routino_Waypoint));
547
548 waypoint->segment=FindClosestSegment(database->nodes,database->segments,database->ways,
549 degrees_to_radians(latitude),degrees_to_radians(longitude),distmax,profile,
550 &dist,&waypoint->node1,&waypoint->node2,&waypoint->dist1,&waypoint->dist2);
551
552 if(waypoint->segment==NO_SEGMENT)
553 {
554 free(waypoint);
555
556 Routino_errno=ROUTINO_ERROR_NO_NEARBY_HIGHWAY;
557 return(NULL);
558 }
559
560 Routino_errno=ROUTINO_ERROR_NONE;
561 return(waypoint);
562 }
563
564
565 /*++++++++++++++++++++++++++++++++++++++
566 Calculate a route using a loaded database, chosen profile, chosen translation and set of waypoints.
567
568 Routino_Output *Routino_CalculateRoute Returns the head of a linked list of route data (if requested) or NULL.
569
570 Routino_Database *database The loaded database to use.
571
572 Routino_Profile *profile The chosen routing profile to use.
573
574 Routino_Translation *translation The chosen translation information to use.
575
576 Routino_Waypoint **waypoints The set of waypoints.
577
578 int nwaypoints The number of waypoints.
579
580 int options The set of routing options (ROUTINO_ROUTE_*) ORed together.
581
582 Routino_ProgressFunc progress A function to be called occasionally to report progress or NULL.
583 ++++++++++++++++++++++++++++++++++++++*/
584
585 DLL_PUBLIC Routino_Output *Routino_CalculateRoute(Routino_Database *database,Routino_Profile *profile,Routino_Translation *translation,
586 Routino_Waypoint **waypoints,int nwaypoints,int options,Routino_ProgressFunc progress)
587 {
588 int first_waypoint,last_waypoint,this_waypoint,nwaypoints_routed,inc_dec_waypoint,start_waypoint,finish_waypoint=-1;
589 index_t start_node,finish_node=NO_NODE;
590 index_t join_segment=NO_SEGMENT;
591 Results **results;
592 Routino_Output *output=NULL;
593
594 /* Check the input data */
595
596 if(!database)
597 {
598 Routino_errno=ROUTINO_ERROR_NO_DATABASE;
599 return(NULL);
600 }
601
602 if(!profile)
603 {
604 Routino_errno=ROUTINO_ERROR_NO_PROFILE;
605 return(NULL);
606 }
607
608 if(!profile->transports)
609 {
610 Routino_errno=ROUTINO_ERROR_NOTVALID_PROFILE;
611 return(NULL);
612 }
613
614 if(!translation)
615 {
616 Routino_errno=ROUTINO_ERROR_NO_TRANSLATION;
617 return(NULL);
618 }
619
620 /* Extract the options */
621
622 if(options&ROUTINO_ROUTE_QUICKEST) option_quickest=1; else option_quickest=0;
623
624 if(options&ROUTINO_ROUTE_FILE_HTML) option_file_html=1; else option_file_html=0;
625 if(options&ROUTINO_ROUTE_FILE_GPX_TRACK) option_file_gpx_track=1; else option_file_gpx_track=0;
626 if(options&ROUTINO_ROUTE_FILE_GPX_ROUTE) option_file_gpx_route=1; else option_file_gpx_route=0;
627 if(options&ROUTINO_ROUTE_FILE_TEXT) option_file_text=1; else option_file_text=0;
628 if(options&ROUTINO_ROUTE_FILE_TEXT_ALL) option_file_text_all=1; else option_file_text_all=0;
629
630 if(options&ROUTINO_ROUTE_FILE_STDOUT) option_file_stdout=1; else option_file_stdout=0;
631
632 if(option_file_stdout && (option_file_html+option_file_gpx_track+option_file_gpx_route+option_file_text+option_file_text_all)!=1)
633 {
634 Routino_errno=ROUTINO_ERROR_BAD_OPTIONS;
635 return(NULL);
636 }
637
638 if(options&ROUTINO_ROUTE_LIST_HTML) option_list_html=1; else option_list_html=0;
639 if(options&ROUTINO_ROUTE_LIST_HTML_ALL) option_list_html_all=1; else option_list_html_all=0;
640 if(options&ROUTINO_ROUTE_LIST_TEXT) option_list_text=1; else option_list_text=0;
641 if(options&ROUTINO_ROUTE_LIST_TEXT_ALL) option_list_text_all=1; else option_list_text_all=0;
642
643 if((option_list_html+option_list_html_all+option_list_text+option_list_text_all)>1)
644 {
645 Routino_errno=ROUTINO_ERROR_BAD_OPTIONS;
646 return(NULL);
647 }
648
649 /* Set up the progress callback */
650
651 progress_func=progress;
652 progress_value=0.0;
653 progress_abort=0;
654
655 /* Check for loop and reverse options */
656
657 if(options&ROUTINO_ROUTE_LOOP)
658 nwaypoints_routed=nwaypoints+1;
659 else
660 nwaypoints_routed=nwaypoints;
661
662 if(options&ROUTINO_ROUTE_REVERSE)
663 {
664 first_waypoint=nwaypoints_routed-1;
665 last_waypoint=0;
666
667 inc_dec_waypoint=-1;
668 }
669 else
670 {
671 first_waypoint=0;
672 last_waypoint=nwaypoints_routed-1;
673
674 inc_dec_waypoint=1;
675 }
676
677 /* Loop through all pairs of waypoints */
678
679 results=calloc(nwaypoints,sizeof(Results*));
680
681 for(this_waypoint=first_waypoint;this_waypoint!=(last_waypoint+inc_dec_waypoint);this_waypoint+=inc_dec_waypoint)
682 {
683 int waypoint=this_waypoint%nwaypoints;
684 int waypoint_count=(this_waypoint-first_waypoint)*inc_dec_waypoint;
685
686 if(progress_func)
687 {
688 progress_value=(double)waypoint_count/(double)(nwaypoints_routed+1);
689
690 if(!progress_func(progress_value))
691 {
692 Routino_errno=ROUTINO_ERROR_PROGRESS_ABORTED;
693 goto tidy_and_exit;
694 }
695 }
696
697 start_waypoint=finish_waypoint;
698 start_node=finish_node;
699
700 finish_waypoint=waypoint+1;
701 finish_node=CreateFakes(database->nodes,database->segments,finish_waypoint,
702 LookupSegment(database->segments,waypoints[waypoint]->segment,1),
703 waypoints[waypoint]->node1,waypoints[waypoint]->node2,waypoints[waypoint]->dist1,waypoints[waypoint]->dist2);
704
705 if(waypoint_count==0)
706 continue;
707
708 results[waypoint_count-1]=CalculateRoute(database->nodes,database->segments,database->ways,database->relations,
709 profile,start_node,join_segment,finish_node,start_waypoint,finish_waypoint);
710
711 if(!results[waypoint_count-1])
712 {
713 if(progress_func && progress_abort)
714 Routino_errno=ROUTINO_ERROR_PROGRESS_ABORTED;
715 else
716 Routino_errno=ROUTINO_ERROR_NO_ROUTE_1-1+start_waypoint;
717
718 goto tidy_and_exit;
719 }
720
721 join_segment=results[waypoint_count-1]->last_segment;
722 }
723
724 if(progress_func)
725 {
726 progress_value=(double)this_waypoint/(double)(nwaypoints_routed+1);
727
728 if(!progress_func(progress_value))
729 {
730 Routino_errno=ROUTINO_ERROR_PROGRESS_ABORTED;
731 goto tidy_and_exit;
732 }
733 }
734
735 /* Print the route */
736
737 output=PrintRoute(results,nwaypoints_routed-1,database->nodes,database->segments,database->ways,database->relations,profile,translation);
738
739 if(progress_func && !progress_func(1.0))
740 {
741 Routino_errno=ROUTINO_ERROR_PROGRESS_ABORTED;
742 goto tidy_and_exit;
743 }
744
745 /* Tidy up and exit */
746
747 tidy_and_exit:
748
749 DeleteFakeNodes();
750
751 for(this_waypoint=0;this_waypoint<nwaypoints;this_waypoint++)
752 if(results[this_waypoint])
753 FreeResultsList(results[this_waypoint]);
754
755 free(results);
756
757 return(output);
758 }
759
760
761 /*++++++++++++++++++++++++++++++++++++++
762 Delete the linked list created by Routino_CalculateRoute.
763
764 Routino_Output *output The output to be deleted.
765 ++++++++++++++++++++++++++++++++++++++*/
766
767 DLL_PUBLIC void Routino_DeleteRoute(Routino_Output *output)
768 {
769 while(output)
770 {
771 Routino_Output *next=output->next;
772
773 if(output->name)
774 free(output->name);
775
776 if(output->desc1)
777 free(output->desc1);
778
779 if(output->desc2)
780 free(output->desc2);
781
782 if(output->desc3)
783 free(output->desc3);
784
785 free(output);
786
787 output=next;
788 }
789 }