1 /***************************************
2 $Header: /home/amb/routino/src/RCS/output.c,v 1.40 2010/09/15 18:30:08 amb Exp $
4 Routing output generator.
6 Part of the Routino routing software.
7 ******************/ /******************
8 This file Copyright 2008-2010 Andrew M. Bishop
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.
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.
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 ***************************************/
31 #include <sys/types.h>
41 #include "functions.h"
42 #include "translations.h"
47 /* Global variables */
49 /*+ The option to calculate the quickest route insted of the shortest. +*/
50 extern int option_quickest;
52 /*+ The options to select the format of the output. +*/
53 extern int option_html,option_gpx_track,option_gpx_route,option_text,option_text_all;
57 /*+ Heuristics for determining if a junction is important. +*/
58 static char junction_other_way[Way_Count][Way_Count]=
59 { /* M, T, P, S, T, U, R, S, T, C, P, S, F = Way type of route not taken */
60 { 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, /* Motorway */
61 { 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, /* Trunk */
62 { 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, /* Primary */
63 { 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1 }, /* Secondary */
64 { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1 }, /* Tertiary */
65 { 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1 }, /* Unclassified */
66 { 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1 }, /* Residential */
67 { 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1 }, /* Service */
68 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1 }, /* Track */
69 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1 }, /* Cycleway */
70 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* Path */
71 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* Steps */
72 { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }, /* Ferry */
78 static int turn_angle(Nodes *nodes,Segment *segment1,Segment *segment2,index_t node);
79 static int bearing_angle(Nodes *nodes,Segment *segment,index_t node);
82 /*++++++++++++++++++++++++++++++++++++++
83 Print the optimum route between two nodes.
85 Results **results The set of results to print (some may be NULL - ignore them).
87 int nresults The number of results in the list.
89 Nodes *nodes The list of nodes.
91 Segments *segments The set of segments to use.
93 Ways *ways The list of ways.
95 Profile *profile The profile containing the transport type, speeds and allowed highways.
96 ++++++++++++++++++++++++++++++++++++++*/
98 void PrintRoute(Results **results,int nresults,Nodes *nodes,Segments *segments,Ways *ways,Profile *profile)
100 FILE *htmlfile=NULL,*gpxtrackfile=NULL,*gpxroutefile=NULL,*textfile=NULL,*textallfile=NULL;
103 distance_t cum_distance=0;
104 duration_t cum_duration=0;
105 double finish_lat,finish_lon;
111 if(option_quickest==0)
113 /* Print the result for the shortest route */
116 htmlfile =fopen("shortest.html","w");
118 gpxtrackfile=fopen("shortest-track.gpx","w");
120 gpxroutefile=fopen("shortest-route.gpx","w");
122 textfile =fopen("shortest.txt","w");
124 textallfile =fopen("shortest-all.txt","w");
126 if(option_html && !htmlfile)
127 fprintf(stderr,"Warning: Cannot open file 'shortest.html' for writing [%s].\n",strerror(errno));
128 if(option_gpx_track && !gpxtrackfile)
129 fprintf(stderr,"Warning: Cannot open file 'shortest-track.gpx' for writing [%s].\n",strerror(errno));
130 if(option_gpx_route && !gpxroutefile)
131 fprintf(stderr,"Warning: Cannot open file 'shortest-route.gpx' for writing [%s].\n",strerror(errno));
132 if(option_text && !textfile)
133 fprintf(stderr,"Warning: Cannot open file 'shortest.txt' for writing [%s].\n",strerror(errno));
134 if(option_text_all && !textallfile)
135 fprintf(stderr,"Warning: Cannot open file 'shortest-all.txt' for writing [%s].\n",strerror(errno));
139 /* Print the result for the quickest route */
142 htmlfile =fopen("quickest.html","w");
144 gpxtrackfile=fopen("quickest-track.gpx","w");
146 gpxroutefile=fopen("quickest-route.gpx","w");
148 textfile =fopen("quickest.txt","w");
150 textallfile =fopen("quickest-all.txt","w");
152 if(option_html && !htmlfile)
153 fprintf(stderr,"Warning: Cannot open file 'quickest.html' for writing [%s].\n",strerror(errno));
154 if(option_gpx_track && !gpxtrackfile)
155 fprintf(stderr,"Warning: Cannot open file 'quickest-track.gpx' for writing [%s].\n",strerror(errno));
156 if(option_gpx_route && !gpxroutefile)
157 fprintf(stderr,"Warning: Cannot open file 'quickest-route.gpx' for writing [%s].\n",strerror(errno));
158 if(option_text && !textfile)
159 fprintf(stderr,"Warning: Cannot open file 'quickest.txt' for writing [%s].\n",strerror(errno));
160 if(option_text_all && !textallfile)
161 fprintf(stderr,"Warning: Cannot open file 'quickest-all.txt' for writing [%s].\n",strerror(errno));
164 /* Print the head of the files */
168 fprintf(htmlfile,"<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n");
169 fprintf(htmlfile,"<HTML>\n");
170 if(translate_copyright_creator[0] && translate_copyright_creator[1])
171 fprintf(htmlfile,"<!-- %s : %s -->\n",translate_copyright_creator[0],translate_copyright_creator[1]);
172 if(translate_copyright_source[0] && translate_copyright_source[1])
173 fprintf(htmlfile,"<!-- %s : %s -->\n",translate_copyright_source[0],translate_copyright_source[1]);
174 if(translate_copyright_license[0] && translate_copyright_license[1])
175 fprintf(htmlfile,"<!-- %s : %s -->\n",translate_copyright_license[0],translate_copyright_license[1]);
176 fprintf(htmlfile,"<HEAD>\n");
177 fprintf(htmlfile,"<TITLE>");
178 fprintf(htmlfile,translate_html_title,option_quickest?translate_route_quickest:translate_route_shortest);
179 fprintf(htmlfile,"</TITLE>\n");
180 fprintf(htmlfile,"<META http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">\n");
181 fprintf(htmlfile,"<STYLE type=\"text/css\">\n");
182 fprintf(htmlfile,"<!--\n");
183 fprintf(htmlfile," table {table-layout: fixed; border: none; border-collapse: collapse;}\n");
184 fprintf(htmlfile," table.c {color: grey; font-size: x-small;} /* copyright */\n");
185 fprintf(htmlfile," tr {border: 0px;}\n");
186 fprintf(htmlfile," tr.c {display: none;} /* coords */\n");
187 fprintf(htmlfile," tr.n {} /* node */\n");
188 fprintf(htmlfile," tr.s {} /* segment */\n");
189 fprintf(htmlfile," tr.t {font-weight: bold;} /* total */\n");
190 fprintf(htmlfile," td.l {font-weight: bold;}\n");
191 fprintf(htmlfile," td.r {}\n");
192 fprintf(htmlfile," span.w {font-weight: bold;} /* waypoint */\n");
193 fprintf(htmlfile," span.h {text-decoration: underline;} /* highway */\n");
194 fprintf(htmlfile," span.d {} /* segment distance */\n");
195 fprintf(htmlfile," span.j {font-style: italic;} /* total journey distance */\n");
196 fprintf(htmlfile," span.t {font-variant: small-caps;} /* turn */\n");
197 fprintf(htmlfile," span.b {font-variant: small-caps;} /* bearing */\n");
198 fprintf(htmlfile,"-->\n");
199 fprintf(htmlfile,"</STYLE>\n");
200 fprintf(htmlfile,"</HEAD>\n");
201 fprintf(htmlfile,"<BODY>\n");
202 fprintf(htmlfile,"<H1>");
203 fprintf(htmlfile,translate_html_title,option_quickest?translate_route_quickest:translate_route_shortest);
204 fprintf(htmlfile,"</H1>\n");
205 fprintf(htmlfile,"<table>\n");
210 fprintf(gpxtrackfile,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
211 fprintf(gpxtrackfile,"<gpx version=\"1.1\" creator=\"Routino\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.topografix.com/GPX/1/1\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\">\n");
213 fprintf(gpxtrackfile,"<metadata>\n");
214 fprintf(gpxtrackfile,"<desc>%s : %s</desc>\n",translate_copyright_creator[0],translate_copyright_creator[1]);
215 if(translate_copyright_source[1])
217 fprintf(gpxtrackfile,"<copyright author=\"%s\">\n",translate_copyright_source[1]);
219 if(translate_copyright_license[1])
220 fprintf(gpxtrackfile,"<license>%s</license>\n",translate_copyright_license[1]);
222 fprintf(gpxtrackfile,"</copyright>\n");
224 fprintf(gpxtrackfile,"</metadata>\n");
226 fprintf(gpxtrackfile,"<trk>\n");
227 fprintf(gpxtrackfile,"<name>");
228 fprintf(gpxtrackfile,translate_gpx_name,option_quickest?translate_route_quickest:translate_route_shortest);
229 fprintf(gpxtrackfile,"</name>\n");
230 fprintf(gpxtrackfile,"<desc>");
231 fprintf(gpxtrackfile,translate_gpx_desc,option_quickest?translate_route_quickest:translate_route_shortest);
232 fprintf(gpxtrackfile,"</desc>\n");
237 fprintf(gpxroutefile,"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
238 fprintf(gpxroutefile,"<gpx version=\"1.1\" creator=\"Routino\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"http://www.topografix.com/GPX/1/1\" xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\">\n");
240 fprintf(gpxroutefile,"<metadata>\n");
241 fprintf(gpxroutefile,"<desc>%s : %s</desc>\n",translate_copyright_creator[0],translate_copyright_creator[1]);
242 if(translate_copyright_source[1])
244 fprintf(gpxroutefile,"<copyright author=\"%s\">\n",translate_copyright_source[1]);
246 if(translate_copyright_license[1])
247 fprintf(gpxroutefile,"<license>%s</license>\n",translate_copyright_license[1]);
249 fprintf(gpxroutefile,"</copyright>\n");
251 fprintf(gpxroutefile,"</metadata>\n");
253 fprintf(gpxroutefile,"<rte>\n");
254 fprintf(gpxroutefile,"<name>");
255 fprintf(gpxroutefile,translate_gpx_name,option_quickest?translate_route_quickest:translate_route_shortest);
256 fprintf(gpxroutefile,"</name>\n");
257 fprintf(gpxroutefile,"<desc>");
258 fprintf(gpxroutefile,translate_gpx_desc,option_quickest?translate_route_quickest:translate_route_shortest);
259 fprintf(gpxroutefile,"</desc>\n");
264 if(translate_copyright_creator[0] && translate_copyright_creator[1])
265 fprintf(textfile,"# %s : %s\n",translate_copyright_creator[0],translate_copyright_creator[1]);
266 if(translate_copyright_source[0] && translate_copyright_source[1])
267 fprintf(textfile,"# %s : %s\n",translate_copyright_source[0],translate_copyright_source[1]);
268 if(translate_copyright_license[0] && translate_copyright_license[1])
269 fprintf(textfile,"# %s : %s\n",translate_copyright_license[0],translate_copyright_license[1]);
270 if((translate_copyright_creator[0] && translate_copyright_creator[1]) ||
271 (translate_copyright_source[0] && translate_copyright_source[1]) ||
272 (translate_copyright_license[0] && translate_copyright_license[1]))
273 fprintf(textfile,"#\n");
275 fprintf(textfile,"#Latitude\tLongitude\tSection \tSection \tTotal \tTotal \tPoint\tTurn\tBearing\tHighway\n");
276 fprintf(textfile,"# \t \tDistance\tDuration\tDistance\tDuration\tType \t \t \t \n");
277 /* "%10.6f\t%11.6f\t%6.3f km\t%4.1f min\t%5.1f km\t%4.0f min\t%s\t %+d\t %+d\t%s\n" */
282 if(translate_copyright_creator[0] && translate_copyright_creator[1])
283 fprintf(textallfile,"# %s : %s\n",translate_copyright_creator[0],translate_copyright_creator[1]);
284 if(translate_copyright_source[0] && translate_copyright_source[1])
285 fprintf(textallfile,"# %s : %s\n",translate_copyright_source[0],translate_copyright_source[1]);
286 if(translate_copyright_license[0] && translate_copyright_license[1])
287 fprintf(textallfile,"# %s : %s\n",translate_copyright_license[0],translate_copyright_license[1]);
288 if((translate_copyright_creator[0] && translate_copyright_creator[1]) ||
289 (translate_copyright_source[0] && translate_copyright_source[1]) ||
290 (translate_copyright_license[0] && translate_copyright_license[1]))
291 fprintf(textallfile,"#\n");
293 fprintf(textallfile,"#Latitude\tLongitude\t Node\tType\tSegment\tSegment\tTotal\tTotal \tSpeed\tBearing\tHighway\n");
294 fprintf(textallfile,"# \t \t \t \tDist \tDurat'n\tDist \tDurat'n\t \t \t \n");
295 /* "%10.6f\t%11.6f\t%8d%c\t%s\t%5.3f\t%5.2f\t%5.2f\t%5.1f\t%3d\t%4d\t%s\n" */
298 /* Loop through the segments of the route and print it */
300 while(!results[point])
303 while(point<=nresults)
306 double start_lat,start_lon;
307 distance_t junc_distance=0;
308 duration_t junc_duration=0;
312 fprintf(gpxtrackfile,"<trkseg>\n");
314 if(IsFakeNode(results[point]->start))
315 GetFakeLatLong(results[point]->start,&start_lat,&start_lon);
317 GetLatLong(nodes,results[point]->start,&start_lat,&start_lon);
319 if(IsFakeNode(results[point]->finish))
320 GetFakeLatLong(results[point]->finish,&finish_lat,&finish_lon);
322 GetLatLong(nodes,results[point]->finish,&finish_lat,&finish_lon);
324 result=FindResult(results[point],results[point]->start);
328 double latitude,longitude;
330 Segment *nextresultsegment;
332 if(result->node==results[point]->start)
333 {latitude=start_lat; longitude=start_lon;}
334 else if(result->node==results[point]->finish)
335 {latitude=finish_lat; longitude=finish_lon;}
337 GetLatLong(nodes,result->node,&latitude,&longitude);
340 fprintf(gpxtrackfile,"<trkpt lat=\"%.6f\" lon=\"%.6f\"/>\n",
341 radians_to_degrees(latitude),radians_to_degrees(longitude));
343 nextresult=FindResult(results[point],result->next);
346 for(nextpoint=point+1;nextpoint<=nresults;nextpoint++)
347 if(results[nextpoint])
349 nextresult=FindResult(results[nextpoint],results[nextpoint]->start);
350 nextresult=FindResult(results[nextpoint],nextresult->next);
356 if(IsFakeSegment(nextresult->segment))
357 nextresultsegment=LookupFakeSegment(nextresult->segment);
359 nextresultsegment=LookupSegment(segments,nextresult->segment,2);
362 nextresultsegment=NULL;
364 if(result->node!=results[point]->start)
366 distance_t seg_distance=0;
367 duration_t seg_duration=0;
368 Segment *resultsegment;
372 /* Cache the values to be printed rather than calculating them repeatedly for each output format */
374 char *waynameraw=NULL,*waynamexml=NULL;
375 const char *wayname=NULL;
376 int bearing_int=0,bearing_next_int=0,turn_int=0;
377 char *bearing_str=NULL,*bearing_next_str=NULL,*turn_str=NULL;
379 /* Get the properties of this segment */
381 if(IsFakeSegment(result->segment))
382 resultsegment=LookupFakeSegment(result->segment);
384 resultsegment=LookupSegment(segments,result->segment,3);
385 resultway=LookupWay(ways,resultsegment->way,1);
387 seg_distance+=DISTANCE(resultsegment->distance);
388 seg_duration+=Duration(resultsegment,resultway,profile);
389 junc_distance+=seg_distance;
390 junc_duration+=seg_duration;
391 cum_distance+=seg_distance;
392 cum_duration+=seg_duration;
394 /* Decide if this is an important junction */
396 if(result->node==results[point]->finish)
400 Segment *segment=FirstSegment(segments,nodes,result->node);
404 index_t othernode=OtherNode(segment,result->node);
406 if(othernode!=result->prev && segment!=resultsegment)
407 if(IsNormalSegment(segment) && (!profile->oneway || !IsOnewayTo(segment,result->node)))
409 Way *way=LookupWay(ways,segment->way,2);
411 if(othernode==result->next) /* the next segment that we follow */
413 if(HIGHWAY(way->type)!=HIGHWAY(resultway->type))
417 else /* a segment that we don't follow */
419 if(junction_other_way[HIGHWAY(resultway->type)-1][HIGHWAY(way->type)-1])
428 segment=NextSegment(segments,segment,result->node);
433 /* Print out the important points (junctions / waypoints) */
437 /* Print the intermediate finish points (because they have correct junction distances) */
444 type=translate_html_waypoint;
446 type=translate_html_junction;
450 waynameraw=WayName(ways,resultway);
452 waynameraw=translate_highway[HIGHWAY(resultway->type)];
456 waynamexml=ParseXML_Encode_Safe_XML(waynameraw);
458 fprintf(htmlfile,"<tr class='s'><td class='l'>%s:<td class='r'>",translate_html_segment[0]);
459 fprintf(htmlfile,translate_html_segment[1],
461 distance_to_km(junc_distance),duration_to_minutes(junc_duration));
462 fprintf(htmlfile," [<span class='j'>");
463 fprintf(htmlfile,translate_html_total[1],
464 distance_to_km(cum_distance),duration_to_minutes(cum_duration));
465 fprintf(htmlfile,"</span>]\n");
467 fprintf(htmlfile,"<tr class='c'><td class='l'><td class='r'>%.6f %.6f\n",
468 radians_to_degrees(latitude),radians_to_degrees(longitude));
474 turn_int=turn_angle(nodes,resultsegment,nextresultsegment,result->node);
475 turn_str=translate_turn[(4+(22+turn_int)/45)%8];
478 if(!bearing_next_str)
480 bearing_next_int=bearing_angle(nodes,nextresultsegment,nextresult->node);
481 bearing_next_str=translate_heading[(4+(22+bearing_next_int)/45)%8];
484 fprintf(htmlfile,"<tr class='n'><td class='l'>%s:<td class='r'>",translate_html_node[0]);
485 fprintf(htmlfile,translate_html_node[1],
489 fprintf(htmlfile,"\n");
493 fprintf(htmlfile,"<tr class='n'><td class='l'>%s:<td class='r'>",translate_html_stop[0]);
494 fprintf(htmlfile,translate_html_stop[1],
495 translate_html_waypoint);
496 fprintf(htmlfile,"\n");
497 fprintf(htmlfile,"<tr class='t'><td class='l'>%s:<td class='r'><span class='j'>",translate_html_total[0]);
498 fprintf(htmlfile,translate_html_total[1],
499 distance_to_km(cum_distance),duration_to_minutes(cum_duration));
500 fprintf(htmlfile,"</span>\n");
508 waynameraw=WayName(ways,resultway);
510 waynameraw=translate_highway[HIGHWAY(resultway->type)];
514 waynamexml=ParseXML_Encode_Safe_XML(waynameraw);
518 bearing_int=bearing_angle(nodes,resultsegment,result->node);
519 bearing_str=translate_heading[(4+(22+bearing_int)/45)%8];
522 fprintf(gpxroutefile,"<desc>");
523 fprintf(gpxroutefile,translate_gpx_step,
526 distance_to_km(junc_distance),duration_to_minutes(junc_duration));
527 fprintf(gpxroutefile,"</desc></rtept>\n");
531 fprintf(gpxroutefile,"<rtept lat=\"%.6f\" lon=\"%.6f\"><name>%s</name>\n",
532 radians_to_degrees(finish_lat),radians_to_degrees(finish_lon),
533 translate_gpx_finish);
534 fprintf(gpxroutefile,"<desc>");
535 fprintf(gpxroutefile,translate_gpx_final,
536 distance_to_km(cum_distance),duration_to_minutes(cum_duration));
537 fprintf(gpxroutefile,"</desc></rtept>\n");
539 else if(important==10)
540 fprintf(gpxroutefile,"<rtept lat=\"%.6f\" lon=\"%.6f\"><name>%s%d</name>\n",
541 radians_to_degrees(latitude),radians_to_degrees(longitude),
542 translate_gpx_inter,++segment_count);
544 fprintf(gpxroutefile,"<rtept lat=\"%.6f\" lon=\"%.6f\"><name>%s%03d</name>\n",
545 radians_to_degrees(latitude),radians_to_degrees(longitude),
546 translate_gpx_trip,++route_count);
560 wayname=WayName(ways,resultway);
562 wayname=HighwayName(HIGHWAY(resultway->type));
569 turn_int=turn_angle(nodes,resultsegment,nextresultsegment,result->node);
570 turn_str=translate_turn[(4+(22+turn_int)/45)%8];
573 if(!bearing_next_str)
575 bearing_next_int=bearing_angle(nodes,nextresultsegment,nextresult->node);
576 bearing_next_str=translate_heading[(4+(22+bearing_next_int)/45)%8];
579 fprintf(textfile,"%10.6f\t%11.6f\t%6.3f km\t%4.1f min\t%5.1f km\t%4.0f min\t%s\t %+d\t %+d\t%s\n",
580 radians_to_degrees(latitude),radians_to_degrees(longitude),
581 distance_to_km(junc_distance),duration_to_minutes(junc_duration),
582 distance_to_km(cum_distance),duration_to_minutes(cum_duration),
585 ((22+bearing_next_int)/45+4)%8-4,
589 fprintf(textfile,"%10.6f\t%11.6f\t%6.3f km\t%4.1f min\t%5.1f km\t%4.0f min\t%s\t\t\t%s\n",
590 radians_to_degrees(latitude),radians_to_degrees(longitude),
591 distance_to_km(junc_distance),duration_to_minutes(junc_duration),
592 distance_to_km(cum_distance),duration_to_minutes(cum_duration),
601 /* Print out all of the results */
609 else if(important==2)
611 else if(important>=1)
618 wayname=WayName(ways,resultway);
620 wayname=HighwayName(HIGHWAY(resultway->type));
625 bearing_int=bearing_angle(nodes,resultsegment,result->node);
626 bearing_str=translate_heading[(4+(22+bearing_int)/45)%8];
629 fprintf(textallfile,"%10.6f\t%11.6f\t%8d%c\t%s\t%5.3f\t%5.2f\t%5.2f\t%5.1f\t%3d\t%4d\t%s\n",
630 radians_to_degrees(latitude),radians_to_degrees(longitude),
631 IsFakeNode(result->node)?(NODE_FAKE-result->node):result->node,
632 (!IsFakeNode(result->node) && IsSuperNode(nodes,result->node))?'*':' ',type,
633 distance_to_km(seg_distance),duration_to_minutes(seg_duration),
634 distance_to_km(cum_distance),duration_to_minutes(cum_duration),
635 profile->speed[HIGHWAY(resultway->type)],
640 if(waynamexml && waynamexml!=waynameraw)
643 else if(!cum_distance)
645 int bearing_next_int=bearing_angle(nodes,nextresultsegment,nextresult->node);
646 char *bearing_next_str=translate_heading[(4+(22+bearing_next_int)/45)%8];
648 /* Print out the very first start point */
652 fprintf(htmlfile,"<tr class='c'><td class='l'><td class='r'>%.6f %.6f\n",
653 radians_to_degrees(latitude),radians_to_degrees(longitude));
654 fprintf(htmlfile,"<tr class='n'><td class='l'>%s:<td class='r'>",translate_html_start[0]);
655 fprintf(htmlfile,translate_html_start[1],
656 translate_html_waypoint,
658 fprintf(htmlfile,"\n");
662 fprintf(gpxroutefile,"<rtept lat=\"%.6f\" lon=\"%.6f\"><name>%s</name>\n",
663 radians_to_degrees(latitude),radians_to_degrees(longitude),
664 translate_gpx_start);
667 fprintf(textfile,"%10.6f\t%11.6f\t%6.3f km\t%4.1f min\t%5.1f km\t%4.0f min\t%s\t\t +%d\t\n",
668 radians_to_degrees(latitude),radians_to_degrees(longitude),
671 (22+bearing_next_int)/45);
674 fprintf(textallfile,"%10.6f\t%11.6f\t%8d%c\t%s\t%5.3f\t%5.2f\t%5.2f\t%5.1f\t\t\t\n",
675 radians_to_degrees(latitude),radians_to_degrees(longitude),
676 IsFakeNode(result->node)?(NODE_FAKE-result->node):result->node,
677 (!IsFakeNode(result->node) && IsSuperNode(nodes,result->node))?'*':' ',"Waypt",
683 while(point==nextpoint);
686 fprintf(gpxtrackfile,"</trkseg>\n");
691 /* Print the tail of the files */
695 fprintf(htmlfile,"</table>\n");
697 if((translate_copyright_creator[0] && translate_copyright_creator[1]) ||
698 (translate_copyright_source[0] && translate_copyright_source[1]) ||
699 (translate_copyright_license[0] && translate_copyright_license[1]))
701 fprintf(htmlfile,"<p>\n");
702 fprintf(htmlfile,"<table class='c'>\n");
703 if(translate_copyright_creator[0] && translate_copyright_creator[1])
704 fprintf(htmlfile,"<tr><td class='l'>%s:<td class='r'>%s\n",translate_copyright_creator[0],translate_copyright_creator[1]);
705 if(translate_copyright_source[0] && translate_copyright_source[1])
706 fprintf(htmlfile,"<tr><td class='l'>%s:<td class='r'>%s\n",translate_copyright_source[0],translate_copyright_source[1]);
707 if(translate_copyright_license[0] && translate_copyright_license[1])
708 fprintf(htmlfile,"<tr><td class='l'>%s:<td class='r'>%s\n",translate_copyright_license[0],translate_copyright_license[1]);
709 fprintf(htmlfile,"</table>\n");
712 fprintf(htmlfile,"</BODY>\n");
713 fprintf(htmlfile,"</HTML>\n");
718 fprintf(gpxtrackfile,"</trk>\n");
719 fprintf(gpxtrackfile,"</gpx>\n");
724 fprintf(gpxroutefile,"</rte>\n");
725 fprintf(gpxroutefile,"</gpx>\n");
728 /* Close the files */
733 fclose(gpxtrackfile);
735 fclose(gpxroutefile);
743 /*++++++++++++++++++++++++++++++++++++++
744 Calculate the angle to turn at a junction from segment1 to segment2 at node.
746 int turn_angle Returns a value in the range -4 to +4 indicating the angle to turn.
748 Nodes *nodes The set of nodes.
750 Segment *segment1 The current segment.
752 Segment *segment2 The next segment.
754 index_t node The node at which they join.
756 Straight ahead is zero, turning to the right is positive (90 degrees) and turning to the left is negative.
757 Angles are calculated using flat Cartesian lat/long grid approximation (after scaling longitude due to latitude).
758 ++++++++++++++++++++++++++++++++++++++*/
760 static int turn_angle(Nodes *nodes,Segment *segment1,Segment *segment2,index_t node)
762 double lat1,latm,lat2;
763 double lon1,lonm,lon2;
764 double angle1,angle2,angle;
767 node1=OtherNode(segment1,node);
768 node2=OtherNode(segment2,node);
770 if(IsFakeNode(node1))
771 GetFakeLatLong(node1,&lat1,&lon1);
773 GetLatLong(nodes,node1,&lat1,&lon1);
776 GetFakeLatLong(node,&latm,&lonm);
778 GetLatLong(nodes,node,&latm,&lonm);
780 if(IsFakeNode(node2))
781 GetFakeLatLong(node2,&lat2,&lon2);
783 GetLatLong(nodes,node2,&lat2,&lon2);
785 angle1=atan2((lonm-lon1)*cos(latm),(latm-lat1));
786 angle2=atan2((lon2-lonm)*cos(latm),(lat2-latm));
790 angle=radians_to_degrees(angle);
794 if(angle<-180) angle+=360;
795 if(angle> 180) angle-=360;
801 /*++++++++++++++++++++++++++++++++++++++
802 Calculate the bearing of a segment from the given node.
804 int bearing_angle Returns a value in the range 0 to 359 indicating the bearing.
806 Nodes *nodes The set of nodes.
808 Segment *segment The segment.
810 index_t node The node to start.
812 Angles are calculated using flat Cartesian lat/long grid approximation (after scaling longitude due to latitude).
813 ++++++++++++++++++++++++++++++++++++++*/
815 static int bearing_angle(Nodes *nodes,Segment *segment,index_t node)
823 node2=OtherNode(segment,node);
825 if(IsFakeNode(node1))
826 GetFakeLatLong(node1,&lat1,&lon1);
828 GetLatLong(nodes,node1,&lat1,&lon1);
830 if(IsFakeNode(node2))
831 GetFakeLatLong(node2,&lat2,&lon2);
833 GetLatLong(nodes,node2,&lat2,&lon2);
835 angle=atan2((lat2-lat1),(lon2-lon1)*cos(lat1));
837 angle=radians_to_degrees(angle);
839 angle=round(270-angle);
841 if(angle< 0) angle+=360;
842 if(angle>360) angle-=360;