source: subversion/applications/utils/gary68/checkconn.pl @ 24893

Last change on this file since 24893 was 19331, checked in by gary68, 10 years ago

versin 42 of checkconn, noexit=yes

  • Property svn:executable set to *
File size: 16.3 KB
Line 
1#
2#
3# checkconn.pl by gary68
4#
5# this program check for connections at start or end of a way. this is intended to check motorways, trunks, their links, primary, secondary and
6# tertiary highways. it might not be too useful for i.e. highway=residential
7#
8#
9#
10# Copyright (C) 2008, 2009 Gerhard Schwanz
11#
12# This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the
13# Free Software Foundation; either version 3 of the License, or (at your option) any later version.
14#
15# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
17#
18# You should have received a copy of the GNU General Public License along with this program; if not, see <http://www.gnu.org/licenses/>
19#
20#
21# example definition file:
22# (IMPORTANT: don't enter a tag in both sections!)
23#
24#<XML>
25#  <k="check" v="highway:motorway">
26#  <k="check" v="highway:motorway_link">
27#  <k="check" v="highway:trunk">
28#  <k="check" v="highway:trunk_link">
29#  <k="against" v="highway:primary">
30#  <k="against" v="highway:primary_link">
31#  <k="against" v="highway:secondary">
32#  <k="against" v="highway:tertiary">
33#  <k="against" v="junction:roundabout">
34#</XML>
35#
36# Version 2.0
37# 001
38# - new improved algorythm
39# 002
40# - gpx format support
41# - needed nodes sorted removed
42#
43# Version 2.1
44# - add stat output
45#
46# Version 2.2
47# - add stat output 2
48#
49# Version 3.0
50# - add boundary file support
51#
52# Version 4.0
53# - added online api support
54# - removed boundary support
55#
56# Version 4.1
57# - omit contruction sites
58#
59# Version 4.2
60# omit noexit = yes
61#
62
63use strict ;
64use warnings ;
65
66use OSM::osm ;
67use File::stat;
68use Time::localtime;
69
70my $program = "checkconn.pl" ;
71my $usage = $program . " def.xml file.osm out.htm out.gpx" ;
72my $version = "4.2" ;
73
74my $wayId ; my $wayId2 ;
75my $wayUser ; my @wayNodes ; my @wayTags ;
76my $nodeId ; my $nodeId2 ;
77my $nodeUser ; my $nodeLat ; my $nodeLon ; my @nodeTags ;
78my $aRef1 ; my $aRef2 ;
79my $wayCount = 0 ;
80my $againstCount = 0 ;
81my $checkWayCount = 0 ;
82my $againstWayCount = 0 ;
83my $checkedWays = 0 ;
84my $invalidWays ;
85
86my @check ;
87my @against ;
88
89my $time0 = time() ; my $time1 ; my $timeA ;
90my $i ;
91my $key ;
92my $num ;
93my $tag1 ; my $tag2 ;
94my $progress ;
95
96my $html ;
97my $def ;
98my $gpx ;
99my $osmName ;
100my $htmlName ;
101my $defName ;
102my $gpxName ;
103
104my @wayStat = () ; # 0= fully connected; 3= unconnected; 2= end unconnected; 1= start unconnected
105my @cat1 ; my %cat1hash ;
106my @allWayNodes ;
107my @allCat1Nodes ;
108my %cat1Connected ;
109my @cat1Nodes ; my @cat12Nodes ;
110my %nodeNumber = () ;
111my %construction = () ;
112my %noexit = () ;
113
114my @neededNodes ;
115my %lon ; my %lat ;
116my %wayStart ; my %wayEnd ; my %wayStat ;
117
118my $APIcount = 0 ;
119my $APIerrors = 0 ;
120my $APIrejections = 0 ;
121
122###############
123# get parameter
124###############
125$defName = shift||'';
126if (!$defName)
127{
128        die (print $usage, "\n");
129}
130
131$osmName = shift||'';
132if (!$osmName)
133{
134        die (print $usage, "\n");
135}
136
137$htmlName = shift||'';
138if (!$htmlName)
139{
140        die (print $usage, "\n");
141}
142
143$gpxName = shift||'';
144if (!$gpxName)
145{
146        die (print $usage, "\n");
147}
148
149print "\n$program $version for file $osmName\n\n" ;
150
151
152
153##################
154# read definitions
155##################
156
157print "read definitions $defName...\n" ;
158open ($def, , "<", $defName) or die "definition file $defName not found" ;
159
160while (my $line = <$def>) {
161        #print "read line: ", $line, "\n" ;
162        my ($k)   = ($line =~ /^\s*<k=[\'\"]([:\w\s\d]+)[\'\"]/); # get key
163        my ($v) = ($line =~ /^.+v=[\'\"]([:\w\s\d]+)[\'\"]/);       # get value
164       
165        if ($k and defined ($v)) {
166                #print "key: ", $k, "\n" ;
167                #print "val: ", $v, "\n" ;
168
169                if ($k eq "check") {
170                        push @check, $v ;
171                }
172                if ($k eq "against") {
173                        push @against, $v ;
174                }
175        }
176}
177
178close ($def) ;
179
180
181# TODO: remove check from against, if specified!
182
183
184print "Check ways: " ;
185foreach (@check) { print $_, " " ;} print "\n" ;
186print "Against: " ;
187foreach (@against) { print $_, " " ;} print "\n\n" ;
188
189
190
191######################
192# skip all nodes first
193######################
194openOsmFile ($osmName) ;
195print "pass1: skipping nodes...\n" ;
196skipNodes () ;
197
198
199#############################
200# identify check/against ways
201#############################
202print "pass1: identify check ways...\n" ;
203($wayId, $wayUser, $aRef1, $aRef2) = getWay () ;
204if ($wayId != -1) {
205        @wayNodes = @$aRef1 ;
206        @wayTags = @$aRef2 ;
207}
208while ($wayId != -1) { 
209        $wayCount++ ;
210        if (scalar (@wayNodes) >= 2) {
211
212                my $found = 0 ;
213                my $round = 0 ;
214                foreach $tag1 (@wayTags) {
215                        if ($tag1 eq "junction:roundabout") { $round = 1 ; }
216                        foreach $tag2 (@check) {
217                                if ($tag1 eq $tag2) { $found = 1 ; }
218                        }
219                        if ($tag1 eq "highway:construction") { $construction{$wayId} = 1 ; } 
220                        if ($tag1 eq "construction:yes") { $construction{$wayId} = 1 ; } 
221                }
222                if (($found) and ($round == 0)) { 
223                        push @cat1, $wayId ; 
224                        $checkWayCount++ ; 
225                        $wayStart{$wayId} = $wayNodes[0] ; 
226                        $wayEnd{$wayId} = $wayNodes[-1] ; 
227                        $wayStat{$wayId} = 3 ;
228                        push @allWayNodes, @wayNodes ;
229                        push @allCat1Nodes, ($wayNodes[0], $wayNodes[-1]) ;
230                        $nodeNumber{$wayId} = scalar @wayNodes ;
231                }
232
233                $found = 0 ;
234                foreach $tag1 (@wayTags) {
235                        foreach $tag2 (@against) {
236                                if ($tag1 eq $tag2) { $found = 1 ; }
237                        }
238                }
239                if ($found) {
240                        $againstWayCount++ ;
241                        push @allWayNodes, @wayNodes ;
242                        $nodeNumber{$wayId} = scalar @wayNodes ;
243                }
244        }
245        else {
246                #print "invalid way (one node only): ", $wayId, "\n" ;
247                $invalidWays++ ;
248        }
249
250        # next way
251        ($wayId, $wayUser, $aRef1, $aRef2) = getWay () ;
252        if ($wayId != -1) {
253                @wayNodes = @$aRef1 ;
254                @wayTags = @$aRef2 ;
255        }
256}
257
258closeOsmFile () ;
259
260print "number total ways: $wayCount\n" ;
261print "number invalid ways (1 node only): $invalidWays\n" ;
262print "number check ways: $checkWayCount\n" ;
263print "number against ways: $againstWayCount\n" ;
264
265$" = " " ;
266#print "Cat1 ways: @cat1\n" ;
267#print "Cat1 nodes: @allCat1Nodes\n" ;
268#print "All way nodes: @allWayNodes\n" ;
269
270
271
272###############################
273# pass 2; check for connections
274###############################
275print "check for connections...\n" ;
276
277$progress = 0 ;
278$timeA = time() ;
279
280# init cat1Connected
281foreach (@allCat1Nodes) { $cat1Connected{$_} = 0 ; }
282
283# sort cat 1
284print "sort cat1 nodes...\n" ;
285@allCat1Nodes = sort {$a <=> $b} @allCat1Nodes ;
286
287#print "Cat1 nodes sorted: @allCat1Nodes\n" ;
288
289
290# find doubles in allCat1Nodes and mark as connected in @cat1Connected
291# remove doubles completely, create @cat12Nodes
292
293print "find doubles in cat1 nodes...\n" ;
294
295my $actualId = $allCat1Nodes[0] ;
296my $actualNumber = 1 ;
297my $actualIndex = 0 ;
298while ($actualIndex < $#allCat1Nodes) {
299        $actualIndex++ ;
300        if ($allCat1Nodes[$actualIndex] == $actualId) { 
301                $actualNumber++ ;
302        }
303        else
304        {
305                if ($actualNumber > 1) {
306                        $cat1Connected{$actualId} = 1 ;
307                        #print "cat1/cat1 connection found on node id = $actualId\n" ;
308                }
309                else {
310                        push @cat12Nodes, $actualId ;
311                }
312                $actualNumber = 1 ;
313                $actualId = $allCat1Nodes[$actualIndex] ;
314        }
315}
316if ($actualNumber > 1) {
317        $cat1Connected{$actualId} = 1 ;
318        #print "cat1/cat1 connection found on node id = $actualId\n" ;
319}
320else {
321        push @cat12Nodes, $actualId ;
322}
323
324print "sort cat1-2 way nodes...\n" ;
325@cat12Nodes = sort {$a <=> $b} @cat12Nodes ;
326
327#print "Cat12 nodes sorted: @cat12Nodes\n" ;
328
329
330# sort allWayNodes
331print "sort all way nodes...\n" ;
332@allWayNodes = sort {$a <=> $b} @allWayNodes ;
333
334#print "All way nodes sorted: @allWayNodes\n" ;
335
336
337
338# init loop allWayNodes (index)
339# loop through cat12Nodes ascending
340        # inc indexAll until >= cat12NodeId
341        # if == then check for number occurrences
342        # if num occurrences > 1 then mark cat12NodeId as connected
343#
344
345print "big loop running...\n" ;
346
347my $cat1Index = 0 ;
348my $allIndex = 0 ;
349my $actualCat1Id = $cat12Nodes[0] ;
350my $actualAllId = $allWayNodes[0] ;
351
352while ($cat1Index <= $#cat12Nodes) {
353        while ( ($allWayNodes[$allIndex] < $cat12Nodes[$cat1Index]) and ($allIndex < $#allWayNodes) ) {$allIndex++}
354        if ($allWayNodes[$allIndex] == $cat12Nodes[$cat1Index]) {
355                if ( ($allIndex < $#allWayNodes) and ($allWayNodes[$allIndex+1] == $cat12Nodes[$cat1Index]) ) {
356                        $cat1Connected{$cat12Nodes[$cat1Index]} = 1 ;
357                        #print "cat12 node found > 1x in allWayNodes id =", $cat12Nodes[$cat1Index], "\n" ;
358                }
359        }
360        $cat1Index++ ;
361}
362
363
364# check all starts and end for connection
365# waystat filled
366
367foreach $wayId (@cat1) {
368        # check start
369        if ($cat1Connected{$wayStart{$wayId}} == 1) { 
370                if ($wayStat{$wayId} == 1) { $wayStat{$wayId} = 0 ; }
371                if ($wayStat{$wayId} == 3) { $wayStat{$wayId} = 2 ; }
372        } 
373       
374        # check end
375        if ($cat1Connected{$wayEnd{$wayId}} == 1) { 
376                if ($wayStat{$wayId} == 2) { $wayStat{$wayId} = 0 ; }
377                if ($wayStat{$wayId} == 3) { $wayStat{$wayId} = 1 ; }
378        } 
379}
380
381
382
383
384#print "status\n" ;
385#foreach (@cat1) { print "$_ $wayStat{$_}\n" ; }
386#print "\n" ;
387
388
389######################
390# collect needed nodes
391######################
392print "collect needed nodes...\n" ;
393foreach $wayId (@cat1) {
394        if (($wayStat{$wayId} && 1) == 1) {
395                push @neededNodes, $wayStart{$wayId} ;
396        }
397        if (($wayStat{$wayId} && 2) == 2) {
398                push @neededNodes, $wayEnd{$wayId} ;
399        }
400}
401
402
403######################
404# get node information
405######################
406print "pass2: get node information...\n" ;
407openOsmFile ($osmName) ;
408
409@neededNodes = sort { $a <=> $b } @neededNodes ;
410
411($nodeId, $nodeLon, $nodeLat, $nodeUser, $aRef1) = getNode () ;
412if ($nodeId != -1) {
413        @nodeTags = @$aRef1 ;
414}
415
416while ($nodeId != -1) {
417        my $needed = 0 ;
418
419        $needed = binSearch ($nodeId, \@neededNodes ) ;
420
421        if ($needed >= 0) { 
422                $lon{$nodeId} = $nodeLon ; 
423                $lat{$nodeId} = $nodeLat ;
424
425                # check for noexit
426                foreach my $tag (@nodeTags) {
427                        if ($tag eq "noexit:yes") { $noexit{$nodeId} = 1 ; }
428                }
429
430        }
431
432        # next
433        ($nodeId, $nodeLon, $nodeLat, $nodeUser, $aRef1) = getNode () ;
434        if ($nodeId != -1) {
435                @nodeTags = @$aRef1 ;
436        }
437}
438
439closeOsmFile () ;
440
441$time1 = time () ;
442
443
444##################
445# PRINT HTML INFOS
446##################
447print "\nwrite HTML tables and GPX file...\n" ;
448
449open ($html, ">", $htmlName) || die ("Can't open html output file") ;
450open ($gpx, ">", $gpxName) || die ("Can't open gpx output file") ;
451
452
453printHTMLiFrameHeader ($html, "Connection Check by Gary68") ;
454printGPXHeader ($gpx) ;
455
456print $html "<H1>Connection Check by Gary68</H1>\n" ;
457print $html "<p>Version ", $version, "</p>\n" ;
458print $html "<H2>Statistics</H2>\n" ;
459print $html "<p>", stringFileInfo ($osmName), "<br>\n" ;
460print $html "number ways total: $wayCount<br>\n" ;
461print $html "number invalid ways (1 node only): $invalidWays<br>\n" ;
462print $html "number check ways: $checkWayCount<br>\n" ;
463print $html "number against ways: $againstWayCount</p>\n" ;
464
465
466print $html "<p>Check ways: " ;
467foreach (@check) { print $html $_, " " ;} print $html "</p>\n" ;
468print $html "<p>Against: " ;
469foreach (@against) { print $html $_, " " ;} print $html "</p>\n" ;
470
471
472print $html "<H2>Unconnected Start/End</H2>\n" ;
473print $html "<p>These ways are either unconnected at start or end (or both). " ;
474print $html " Please be aware that most osm files are excerpts of some sort with cut ways at their limits. " ;
475print $html " This causes false positives! In case of countries or other entities with boundaries they can " ;
476print $html " easily be spotted in maps or JOSM because there are borders in the vincinity.</p>" ;
477print $html "<table border=\"1\">\n";
478print $html "<tr>\n" ;
479print $html "<th>Line</th>\n" ;
480print $html "<th>WayId</th>\n" ;
481print $html "<th>Unconnected</th>\n" ;
482print $html "<th>OSM/OSB Start</th>\n" ;
483print $html "<th>JOSM Start</th>\n" ;
484print $html "<th>OSM/OSB End</th>\n" ;
485print $html "<th>JOSM End</th>\n" ;
486print $html "<th>Pic Start</th>\n" ;
487print $html "<th>Pic End</th>\n" ;
488print $html "</tr>\n" ;
489$i = 0 ;
490
491foreach $wayId (@cat1) {
492        if ( ($wayStat{$wayId} > 0) and (!defined($construction{$wayId})) ) {
493                # check API way data
494                my $APIok = 1 ;
495                #print "request API data for way $wayId...\n" ;
496                $APIcount++ ;
497                sleep (1) ; # don't stress API
498                my ($id, $u, @nds, @tags, $ndsRef, $tagRef) ;
499                ($id, $u, $ndsRef, $tagRef) = APIgetWay ($wayId) ;
500                #print "API request finished.\n" ;
501                @nds = @$ndsRef ; @tags = @$tagRef ;
502                if ($id == 0) { $APIerrors++ ; }
503                if ( ( $nodeNumber{$wayId} != scalar @nds) and ($wayId == $id) ) { 
504                        $APIok = 0 ;
505                        $APIrejections++ ;
506                        print "WARNING: $wayId ignored because node count of osm file not equal to API node count\n" ;
507                }
508                if ($APIok == 1) {
509
510                        my $status = "" ;
511                        if ( ($wayStat{$wayId} == 1) and (!defined $noexit{$wayStart{$wayId}}) ) { $status = "start" ; } 
512                        if ( ($wayStat{$wayId} == 2) and (!defined $noexit{$wayEnd{$wayId}}) ) { $status = "end" ; } 
513
514                        if      ( ($wayStat{$wayId} == 3) and 
515                                ( (!defined $noexit{$wayStart{$wayId}}) and (!defined $noexit{$wayEnd{$wayId}}) ) 
516                                ) { $status = "start/end" ; } 
517
518                        if ($status ne "") {
519                                # HTML
520                                $i++ ;
521                                print $html "<tr>\n" ;
522                                print $html "<td>", $i , "</td>\n" ;
523                                print $html "<td>", historyLink ("way", $wayId) , "</td>\n" ;
524                                print $html "<td>", $status , "</td>\n" ;
525               
526                                print $html "<td>start ", osmLink ($lon{$wayStart{$wayId}}, $lat{$wayStart{$wayId}}, 16) , "<br>\n" ;
527                                print $html "start ", osbLink ($lon{$wayStart{$wayId}}, $lat{$wayStart{$wayId}}, 16) , "</td>\n" ;
528                                print $html "<td>start ", josmLink ($lon{$wayStart{$wayId}}, $lat{$wayStart{$wayId}}, 0.01, $wayId), "</td>\n" ;
529               
530                                print $html "<td>end ", osmLink ($lon{$wayEnd{$wayId}}, $lat{$wayEnd{$wayId}}, 16) , "<br>\n" ;
531                                print $html "end ", osbLink ($lon{$wayEnd{$wayId}}, $lat{$wayEnd{$wayId}}, 16) , "</td>\n" ;
532                                print $html "<td>end ", josmLink ($lon{$wayEnd{$wayId}}, $lat{$wayEnd{$wayId}}, 0.01, $wayId), "</td>\n" ;
533               
534                                print $html "<td>", picLinkOsmarender ($lon{$wayStart{$wayId}}, $lat{$wayStart{$wayId}}, 16), "</td>\n" ;
535                                print $html "<td>", picLinkOsmarender ($lon{$wayEnd{$wayId}}, $lat{$wayEnd{$wayId}}, 16), "</td>\n" ;
536                                print $html "</tr>\n" ;
537               
538                                # GPX
539                                if (($wayStat{$wayId} == 1) or ($wayStat{$wayId} == 3) ) { 
540                                        my ($text) = "ChkCon - " . $defName . " - way start unconnected" ;
541                                        printGPXWaypoint ($gpx, $lon{$wayStart{$wayId}}, $lat{$wayStart{$wayId}}, $text) ;
542                                } 
543                                if (($wayStat{$wayId} == 2) or ($wayStat{$wayId} == 3) ) { 
544                                        my ($text) = "ChkCon - " . $defName . " - way end unconnected" ;
545                                        printGPXWaypoint ($gpx, $lon{$wayEnd{$wayId}}, $lat{$wayEnd{$wayId}}, $text) ;
546                                } 
547                        }
548                }
549        }
550}
551print $html "</table>\n" ;
552print $html "<p>$i lines total</p>\n" ;
553
554
555
556########
557# FINISH
558########
559print $html "<p>$APIcount API calls</p>" ;
560print $html "<p>$APIerrors API errors</p>" ;
561print $html "<p>$APIrejections API rejections</p>" ;
562print $html "<p>", stringTimeSpent ($time1-$time0), "</p>\n" ;
563printHTMLFoot ($html) ;
564printGPXFoot ($gpx) ;
565
566close ($html) ;
567close ($gpx) ;
568
569statistics ( ctime(stat($osmName)->mtime),  $program,  $defName, $osmName,  $checkWayCount,  $i) ;
570
571print "\n$APIcount API calls\n" ;
572print "$APIerrors API errors\n" ;
573print "$APIrejections API rejections\n" ;
574print "\n$program finished after ", stringTimeSpent ($time1-$time0), "\n\n" ;
575
576
577sub statistics {
578        my ($date, $program, $def, $area, $total, $errors) = @_ ;
579        my $statfile ; my ($statfileName) = "statistics.csv" ;
580
581        if (grep /\.bz2/, $area) { $area =~ s/\.bz2// ; }
582        if (grep /\.osm/, $area) { $area =~ s/\.osm// ; }
583        my ($area2) = ($area =~ /.+\/([\w\-]+)$/ ) ;
584
585        if (grep /\.xml/, $def) { $def =~ s/\.xml// ; }
586        my ($def2) = ($def =~ /([\w\d\_]+)$/ ) ;
587
588        my ($success) = open ($statfile, "<", $statfileName) ;
589
590        if ($success) {
591                print "statfile found. writing stats...\n" ;
592                close $statfile ;
593                open $statfile, ">>", $statfileName ;
594                printf $statfile "%02d.%02d.%4d;", localtime->mday(), localtime->mon()+1, localtime->year() + 1900 ;
595                printf $statfile "%02d/%02d/%4d;", localtime->mon()+1, localtime->mday(), localtime->year() + 1900 ;
596                print $statfile $date, ";" ;
597                print $statfile $program, ";" ;
598                print $statfile $def2, ";" ;
599                print $statfile $area2, ";" ;
600                print $statfile $total, ";" ;
601                print $statfile $errors ;
602                print $statfile "\n" ;
603                close $statfile ;
604        }
605        return ;
606}
607
Note: See TracBrowser for help on using the repository browser.