< 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.