Hallo Liste!

Inzwischen gibt es ja einige Relationen, die Routen der verschiedensten Art abbilden, z.B. (Rad)wanderwege, Buslinien, Bundesstraßen. Im Idealfall sind solche Routen ja eine kontinuierliche Aneinanderreihung von ways, d.h der Endnode eines way ist der erste node des anschließenden way - die Richtung der ways mal außen vor gelassen. Da die API die memebers einer Relation nun aber in willkürlicher Reihenfolge zurückliefert, kann man das nicht mehr so einfach überprüfen, um Lücken aufzuspüren.

Ich habe daher ein Perl-Skript geschrieben (siehe Anhang), das eine oder meherere relations über die API lädt und dann zählt, wie oft die Nodes an den "Enden" der member-ways verwendet werden. Es werden die ID aller Nodes ausgegeben, die != 2 mal Verwendung finden.

Dabei sind wahrscheinlich allerdings auch einige "false positive" dabei, z.B.
- Der Anfang und das Ende der Route werden jeweils nur einmal verwendet,
  wenn es sich nicht um einen Rundweg handelt.
- Bei Alternativrouten wird der Node an der Verzweigung nur einmal (wenn
  einer der ways dort nicht gesplittet wurde) oder dreimal am Ende eines
  Member-ways auftauchen. (Ein Kreisverkehr ist übrigens auch eine
  Alternative in diesem Sinne - es geht ja je nach Fahrtrichtung über
  einen anderen Teil des Kreisels.)
- Die berühmte Buslinie, die zweimal über die Kreuzung fährt:
          _______
         |       |
         A       |
         |       |
  <--B---K---C---/
         |
         B
         |
         ^
  Hier kann der Kreuzungsnode K viermal auftauchen, wenn nämlich A, B, C
  und D selbständige ways sind.
- vielleicht noch andere Fälle.

Dennoch habe ich gestern damit einige fehlende Brücken (und weitere Fehler) im Radweg Berlin-Kopenhagen gefunden.

Das Skript wird einfach von der Befehlszeile aus aufgerufen und erhält als Parameter die ID der zu untersuchenden Relation(en).

HTH, Gruß Andreas


PS: zu Debugging-Zwecken gab das Skript eine OSM-Datei aus, der entsprechende Code ist auskommentiert. - Um ihn wieder zu verwenden, einfach die beiden Zeilen, die mit "=head1" bzw. "=cut" anfangen, löschen oder durch Voranstellen eines "#" auskommentieren.

PS2: Kann man in JOSM eigentlich ein Objekt über dessen ID auswählen?
#!/usr/bin/perl -w

# Copyright 2008, Andreas Titz
#
# 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 Free Software Foundation, either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

use strict;
use LWP::UserAgent;
use XML::Parser;

my $agent  = new LWP::UserAgent();
my $parser = new XML::Parser(Style => 'Tree');
$| = 1;

my %nodes;
my %ways;
my %relations;
my %ARGV;

if ( $#ARGV == -1 ) {
        die <<EOT;
        usage: $0 relation-id [relation-id]...
EOT
};

