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