< Relations
Relations/Relations to GPX
What it does
This little Perl script takes a bunch of route relations, and writes them out as a single GPX file.
The idea is that you use it in conjunction with a GPX visualiser. Just for example, if you were a ranger for your local cycle route, and wanted to embed a map of the route on your website, you could use this.
Possible future development
- a web interface
- the ability to load a list of ways, or the results of a XAPI query
- investigate using GML rather than GPX, which with OpenLayers' BBOX strategy should work better for big datasets
Code
Some consideration
- Due to http calls code may be slow.
- Program uses STDIN & STDOUT.
- I do not calculate bbox, because gpsbabel and gpsvisualizer do not need it.
- Was checked on single relation 5583485.
- Was checked on many relations 9327, 9333, 34610, 47904.
#!/usr/bin/perl -w
use strict;
use warnings;
use LWP::Simple qw(get);
use XML::Mini::Document;
sub read_relations() {
sub check_if_natural_number($) {
my ($checked_string) = @_;
unless ( $checked_string =~ /^\d+$/ ) {
print "\nI got a $checked_string, which doesn't look like a valid relation id!\n";
exit 1;
}
}
my @relations = <STDIN>;
chomp @relations;
map { check_if_natural_number($_) } @relations;
return @relations;
}
sub call_osm_api($$) {
my ( $member_type, $member_id ) = @_;
sub osm_api_url($$) {
my ( $member_type, $member_id ) = @_;
my $common_part = "http://www.openstreetmap.org/api/0.6/";
if ( $member_type eq 'relation' ) {
return "$common_part/relation/$member_id";
}
if ( $member_type eq 'way' ) {
return "$common_part/way/$member_id/full";
}
}
my $url = osm_api_url( $member_type, $member_id );
my $osm_data = get($url);
unless ( defined($osm_data) ) {
print "\nOSM knows nothing about the $member_type $member_id.\n";
exit 1;
}
my $parser = XML::Mini::Document->new();
$parser->fromString($osm_data);
return $parser->toHash();
}
sub read_ways_from_relation(@) {
my @relations = @_;
sub filter_ways($) {
my ($all_memberes) = @_;
return grep( { $_->{type} eq 'way' } @$all_memberes );
}
sub extract_ids(@) {
return map( { $_->{ref} } @_ );
}
my @ways = ();
foreach my $relation_id (@relations) {
my $relation = call_osm_api( "relation", $relation_id );
push @ways,
extract_ids( filter_ways( $relation->{osm}->{relation}->{member} ) );
}
return \@ways;
}
sub ways_as_nodes($) {
my ($way_ids) = @_;
sub node_lat_lon($$) {
my ( $node_id, $nodes_details ) = @_;
my @node = grep { $_->{id} eq $node_id } @$nodes_details;
my $node_data = $node[0];
return {
lat => $node_data->{lat},
lon => $node_data->{lon},
};
}
sub collect_nodes_data($) {
my ($way_data) = @_;
my $nodes_in_way = $way_data->{osm}->{way}->{nd};
my $nodes_details = $way_data->{osm}->{node};
my @nodes_ids = map( { $_->{ref} } @$nodes_in_way );
my @nodes = map( { node_lat_lon( $_, $nodes_details ) } @nodes_ids );
return \@nodes;
}
my @ways = ();
foreach my $way_id (@$way_ids) {
my $way_data = call_osm_api( 'way', $way_id );
push @ways, collect_nodes_data($way_data);
}
return \@ways;
}
sub dump_gpx_to_stdout($) {
my ($ways) = @_;
my $xml = XML::Mini::Document->new();
my $xml_root = $xml->getRoot();
my $xml_header = $xml_root->header('xml');
$xml_header->attribute( 'version', '1.0' );
$xml_header->attribute( 'encoding', 'UTF-8' );
my $gpx = $xml_root->createChild('gpx');
$gpx->attribute( 'xmlns', 'http://www.topografix.com/GPX/1/0' );
$gpx->attribute( 'version', '1.0' );
$gpx->attribute( 'creator', 'https://wiki.openstreetmap.org/wiki/Relations/Relations_to_GPX' );
my $trk = $gpx->createChild('trk');
foreach my $way (@$ways) {
my $trkseg = $trk->createChild('trkseg');
foreach my $node (@$way) {
my $trkpt = $trkseg->createChild('trkpt');
$trkpt->attribute( 'lat', $node->{lat} );
$trkpt->attribute( 'lon', $node->{lon} );
}
}
print $xml->toString();
}
dump_gpx_to_stdout(
ways_as_nodes(
read_ways_from_relation(
read_relations()
)
)
);
This article is issued from Openstreetmap. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.