foreach ( @ARGV ) {
        $ARGV{$_}++;
        my $request = 
$agent->get("http://www.openstreetmap.org/api/0.5/relation/$_/full";);
        die unless $request->is_success;

        my $xml = $request->content;
        $xml =~ s/>\s+</></gs;
        $xml = $parser->parse($xml);

        my $osm = @{$xml}[1];

        for (  my $pos = 1; $pos <= [EMAIL PROTECTED]; $pos++ ) {
                my $element = [EMAIL PROTECTED];
                if ( $element eq 'node' ) {
                        my %node;
                        my $id;

                        my @node = @[EMAIL PROTECTED];
                        my %attribs = %{shift @node};
                        foreach ( keys %attribs ) {
                                $node{$_} = $attribs{$_};
                                $id = $attribs{$_} if $_ eq 'id';
                        };
                        while ( defined $node[0] ) {
                                if ( $node[0] eq 'tag' ) {
                                        my %tagvalue = [EMAIL PROTECTED];
                                        my ( $key, $value );
                                        foreach ( keys %tagvalue ) {
                                                if ( $_ eq 'k' ) {
                                                        $key = $tagvalue{$_};
                                                } elsif ( $_ eq 'v' ) {
                                                        $value = $tagvalue{$_};
                                                } else {
                                                        warn "unknown 
XML-Attribute in tag \"tag\" of node $id";
                                                };
                                        };
                                        push @{$node{$key}}, $value;
                                } else {
                                        warn "unknown XML-Tag $node[0] in node 
$id: $node[1]";
                                };
                                splice(@node, 0, 2);
                        };
                        $nodes{$id} = \%node;
                } elsif ( $element eq 'way' ) {
                        my %way;
                        my $id;
                        
                        my @way = @[EMAIL PROTECTED];
                        my %attribs = %{shift @way};
                        foreach ( keys %attribs ) {
                                $way{$_} = $attribs{$_};
                                $id = $attribs{$_} if $_ eq 'id';
                        };
                        while ( defined $way[0] ) {
                                if ( $way[0] eq 'nd' ) {
                                        my %nd = [EMAIL PROTECTED];
                                        foreach ( keys %nd ) {
                                                push @{$way{nd}}, $nd{$_};
                                        };
                                } elsif ( $way[0] eq 'tag' ) {
                                        my %tagvalue = [EMAIL PROTECTED];
                                        my ( $key, $value );
                                        foreach ( keys %tagvalue ) {
                                                if ( $_ eq 'k' ) {
                                                        $key = $tagvalue{$_};
                                                } elsif ( $_ eq 'v' ) {
                                                        $value = $tagvalue{$_};
                                                } else {
                                                        warn "unknown 
XML-Attribute in tag \"tag\" of way $id";
                                                };
                                        };
                                        push @{$way{$key}}, $value;
                                } else {
                                        warn "unknown XML-Tag in way $id: 
$way[1]";
                                };
                                splice(@way, 0, 2);
                        };
                        $ways{$id} = \%way;
                } elsif ( $element eq 'relation' ) {
                        my %relation;
                        my $id;
                        
                        my @relation = @[EMAIL PROTECTED];
                        my %attribs = %{shift @relation};
                        foreach ( keys %attribs ) {
                                $relation{$_} = $attribs{$_};
                                $id = $attribs{$_} if $_ eq 'id';
                        };
                        while ( defined $relation[0] ) {
                                if ( $relation[0] eq 'member' ) {
                                        my %membertype = [EMAIL PROTECTED];
                                        my ( $type, $ref, $role );
                                        foreach ( keys %membertype ) {
                                                if ( $_ eq 'type' ) {
                                                        $type = $membertype{$_};
                                                } elsif ( $_ eq 'ref' ) {
                                                        $ref = $membertype{$_};
                                                } elsif ( $_ eq 'role' ) {
                                                        $role = $membertype{$_};
                                                } else {
                                                        warn "unknown 
XML-Attribute in tag \"tag\" of relation $id";
                                                };
                                        };
                                        push @{$relation{member}}, [$type, 
$ref, $role];
                                } elsif ( $relation[0] eq 'tag' ) {
                                        my %tagvalue = [EMAIL PROTECTED];
                                        my ( $key, $value );
                                        foreach ( keys %tagvalue ) {
                                                if ( $_ eq 'k' ) {
                                                        $key = $tagvalue{$_};
                                                } elsif ( $_ eq 'v' ) {
                                                        $value = $tagvalue{$_};
                                                } else {
                                                        warn "unknown 
XML-Attribute in tag \"tag\" of relation $id";
                                                };
                                        };
                                        push @{$relation{$key}}, $value;
                                } else {
                                        warn "unknown XML-Tag in relation $id: 
$relation[1]";
                                };
                                splice(@relation, 0, 2);
                        };
                        $relations{$id} = \%relation;
                } else {
                        warn "unknown OSM-Element: $element";
                };
        };
};      

