Merge branch 'upstream'
[routino] / src / visualiser.c
1 /***************************************
2  $Header: /home/amb/routino/src/RCS/visualiser.c,v 1.10 2010/07/26 18:17:20 amb Exp $
3
4  Extract data from Routino.
5
6  Part of the Routino routing software.
7  ******************/ /******************
8  This file Copyright 2008-2010 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 <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29 #include "types.h"
30 #include "visualiser.h"
31 #include "nodes.h"
32 #include "segments.h"
33 #include "ways.h"
34
35
36 #define SPEED_LIMIT  1
37 #define WEIGHT_LIMIT 2
38 #define HEIGHT_LIMIT 3
39 #define WIDTH_LIMIT  4
40 #define LENGTH_LIMIT 5
41
42 /* Local types */
43
44 typedef void (*callback_t)(index_t node,double latitude,double longitude);
45
46 /* Local variables */
47
48 static Nodes    *OSMNodes;
49 static Segments *OSMSegments;
50 static Ways     *OSMWays;
51
52 static double LatMin;
53 static double LatMax;
54 static double LonMin;
55 static double LonMax;
56
57 static int limit_type=0;
58
59 /* Local functions */
60
61 static void find_all_nodes(Nodes *nodes,callback_t callback);
62 static void output_junctions(index_t node,double latitude,double longitude);
63 static void output_super(index_t node,double latitude,double longitude);
64 static void output_oneway(index_t node,double latitude,double longitude);
65 static void output_limits(index_t node,double latitude,double longitude);
66
67
68 /*++++++++++++++++++++++++++++++++++++++
69   Output the data for junctions.
70
71   Nodes *nodes The set of nodes to use.
72
73   Segments *segments The set of segments to use.
74
75   Ways *ways The set of ways to use.
76
77   double latmin The minimum latitude.
78
79   double latmax The maximum latitude.
80
81   double lonmin The minimum longitude.
82
83   double lonmax The maximum longitude.
84   ++++++++++++++++++++++++++++++++++++++*/
85
86 void OutputJunctions(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax)
87 {
88  /* Use local variables so that the callback doesn't need to pass them backwards and forwards */
89
90  OSMNodes=nodes;
91  OSMSegments=segments;
92  OSMWays=ways;
93
94  LatMin=latmin;
95  LatMax=latmax;
96  LonMin=lonmin;
97  LonMax=lonmax;
98
99  /* Iterate through the nodes and process them */
100
101  find_all_nodes(nodes,(callback_t)output_junctions);
102 }
103
104
105 /*++++++++++++++++++++++++++++++++++++++
106   Process a single node (called as a callback).
107
108   index_t node The node to output.
109
110   double latitude The latitude of the node.
111
112   double longitude The longitude of the node.
113   ++++++++++++++++++++++++++++++++++++++*/
114
115 static void output_junctions(index_t node,double latitude,double longitude)
116 {
117  Segment *segment;
118  Way *firstway;
119  int count=0,difference=0;
120
121  segment=FirstSegment(OSMSegments,OSMNodes,node);
122  firstway=LookupWay(OSMWays,segment->way,1);
123
124  do
125    {
126     Way *way=LookupWay(OSMWays,segment->way,2);
127
128     if(IsNormalSegment(segment))
129        count++;
130
131     if(WaysCompare(firstway,way))
132        difference=1;
133
134     segment=NextSegment(OSMSegments,segment,node);
135    }
136  while(segment);
137
138  if(count!=2 || difference)
139     printf("%.6f %.6f %d\n",radians_to_degrees(latitude),radians_to_degrees(longitude),count);
140 }
141
142
143 /*++++++++++++++++++++++++++++++++++++++
144   Output the data for super-nodes and super-segments.
145
146   Nodes *nodes The set of nodes to use.
147
148   Segments *segments The set of segments to use.
149
150   Ways *ways The set of ways to use.
151
152   double latmin The minimum latitude.
153
154   double latmax The maximum latitude.
155
156   double lonmin The minimum longitude.
157
158   double lonmax The maximum longitude.
159   ++++++++++++++++++++++++++++++++++++++*/
160
161 void OutputSuper(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax)
162 {
163  /* Use local variables so that the callback doesn't need to pass them backwards and forwards */
164
165  OSMNodes=nodes;
166  OSMSegments=segments;
167  OSMWays=ways;
168
169  LatMin=latmin;
170  LatMax=latmax;
171  LonMin=lonmin;
172  LonMax=lonmax;
173
174  /* Iterate through the nodes and process them */
175
176  find_all_nodes(nodes,(callback_t)output_super);
177 }
178
179
180 /*++++++++++++++++++++++++++++++++++++++
181   Process a single node (called as a callback).
182
183   index_t node The node to output.
184
185   double latitude The latitude of the node.
186
187   double longitude The longitude of the node.
188   ++++++++++++++++++++++++++++++++++++++*/
189
190 static void output_super(index_t node,double latitude,double longitude)
191 {
192  Segment *segment;
193
194  if(!IsSuperNode(OSMNodes,node))
195     return;
196
197  printf("%.6f %.6f n\n",radians_to_degrees(latitude),radians_to_degrees(longitude));
198
199  segment=FirstSegment(OSMSegments,OSMNodes,node);
200
201  do
202    {
203     if(IsSuperSegment(segment))
204       {
205        index_t othernode=OtherNode(segment,node);
206        double lat,lon;
207
208        GetLatLong(OSMNodes,othernode,&lat,&lon);
209
210        if(node>othernode || (lat<LatMin || lat>LatMax || lon<LonMin || lon>LonMax))
211           printf("%.6f %.6f s\n",radians_to_degrees(lat),radians_to_degrees(lon));
212       }
213
214     segment=NextSegment(OSMSegments,segment,node);
215    }
216  while(segment);
217 }
218
219
220 /*++++++++++++++++++++++++++++++++++++++
221   Output the data for one-way segments.
222
223   Nodes *nodes The set of nodes to use.
224
225   Segments *segments The set of segments to use.
226
227   Ways *ways The set of ways to use.
228
229   double latmin The minimum latitude.
230
231   double latmax The maximum latitude.
232
233   double lonmin The minimum longitude.
234
235   double lonmax The maximum longitude.
236   ++++++++++++++++++++++++++++++++++++++*/
237
238 void OutputOneway(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax)
239 {
240  /* Use local variables so that the callback doesn't need to pass them backwards and forwards */
241
242  OSMNodes=nodes;
243  OSMSegments=segments;
244  OSMWays=ways;
245
246  LatMin=latmin;
247  LatMax=latmax;
248  LonMin=lonmin;
249  LonMax=lonmax;
250
251  /* Iterate through the nodes and process them */
252
253  find_all_nodes(nodes,(callback_t)output_oneway);
254 }
255
256
257 /*++++++++++++++++++++++++++++++++++++++
258   Process a single node (called as a callback).
259
260   index_t node The node to output.
261
262   double latitude The latitude of the node.
263
264   double longitude The longitude of the node.
265   ++++++++++++++++++++++++++++++++++++++*/
266
267 static void output_oneway(index_t node,double latitude,double longitude)
268 {
269  Segment *segment;
270
271  segment=FirstSegment(OSMSegments,OSMNodes,node);
272
273  do
274    {
275     if(IsNormalSegment(segment))
276       {
277        index_t othernode=OtherNode(segment,node);
278
279        if(node>othernode)
280          {
281           double lat,lon;
282
283           GetLatLong(OSMNodes,othernode,&lat,&lon);
284
285           if(IsOnewayFrom(segment,node))
286              printf("%.6f %.6f %.6f %.6f\n",radians_to_degrees(latitude),radians_to_degrees(longitude),radians_to_degrees(lat),radians_to_degrees(lon));
287           else if(IsOnewayFrom(segment,othernode))
288              printf("%.6f %.6f %.6f %.6f\n",radians_to_degrees(lat),radians_to_degrees(lon),radians_to_degrees(latitude),radians_to_degrees(longitude));
289          }
290       }
291
292     segment=NextSegment(OSMSegments,segment,node);
293    }
294  while(segment);
295 }
296
297
298 /*++++++++++++++++++++++++++++++++++++++
299   Output the data for speed limits.
300
301   Nodes *nodes The set of nodes to use.
302
303   Segments *segments The set of segments to use.
304
305   Ways *ways The set of ways to use.
306
307   double latmin The minimum latitude.
308
309   double latmax The maximum latitude.
310
311   double lonmin The minimum longitude.
312
313   double lonmax The maximum longitude.
314   ++++++++++++++++++++++++++++++++++++++*/
315
316 void OutputSpeedLimits(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax)
317 {
318  /* Use local variables so that the callback doesn't need to pass them backwards and forwards */
319
320  OSMNodes=nodes;
321  OSMSegments=segments;
322  OSMWays=ways;
323
324  LatMin=latmin;
325  LatMax=latmax;
326  LonMin=lonmin;
327  LonMax=lonmax;
328
329  /* Iterate through the nodes and process them */
330
331  limit_type=SPEED_LIMIT;
332
333  find_all_nodes(nodes,(callback_t)output_limits);
334 }
335
336
337 /*++++++++++++++++++++++++++++++++++++++
338   Output the data for weight limits.
339
340   Nodes *nodes The set of nodes to use.
341
342   Segments *segments The set of segments to use.
343
344   Ways *ways The set of ways to use.
345
346   double latmin The minimum latitude.
347
348   double latmax The maximum latitude.
349
350   double lonmin The minimum longitude.
351
352   double lonmax The maximum longitude.
353   ++++++++++++++++++++++++++++++++++++++*/
354
355 void OutputWeightLimits(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax)
356 {
357  /* Use local variables so that the callback doesn't need to pass them backwards and forwards */
358
359  OSMNodes=nodes;
360  OSMSegments=segments;
361  OSMWays=ways;
362
363  LatMin=latmin;
364  LatMax=latmax;
365  LonMin=lonmin;
366  LonMax=lonmax;
367
368  /* Iterate through the nodes and process them */
369
370  limit_type=WEIGHT_LIMIT;
371
372  find_all_nodes(nodes,(callback_t)output_limits);
373 }
374
375
376 /*++++++++++++++++++++++++++++++++++++++
377   Output the data for height limits.
378
379   Nodes *nodes The set of nodes to use.
380
381   Segments *segments The set of segments to use.
382
383   Ways *ways The set of ways to use.
384
385   double latmin The minimum latitude.
386
387   double latmax The maximum latitude.
388
389   double lonmin The minimum longitude.
390
391   double lonmax The maximum longitude.
392   ++++++++++++++++++++++++++++++++++++++*/
393
394 void OutputHeightLimits(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax)
395 {
396  /* Use local variables so that the callback doesn't need to pass them backwards and forwards */
397
398  OSMNodes=nodes;
399  OSMSegments=segments;
400  OSMWays=ways;
401
402  LatMin=latmin;
403  LatMax=latmax;
404  LonMin=lonmin;
405  LonMax=lonmax;
406
407  /* Iterate through the nodes and process them */
408
409  limit_type=HEIGHT_LIMIT;
410
411  find_all_nodes(nodes,(callback_t)output_limits);
412 }
413
414
415 /*++++++++++++++++++++++++++++++++++++++
416   Output the data for width limits.
417
418   Nodes *nodes The set of nodes to use.
419
420   Segments *segments The set of segments to use.
421
422   Ways *ways The set of ways to use.
423
424   double latmin The minimum latitude.
425
426   double latmax The maximum latitude.
427
428   double lonmin The minimum longitude.
429
430   double lonmax The maximum longitude.
431   ++++++++++++++++++++++++++++++++++++++*/
432
433 void OutputWidthLimits(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax)
434 {
435  /* Use local variables so that the callback doesn't need to pass them backwards and forwards */
436
437  OSMNodes=nodes;
438  OSMSegments=segments;
439  OSMWays=ways;
440
441  LatMin=latmin;
442  LatMax=latmax;
443  LonMin=lonmin;
444  LonMax=lonmax;
445
446  /* Iterate through the nodes and process them */
447
448  limit_type=WIDTH_LIMIT;
449
450  find_all_nodes(nodes,(callback_t)output_limits);
451 }
452
453
454 /*++++++++++++++++++++++++++++++++++++++
455   Output the data for length limits.
456
457   Nodes *nodes The set of nodes to use.
458
459   Segments *segments The set of segments to use.
460
461   Ways *ways The set of ways to use.
462
463   double latmin The minimum latitude.
464
465   double latmax The maximum latitude.
466
467   double lonmin The minimum longitude.
468
469   double lonmax The maximum longitude.
470   ++++++++++++++++++++++++++++++++++++++*/
471
472 void OutputLengthLimits(Nodes *nodes,Segments *segments,Ways *ways,double latmin,double latmax,double lonmin,double lonmax)
473 {
474  /* Use local variables so that the callback doesn't need to pass them backwards and forwards */
475
476  OSMNodes=nodes;
477  OSMSegments=segments;
478  OSMWays=ways;
479
480  LatMin=latmin;
481  LatMax=latmax;
482  LonMin=lonmin;
483  LonMax=lonmax;
484
485  /* Iterate through the nodes and process them */
486
487  limit_type=LENGTH_LIMIT;
488
489  find_all_nodes(nodes,(callback_t)output_limits);
490 }
491
492
493 /*++++++++++++++++++++++++++++++++++++++
494   Process a single node (called as a callback).
495
496   index_t node The node to output.
497
498   double latitude The latitude of the node.
499
500   double longitude The longitude of the node.
501   ++++++++++++++++++++++++++++++++++++++*/
502
503 static void output_limits(index_t node,double latitude,double longitude)
504 {
505  Segment *segment,*segments[16];
506  Way *ways[16];
507  int limits[16];
508  int count=0;
509  int i,j,same=0;
510
511  segment=FirstSegment(OSMSegments,OSMNodes,node);
512
513  do
514    {
515     if(IsNormalSegment(segment) && count<16)
516       {
517        ways    [count]=LookupWay(OSMWays,segment->way,1);
518        segments[count]=segment;
519
520        switch(limit_type)
521          {
522          case SPEED_LIMIT:  limits[count]=ways[count]->speed;  break;
523          case WEIGHT_LIMIT: limits[count]=ways[count]->weight; break;
524          case HEIGHT_LIMIT: limits[count]=ways[count]->height; break;
525          case WIDTH_LIMIT:  limits[count]=ways[count]->width;  break;
526          case LENGTH_LIMIT: limits[count]=ways[count]->length; break;
527          }
528
529        if(limits[count] || ways[count]->type<Way_Track)
530           count++;
531       }
532
533     segment=NextSegment(OSMSegments,segment,node);
534    }
535  while(segment);
536
537  /* Nodes with only one limit are not interesting */
538
539  if(count==1)
540     return;
541
542  /* Nodes with all segments the same limit is not interesting */
543
544  same=0;
545  for(j=0;j<count;j++)
546     if(limits[0]==limits[j])
547        same++;
548
549  if(same==count)
550     return;
551
552  /* Display the interesting speed limits */
553
554  printf("%.6f %.6f\n",radians_to_degrees(latitude),radians_to_degrees(longitude));
555
556  for(i=0;i<count;i++)
557    {
558     same=0;
559     for(j=0;j<count;j++)
560        if(limits[i]==limits[j])
561           same++;
562
563     if(count==2 || same!=(count-1))
564       {
565        double lat,lon;
566
567        GetLatLong(OSMNodes,OtherNode(segments[i],node),&lat,&lon);
568
569        switch(limit_type)
570          {
571          case SPEED_LIMIT:
572           printf("%.6f %.6f %d\n",radians_to_degrees(lat),radians_to_degrees(lon),speed_to_kph(limits[i]));
573           break;
574          case WEIGHT_LIMIT:
575           printf("%.6f %.6f %.1f\n",radians_to_degrees(lat),radians_to_degrees(lon),weight_to_tonnes(limits[i]));
576           break;
577          case HEIGHT_LIMIT:
578           printf("%.6f %.6f %.1f\n",radians_to_degrees(lat),radians_to_degrees(lon),height_to_metres(limits[i]));
579           break;
580          case WIDTH_LIMIT:
581           printf("%.6f %.6f %.1f\n",radians_to_degrees(lat),radians_to_degrees(lon),width_to_metres(limits[i]));
582           break;
583          case LENGTH_LIMIT:
584           printf("%.6f %.6f %.1f\n",radians_to_degrees(lat),radians_to_degrees(lon),length_to_metres(limits[i]));
585           break;
586          }
587       }
588    }
589 }
590
591
592 /*++++++++++++++++++++++++++++++++++++++
593   A function to iterate through all nodes and call a callback function for each one.
594
595   Nodes *nodes The list of nodes to process.
596
597   callback_t callback The callback function for each node.
598   ++++++++++++++++++++++++++++++++++++++*/
599
600 static void find_all_nodes(Nodes *nodes,callback_t callback)
601 {
602  int32_t latminbin=latlong_to_bin(radians_to_latlong(LatMin))-nodes->file.latzero;
603  int32_t latmaxbin=latlong_to_bin(radians_to_latlong(LatMax))-nodes->file.latzero;
604  int32_t lonminbin=latlong_to_bin(radians_to_latlong(LonMin))-nodes->file.lonzero;
605  int32_t lonmaxbin=latlong_to_bin(radians_to_latlong(LonMax))-nodes->file.lonzero;
606  int latb,lonb,llbin;
607  index_t i,index1,index2;
608
609  /* Loop through all of the nodes. */
610
611  for(latb=latminbin;latb<=latmaxbin;latb++)
612     for(lonb=lonminbin;lonb<=lonmaxbin;lonb++)
613       {
614        llbin=lonb*nodes->file.latbins+latb;
615
616        if(llbin<0 || llbin>(nodes->file.latbins*nodes->file.lonbins))
617           continue;
618
619        index1=LookupNodeOffset(nodes,llbin);
620        index2=LookupNodeOffset(nodes,llbin+1);
621
622        for(i=index1;i<index2;i++)
623          {
624           Node *node=LookupNode(nodes,i,1);
625
626           double lat=latlong_to_radians(bin_to_latlong(nodes->file.latzero+latb)+off_to_latlong(node->latoffset));
627           double lon=latlong_to_radians(bin_to_latlong(nodes->file.lonzero+lonb)+off_to_latlong(node->lonoffset));
628
629           if(lat>LatMin && lat<LatMax && lon>LonMin && lon<LonMax)
630              (*callback)(i,lat,lon);
631          }
632       }
633 }