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 1989 - (show annotations) (download) (as text)
Wed Apr 17 17:54:45 2019 UTC (5 years, 11 months ago) by amb
File MIME type: text/x-csrc
File size: 21939 byte(s)
Rename some structure members and function names to reflect more
clearly their meaning (mostly change "allow" to "transport").  No
changes to file formats or API.

1 /***************************************
2 Routino library functions file.
3
4 Part of the Routino routing software.
5 ******************/ /******************
6 This file Copyright 2015-2017, 2019 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(nodes_filename) || !ExistsFile(nodes_filename) || !ExistsFile(nodes_filename))
137 {
138 Routino_errno=ROUTINO_ERROR_NO_DATABASE_FILES;
139 return(NULL);
140 }
141 else
142 {
143 database=calloc(sizeof(Routino_Database),1);
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->transport<=0 || profile->transport>=Transport_Count)
370 Routino_errno=ROUTINO_ERROR_BAD_USER_PROFILE;
371 else
372 rprofile->transport=profile->transport;
373
374 for(i=1;i<Highway_Count;i++)
375 {
376 if(profile->highway[i]<0 || profile->highway[i]>1)
377 Routino_errno=ROUTINO_ERROR_BAD_USER_PROFILE;
378 else
379 rprofile->highway[i]=profile->highway[i];
380
381 if(profile->speed[i]<=0)
382 Routino_errno=ROUTINO_ERROR_BAD_USER_PROFILE;
383 else
384 rprofile->speed[i]=kph_to_speed(profile->speed[i]);
385 }
386
387 for(i=1;i<Property_Count;i++)
388 {
389 if(profile->props[i]<0 || profile->props[i]>1)
390 Routino_errno=ROUTINO_ERROR_BAD_USER_PROFILE;
391 else
392 rprofile->props[i]=profile->props[i];
393 }
394
395 if(profile->weight<=0)
396 Routino_errno=ROUTINO_ERROR_BAD_USER_PROFILE;
397 else
398 rprofile->weight=tonnes_to_weight(profile->weight);
399
400 if(profile->height<=0)
401 Routino_errno=ROUTINO_ERROR_BAD_USER_PROFILE;
402 else
403 rprofile->height=metres_to_height(profile->height);
404
405 if(profile->width<=0)
406 Routino_errno=ROUTINO_ERROR_BAD_USER_PROFILE;
407 else
408 rprofile->width=metres_to_width(profile->width);
409
410 if(profile->length<=0)
411 Routino_errno=ROUTINO_ERROR_BAD_USER_PROFILE;
412 else
413 rprofile->length=metres_to_length(profile->length);
414
415 if(Routino_errno==ROUTINO_ERROR_NONE)
416 return(rprofile);
417
418 free(rprofile);
419 return(NULL);
420 }
421
422
423 /*++++++++++++++++++++++++++++++++++++++
424 Create a Routino User Profile from a Routino Profile loaded from an XML file.
425
426 Routino_UserProfile *Routino_CreateUserProfileFromProfile Returns an allocated Routino User Profile.
427
428 Routino_Profile *profile The Routino Profile to convert (not modified by this).
429 ++++++++++++++++++++++++++++++++++++++*/
430
431 DLL_PUBLIC Routino_UserProfile *Routino_CreateUserProfileFromProfile(Routino_Profile *profile)
432 {
433 Routino_UserProfile *uprofile=calloc(1,sizeof(Routino_UserProfile));
434 int i;
435
436 Routino_errno=ROUTINO_ERROR_NONE;
437
438 uprofile->transport=profile->transport;
439
440 for(i=1;i<Highway_Count;i++)
441 {
442 uprofile->highway[i]=profile->highway[i];
443
444 uprofile->speed[i]=speed_to_kph(profile->speed[i]);
445 }
446
447 for(i=1;i<Property_Count;i++)
448 uprofile->props[i]=profile->props[i];
449
450 uprofile->weight=weight_to_tonnes(profile->weight);
451
452 uprofile->height=height_to_metres(profile->height);
453
454 uprofile->width=width_to_metres(profile->width);
455
456 uprofile->length=length_to_metres(profile->length);
457
458 return(uprofile);
459 }
460
461
462 /*++++++++++++++++++++++++++++++++++++++
463 Validates that a selected routing profile is valid for use with the selected routing database.
464
465 int Routino_ValidateProfile Returns zero if OK or something else in case of an error.
466
467 Routino_Database *database The Routino database to use.
468
469 Routino_Profile *profile The Routino profile to validate.
470 ++++++++++++++++++++++++++++++++++++++*/
471
472 DLL_PUBLIC int Routino_ValidateProfile(Routino_Database *database,Routino_Profile *profile)
473 {
474 Routino_errno=ROUTINO_ERROR_NONE;
475
476 if(UpdateProfile(profile,database->ways))
477 Routino_errno=ROUTINO_ERROR_PROFILE_DATABASE_ERR;
478
479 return(Routino_errno);
480 }
481
482
483 /*++++++++++++++++++++++++++++++++++++++
484 Finds the nearest point in the database to the specified latitude and longitude.
485
486 Routino_Waypoint *Routino_FindWaypoint Returns a pointer to a newly allocated Routino waypoint or NULL if none could be found.
487
488 Routino_Database *database The Routino database to use.
489
490 Routino_Profile *profile The Routino profile to use.
491
492 double latitude The latitude in degrees of the point.
493
494 double longitude The longitude in degrees of the point.
495 ++++++++++++++++++++++++++++++++++++++*/
496
497 DLL_PUBLIC Routino_Waypoint *Routino_FindWaypoint(Routino_Database *database,Routino_Profile *profile,double latitude,double longitude)
498 {
499 distance_t dist;
500 Routino_Waypoint *waypoint;
501
502 if(!database)
503 {
504 Routino_errno=ROUTINO_ERROR_NO_DATABASE;
505 return(NULL);
506 }
507
508 if(!profile)
509 {
510 Routino_errno=ROUTINO_ERROR_NO_PROFILE;
511 return(NULL);
512 }
513
514 if(!profile->transports)
515 {
516 Routino_errno=ROUTINO_ERROR_NOTVALID_PROFILE;
517 return(NULL);
518 }
519
520 waypoint=calloc(sizeof(Routino_Waypoint),1);
521
522 waypoint->segment=FindClosestSegment(database->nodes,database->segments,database->ways,
523 degrees_to_radians(latitude),degrees_to_radians(longitude),distmax,profile,
524 &dist,&waypoint->node1,&waypoint->node2,&waypoint->dist1,&waypoint->dist2);
525
526 if(waypoint->segment==NO_SEGMENT)
527 {
528 free(waypoint);
529
530 Routino_errno=ROUTINO_ERROR_NO_NEARBY_HIGHWAY;
531 return(NULL);
532 }
533
534 Routino_errno=ROUTINO_ERROR_NONE;
535 return(waypoint);
536 }
537
538
539 /*++++++++++++++++++++++++++++++++++++++
540 Calculate a route using a loaded database, chosen profile, chosen translation and set of waypoints.
541
542 Routino_Output *Routino_CalculateRoute Returns the head of a linked list of route data (if requested) or NULL.
543
544 Routino_Database *database The loaded database to use.
545
546 Routino_Profile *profile The chosen routing profile to use.
547
548 Routino_Translation *translation The chosen translation information to use.
549
550 Routino_Waypoint **waypoints The set of waypoints.
551
552 int nwaypoints The number of waypoints.
553
554 int options The set of routing options (ROUTINO_ROUTE_*) ORed together.
555
556 Routino_ProgressFunc progress A function to be called occasionally to report progress or NULL.
557 ++++++++++++++++++++++++++++++++++++++*/
558
559 DLL_PUBLIC Routino_Output *Routino_CalculateRoute(Routino_Database *database,Routino_Profile *profile,Routino_Translation *translation,
560 Routino_Waypoint **waypoints,int nwaypoints,int options,Routino_ProgressFunc progress)
561 {
562 int first_waypoint,last_waypoint,this_waypoint,nwaypoints_routed,inc_dec_waypoint,start_waypoint,finish_waypoint=-1;
563 index_t start_node,finish_node=NO_NODE;
564 index_t join_segment=NO_SEGMENT;
565 Results **results;
566 Routino_Output *output=NULL;
567
568 /* Check the input data */
569
570 if(!database)
571 {
572 Routino_errno=ROUTINO_ERROR_NO_DATABASE;
573 return(NULL);
574 }
575
576 if(!profile)
577 {
578 Routino_errno=ROUTINO_ERROR_NO_PROFILE;
579 return(NULL);
580 }
581
582 if(!profile->transports)
583 {
584 Routino_errno=ROUTINO_ERROR_NOTVALID_PROFILE;
585 return(NULL);
586 }
587
588 if(!translation)
589 {
590 Routino_errno=ROUTINO_ERROR_NO_TRANSLATION;
591 return(NULL);
592 }
593
594 /* Extract the options */
595
596 if(options&ROUTINO_ROUTE_QUICKEST) option_quickest=1; else option_quickest=0;
597
598 if(options&ROUTINO_ROUTE_FILE_HTML) option_file_html=1; else option_file_html=0;
599 if(options&ROUTINO_ROUTE_FILE_GPX_TRACK) option_file_gpx_track=1; else option_file_gpx_track=0;
600 if(options&ROUTINO_ROUTE_FILE_GPX_ROUTE) option_file_gpx_route=1; else option_file_gpx_route=0;
601 if(options&ROUTINO_ROUTE_FILE_TEXT) option_file_text=1; else option_file_text=0;
602 if(options&ROUTINO_ROUTE_FILE_TEXT_ALL) option_file_text_all=1; else option_file_text_all=0;
603
604 if(options&ROUTINO_ROUTE_FILE_STDOUT) option_file_stdout=1; else option_file_stdout=0;
605
606 if(option_file_stdout && (option_file_html+option_file_gpx_track+option_file_gpx_route+option_file_text+option_file_text_all)!=1)
607 {
608 Routino_errno=ROUTINO_ERROR_BAD_OPTIONS;
609 return(NULL);
610 }
611
612 if(options&ROUTINO_ROUTE_LIST_HTML) option_list_html=1; else option_list_html=0;
613 if(options&ROUTINO_ROUTE_LIST_HTML_ALL) option_list_html_all=1; else option_list_html_all=0;
614 if(options&ROUTINO_ROUTE_LIST_TEXT) option_list_text=1; else option_list_text=0;
615 if(options&ROUTINO_ROUTE_LIST_TEXT_ALL) option_list_text_all=1; else option_list_text_all=0;
616
617 if((option_list_html+option_list_html_all+option_list_text+option_list_text_all)>1)
618 {
619 Routino_errno=ROUTINO_ERROR_BAD_OPTIONS;
620 return(NULL);
621 }
622
623 /* Set up the progress callback */
624
625 progress_func=progress;
626 progress_value=0.0;
627 progress_abort=0;
628
629 /* Check for loop and reverse options */
630
631 if(options&ROUTINO_ROUTE_LOOP)
632 nwaypoints_routed=nwaypoints+1;
633 else
634 nwaypoints_routed=nwaypoints;
635
636 if(options&ROUTINO_ROUTE_REVERSE)
637 {
638 first_waypoint=nwaypoints_routed-1;
639 last_waypoint=0;
640
641 inc_dec_waypoint=-1;
642 }
643 else
644 {
645 first_waypoint=0;
646 last_waypoint=nwaypoints_routed-1;
647
648 inc_dec_waypoint=1;
649 }
650
651 /* Loop through all pairs of waypoints */
652
653 results=calloc(sizeof(Results*),nwaypoints);
654
655 for(this_waypoint=first_waypoint;this_waypoint!=(last_waypoint+inc_dec_waypoint);this_waypoint+=inc_dec_waypoint)
656 {
657 int waypoint=this_waypoint%nwaypoints;
658 int waypoint_count=(this_waypoint-first_waypoint)*inc_dec_waypoint;
659
660 if(progress_func)
661 {
662 progress_value=(double)waypoint_count/(double)(nwaypoints_routed+1);
663
664 if(!progress_func(progress_value))
665 {
666 Routino_errno=ROUTINO_ERROR_PROGRESS_ABORTED;
667 goto tidy_and_exit;
668 }
669 }
670
671 start_waypoint=finish_waypoint;
672 start_node=finish_node;
673
674 finish_waypoint=waypoint+1;
675 finish_node=CreateFakes(database->nodes,database->segments,finish_waypoint,
676 LookupSegment(database->segments,waypoints[waypoint]->segment,1),
677 waypoints[waypoint]->node1,waypoints[waypoint]->node2,waypoints[waypoint]->dist1,waypoints[waypoint]->dist2);
678
679 if(waypoint_count==0)
680 continue;
681
682 results[waypoint_count-1]=CalculateRoute(database->nodes,database->segments,database->ways,database->relations,
683 profile,start_node,join_segment,finish_node,start_waypoint,finish_waypoint);
684
685 if(!results[waypoint_count-1])
686 {
687 if(progress_func && progress_abort)
688 Routino_errno=ROUTINO_ERROR_PROGRESS_ABORTED;
689 else
690 Routino_errno=ROUTINO_ERROR_NO_ROUTE_1-1+start_waypoint;
691
692 goto tidy_and_exit;
693 }
694
695 join_segment=results[waypoint_count-1]->last_segment;
696 }
697
698 if(progress_func)
699 {
700 progress_value=(double)this_waypoint/(double)(nwaypoints_routed+1);
701
702 if(!progress_func(progress_value))
703 {
704 Routino_errno=ROUTINO_ERROR_PROGRESS_ABORTED;
705 goto tidy_and_exit;
706 }
707 }
708
709 /* Print the route */
710
711 output=PrintRoute(results,nwaypoints_routed-1,database->nodes,database->segments,database->ways,database->relations,profile,translation);
712
713 if(progress_func && !progress_func(1.0))
714 {
715 Routino_errno=ROUTINO_ERROR_PROGRESS_ABORTED;
716 goto tidy_and_exit;
717 }
718
719 /* Tidy up and exit */
720
721 tidy_and_exit:
722
723 DeleteFakeNodes();
724
725 for(this_waypoint=0;this_waypoint<nwaypoints;this_waypoint++)
726 if(results[this_waypoint])
727 FreeResultsList(results[this_waypoint]);
728
729 free(results);
730
731 return(output);
732 }
733
734
735 /*++++++++++++++++++++++++++++++++++++++
736 Delete the linked list created by Routino_CalculateRoute.
737
738 Routino_Output *output The output to be deleted.
739 ++++++++++++++++++++++++++++++++++++++*/
740
741 DLL_PUBLIC void Routino_DeleteRoute(Routino_Output *output)
742 {
743 while(output)
744 {
745 Routino_Output *next=output->next;
746
747 if(output->name)
748 free(output->name);
749
750 if(output->desc1)
751 free(output->desc1);
752
753 if(output->desc2)
754 free(output->desc2);
755
756 if(output->desc3)
757 free(output->desc3);
758
759 free(output);
760
761 output=next;
762 }
763 }