=head1 output middle part of an OSM-file for checking purposes

print "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<osm version=\"0.5\" 
generator=\"rel_check_route\">\n";

foreach my $id ( keys %nodes ) {
        print "  <node id=\"" . $id . "\" lat=\"" . $nodes{$id}{lat} . "\" 
lon=\"" . $nodes{$id}{lon} . "\">\n";
        foreach my $key ( keys %{$nodes{$id}} ) {
                next if $key =~ /^id|lat|lon$/;
                next unless ref($nodes{$id}{$key}) eq 'ARRAY'; # XML-attributes 
"produce" scalars
                foreach ( @{$nodes{$id}{$key}} ) {
                        print "    <tag k=\"" . $key . "\" v=\"" . $_ . 
"\"/>\n";
                };
        };
        print "  </node>\n";
};

foreach my $id ( keys %ways ) {
        print "  <way id=\"" . $id . "\">\n";
        my @nd = @{$ways{$id}{nd}};
        foreach ( @nd ) {
                print "    <nd ref=\"" . $_ . "\"/>\n";
        };
        foreach my $key ( keys %{$ways{$id}} ) {
                next if $key =~ /^id|nd$/;
                next unless ref($ways{$id}{$key}) eq 'ARRAY'; # XML-attributes 
"produce" scalars
                foreach ( @{$ways{$id}{$key}} ) {
                        print "    <tag k=\"" . $key . "\" v=\"" . $_ . 
"\"/>\n";
                };
        };
        print "  </way>\n";
};

foreach my $id ( keys %relations ) {
        print "  <relation id=\"" . $id . "\">\n";
        my @members = @{$relations{$id}{member}};
        foreach ( @members ) {
                print "    <member type=\"" . $$_[0] . "\" ref=\"" . $$_[1] . 
"\" role=\"" . $$_[2] . "\"/>\n";
        };
        foreach my $key ( keys %{$relations{$id}} ) {
                next if $key =~ /^id|member$/;
                next unless ref($relations{$id}{$key}) eq 'ARRAY'; # 
XML-attributes "produce" scalars
                foreach ( @{$relations{$id}{$key}} ) {
                        print "    <tag k=\"" . $key . "\" v=\"" . $_ . 
"\"/>\n";
                };
        };
        print "  </relation>\n";
};

print "</osm>\n";

=cut

my %usednodes;
foreach my $relid ( keys %relations ) {
        my @members = @{$relations{$relid}{member}};
        foreach ( @members ) {
                my ( $type, $ref, $role ) = @$_;
                if ( $type eq 'way' ) {
                        if ( exists $ways{$ref} ) {
                                $usednodes{$ways{$ref}{nd}[0]}++;
                                $usednodes{$ways{$ref}{nd}[-1]}++;
                        } else {
                                warn "way $ref not downloaded (was probably 
included via a 2nd-level-relation)\n";
                        };
                } elsif ( $type eq 'node' ) {
                        warn "probably useless node $ref in one of the 
relations\n";
                } elsif ( $type eq 'relation' ) {
                        unless ( exists $relations{$ref} ) {
                                warn "relation $ref in one of the relations, 
but not downloaded\n";
                        } elsif ( ! exists $ARGV{$ref} ) {
                                warn "relation $ref in one of the relations, 
maybe there are more needed ways in it\n";
                        };
                } else {
                        warn "unknown type $type in one of the relations\n";
                };
        };      
};

my @usednodes = sort { $usednodes{$a} <=> $usednodes{$b} } keys %usednodes;

foreach ( @usednodes ) {
        print $usednodes{$_} . "\t" . $_ . "\n" unless $usednodes{$_} == 2;
};
_______________________________________________
Talk-de mailing list
Talk-de@openstreetmap.org
http://lists.openstreetmap.org/cgi-bin/mailman/listinfo/talk-de

Antwort per Email an