summaryrefslogtreecommitdiff
path: root/navit/script
diff options
context:
space:
mode:
authormartin-s <martin-s@ffa7fe5e-494d-0410-b361-a75ebd5db220>2009-08-27 19:09:25 +0000
committermartin-s <martin-s@ffa7fe5e-494d-0410-b361-a75ebd5db220>2009-08-27 19:09:25 +0000
commitc27854879123aadbed446247d891896f3c1d1246 (patch)
tree9fe4fc65de5c9cfccf391891f0b5ac5677d0a45e /navit/script
parenta795f1486e1203da44c15b93017587af62738e48 (diff)
downloadnavit-c27854879123aadbed446247d891896f3c1d1246.tar.gz
Fix:script:Converted to new osm api
git-svn-id: http://svn.code.sf.net/p/navit/code/trunk/navit@2534 ffa7fe5e-494d-0410-b361-a75ebd5db220
Diffstat (limited to 'navit/script')
-rw-r--r--navit/script/osm/Geo/OSM/APIClientV4.pm226
-rw-r--r--navit/script/osm/Geo/OSM/APIClientV5.pm327
-rw-r--r--navit/script/osm/Geo/OSM/APIClientV6.pm364
-rw-r--r--navit/script/osm/Geo/OSM/EntitiesV3.pm296
-rw-r--r--navit/script/osm/Geo/OSM/EntitiesV5.pm375
-rw-r--r--navit/script/osm/Geo/OSM/EntitiesV6.pm404
-rw-r--r--navit/script/osm/Geo/OSM/MapFeatures.pm194
-rw-r--r--navit/script/osm/Geo/OSM/OsmChangeReaderV3.pm323
-rw-r--r--navit/script/osm/Geo/OSM/OsmChangeReaderV5.pm316
-rw-r--r--navit/script/osm/Geo/OSM/OsmChangeReaderV6.pm316
-rw-r--r--navit/script/osm/Geo/OSM/OsmReaderV3.pm246
-rw-r--r--navit/script/osm/Geo/OSM/OsmReaderV5.pm249
-rw-r--r--navit/script/osm/Geo/OSM/OsmReaderV6.pm249
-rw-r--r--navit/script/osm/Geo/OSM/OsmXML.pm161
-rw-r--r--navit/script/osm/Geo/OSM/Planet.pm336
-rw-r--r--navit/script/osm/Geo/OSM/SegmentList.pm520
-rw-r--r--navit/script/osm/Geo/OSM/Tracks2OSM.pm145
-rw-r--r--navit/script/osm/Geo/OSM/Upload.pm145
-rw-r--r--navit/script/osm/Geo/OSM/Write.pm170
-rwxr-xr-xnavit/script/osm/osmtool.pl20
20 files changed, 5380 insertions, 2 deletions
diff --git a/navit/script/osm/Geo/OSM/APIClientV4.pm b/navit/script/osm/Geo/OSM/APIClientV4.pm
new file mode 100644
index 000000000..26b8ec5fc
--- /dev/null
+++ b/navit/script/osm/Geo/OSM/APIClientV4.pm
@@ -0,0 +1,226 @@
+##################################################################
+## APIClientV4.pm - General Perl client for the API ##
+## By Martijn van Oosterhout <kleptog@svana.org> ##
+## ##
+## Currently only supports uploading. Note the package actually ##
+## creates a package named Geo::OSM::APIClient so upgrades to ##
+## later versions will be easier. ##
+## Licence: LGPL ##
+##################################################################
+
+use LWP::UserAgent;
+use strict;
+
+package Geo::OSM::APIClient;
+use Geo::OSM::OsmReaderV3;
+use MIME::Base64;
+use HTTP::Request;
+use Carp;
+use Encode;
+use POSIX qw(sigprocmask);
+
+sub new
+{
+ my( $class, %attr ) = @_;
+
+ my $obj = bless {}, $class;
+
+ my $url = $attr{api};
+ if( not defined $url )
+ {
+ croak "Did not specify aip url";
+ }
+
+ $url =~ s,/$,,; # Strip trailing slash
+ $obj->{url} = $url;
+ $obj->{client} = new LWP::UserAgent(agent => 'Geo::OSM::APIClientV4', timeout => 1200);
+
+ if( defined $attr{username} and defined $attr{password} )
+ {
+ if( $obj->{url} =~ m,http://([\w.]+)/, )
+ {
+ $obj->{client}->credentials( "$1:80", "Web Password", $attr{username}, $attr{password} );
+ }
+ my $encoded = MIME::Base64::encode_base64("$attr{username}:$attr{password}","");
+ $obj->{client}->default_header( "Authorization", "Basic $encoded" );
+ }
+
+ $obj->{reader} = init Geo::OSM::OsmReader( sub { _process($obj,@_) } );
+ return $obj;
+}
+
+# This is the callback from the parser. If checks if the buffer is defined.
+# If the buffer is an array, append the new object. If the buffer is a proc,
+# call it.
+sub _process
+{
+ my($obj,$ent) = @_;
+ if( not defined $obj->{buffer} )
+ { die "Internal error: Received object with buffer" }
+ if( ref $obj->{buffer} eq "ARRAY" )
+ { push @{$obj->{buffer}}, $ent; return }
+ if( ref $obj->{buffer} eq "CODE" )
+ { $obj->{buffer}->($ent); return }
+ die "Internal error: don't know what to do with buffer $obj->{buffer}";
+}
+
+# Utility function to handle the temporary blocking of signals in a way that
+# works with exception handling.
+sub _with_blocked_sigs(&)
+{
+ my $ss = new POSIX::SigSet( &POSIX::SIGINT );
+ my $func = shift;
+ my $os = new POSIX::SigSet;
+ sigprocmask( &POSIX::SIG_BLOCK, $ss, $os );
+ my $ret = eval { &$func };
+ sigprocmask( &POSIX::SIG_SETMASK, $os );
+ die $@ if $@;
+ return $ret;
+}
+
+sub _request
+{
+ my $self = shift;
+ my $req = shift;
+ return _with_blocked_sigs { $self->{client}->request($req) };
+}
+
+sub last_error_code
+{
+ return shift->{last_error}->code;
+}
+
+sub last_error_message
+{
+ return shift->{last_error}->message;
+}
+
+sub create
+{
+ my( $self, $ent ) = @_;
+ my $oldid = $ent->id;
+ $ent->set_id(0);
+ my $content = encode("utf-8", $ent->full_xml);
+ $ent->set_id($oldid);
+ my $req = new HTTP::Request PUT => $self->{url}."/".$ent->type()."/create";
+ $req->content($content);
+
+# print $req->as_string;
+
+ my $res = $self->_request($req);
+
+# print $res->as_string;
+
+ if( $res->code == 200 )
+ {
+ return $res->content
+ }
+
+ $self->{last_error} = $res;
+ return undef;
+}
+
+sub modify
+{
+ my( $self, $ent ) = @_;
+ my $content = encode("utf-8", $ent->full_xml);
+ my $req = new HTTP::Request PUT => $self->{url}."/".$ent->type()."/".$ent->id();
+ $req->content($content);
+
+# print $req->as_string;
+
+ my $res = $self->_request($req);
+
+ return $ent->id() if $res->code == 200;
+ $self->{last_error} = $res;
+ return undef;
+}
+
+sub delete
+{
+ my( $self, $ent ) = @_;
+ my $content = encode("utf-8", $ent->full_xml);
+ my $req = new HTTP::Request DELETE => $self->{url}."/".$ent->type()."/".$ent->id();
+# $req->content($content);
+
+# print $req->as_string;
+
+ my $res = $self->_request($req);
+
+ return $ent->id() if $res->code == 200;
+ $self->{last_error} = $res;
+ return undef;
+}
+
+sub get($$)
+{
+ my $self = shift;
+ my $type = shift;
+ my $id = shift;
+
+ my $req = new HTTP::Request GET => $self->{url}."/$type/$id";
+
+ my $res = $self->_request($req);
+
+ if( $res->code != 200 )
+ {
+ $self->{last_error} = $res;
+ return undef;
+ }
+
+ my @res;
+ $self->{buffer} = \@res;
+ $self->{reader}->parse($res->content);
+ undef $self->{buffer};
+ if( scalar(@res) != 1 )
+ {
+ die "Unexpected response for get_$type [".$res->content()."]\n";
+ }
+
+ return $res[0];
+}
+
+sub get_node($)
+{
+ my $self = shift;
+ return $self->get("node",shift);
+}
+
+sub get_way($)
+{
+ my $self = shift;
+ return $self->get("way",shift);
+}
+
+sub get_segment($)
+{
+ my $self = shift;
+ return $self->get("segment",shift);
+}
+
+
+sub map($$$$)
+{
+ my $self = shift;
+ my @bbox = @_;
+
+ my $req = new HTTP::Request GET => $self->{url}."/map?bbox=$bbox[0],$bbox[1],$bbox[2],$bbox[3]";
+
+ my $res = $self->_request($req);
+
+ if( $res->code != 200 )
+ {
+ $self->{last_error} = $res;
+ return undef;
+ }
+
+ my @res;
+ $self->{buffer} = \@res;
+ $self->{reader}->parse($res->content);
+ undef $self->{buffer};
+
+ return \@res;
+}
+
+
+1;
diff --git a/navit/script/osm/Geo/OSM/APIClientV5.pm b/navit/script/osm/Geo/OSM/APIClientV5.pm
new file mode 100644
index 000000000..5bee097de
--- /dev/null
+++ b/navit/script/osm/Geo/OSM/APIClientV5.pm
@@ -0,0 +1,327 @@
+##################################################################
+## APIClientV5.pm - General Perl client for the API ##
+## By Martijn van Oosterhout <kleptog@svana.org> ##
+## ##
+## Currently only supports uploading. Note the package actually ##
+## creates a package named Geo::OSM::APIClient so upgrades to ##
+## later versions will be easier. ##
+## Licence: LGPL ##
+##################################################################
+
+use LWP::UserAgent;
+use strict;
+
+package Geo::OSM::APIClient;
+use Geo::OSM::OsmReaderV5;
+use MIME::Base64;
+use HTTP::Request;
+use Carp;
+use Encode;
+use POSIX qw(sigprocmask);
+use URI;
+use Socket qw(inet_ntoa);
+
+sub new
+{
+ my( $class, %attr ) = @_;
+
+ my $obj = bless {}, $class;
+
+ my $url = $attr{api};
+ if( not defined $url )
+ {
+ croak "Did not specify api url";
+ }
+
+ $url =~ s,/$,,; # Strip trailing slash
+ $obj->{url} = URI->new($url);
+ $obj->{client} = new LWP::UserAgent(agent => 'Geo::OSM::APIClientV5', timeout => 1200);
+
+ if( defined $attr{username} and defined $attr{password} )
+ {
+ my $encoded = MIME::Base64::encode_base64("$attr{username}:$attr{password}","");
+ $obj->{client}->default_header( "Authorization", "Basic $encoded" );
+ }
+
+ # We had the problem of the client doing a DNS lookup each request. To
+ # solve this we do a gethostbyname now and store that in the URI.
+ {
+ my $addr;
+ (undef, undef, undef, undef, $addr) = gethostbyname($obj->{url}->host);
+ if( defined $addr )
+ {
+ $obj->{client}->default_header( "Host", $obj->{url}->host );
+ $obj->{url}->host( inet_ntoa($addr) );
+ print STDERR "Using address: ".$obj->{url}->as_string()."\n";
+ }
+ }
+ # Hack to avoid protocol lookups each time
+ @LWP::Protocol::http::EXTRA_SOCK_OPTS = ( 'Proto' => 6 );
+
+ $obj->{reader} = init Geo::OSM::OsmReader( sub { _process($obj,@_) } );
+ return $obj;
+}
+
+# This is the callback from the parser. If checks if the buffer is defined.
+# If the buffer is an array, append the new object. If the buffer is a proc,
+# call it.
+sub _process
+{
+ my($obj,$ent) = @_;
+ if( not defined $obj->{buffer} )
+ { die "Internal error: Received object with buffer" }
+ if( ref $obj->{buffer} eq "ARRAY" )
+ { push @{$obj->{buffer}}, $ent; return }
+ if( ref $obj->{buffer} eq "CODE" )
+ { $obj->{buffer}->($ent); return }
+ die "Internal error: don't know what to do with buffer $obj->{buffer}";
+}
+
+# Utility function to handle the temporary blocking of signals in a way that
+# works with exception handling.
+sub _with_blocked_sigs(&)
+{
+ my $ss = new POSIX::SigSet( &POSIX::SIGINT );
+ my $func = shift;
+ my $os = new POSIX::SigSet;
+ sigprocmask( &POSIX::SIG_BLOCK, $ss, $os );
+ my $ret = eval { &$func };
+ sigprocmask( &POSIX::SIG_SETMASK, $os );
+ die $@ if $@;
+ return $ret;
+}
+
+sub _request
+{
+ my $self = shift;
+ my $req = shift;
+ return _with_blocked_sigs { $self->{client}->request($req) };
+}
+
+sub last_error_code
+{
+ my $self=shift;
+ croak "No last error" unless defined $self->{last_error};
+ return $self->{last_error}->code;
+}
+
+sub last_error_message
+{
+ my $self=shift;
+ croak "No last error" unless defined $self->{last_error};
+ return $self->{last_error}->message;
+}
+
+sub create($)
+{
+ my( $self, $ent ) = @_;
+ my $oldid = $ent->id;
+ $ent->set_id(0);
+ my $content = encode("utf-8", $ent->full_xml);
+ $ent->set_id($oldid);
+ my $req = new HTTP::Request PUT => $self->{url}."/".$ent->type()."/create";
+ $req->content($content);
+
+# print $req->as_string;
+
+ my $res = $self->_request($req);
+
+# print $res->as_string;
+
+ if( $res->code == 200 )
+ {
+ return $res->content
+ }
+
+ $self->{last_error} = $res;
+ return undef;
+}
+
+sub modify($)
+{
+ my( $self, $ent ) = @_;
+ my $content = encode("utf-8", $ent->full_xml);
+ my $req = new HTTP::Request PUT => $self->{url}."/".$ent->type()."/".$ent->id();
+ $req->content($content);
+
+# print $req->as_string;
+
+ my $res = $self->_request($req);
+
+ return $ent->id() if $res->code == 200;
+ $self->{last_error} = $res;
+ return undef;
+}
+
+sub delete($)
+{
+ my( $self, $ent ) = @_;
+ my $content = encode("utf-8", $ent->full_xml);
+ my $req = new HTTP::Request DELETE => $self->{url}."/".$ent->type()."/".$ent->id();
+# $req->content($content);
+
+# print $req->as_string;
+
+ my $res = $self->_request($req);
+
+ return $ent->id() if $res->code == 200;
+ $self->{last_error} = $res;
+ return undef;
+}
+
+sub get($$)
+{
+ my $self = shift;
+ my $type = shift;
+ my $id = shift;
+ my $extra = shift;
+
+ $extra = "/".$extra if (defined $extra);
+ $extra = "" if not defined $extra;
+
+ my $req = new HTTP::Request GET => $self->{url}."/$type/$id$extra";
+
+ my $res = $self->_request($req);
+
+ if( $res->code != 200 )
+ {
+ $self->{last_error} = $res;
+ return undef;
+ }
+
+ my @res;
+ $self->{buffer} = \@res;
+ $self->{reader}->parse($res->content);
+ undef $self->{buffer};
+ if($extra =~ /history/)
+ {
+ return @res;
+ }
+ if(scalar(@res) != 1 )
+ {
+ die "Unexpected response for get_$type [".$res->content()."]\n";
+ }
+
+ return $res[0];
+}
+
+sub resurrect($$)
+{
+ my $self = shift;
+ my $type = shift;
+ my $id = shift;
+
+ my $ret = $self->get($type, $id);
+ if (defined $ret || !defined $self->{last_error} || ($self->{last_error}->code != 410)) {
+ return $ret;
+ }
+
+ my @ents = $self->get($type, $id, 'history');
+ # we want the last _visible_ one
+ my $ent = $ents[-2];
+ if ($ent->type eq 'way') {
+ printf("resurrecting way, checking all member nodes...\n");
+ foreach my $node_id (@{$ent->nodes()}) {
+ printf("checking node: $node_id...");
+ my $node_ent = $self->get('node', $node_id);
+ if (defined $node_ent) {
+ printf("good\n");
+ next;
+ }
+ printf("attempting to resurrect node: $node_id...");
+ $node_ent = $self->resurrect('node', $node_id);
+ if (!defined $node_ent) {
+ die "failed";
+ }
+ printf("success!\n");
+ }
+ printf("all way nodes are OK, ");
+ }
+ printf("attempting to resurrect %s...", $ent->type);
+ $ret = $self->modify($ent);
+ if ($ret == $ent->id) {
+ printf("ok\n");
+ return $ret;
+ }
+ die sprintf("unable to resurrect $type $id: %s\n", $self->last_error_message);
+}
+
+sub get_node($)
+{
+ my $self = shift;
+ return $self->get("node",shift);
+}
+
+sub get_way($)
+{
+ my $self = shift;
+ return $self->get("way",shift);
+}
+
+sub get_relation($)
+{
+ my $self = shift;
+ return $self->get("relation",shift);
+}
+
+sub get_subtype($$)
+{
+ my $self = shift;
+ my $type = shift;
+ my $id = shift;
+ my $subtype = shift;
+
+ my $req = new HTTP::Request GET => $self->{url}."/$type/$id/$subtype";
+
+ my $res = $self->_request($req);
+
+ if( $res->code != 200 )
+ {
+ $self->{last_error} = $res;
+ return undef;
+ }
+
+ my @res;
+ $self->{buffer} = \@res;
+ $self->{reader}->parse($res->content);
+ undef $self->{buffer};
+ if( scalar(@res) < 1 )
+ {
+ die "Unexpected response for get_subtype($type,$id,$subtype) [".$res->content()."]\n";
+ }
+
+ return \@res;
+}
+
+sub get_node_ways($)
+{
+ my $self = shift;
+ my $id = shift;
+
+ return $self->get_subtype("node",$id,"ways");
+}
+
+sub map($$$$)
+{
+ my $self = shift;
+ my @bbox = @_;
+
+ my $req = new HTTP::Request GET => $self->{url}."/map?bbox=$bbox[0],$bbox[1],$bbox[2],$bbox[3]";
+
+ my $res = $self->_request($req);
+
+ if( $res->code != 200 )
+ {
+ $self->{last_error} = $res;
+ return undef;
+ }
+
+ my @res;
+ $self->{buffer} = \@res;
+ $self->{reader}->parse($res->content);
+ undef $self->{buffer};
+
+ return \@res;
+}
+
+1;
diff --git a/navit/script/osm/Geo/OSM/APIClientV6.pm b/navit/script/osm/Geo/OSM/APIClientV6.pm
new file mode 100644
index 000000000..d659ac14c
--- /dev/null
+++ b/navit/script/osm/Geo/OSM/APIClientV6.pm
@@ -0,0 +1,364 @@
+##################################################################
+## APIClientV6.pm - General Perl client for the API ##
+## By Martijn van Oosterhout <kleptog@svana.org> ##
+## ##
+## Currently only supports uploading. Note the package actually ##
+## creates a package named Geo::OSM::APIClient so upgrades to ##
+## later versions will be easier. ##
+## Licence: LGPL ##
+##################################################################
+
+use LWP::UserAgent;
+use strict;
+
+package Geo::OSM::APIClient;
+use Geo::OSM::OsmReaderV6;
+use MIME::Base64;
+use HTTP::Request;
+use Carp;
+use Encode;
+use POSIX qw(sigprocmask);
+use URI;
+use Socket qw(inet_ntoa);
+
+sub new
+{
+ my( $class, %attr ) = @_;
+
+ my $obj = bless {}, $class;
+
+ my $url = $attr{api};
+ if( not defined $url )
+ {
+ croak "Did not specify api url";
+ }
+
+ $url =~ s,/$,,; # Strip trailing slash
+ $obj->{url} = URI->new($url);
+ $obj->{client} = new LWP::UserAgent(agent => 'Geo::OSM::APIClientV6', timeout => 1200);
+
+ if( defined $attr{username} and defined $attr{password} )
+ {
+ my $encoded = MIME::Base64::encode_base64("$attr{username}:$attr{password}","");
+ $obj->{client}->default_header( "Authorization", "Basic $encoded" );
+ }
+
+ # We had the problem of the client doing a DNS lookup each request. To
+ # solve this we do a gethostbyname now and store that in the URI.
+ {
+ my $addr;
+ (undef, undef, undef, undef, $addr) = gethostbyname($obj->{url}->host);
+ if( defined $addr )
+ {
+ $obj->{client}->default_header( "Host", $obj->{url}->host );
+ $obj->{url}->host( inet_ntoa($addr) );
+ print STDERR "Using address: ".$obj->{url}->as_string()."\n";
+ }
+ }
+ # Hack to avoid protocol lookups each time
+ @LWP::Protocol::http::EXTRA_SOCK_OPTS = ( 'Proto' => 6 );
+
+ $obj->{reader} = init Geo::OSM::OsmReader( sub { _process($obj,@_) } );
+ return $obj;
+}
+
+# This is the callback from the parser. If checks if the buffer is defined.
+# If the buffer is an array, append the new object. If the buffer is a proc,
+# call it.
+sub _process
+{
+ my($obj,$ent) = @_;
+ if( not defined $obj->{buffer} )
+ { die "Internal error: Received object with buffer" }
+ if( ref $obj->{buffer} eq "ARRAY" )
+ { push @{$obj->{buffer}}, $ent; return }
+ if( ref $obj->{buffer} eq "CODE" )
+ { $obj->{buffer}->($ent); return }
+ die "Internal error: don't know what to do with buffer $obj->{buffer}";
+}
+
+# Utility function to handle the temporary blocking of signals in a way that
+# works with exception handling.
+sub _with_blocked_sigs(&)
+{
+ my $ss = new POSIX::SigSet( &POSIX::SIGINT );
+ my $func = shift;
+ my $os = new POSIX::SigSet;
+ sigprocmask( &POSIX::SIG_BLOCK, $ss, $os );
+ my $ret = eval { &$func };
+ sigprocmask( &POSIX::SIG_SETMASK, $os );
+ die $@ if $@;
+ return $ret;
+}
+
+sub _request
+{
+ my $self = shift;
+ my $req = shift;
+ return _with_blocked_sigs { $self->{client}->request($req) };
+}
+
+sub last_error_code
+{
+ my $self=shift;
+ croak "No last error" unless defined $self->{last_error};
+ return $self->{last_error}->code;
+}
+
+sub last_error_message
+{
+ my $self=shift;
+ croak "No last error" unless defined $self->{last_error};
+ return $self->{last_error}->message;
+}
+
+sub create_changeset
+{
+ my( $self ) = @_;
+ my $req = new HTTP::Request PUT => $self->{url}."/changeset/create";
+ my $content="<osm><changeset></changeset></osm>";
+ $req->content($content);
+ my $res = $self->_request($req);
+
+ if( $res->code == 200 )
+ {
+ $self->{changeset}=$res->content;
+ return 1;
+ }
+
+ $self->{last_error} = $res;
+ $self->{changeset}=undef;
+ return 0;
+
+}
+
+sub close_changeset
+{
+ my( $self ) = @_;
+ my $req = new HTTP::Request PUT => $self->{url}."/changeset/".$self->{changeset}."/close";
+ my $res = $self->_request($req);
+
+ $self->{changeset}=undef;
+ if( $res->code == 200 )
+ {
+ return 1;
+ }
+ return 0;
+
+}
+
+sub create($)
+{
+ my( $self, $ent ) = @_;
+ my $oldid = $ent->id;
+ $ent->set_id(0);
+ my $content = encode("utf-8", $ent->full_xml);
+ $ent->set_id($oldid);
+ my $req = new HTTP::Request PUT => $self->{url}."/".$ent->type()."/create";
+ $req->content($content);
+
+# print $req->as_string;
+
+ my $res = $self->_request($req);
+
+# print $res->as_string;
+
+ if( $res->code == 200 )
+ {
+ return $res->content
+ }
+
+ $self->{last_error} = $res;
+ return undef;
+}
+
+sub modify($)
+{
+ my( $self, $ent ) = @_;
+ $ent->set_changeset($self->{changeset});
+ my $content = encode("utf-8", $ent->full_xml);
+ my $req = new HTTP::Request PUT => $self->{url}."/".$ent->type()."/".$ent->id();
+ $req->content($content);
+
+# print $req->as_string;
+
+ my $res = $self->_request($req);
+
+ return $ent->id() if $res->code == 200;
+ $self->{last_error} = $res;
+ return undef;
+}
+
+sub delete($)
+{
+ my( $self, $ent ) = @_;
+ $ent->set_changeset($self->{changeset});
+ my $content = encode("utf-8", $ent->full_xml);
+ my $req = new HTTP::Request DELETE => $self->{url}."/".$ent->type()."/".$ent->id();
+ $req->content($content);
+
+# print $req->as_string;
+
+ my $res = $self->_request($req);
+
+ return $ent->id() if $res->code == 200;
+ $self->{last_error} = $res;
+ return undef;
+}
+
+sub get($$)
+{
+ my $self = shift;
+ my $type = shift;
+ my $id = shift;
+ my $extra = shift;
+
+ $extra = "/".$extra if (defined $extra);
+ $extra = "" if not defined $extra;
+
+ my $req = new HTTP::Request GET => $self->{url}."/$type/$id$extra";
+
+ my $res = $self->_request($req);
+
+ if( $res->code != 200 )
+ {
+ $self->{last_error} = $res;
+ return undef;
+ }
+
+ my @res;
+ $self->{buffer} = \@res;
+ $self->{reader}->parse($res->content);
+ undef $self->{buffer};
+ if($extra =~ /history/)
+ {
+ return @res;
+ }
+ if(scalar(@res) != 1 )
+ {
+ die "Unexpected response for get_$type [".$res->content()."]\n";
+ }
+
+ return $res[0];
+}
+
+sub resurrect($$)
+{
+ my $self = shift;
+ my $type = shift;
+ my $id = shift;
+
+ my $ret = $self->get($type, $id);
+ if (defined $ret || !defined $self->{last_error} || ($self->{last_error}->code != 410)) {
+ return $ret;
+ }
+
+ my @ents = $self->get($type, $id, 'history');
+ # we want the last _visible_ one
+ my $ent = $ents[-2];
+ if ($ent->type eq 'way') {
+ printf("resurrecting way, checking all member nodes...\n");
+ foreach my $node_id (@{$ent->nodes()}) {
+ printf("checking node: $node_id...");
+ my $node_ent = $self->get('node', $node_id);
+ if (defined $node_ent) {
+ printf("good\n");
+ next;
+ }
+ printf("attempting to resurrect node: $node_id...");
+ $node_ent = $self->resurrect('node', $node_id);
+ if (!defined $node_ent) {
+ die "failed";
+ }
+ printf("success!\n");
+ }
+ printf("all way nodes are OK, ");
+ }
+ printf("attempting to resurrect %s...", $ent->type);
+ $ret = $self->modify($ent);
+ if ($ret == $ent->id) {
+ printf("ok\n");
+ return $ret;
+ }
+ die sprintf("unable to resurrect $type $id: %s\n", $self->last_error_message);
+}
+
+sub get_node($)
+{
+ my $self = shift;
+ return $self->get("node",shift);
+}
+
+sub get_way($)
+{
+ my $self = shift;
+ return $self->get("way",shift);
+}
+
+sub get_relation($)
+{
+ my $self = shift;
+ return $self->get("relation",shift);
+}
+
+sub get_subtype($$)
+{
+ my $self = shift;
+ my $type = shift;
+ my $id = shift;
+ my $subtype = shift;
+
+ my $req = new HTTP::Request GET => $self->{url}."/$type/$id/$subtype";
+
+ my $res = $self->_request($req);
+
+ if( $res->code != 200 )
+ {
+ $self->{last_error} = $res;
+ return undef;
+ }
+
+ my @res;
+ $self->{buffer} = \@res;
+ $self->{reader}->parse($res->content);
+ undef $self->{buffer};
+ if( scalar(@res) < 1 )
+ {
+ die "Unexpected response for get_subtype($type,$id,$subtype) [".$res->content()."]\n";
+ }
+
+ return \@res;
+}
+
+sub get_node_ways($)
+{
+ my $self = shift;
+ my $id = shift;
+
+ return $self->get_subtype("node",$id,"ways");
+}
+
+sub map($$$$)
+{
+ my $self = shift;
+ my @bbox = @_;
+
+ my $req = new HTTP::Request GET => $self->{url}."/map?bbox=$bbox[0],$bbox[1],$bbox[2],$bbox[3]";
+
+ my $res = $self->_request($req);
+
+ if( $res->code != 200 )
+ {
+ $self->{last_error} = $res;
+ return undef;
+ }
+
+ my @res;
+ $self->{buffer} = \@res;
+ $self->{reader}->parse($res->content);
+ undef $self->{buffer};
+
+ return \@res;
+}
+
+1;
diff --git a/navit/script/osm/Geo/OSM/EntitiesV3.pm b/navit/script/osm/Geo/OSM/EntitiesV3.pm
new file mode 100644
index 000000000..2708463c7
--- /dev/null
+++ b/navit/script/osm/Geo/OSM/EntitiesV3.pm
@@ -0,0 +1,296 @@
+##################################################################
+## EntitiesV3.pm - Wraps entities used by OSM ##
+## By Martijn van Oosterhout <kleptog@svana.org> ##
+## ##
+## Package that wraps the entities used by OSM into Perl ##
+## object, so they can be easily manipulated by various ##
+## packages. ##
+## ##
+## Licence: LGPL ##
+##################################################################
+
+use XML::Writer;
+use strict;
+
+############################################################################
+## Top level Entity type, parent of all types, includes stuff relating to ##
+## tags and IDs which are shared by all entity types ##
+############################################################################
+package Geo::OSM::Entity;
+use POSIX qw(strftime);
+
+use Carp;
+
+sub _new
+{
+ bless {}, shift;
+}
+
+sub _get_writer
+{
+ my($self,$res) = @_;
+ return new XML::Writer(OUTPUT => $res, NEWLINES => 0, ENCODING => 'utf-8');
+}
+
+sub add_tag
+{
+ my($self, $k,$v) = @_;
+ push @{$self->{tags}}, $k, $v;
+}
+
+sub add_tags
+{
+ my($self, @tags) = @_;
+ if( scalar(@tags)&1 )
+ { croak "add_tags requires an even number of arguments" }
+ push @{$self->{tags}}, @tags;
+}
+
+sub set_tags
+{
+ my($self,$tags) = @_;
+ if( ref($tags) eq "HASH" )
+ { $self->{tags} = [%$tags] }
+ elsif( ref($tags) eq "ARRAY" )
+ { $self->{tags} = [@$tags] }
+ else
+ { croak "set_tags must be HASH or ARRAY" }
+}
+
+sub tags
+{
+ my $self = shift;
+ return [@{$self->{tags}}]; # Return copy
+}
+
+sub tag_xml
+{
+ my ($self,$writer) = @_;
+ my @a = @{$self->{tags}};
+
+ my $str = "";
+
+ while( my($k,$v) = splice @a, 0, 2 )
+ {
+ $writer->emptyTag( "tag", 'k' => $k, 'v' => $v );
+ }
+}
+
+our $_ID = -1;
+
+sub set_id
+{
+ my($self,$id) = @_;
+
+ if( not defined $id )
+ { $id = $_ID-- }
+ $self->{id} = $id;
+}
+
+sub id
+{
+ my $self = shift;
+ return $self->{id};
+}
+
+sub set_timestamp
+{
+ my($self,$time) = @_;
+ if( defined $time )
+ { $self->{timestamp} = $time }
+ else
+ { $self->{timestamp} = strftime "%Y-%m-%dT%H:%M:%S+00:00", gmtime(time) }
+}
+
+sub timestamp
+{
+ my $self = shift;
+ return $self->{timestamp};
+}
+
+sub full_xml
+{
+ my $self = shift;
+ return qq(<?xml version="1.0"?>\n<osm version="0.4">\n).$self->xml()."</osm>\n";
+}
+
+package Geo::OSM::Way;
+our @ISA = qw(Geo::OSM::Entity);
+
+sub new
+{
+ my($class, $attr, $tags, $segs) = @_;
+
+ my $obj = bless $class->SUPER::_new(), $class;
+
+ $obj->set_tags($tags);
+ $obj->set_segs($segs);
+ $obj->set_id($attr->{id} );
+ $obj->set_timestamp( $attr->{timestamp} );
+
+ return $obj;
+}
+
+sub type { return "way" }
+
+sub set_segs
+{
+ my($self,$segs) = @_;
+ $self->{segs} = $segs;
+}
+
+sub segs
+{
+ my $self = shift;
+ return [@{$self->{segs}}]; # Return a copy
+}
+
+sub xml
+{
+ my $self = shift;
+ my $str = "";
+ my $writer = $self->_get_writer(\$str);
+
+ $writer->startTag( "way", id => $self->id, timestamp => $self->timestamp );
+ $self->tag_xml( $writer );
+ for my $seg (@{$self->segs})
+ {
+ $writer->emptyTag( "seg", id => $seg );
+ }
+ $writer->endTag( "way" );
+ $writer->end;
+ return $str;
+}
+
+sub map
+{
+ my($self,$mapper) = @_;
+ my $incomplete = 0;
+ my ($new_id) = $mapper->map('way',$self->id); # Determine mapped ID
+ # It is ok for the new_id to be incomplete; it may be a create request
+
+ my @new_segs = map { [ $mapper->map('segment',$_) ] } @{$self->segs};
+ map { $incomplete |= $_->[1] } @new_segs;
+ # incomplete tracks if any of the segs are incomplete
+
+ my $new_ent = new Geo::OSM::Way( {id=>$new_id, timestamp=>$self->timestamp}, $self->tags, [map {$_->[0]} @new_segs] );
+ return($new_ent,$incomplete);
+}
+
+package Geo::OSM::Segment;
+our @ISA = qw(Geo::OSM::Entity);
+
+sub new
+{
+ my($class, $attr, $tags) = @_;
+
+ my $obj = bless $class->SUPER::_new(), $class;
+
+ $obj->set_tags($tags);
+ $obj->set_id($attr->{id} );
+ $obj->set_timestamp( $attr->{timestamp} );
+ $obj->{from} = $attr->{from};
+ $obj->{to} = $attr->{to};
+
+ return $obj;
+}
+
+sub type { return "segment" }
+
+sub set_fromto
+{
+ my($self,$from,$to) = @_;
+ $self->{from} = $from;
+ $self->{to} = $to;
+}
+
+sub from
+{
+ shift->{from};
+}
+sub to
+{
+ shift->{to};
+}
+
+sub xml
+{
+ my $self = shift;
+ my $str = "";
+ my $writer = $self->_get_writer(\$str);
+
+ $writer->startTag( "segment", id => $self->id, from => $self->from, to => $self->to, timestamp => $self->timestamp );
+ $self->tag_xml( $writer );
+ $writer->endTag( "segment" );
+ $writer->end;
+ return $str;
+}
+
+sub map
+{
+ my($self,$mapper) = @_;
+ my ($new_id) = $mapper->map('segment',$self->id);
+ my ($new_from,$i1) = $mapper->map('node',$self->from);
+ my ($new_to,$i2) = $mapper->map('node',$self->to);
+ my $new_ent = new Geo::OSM::Segment( {id=>$new_id, timestamp=>$self->timestamp, from=>$new_from, to=>$new_to}, $self->tags );
+ return($new_ent,$i1|$i2);
+}
+
+package Geo::OSM::Node;
+our @ISA = qw(Geo::OSM::Entity);
+
+sub new
+{
+ my($class, $attr, $tags) = @_;
+
+ my $obj = bless $class->SUPER::_new(), $class;
+
+ $obj->set_tags($tags);
+ $obj->set_id($attr->{id} );
+ $obj->set_timestamp( $attr->{timestamp} );
+ $obj->{lon} = $attr->{lon};
+ $obj->{lat} = $attr->{lat};
+
+ return $obj;
+}
+
+sub type { return "node" }
+
+sub set_latlon
+{
+ my($self,$lat,$lon) = @_;
+ $self->{lat} = $lat;
+ $self->{lon} = $lon;
+}
+
+sub lat
+{
+ shift->{lat};
+}
+sub lon
+{
+ shift->{lon};
+}
+
+sub xml
+{
+ my $self = shift;
+ my $str = "";
+ my $writer = $self->_get_writer(\$str);
+
+ $writer->startTag( "node", id => $self->id, lat => $self->lat, lon => $self->lon, timestamp => $self->timestamp );
+ $self->tag_xml( $writer );
+ $writer->endTag( "node" );
+ $writer->end;
+ return $str;
+}
+
+sub map
+{
+ my($self,$mapper) = @_;
+ my ($new_id) = $mapper->map('node',$self->id);
+ my $new_ent = new Geo::OSM::Node( {id=>$new_id, timestamp=>$self->timestamp, lat=>$self->lat, lon=>$self->lon}, $self->tags );
+ return($new_ent,0);
+}
+
+1;
diff --git a/navit/script/osm/Geo/OSM/EntitiesV5.pm b/navit/script/osm/Geo/OSM/EntitiesV5.pm
new file mode 100644
index 000000000..625ff6b03
--- /dev/null
+++ b/navit/script/osm/Geo/OSM/EntitiesV5.pm
@@ -0,0 +1,375 @@
+##################################################################
+## EntitiesV3.pm - Wraps entities used by OSM ##
+## By Martijn van Oosterhout <kleptog@svana.org> ##
+## ##
+## Package that wraps the entities used by OSM into Perl ##
+## object, so they can be easily manipulated by various ##
+## packages. ##
+## ##
+## Licence: LGPL ##
+##################################################################
+
+use XML::Writer;
+use strict;
+
+############################################################################
+## Top level Entity type, parent of all types, includes stuff relating to ##
+## tags and IDs which are shared by all entity types ##
+############################################################################
+package Geo::OSM::Entity;
+use POSIX qw(strftime);
+
+use Carp;
+
+sub _new
+{
+ bless {}, shift;
+}
+
+sub _get_writer
+{
+ my($self,$res) = @_;
+ return new XML::Writer(OUTPUT => $res, NEWLINES => 0, ENCODING => 'utf-8');
+}
+
+sub add_tag
+{
+ my($self, $k,$v) = @_;
+ push @{$self->{tags}}, $k, $v;
+}
+
+sub add_tags
+{
+ my($self, @tags) = @_;
+ if( scalar(@tags)&1 )
+ { croak "add_tags requires an even number of arguments" }
+ push @{$self->{tags}}, @tags;
+}
+
+sub set_tags
+{
+ my($self,$tags) = @_;
+ if( ref($tags) eq "HASH" )
+ { $self->{tags} = [%$tags] }
+ elsif( ref($tags) eq "ARRAY" )
+ { $self->{tags} = [@$tags] }
+ else
+ { croak "set_tags must be HASH or ARRAY" }
+}
+
+sub tags
+{
+ my $self = shift;
+ return [@{$self->{tags}}]; # Return copy
+}
+
+sub tag_xml
+{
+ my ($self,$writer) = @_;
+ my @a = @{$self->{tags}};
+
+ my $str = "";
+
+ while( my($k,$v) = splice @a, 0, 2 )
+ {
+ $writer->emptyTag( "tag", 'k' => $k, 'v' => $v );
+ }
+}
+
+our $_ID = -1;
+
+sub set_id
+{
+ my($self,$id) = @_;
+
+ if( not defined $id )
+ { $id = $_ID-- }
+ $self->{id} = $id;
+}
+
+sub id
+{
+ my $self = shift;
+ return $self->{id};
+}
+
+sub set_timestamp
+{
+ my($self,$time) = @_;
+ if( defined $time )
+ { $self->{timestamp} = $time }
+ else
+ { $self->{timestamp} = strftime "%Y-%m-%dT%H:%M:%S+00:00", gmtime(time) }
+}
+
+sub timestamp
+{
+ my $self = shift;
+ return $self->{timestamp};
+}
+
+sub full_xml
+{
+ my $self = shift;
+ return qq(<?xml version="1.0"?>\n<osm version="0.5">\n).$self->xml()."</osm>\n";
+}
+
+package Geo::OSM::Way;
+our @ISA = qw(Geo::OSM::Entity);
+use Carp;
+
+sub new
+{
+ my($class, $attr, $tags, $nodes) = @_;
+
+ my $obj = bless $class->SUPER::_new(), $class;
+
+ $obj->set_tags($tags);
+ $obj->set_nodes($nodes);
+ $obj->set_id($attr->{id} );
+ $obj->set_timestamp( $attr->{timestamp} );
+
+ return $obj;
+}
+
+sub type { return "way" }
+
+sub set_nodes
+{
+ my($self,$nodes) = @_;
+ if( not defined $nodes )
+ { $nodes = [] }
+ if( ref($nodes) ne "ARRAY" )
+ { $nodes = [$nodes] }
+ if( scalar( grep { (ref($_) ne "")?$_->type ne "node":$_ !~ /^-?\d+/ } @$nodes ) )
+ { croak "Expected array of nodes" }
+ $self->{nodes} = [map { ref($_)?$_->id:$_ } @$nodes];
+}
+
+sub nodes
+{
+ my $self = shift;
+ return [@{$self->{nodes}}]; # Return a copy
+}
+
+sub xml
+{
+ my $self = shift;
+ my $str = "";
+ my $writer = $self->_get_writer(\$str);
+
+ $writer->startTag( "way", id => $self->id, timestamp => $self->timestamp );
+ $self->tag_xml( $writer );
+ for my $node (@{$self->nodes})
+ {
+ $writer->emptyTag( "nd", ref => $node );
+ }
+ $writer->endTag( "way" );
+ $writer->end;
+ return $str;
+}
+
+sub map
+{
+ my($self,$mapper) = @_;
+ my $incomplete = 0;
+ my ($new_id) = $mapper->map('way',$self->id); # Determine mapped ID
+ # It is ok for the new_id to be incomplete; it may be a create request
+
+ my @new_nodes = map { [ $mapper->map('node',$_) ] } @{$self->nodes};
+ map { $incomplete |= $_->[1] } @new_nodes;
+ # incomplete tracks if any of the segs are incomplete
+
+ my $new_ent = new Geo::OSM::Way( {id=>$new_id, timestamp=>$self->timestamp}, $self->tags, [map {$_->[0]} @new_nodes] );
+ return($new_ent,$incomplete);
+}
+
+package Geo::OSM::Relation::Member;
+use Carp;
+# Relation reference can be specified in several ways:
+# { type => $type, ref => $id [ , role => $str ] }
+# { ref => $obj [ , role => $str ] }
+# [ $type, $id [,$role] ]
+# [ $obj, [,$role] ]
+sub new
+{
+ my $class = shift;
+ my $arg = shift;
+ return $arg if ref($arg) eq $class; # Return if already object
+ if( ref($arg) eq "ARRAY" )
+ {
+ if( ref $arg->[0] )
+ { $arg = { ref => $arg->[0], role => $arg->[1] } }
+ else
+ { $arg = { type => $arg->[0], ref => $arg->[1], role => $arg->[2] } }
+ }
+ if( ref($arg) eq "HASH" )
+ {
+ if( ref $arg->{ref} )
+ { $arg = [ $arg->{ref}->type, $arg->{ref}->id, $arg->{role} ] }
+ else
+ { $arg = [ $arg->{type}, $arg->{ref}, $arg->{role} ] }
+ }
+ else
+ { croak "Relation reference must be array or hash" }
+ croak "Bad type of member '$arg->[0]'"
+ unless $arg->[0] =~ /^(way|node|relation)$/;
+ croak "Bad member id '$arg->[1]'"
+ unless $arg->[1] =~ /^-?\d+$/;
+ $arg->[2] ||= "";
+
+ return bless $arg, $class;
+}
+
+sub member_type { shift->[0] }
+sub ref { shift->[1] }
+sub role { shift->[2] }
+
+sub type { return "relation:member" }
+
+sub _xml
+{
+ my $self = shift;
+ my $writer = shift;
+
+ $writer->emptyTag( "member", type => $self->member_type, ref => $self->ref, role => $self->role );
+}
+
+sub map
+{
+ my($self,$mapper) = @_;
+ my ($new_ref,$incomplete) = $mapper->map($self->member_type,$self->ref);
+ my $new_member = new Geo::OSM::Relation::Member( { type => $self->member_type, ref => $new_ref, role => $self->role } );
+ return($new_member,$incomplete);
+}
+
+package Geo::OSM::Relation;
+our @ISA = qw(Geo::OSM::Entity);
+
+sub new
+{
+ my($class, $attr, $tags, $members) = @_;
+
+ my $obj = bless $class->SUPER::_new(), $class;
+
+ $obj->set_tags($tags);
+ $obj->set_members($members);
+ $obj->set_id($attr->{id} );
+ $obj->set_timestamp( $attr->{timestamp} );
+
+ return $obj;
+}
+
+sub set_members
+{
+ my($self,$members) = @_;
+ if( not defined $members )
+ { $members = [] }
+ if( ref($members) ne "ARRAY" )
+ { $members = [$members] }
+ $self->{members} = [map { new Geo::OSM::Relation::Member($_) } @$members];
+}
+
+sub members
+{
+ my $self = shift;
+ return [@{$self->{members}}];
+}
+
+sub type { return "relation" }
+
+sub xml
+{
+ my $self = shift;
+ my $str = "";
+ my $writer = $self->_get_writer(\$str);
+
+ $writer->startTag( "relation", id => $self->id, timestamp => $self->timestamp );
+ $self->tag_xml( $writer );
+ # Write members
+ foreach my $member (@{$self->{members}})
+ { $member->_xml( $writer ) }
+ $writer->endTag( "relation" );
+ $writer->end;
+ return $str;
+}
+
+sub map
+{
+ my($self,$mapper) = @_;
+ my $incomplete = 0;
+
+ my ($new_id) = $mapper->map('relation',$self->id);
+ my @new_members = map { [ $_->map($mapper) ] } @{$self->members};
+ map { $incomplete |= $_->[1] } @new_members;
+ # incomplete tracks if any of the members are incomplete
+ my $new_ent = new Geo::OSM::Relation( {id=>$new_id, timestamp=>$self->timestamp}, $self->tags, [map {$_->[0]} @new_members] );
+ return($new_ent,$incomplete);
+}
+
+package Geo::OSM::Node;
+use Carp;
+our @ISA = qw(Geo::OSM::Entity);
+
+sub new
+{
+ my($class, $attr, $tags) = @_;
+
+ my $obj = bless $class->SUPER::_new(), $class;
+
+ $obj->set_tags($tags);
+ $obj->set_id($attr->{id} );
+ $obj->set_timestamp( $attr->{timestamp} );
+ if( $attr->{lon} !~ /^[-+]?\d+(\.\d+)?([eE][+-]?\d+)?$/ or
+ $attr->{lat} !~ /^[-+]?\d+(\.\d+)?([eE][+-]?\d+)?$/ )
+ {
+ croak "Invalid lat,lon values ($attr->{lat},$attr->{lon})\n";
+ }
+ $obj->{lon} = $attr->{lon};
+ $obj->{lat} = $attr->{lat};
+
+ return $obj;
+}
+
+sub type { return "node" }
+
+sub set_latlon
+{
+ my($self,$lat,$lon) = @_;
+ $self->{lat} = $lat;
+ $self->{lon} = $lon;
+}
+
+sub lat
+{
+ shift->{lat};
+}
+sub lon
+{
+ shift->{lon};
+}
+
+sub xml
+{
+ my $self = shift;
+ my $str = "";
+ my $writer = $self->_get_writer(\$str);
+
+ $writer->startTag( "node", id => $self->id, lat => $self->lat, lon => $self->lon, timestamp => $self->timestamp );
+ $self->tag_xml( $writer );
+ $writer->endTag( "node" );
+ $writer->end;
+ return $str;
+}
+
+sub map
+{
+ my($self,$mapper) = @_;
+ my ($new_id) = $mapper->map('node',$self->id);
+ my $new_ent = new Geo::OSM::Node( {id=>$new_id, timestamp=>$self->timestamp, lat=>$self->lat, lon=>$self->lon}, $self->tags );
+ return($new_ent,0);
+}
+
+
+
+1;
diff --git a/navit/script/osm/Geo/OSM/EntitiesV6.pm b/navit/script/osm/Geo/OSM/EntitiesV6.pm
new file mode 100644
index 000000000..8747c17f0
--- /dev/null
+++ b/navit/script/osm/Geo/OSM/EntitiesV6.pm
@@ -0,0 +1,404 @@
+##################################################################
+## EntitiesV3.pm - Wraps entities used by OSM ##
+## By Martijn van Oosterhout <kleptog@svana.org> ##
+## ##
+## Package that wraps the entities used by OSM into Perl ##
+## object, so they can be easily manipulated by various ##
+## packages. ##
+## ##
+## Licence: LGPL ##
+##################################################################
+
+use XML::Writer;
+use strict;
+
+############################################################################
+## Top level Entity type, parent of all types, includes stuff relating to ##
+## tags and IDs which are shared by all entity types ##
+############################################################################
+package Geo::OSM::Entity;
+use POSIX qw(strftime);
+
+use Carp;
+
+sub _new
+{
+ bless {}, shift;
+}
+
+sub _get_writer
+{
+ my($self,$res) = @_;
+ return new XML::Writer(OUTPUT => $res, NEWLINES => 0, ENCODING => 'utf-8');
+}
+
+sub add_tag
+{
+ my($self, $k,$v) = @_;
+ push @{$self->{tags}}, $k, $v;
+}
+
+sub add_tags
+{
+ my($self, @tags) = @_;
+ if( scalar(@tags)&1 )
+ { croak "add_tags requires an even number of arguments" }
+ push @{$self->{tags}}, @tags;
+}
+
+sub set_tags
+{
+ my($self,$tags) = @_;
+ if( ref($tags) eq "HASH" )
+ { $self->{tags} = [%$tags] }
+ elsif( ref($tags) eq "ARRAY" )
+ { $self->{tags} = [@$tags] }
+ else
+ { croak "set_tags must be HASH or ARRAY" }
+}
+
+sub tags
+{
+ my $self = shift;
+ return [@{$self->{tags}}]; # Return copy
+}
+
+sub tag_xml
+{
+ my ($self,$writer) = @_;
+ my @a = @{$self->{tags}};
+
+ my $str = "";
+
+ while( my($k,$v) = splice @a, 0, 2 )
+ {
+ $writer->emptyTag( "tag", 'k' => $k, 'v' => $v );
+ }
+}
+
+our $_ID = -1;
+
+sub set_id
+{
+ my($self,$id) = @_;
+
+ if( not defined $id )
+ { $id = $_ID-- }
+ $self->{id} = $id;
+}
+
+sub id
+{
+ my $self = shift;
+ return $self->{id};
+}
+
+sub set_timestamp
+{
+ my($self,$time) = @_;
+ if( defined $time )
+ { $self->{timestamp} = $time }
+ else
+ { $self->{timestamp} = strftime "%Y-%m-%dT%H:%M:%S+00:00", gmtime(time) }
+}
+
+sub timestamp
+{
+ my $self = shift;
+ return $self->{timestamp};
+}
+
+sub set_changeset
+{
+ my($self,$changeset) = @_;
+ $self->{changeset} = $changeset;
+}
+
+sub changeset
+{
+ shift->{changeset};
+}
+
+sub set_version
+{
+ my($self,$version) = @_;
+ $self->{version} = $version;
+}
+
+sub version
+{
+ shift->{version};
+}
+
+sub full_xml
+{
+ my $self = shift;
+ return qq(<?xml version="1.0"?>\n<osm version="0.6">\n).$self->xml()."</osm>\n";
+}
+
+package Geo::OSM::Way;
+our @ISA = qw(Geo::OSM::Entity);
+use Carp;
+
+sub new
+{
+ my($class, $attr, $tags, $nodes) = @_;
+
+ my $obj = bless $class->SUPER::_new(), $class;
+
+ $obj->set_tags($tags);
+ $obj->set_nodes($nodes);
+ $obj->set_id($attr->{id} );
+ $obj->set_timestamp( $attr->{timestamp} );
+ $obj->set_changeset( $attr->{changeset} );
+ $obj->set_version( $attr->{version} );
+
+ return $obj;
+}
+
+sub type { return "way" }
+
+sub set_nodes
+{
+ my($self,$nodes) = @_;
+ if( not defined $nodes )
+ { $nodes = [] }
+ if( ref($nodes) ne "ARRAY" )
+ { $nodes = [$nodes] }
+ if( scalar( grep { (ref($_) ne "")?$_->type ne "node":$_ !~ /^-?\d+/ } @$nodes ) )
+ { croak "Expected array of nodes" }
+ $self->{nodes} = [map { ref($_)?$_->id:$_ } @$nodes];
+}
+
+sub nodes
+{
+ my $self = shift;
+ return [@{$self->{nodes}}]; # Return a copy
+}
+
+sub xml
+{
+ my $self = shift;
+ my $str = "";
+ my $writer = $self->_get_writer(\$str);
+
+ $writer->startTag( "way", id => $self->id, timestamp => $self->timestamp, changeset => $self->changeset, version => $self->version);
+ $self->tag_xml( $writer );
+ for my $node (@{$self->nodes})
+ {
+ $writer->emptyTag( "nd", ref => $node );
+ }
+ $writer->endTag( "way" );
+ $writer->end;
+ return $str;
+}
+
+sub map
+{
+ my($self,$mapper) = @_;
+ my $incomplete = 0;
+ my ($new_id) = $mapper->map('way',$self->id); # Determine mapped ID
+ # It is ok for the new_id to be incomplete; it may be a create request
+
+ my @new_nodes = map { [ $mapper->map('node',$_) ] } @{$self->nodes};
+ map { $incomplete |= $_->[1] } @new_nodes;
+ # incomplete tracks if any of the segs are incomplete
+
+ my $new_ent = new Geo::OSM::Way( {id=>$new_id, timestamp=>$self->timestamp}, $self->tags, [map {$_->[0]} @new_nodes] );
+ return($new_ent,$incomplete);
+}
+
+package Geo::OSM::Relation::Member;
+use Carp;
+# Relation reference can be specified in several ways:
+# { type => $type, ref => $id [ , role => $str ] }
+# { ref => $obj [ , role => $str ] }
+# [ $type, $id [,$role] ]
+# [ $obj, [,$role] ]
+sub new
+{
+ my $class = shift;
+ my $arg = shift;
+ return $arg if ref($arg) eq $class; # Return if already object
+ if( ref($arg) eq "ARRAY" )
+ {
+ if( ref $arg->[0] )
+ { $arg = { ref => $arg->[0], role => $arg->[1] } }
+ else
+ { $arg = { type => $arg->[0], ref => $arg->[1], role => $arg->[2] } }
+ }
+ if( ref($arg) eq "HASH" )
+ {
+ if( ref $arg->{ref} )
+ { $arg = [ $arg->{ref}->type, $arg->{ref}->id, $arg->{role} ] }
+ else
+ { $arg = [ $arg->{type}, $arg->{ref}, $arg->{role} ] }
+ }
+ else
+ { croak "Relation reference must be array or hash" }
+ croak "Bad type of member '$arg->[0]'"
+ unless $arg->[0] =~ /^(way|node|relation)$/;
+ croak "Bad member id '$arg->[1]'"
+ unless $arg->[1] =~ /^-?\d+$/;
+ $arg->[2] ||= "";
+
+ return bless $arg, $class;
+}
+
+sub member_type { shift->[0] }
+sub ref { shift->[1] }
+sub role { shift->[2] }
+
+sub type { return "relation:member" }
+
+sub _xml
+{
+ my $self = shift;
+ my $writer = shift;
+
+ $writer->emptyTag( "member", type => $self->member_type, ref => $self->ref, role => $self->role );
+}
+
+sub map
+{
+ my($self,$mapper) = @_;
+ my ($new_ref,$incomplete) = $mapper->map($self->member_type,$self->ref);
+ my $new_member = new Geo::OSM::Relation::Member( { type => $self->member_type, ref => $new_ref, role => $self->role } );
+ return($new_member,$incomplete);
+}
+
+package Geo::OSM::Relation;
+our @ISA = qw(Geo::OSM::Entity);
+
+sub new
+{
+ my($class, $attr, $tags, $members) = @_;
+
+ my $obj = bless $class->SUPER::_new(), $class;
+
+ $obj->set_tags($tags);
+ $obj->set_members($members);
+ $obj->set_id($attr->{id} );
+ $obj->set_timestamp( $attr->{timestamp} );
+ $obj->set_changeset( $attr->{changeset} );
+ $obj->set_version( $attr->{version} );
+
+ return $obj;
+}
+
+sub set_members
+{
+ my($self,$members) = @_;
+ if( not defined $members )
+ { $members = [] }
+ if( ref($members) ne "ARRAY" )
+ { $members = [$members] }
+ $self->{members} = [map { new Geo::OSM::Relation::Member($_) } @$members];
+}
+
+sub members
+{
+ my $self = shift;
+ return [@{$self->{members}}];
+}
+
+sub type { return "relation" }
+
+sub xml
+{
+ my $self = shift;
+ my $str = "";
+ my $writer = $self->_get_writer(\$str);
+
+ $writer->startTag( "relation", id => $self->id, timestamp => $self->timestamp, changeset => $self->changeset, version => $self->version );
+ $self->tag_xml( $writer );
+ # Write members
+ foreach my $member (@{$self->{members}})
+ { $member->_xml( $writer ) }
+ $writer->endTag( "relation" );
+ $writer->end;
+ return $str;
+}
+
+sub map
+{
+ my($self,$mapper) = @_;
+ my $incomplete = 0;
+
+ my ($new_id) = $mapper->map('relation',$self->id);
+ my @new_members = map { [ $_->map($mapper) ] } @{$self->members};
+ map { $incomplete |= $_->[1] } @new_members;
+ # incomplete tracks if any of the members are incomplete
+ my $new_ent = new Geo::OSM::Relation( {id=>$new_id, timestamp=>$self->timestamp}, $self->tags, [map {$_->[0]} @new_members] );
+ return($new_ent,$incomplete);
+}
+
+package Geo::OSM::Node;
+use Carp;
+use Data::Dumper;
+our @ISA = qw(Geo::OSM::Entity);
+
+sub new
+{
+ my($class, $attr, $tags) = @_;
+
+ my $obj = bless $class->SUPER::_new(), $class;
+
+ $obj->set_tags($tags);
+ $obj->set_id($attr->{id} );
+ $obj->set_timestamp( $attr->{timestamp} );
+ $obj->set_changeset( $attr->{changeset} );
+ $obj->set_version( $attr->{version} );
+ if( $attr->{lon} !~ /^[-+]?\d+(\.\d+)?([eE][+-]?\d+)?$/ or
+ $attr->{lat} !~ /^[-+]?\d+(\.\d+)?([eE][+-]?\d+)?$/ )
+ {
+ croak "Invalid lat,lon values ($attr->{lat},$attr->{lon})\n";
+ }
+ $obj->{lon} = $attr->{lon};
+ $obj->{lat} = $attr->{lat};
+
+ return $obj;
+}
+
+sub type { return "node" }
+
+sub set_latlon
+{
+ my($self,$lat,$lon) = @_;
+ $self->{lat} = $lat;
+ $self->{lon} = $lon;
+}
+
+sub lat
+{
+ shift->{lat};
+}
+sub lon
+{
+ shift->{lon};
+}
+
+sub xml
+{
+ my $self = shift;
+ my $str = "";
+ my $writer = $self->_get_writer(\$str);
+
+ $writer->startTag( "node", id => $self->id, lat => $self->lat, lon => $self->lon, timestamp => $self->timestamp, changeset => $self->changeset, version => $self->version);
+ $self->tag_xml( $writer );
+ $writer->endTag( "node" );
+ $writer->end;
+ return $str;
+}
+
+sub map
+{
+ my($self,$mapper) = @_;
+ my ($new_id) = $mapper->map('node',$self->id);
+ my $new_ent = new Geo::OSM::Node( {id=>$new_id, timestamp=>$self->timestamp, lat=>$self->lat, lon=>$self->lon}, $self->tags );
+ return($new_ent,0);
+}
+
+
+
+1;
diff --git a/navit/script/osm/Geo/OSM/MapFeatures.pm b/navit/script/osm/Geo/OSM/MapFeatures.pm
new file mode 100644
index 000000000..c4ae62f89
--- /dev/null
+++ b/navit/script/osm/Geo/OSM/MapFeatures.pm
@@ -0,0 +1,194 @@
+##################################################################
+package Geo::OSM::MapFeatures;
+##################################################################
+
+use Exporter;
+@ISA = qw( Exporter );
+use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION);
+@EXPORT = qw( );
+
+use strict;
+use warnings;
+
+use HTTP::Request;
+use File::Basename;
+use File::Copy;
+use File::Path;
+use Getopt::Long;
+use HTTP::Request;
+use Storable ();
+use Data::Dumper;
+
+use Utils::File;
+use Utils::Debug;
+use Utils::LWP::Utils;
+use XML::Parser;
+use XML::Simple;
+
+my $self;
+
+# ------------------------------------------------------------------
+sub style($){
+ my $self = shift;
+
+}
+
+# ------------------------------------------------------------------
+# load the complete MapFeatures Structure into memory
+sub load($;$){
+ my ($class, $filename) = @_;
+ #$filename ||= '../../freemap/freemap.xml';
+ $filename ||= './map-features.xml';
+ print("Loading Map Features from $filename\n") if $VERBOSE || $DEBUG;
+ print "$filename: ".(-s $filename)." Bytes\n" if $DEBUG;
+ print STDERR "Parsing file: $filename\n" if $DEBUG;
+
+ my $fh = data_open($filename);
+ if (not $fh) {
+ print STDERR "WARNING: Could not open osm data from $filename\n";
+ return;
+ }
+ my $self = XMLin($fh);
+
+ if (not $self) {
+ print STDERR "WARNING: Could not parse osm data from $filename\n";
+ return;
+ }
+
+ #delete $self->{defs}->{symbol};
+ #warn Dumper(\$self->{defs});
+ #warn Dumper(\$self->{data});
+ #warn Dumper(\$self->{rule});
+ #warn Dumper(keys %{$self});
+ #warn Dumper(%{$self});
+
+ bless($self,$class);
+ return $self;
+}
+
+# ------------------------------------------------------------------
+# Load icons into memory nad create a PDF Version out of it
+sub load_icons($$){
+ my $self = shift;
+ my $PDF = shift;
+ die "No PDF Document defined\n" unless $PDF;
+
+ print STDERR "load_icons():\n" if $DEBUG;
+# print STDERR Dumper(\$self);
+
+ for my $rule ( @{$self->{rule}} ) {
+ my $img = $rule->{style}->{image};
+ next unless defined $img;
+ $img =~s/^images\///;
+ my $img_filename;
+ for my $path ( qw( ../../freemap/images
+ ../../map-icons/square.small
+ ../../map-icons/square.big
+ ../../map-icons/classic.big
+ ../../map-icons/classic.small
+ ../../map-icons/nick
+ ../../map-icons/classic/other
+ ) ) {
+ $img_filename = "$path/$img";
+ if ( -s $img_filename ) {
+ my $png = $PDF->image_png($img_filename);
+ $rule->{png}=$png;
+ #print STDERR "image: $img_filename\n";
+ last;
+ }
+ }
+
+ if ( ! $rule->{png} ) {
+ warn "missing $img\n";
+ }
+ #print STDERR "rule: ".Dumper(\$rule);
+# print STDERR "condition: ".Dumper(\$rule->{condition});
+ my $condition = $rule->{condition};
+# print STDERR "image: $img_filename\t";
+ print STDERR " #condition: $condition->{k}=$condition->{v}\t";
+ printf STDERR "scale: %d-%d",
+ ($rule->{style}->{scale_max}||0),
+ ($rule->{style}->{scale_min}||0);
+ print STDERR "get_icon() image: $img\n";
+
+ }
+}
+
+# ------------------------------------------------------------------
+sub get_icons($$$){
+ my $self = shift;
+ my $rule_line= shift;
+ my $scale = shift;
+ return undef if $rule_line =~ m/^[\s\,]*$/;
+# return undef if $rule_line eq ",";
+
+ my ($dummy1,$dummy2,$attr) = split(",",$rule_line,3);
+ my %attr;
+ foreach my $kv ( split(",",$attr)){
+ my ($k,$v)=split("=",$kv);
+ $attr{$k}=$v;
+ }
+
+
+ print STDERR "get_icon($attr)\n";
+
+ my $png =undef;
+ for my $rule ( @{$self->{rule}} ) {
+ my $img = $rule->{style}->{image};
+ next unless $img;
+
+ my $condition = $rule->{condition};
+# print STDERR "condition: $condition->{k}=$condition->{v}\n";
+ if ( defined ( $attr{scale_max}) &&
+ $scale > $attr{scale_max}) {
+ next;
+ }
+
+ if ( defined( $attr{ $condition->{k}}) &&
+ $attr{ $condition->{k}} eq $condition->{v} ) {
+ print STDERR "condition: $condition->{k}=$condition->{v}\n";
+ print STDERR "get_icon() image: $img\t";
+ $png = $rule->{png};
+ }
+
+ return $png if $png;
+ }
+ return undef;
+}
+1;
+
+=head1 NAME
+
+Geo::OSM::MapFeature
+
+=head1 DESCRIPTION
+
+Load the MapFeatures.xml into memory
+
+=head1 COPYRIGHT
+
+Copyright 2006, Jörg Ostertag
+
+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, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+=head1 AUTHOR
+
+Jörg Ostertag (MapFeatures-for-openstreetmap@ostertag.name)
+
+=head1 SEE ALSO
+
+http://www.openstreetmap.org/
+
+=cut
diff --git a/navit/script/osm/Geo/OSM/OsmChangeReaderV3.pm b/navit/script/osm/Geo/OSM/OsmChangeReaderV3.pm
new file mode 100644
index 000000000..65103a36e
--- /dev/null
+++ b/navit/script/osm/Geo/OSM/OsmChangeReaderV3.pm
@@ -0,0 +1,323 @@
+##################################################################
+## OsmChangeReader.pm - Library for reading OSM change files ##
+## By Martijn van Oosterhout <kleptog@svana.org> ##
+## ##
+## Package that reads both osmChange and JOSM file format change##
+## files. The user creates the parse with a callback and the ##
+## loader will call the callback for each detected change. Note ##
+## that for JOSM file entires that are not changes are ignored. ##
+## ##
+## Licence: LGPL ##
+##################################################################
+package Geo::OSM::OsmChangeReader;
+
+use strict;
+use warnings;
+
+use Utils::File;
+use Utils::Math;
+use Utils::Debug;
+use XML::Parser;
+use Carp;
+
+use Geo::OSM::EntitiesV3;
+
+use constant STATE_INIT => 1;
+use constant STATE_EXPECT_COMMAND => 2;
+use constant STATE_EXPECT_ENTITY => 3;
+use constant STATE_EXPECT_BODY => 4;
+
+use constant FILETYPE_UNKNOWN => 0;
+use constant FILETYPE_OSMCHANGE => 1;
+use constant FILETYPE_OSM => 2;
+
+sub new
+{
+ my $obj = bless{}, shift;
+ my $proc = shift;
+ my $prog = shift;
+ if( ref $proc ne "CODE" )
+ { die "new Geo::OSM::OsmChangeReader requires a sub as argument\n" }
+ $obj->{oldproc} = $proc;
+ if( defined $prog )
+ { $obj->{progress} = $prog }
+ return $obj;
+}
+
+# With this initialiser, your process will get called with instantiated objects rather than useless details
+sub init
+{
+ my $obj = bless{}, shift;
+ my $proc = shift;
+ my $prog = shift;
+ if( ref $proc ne "CODE" )
+ { die "init Geo::OSM::OsmChangeReader requires a sub as argument\n" }
+ $obj->{newproc} = $proc;
+ if( defined $prog )
+ { $obj->{progress} = $prog }
+ return $obj;
+}
+
+sub _process
+{
+ my($self, $command, $entity, $attr, $tags, $segs) = @_;
+
+ if( defined $self->{oldproc} )
+ {
+ return $self->{oldproc}->($command, $entity, $attr, $tags, $segs);
+ }
+
+ my $ent;
+ if( $entity eq "node" )
+ {
+ $ent = new Geo::OSM::Node( $attr, $tags );
+ }
+ if( $entity eq "segment" )
+ {
+ $ent = new Geo::OSM::Segment( $attr, $tags );
+ }
+ if( $entity eq "way" )
+ {
+ $ent = new Geo::OSM::Way( $attr, $tags, $segs );
+ }
+ croak "Unknown entity '$entity'" if not defined $ent;
+
+ return $self->{newproc}->($command, $ent );
+}
+
+sub load{
+ my ($self, $file_name) = @_;
+
+ $self->{filetype} = FILETYPE_UNKNOWN;
+ $self->{state} = STATE_INIT;
+
+ my $start_time = time();
+ my $P = new XML::Parser(Handlers => {Start => sub{ DoStart( $self, @_ )}, End => sub { DoEnd( $self, @_ )}});
+ my $fh = data_open($file_name);
+ die "Cannot open OSM File $file_name\n" unless $fh;
+ $self->{input_length} = -s $fh;
+ $self->{count}=0;
+ eval {
+ $P->parse($fh);
+ };
+ print "\n" if $DEBUG || $VERBOSE;
+ if ( $VERBOSE) {
+ printf "Read and parsed $file_name in %.0f sec\n",time()-$start_time;
+ }
+ if ( $@ ) {
+ warn "$@Error while parsing\n $file_name\n";
+ return;
+ }
+ if (not $P) {
+ warn "WARNING: Could not parse osm data\n";
+ return;
+ }
+
+}
+
+sub parse($)
+{
+ my ($self, $string) = @_;
+
+ $self->{state} = STATE_INIT;
+
+ my $start_time = time();
+ my $P = new XML::Parser(Handlers => {Start => sub{ DoStart( $self, @_ )}, End => sub { DoEnd( $self, @_ )}});
+ $self->{input_length} = length($string);
+ $self->{count}=0;
+ eval {
+ $P->parse($string);
+ };
+ print "\n" if $DEBUG || $VERBOSE;
+ if ( $VERBOSE) {
+ printf "Read and parsed string in %.0f sec\n",time()-$start_time;
+ }
+ if ( $@ ) {
+ warn "$@Error while parsing\n [$string]\n";
+ return;
+ }
+ if (not $P) {
+ warn "WARNING: Could not parse osm data\n";
+ return;
+ }
+}
+
+# Function is called whenever an XML tag is started
+sub DoStart
+{
+#print @_,"\n";
+ my ($self, $Expat, $Name, %Attr) = @_;
+
+ if( $self->{filetype} == FILETYPE_UNKNOWN )
+ {
+ if( $self->{state} == STATE_INIT )
+ {
+ if($Name eq "osmChange"){
+ $self->{state} = STATE_EXPECT_COMMAND;
+ $self->{filetype} = FILETYPE_OSMCHANGE;
+
+ if( $Attr{version} ne "0.3" and $Attr{version} ne "0.4" )
+ { die "OsmChangeReaderV3 can only read 0.3 and 0.4 files, found '$Attr{version}'\n" }
+ } elsif($Name eq "osm"){
+ $self->{state} = STATE_EXPECT_ENTITY;
+ $self->{filetype} = FILETYPE_OSM;
+
+ if( $Attr{version} ne "0.3" and $Attr{version} ne "0.4" )
+ { die "OsmChangeReaderV3 can only read 0.3 and 0.4 files, found '$Attr{version}'\n" }
+ } else {
+ die "Expected 'osmChange' tag, got '$Name'\n";
+ }
+ }
+ }
+ elsif( $self->{state} == STATE_EXPECT_COMMAND )
+ {
+ if($Name eq 'create' or $Name eq 'modify' or $Name eq 'delete'){
+ $self->{command} = $Name;
+ $self->{state} = STATE_EXPECT_ENTITY;
+ } else {
+ die "Expected command\n";
+ }
+ }
+ elsif( $self->{state} == STATE_EXPECT_ENTITY )
+ {
+ # Pick up the origin attribute from the bound tag
+ if( $Name eq "bound" )
+ {
+ if( exists $Attr{origin} )
+ {
+ $self->{origin} = $Attr{origin};
+ }
+ return;
+ }
+ if($Name eq "node" or $Name eq "segment" or $Name eq "way"){
+ $self->{entity} = $Name;
+ $self->{attr} = {%Attr};
+ $self->{tags} = [];
+ $self->{segs} = ($Name eq "way") ? [] : undef;
+ $self->{state} = STATE_EXPECT_BODY;
+ } else {
+ die "Expected entity\n";
+ }
+ }
+ elsif( $self->{state} == STATE_EXPECT_BODY )
+ {
+ if($Name eq "tag"){
+ push @{$self->{tags}}, $Attr{"k"}, $Attr{"v"};
+ }
+ if($Name eq "seg"){
+ push @{$self->{segs}}, $Attr{"id"};
+ }
+ }
+}
+
+# Function is called whenever an XML tag is ended
+sub DoEnd
+{
+ my ($self, $Expat, $Name) = @_;
+ if( $self->{state} == STATE_EXPECT_BODY )
+ {
+ if( $Name eq $self->{entity} )
+ {
+ if( $self->{filetype} == FILETYPE_OSMCHANGE )
+ {
+ $self->_process( $self->{command}, $self->{entity}, $self->{attr}, $self->{tags}, $self->{segs} );
+ }
+ else # FILETYPE_OSM
+ {
+ # Only entities with a modify tag are interesting, or if they have a negative ID (that's create)
+ if( exists $self->{attr}->{action} )
+ {
+ $self->_process( $self->{attr}->{action}, $self->{entity}, $self->{attr}, $self->{tags}, $self->{segs} );
+ }
+ elsif( $self->{attr}{id} < 0 )
+ {
+ $self->_process( "create", $self->{entity}, $self->{attr}, $self->{tags}, $self->{segs} );
+ }
+ }
+ $self->{count}++;
+ if( $self->{progress} and ($self->{count}%11) == 1)
+ {
+ $self->{progress}->($self->{count}, $Expat->current_byte()/$self->{input_length} );
+ }
+ $self->{state} = STATE_EXPECT_ENTITY;
+ }
+ return;
+ }
+ elsif( $self->{state} == STATE_EXPECT_ENTITY )
+ {
+ return if $Name eq "bound";
+ if( $self->{filetype} == FILETYPE_OSMCHANGE )
+ {
+ if( $Name eq $self->{command} )
+ {
+ $self->{state} = STATE_EXPECT_COMMAND;
+ }else {die}
+ }
+ else # FILETYPE_OSM
+ {
+ if( $Name eq "osm" )
+ {
+ $self->{state} = STATE_INIT;
+ } else {die}
+ }
+ return;
+ }
+ elsif( $self->{state} == STATE_EXPECT_COMMAND )
+ {
+ if( $Name eq "osmChange" )
+ {
+ $self->{state} = STATE_INIT;
+ }else {die}
+ return;
+ }
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+OsmChangeReaderV3 - Module for reading OpenStreetMap V3 Change XML data files
+
+=head1 SYNOPSIS
+
+ my $OSM = new Geo::OSM::OsmChangeReader(\&process);
+ $OSM->load("Data/changes.osc");
+
+ sub process
+ {
+ my($OSM, $command, $entity, $attr, $tags, $segs) = @_;
+ print "Doing a $command on a $entity $attr->{id}\n";
+ while( my($k,$v) = splice @{$tags}, 0, 2 )
+ { print " $k: $v\n" }
+ if( defined $segs )
+ { print " Segs: ", join(", ",@$segs),"\n"; }
+ }
+
+=head1 AUTHOR
+
+Martijn van Oosterhout <kleptog@svana.org>
+based on OsmXML.pm written by:
+Oliver White (oliver.white@blibbleblobble.co.uk)
+
+=head1 COPYRIGHT
+
+Copyright 2007, Martijn van Oosterhout
+Copyright 2006, Oliver White
+
+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, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+=cut
diff --git a/navit/script/osm/Geo/OSM/OsmChangeReaderV5.pm b/navit/script/osm/Geo/OSM/OsmChangeReaderV5.pm
new file mode 100644
index 000000000..fdc65e1a9
--- /dev/null
+++ b/navit/script/osm/Geo/OSM/OsmChangeReaderV5.pm
@@ -0,0 +1,316 @@
+##################################################################
+## OsmChangeReader.pm - Library for reading OSM change files ##
+## By Martijn van Oosterhout <kleptog@svana.org> ##
+## ##
+## Package that reads both osmChange and JOSM file format change##
+## files. The user creates the parse with a callback and the ##
+## loader will call the callback for each detected change. Note ##
+## that for JOSM file entires that are not changes are ignored. ##
+## ##
+## Licence: LGPL ##
+##################################################################
+package Geo::OSM::OsmChangeReader;
+
+use strict;
+use warnings;
+
+use Utils::File;
+use Utils::Math;
+use Utils::Debug;
+use XML::Parser;
+use Carp;
+
+use Geo::OSM::EntitiesV5;
+
+use constant STATE_INIT => 1;
+use constant STATE_EXPECT_COMMAND => 2;
+use constant STATE_EXPECT_ENTITY => 3;
+use constant STATE_EXPECT_BODY => 4;
+
+use constant FILETYPE_UNKNOWN => 0;
+use constant FILETYPE_OSMCHANGE => 1;
+use constant FILETYPE_OSM => 2;
+
+# With this initialiser, your process will get called with instantiated objects
+sub init
+{
+ my $obj = bless{}, shift;
+ my $proc = shift;
+ my $prog = shift;
+ if( ref $proc ne "CODE" )
+ { die "init Geo::OSM::OsmChangeReader requires a sub as argument\n" }
+ $obj->{newproc} = $proc;
+ if( defined $prog )
+ { $obj->{progress} = $prog }
+ return $obj;
+}
+
+sub _process
+{
+ my($self, $command, $entity, $attr, $tags, $members) = @_;
+
+ if( defined $self->{oldproc} )
+ {
+ return $self->{oldproc}->($command, $entity, $attr, $tags, $members);
+ }
+
+ my $ent;
+ if( $entity eq "node" )
+ {
+ $ent = new Geo::OSM::Node( $attr, $tags );
+ }
+ if( $entity eq "relation" )
+ {
+ $ent = new Geo::OSM::Relation( $attr, $tags, $members );
+ }
+ if( $entity eq "way" )
+ {
+ $ent = new Geo::OSM::Way( $attr, $tags, $members );
+ }
+ croak "Unknown entity '$entity'" if not defined $ent;
+
+ return $self->{newproc}->($command, $ent );
+}
+
+sub load{
+ my ($self, $file_name) = @_;
+
+ $self->{filetype} = FILETYPE_UNKNOWN;
+ $self->{state} = STATE_INIT;
+
+ my $start_time = time();
+ my $P = new XML::Parser(Handlers => {Start => sub{ DoStart( $self, @_ )}, End => sub { DoEnd( $self, @_ )}});
+ my $fh = data_open($file_name);
+ die "Cannot open OSM File $file_name\n" unless $fh;
+ $self->{input_length} = -s $fh;
+ $self->{count}=0;
+ eval {
+ $P->parse($fh);
+ };
+ print "\n" if $DEBUG || $VERBOSE;
+ if ( $VERBOSE) {
+ printf "Read and parsed $file_name in %.0f sec\n",time()-$start_time;
+ }
+ if ( $@ ) {
+ warn "$@Error while parsing\n $file_name\n";
+ return;
+ }
+ if (not $P) {
+ warn "WARNING: Could not parse osm data\n";
+ return;
+ }
+
+}
+
+sub parse($)
+{
+ my ($self, $string) = @_;
+
+ $self->{state} = STATE_INIT;
+
+ my $start_time = time();
+ my $P = new XML::Parser(Handlers => {Start => sub{ DoStart( $self, @_ )}, End => sub { DoEnd( $self, @_ )}});
+ $self->{input_length} = length($string);
+ $self->{count}=0;
+ eval {
+ $P->parse($string);
+ };
+ print "\n" if $DEBUG || $VERBOSE;
+ if ( $VERBOSE) {
+ printf "Read and parsed string in %.0f sec\n",time()-$start_time;
+ }
+ if ( $@ ) {
+ warn "$@Error while parsing\n [$string]\n";
+ return;
+ }
+ if (not $P) {
+ warn "WARNING: Could not parse osm data\n";
+ return;
+ }
+}
+
+# Function is called whenever an XML tag is started
+sub DoStart
+{
+#print @_,"\n";
+ my ($self, $Expat, $Name, %Attr) = @_;
+
+ if( $self->{filetype} == FILETYPE_UNKNOWN )
+ {
+ if( $self->{state} == STATE_INIT )
+ {
+ if($Name eq "osmChange"){
+ $self->{state} = STATE_EXPECT_COMMAND;
+ $self->{filetype} = FILETYPE_OSMCHANGE;
+
+ if( $Attr{version} ne "0.5" )
+ { die "OsmChangeReaderV3 can only read 0.5 files, found '$Attr{version}'\n" }
+ } elsif($Name eq "osm"){
+ $self->{state} = STATE_EXPECT_ENTITY;
+ $self->{filetype} = FILETYPE_OSM;
+
+ if( $Attr{version} ne "0.5" )
+ { die "OsmChangeReaderV3 can only read 0.5 files, found '$Attr{version}'\n" }
+ } else {
+ die "Expected 'osmChange' tag, got '$Name'\n";
+ }
+ }
+ }
+ elsif( $self->{state} == STATE_EXPECT_COMMAND )
+ {
+ if($Name eq 'create' or $Name eq 'modify' or $Name eq 'delete'){
+ $self->{command} = $Name;
+ $self->{state} = STATE_EXPECT_ENTITY;
+ } else {
+ die "Expected command\n";
+ }
+ }
+ elsif( $self->{state} == STATE_EXPECT_ENTITY )
+ {
+ # Pick up the origin attribute from the bound tag
+ if( $Name eq "bound" )
+ {
+ if( exists $Attr{origin} )
+ {
+ $self->{origin} = $Attr{origin};
+ }
+ return;
+ }
+ if($Name eq "node" or $Name eq "relation" or $Name eq "way"){
+ $self->{entity} = $Name;
+ $self->{attr} = {%Attr};
+ $self->{tags} = [];
+ $self->{members} = ($Name ne "node") ? [] : undef;
+ $self->{state} = STATE_EXPECT_BODY;
+ } else {
+ die "Expected entity\n";
+ }
+ }
+ elsif( $self->{state} == STATE_EXPECT_BODY )
+ {
+ if($Name eq "tag"){
+ push @{$self->{tags}}, $Attr{"k"}, $Attr{"v"};
+ }
+ if($Name eq "nd"){
+ push @{$self->{members}}, $Attr{"ref"};
+ }
+ if($Name eq "member"){
+ push @{$self->{members}}, new Geo::OSM::Relation::Member( \%Attr );
+ }
+ }
+}
+
+# Function is called whenever an XML tag is ended
+sub DoEnd
+{
+ my ($self, $Expat, $Name) = @_;
+ if( $self->{state} == STATE_EXPECT_BODY )
+ {
+ if( $Name eq $self->{entity} )
+ {
+ if( $self->{filetype} == FILETYPE_OSMCHANGE )
+ {
+ $self->_process( $self->{command}, $self->{entity}, $self->{attr}, $self->{tags}, $self->{members} );
+ }
+ else # FILETYPE_OSM
+ {
+ # Only entities with a modify tag are interesting, or if they have a negative ID (that's create)
+ if( exists $self->{attr}->{action} and $self->{attr}->{action} eq "modify" and $self->{attr}{id} < 0 )
+ { $self->{attr}->{action} = "create" }
+ if( exists $self->{attr}->{action} )
+ {
+ $self->_process( $self->{attr}->{action}, $self->{entity}, $self->{attr}, $self->{tags}, $self->{members} );
+ }
+ elsif( $self->{attr}{id} < 0 )
+ {
+ $self->_process( "create", $self->{entity}, $self->{attr}, $self->{tags}, $self->{members} );
+ }
+ }
+ $self->{count}++;
+ if( $self->{progress} and ($self->{count}%11) == 1)
+ {
+ $self->{progress}->($self->{count}, $Expat->current_byte()/$self->{input_length} );
+ }
+ $self->{state} = STATE_EXPECT_ENTITY;
+ }
+ return;
+ }
+ elsif( $self->{state} == STATE_EXPECT_ENTITY )
+ {
+ return if $Name eq "bound";
+ if( $self->{filetype} == FILETYPE_OSMCHANGE )
+ {
+ if( $Name eq $self->{command} )
+ {
+ $self->{state} = STATE_EXPECT_COMMAND;
+ }else {die}
+ }
+ else # FILETYPE_OSM
+ {
+ if( $Name eq "osm" )
+ {
+ $self->{state} = STATE_INIT;
+ } else {die}
+ }
+ return;
+ }
+ elsif( $self->{state} == STATE_EXPECT_COMMAND )
+ {
+ if( $Name eq "osmChange" )
+ {
+ $self->{state} = STATE_INIT;
+ }else {die}
+ return;
+ }
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+OsmChangeReaderV5 - Module for reading OpenStreetMap V5 Change XML data files
+
+=head1 SYNOPSIS
+
+ my $OSM = new Geo::OSM::OsmChangeReader(\&process);
+ $OSM->load("Data/changes.osc");
+
+ sub process
+ {
+ my($OSM, $command, $entity) = @_;
+ print "Doing a $command on a $entity ".$entity->id."\n";
+ my $tags = $entity->tags;
+ while( my($k,$v) = splice @{$tags}, 0, 2 )
+ { print " $k: $v\n" }
+ if( $entity->type eq "way" )
+ { print " Nodes: ", join(", ",@{$entity->nodes}),"\n"; }
+ }
+
+=head1 AUTHOR
+
+Martijn van Oosterhout <kleptog@svana.org>
+based on OsmXML.pm written by:
+Oliver White (oliver.white@blibbleblobble.co.uk)
+
+=head1 COPYRIGHT
+
+Copyright 2007, Martijn van Oosterhout
+Copyright 2006, Oliver White
+
+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, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+=cut
diff --git a/navit/script/osm/Geo/OSM/OsmChangeReaderV6.pm b/navit/script/osm/Geo/OSM/OsmChangeReaderV6.pm
new file mode 100644
index 000000000..e67397829
--- /dev/null
+++ b/navit/script/osm/Geo/OSM/OsmChangeReaderV6.pm
@@ -0,0 +1,316 @@
+##################################################################
+## OsmChangeReader.pm - Library for reading OSM change files ##
+## By Martijn van Oosterhout <kleptog@svana.org> ##
+## ##
+## Package that reads both osmChange and JOSM file format change##
+## files. The user creates the parse with a callback and the ##
+## loader will call the callback for each detected change. Note ##
+## that for JOSM file entires that are not changes are ignored. ##
+## ##
+## Licence: LGPL ##
+##################################################################
+package Geo::OSM::OsmChangeReader;
+
+use strict;
+use warnings;
+
+use Utils::File;
+use Utils::Math;
+use Utils::Debug;
+use XML::Parser;
+use Carp;
+
+use Geo::OSM::EntitiesV6;
+
+use constant STATE_INIT => 1;
+use constant STATE_EXPECT_COMMAND => 2;
+use constant STATE_EXPECT_ENTITY => 3;
+use constant STATE_EXPECT_BODY => 4;
+
+use constant FILETYPE_UNKNOWN => 0;
+use constant FILETYPE_OSMCHANGE => 1;
+use constant FILETYPE_OSM => 2;
+
+# With this initialiser, your process will get called with instantiated objects
+sub init
+{
+ my $obj = bless{}, shift;
+ my $proc = shift;
+ my $prog = shift;
+ if( ref $proc ne "CODE" )
+ { die "init Geo::OSM::OsmChangeReader requires a sub as argument\n" }
+ $obj->{newproc} = $proc;
+ if( defined $prog )
+ { $obj->{progress} = $prog }
+ return $obj;
+}
+
+sub _process
+{
+ my($self, $command, $entity, $attr, $tags, $members) = @_;
+
+ if( defined $self->{oldproc} )
+ {
+ return $self->{oldproc}->($command, $entity, $attr, $tags, $members);
+ }
+
+ my $ent;
+ if( $entity eq "node" )
+ {
+ $ent = new Geo::OSM::Node( $attr, $tags );
+ }
+ if( $entity eq "relation" )
+ {
+ $ent = new Geo::OSM::Relation( $attr, $tags, $members );
+ }
+ if( $entity eq "way" )
+ {
+ $ent = new Geo::OSM::Way( $attr, $tags, $members );
+ }
+ croak "Unknown entity '$entity'" if not defined $ent;
+
+ return $self->{newproc}->($command, $ent );
+}
+
+sub load{
+ my ($self, $file_name) = @_;
+
+ $self->{filetype} = FILETYPE_UNKNOWN;
+ $self->{state} = STATE_INIT;
+
+ my $start_time = time();
+ my $P = new XML::Parser(Handlers => {Start => sub{ DoStart( $self, @_ )}, End => sub { DoEnd( $self, @_ )}});
+ my $fh = data_open($file_name);
+ die "Cannot open OSM File $file_name\n" unless $fh;
+ $self->{input_length} = -s $fh;
+ $self->{count}=0;
+ eval {
+ $P->parse($fh);
+ };
+ print "\n" if $DEBUG || $VERBOSE;
+ if ( $VERBOSE) {
+ printf "Read and parsed $file_name in %.0f sec\n",time()-$start_time;
+ }
+ if ( $@ ) {
+ warn "$@Error while parsing\n $file_name\n";
+ return;
+ }
+ if (not $P) {
+ warn "WARNING: Could not parse osm data\n";
+ return;
+ }
+
+}
+
+sub parse($)
+{
+ my ($self, $string) = @_;
+
+ $self->{state} = STATE_INIT;
+
+ my $start_time = time();
+ my $P = new XML::Parser(Handlers => {Start => sub{ DoStart( $self, @_ )}, End => sub { DoEnd( $self, @_ )}});
+ $self->{input_length} = length($string);
+ $self->{count}=0;
+ eval {
+ $P->parse($string);
+ };
+ print "\n" if $DEBUG || $VERBOSE;
+ if ( $VERBOSE) {
+ printf "Read and parsed string in %.0f sec\n",time()-$start_time;
+ }
+ if ( $@ ) {
+ warn "$@Error while parsing\n [$string]\n";
+ return;
+ }
+ if (not $P) {
+ warn "WARNING: Could not parse osm data\n";
+ return;
+ }
+}
+
+# Function is called whenever an XML tag is started
+sub DoStart
+{
+#print @_,"\n";
+ my ($self, $Expat, $Name, %Attr) = @_;
+
+ if( $self->{filetype} == FILETYPE_UNKNOWN )
+ {
+ if( $self->{state} == STATE_INIT )
+ {
+ if($Name eq "osmChange"){
+ $self->{state} = STATE_EXPECT_COMMAND;
+ $self->{filetype} = FILETYPE_OSMCHANGE;
+
+ if( $Attr{version} ne "0.6" )
+ { die "OsmChangeReaderV6 can only read 0.6 files, found '$Attr{version}'\n" }
+ } elsif($Name eq "osm"){
+ $self->{state} = STATE_EXPECT_ENTITY;
+ $self->{filetype} = FILETYPE_OSM;
+
+ if( $Attr{version} ne "0.6" )
+ { die "OsmChangeReaderV6 can only read 0.6 files, found '$Attr{version}'\n" }
+ } else {
+ die "Expected 'osmChange' tag, got '$Name'\n";
+ }
+ }
+ }
+ elsif( $self->{state} == STATE_EXPECT_COMMAND )
+ {
+ if($Name eq 'create' or $Name eq 'modify' or $Name eq 'delete'){
+ $self->{command} = $Name;
+ $self->{state} = STATE_EXPECT_ENTITY;
+ } else {
+ die "Expected command\n";
+ }
+ }
+ elsif( $self->{state} == STATE_EXPECT_ENTITY )
+ {
+ # Pick up the origin attribute from the bound tag
+ if( $Name eq "bound" )
+ {
+ if( exists $Attr{origin} )
+ {
+ $self->{origin} = $Attr{origin};
+ }
+ return;
+ }
+ if($Name eq "node" or $Name eq "relation" or $Name eq "way"){
+ $self->{entity} = $Name;
+ $self->{attr} = {%Attr};
+ $self->{tags} = [];
+ $self->{members} = ($Name ne "node") ? [] : undef;
+ $self->{state} = STATE_EXPECT_BODY;
+ } else {
+ die "Expected entity\n";
+ }
+ }
+ elsif( $self->{state} == STATE_EXPECT_BODY )
+ {
+ if($Name eq "tag"){
+ push @{$self->{tags}}, $Attr{"k"}, $Attr{"v"};
+ }
+ if($Name eq "nd"){
+ push @{$self->{members}}, $Attr{"ref"};
+ }
+ if($Name eq "member"){
+ push @{$self->{members}}, new Geo::OSM::Relation::Member( \%Attr );
+ }
+ }
+}
+
+# Function is called whenever an XML tag is ended
+sub DoEnd
+{
+ my ($self, $Expat, $Name) = @_;
+ if( $self->{state} == STATE_EXPECT_BODY )
+ {
+ if( $Name eq $self->{entity} )
+ {
+ if( $self->{filetype} == FILETYPE_OSMCHANGE )
+ {
+ $self->_process( $self->{command}, $self->{entity}, $self->{attr}, $self->{tags}, $self->{members} );
+ }
+ else # FILETYPE_OSM
+ {
+ # Only entities with a modify tag are interesting, or if they have a negative ID (that's create)
+ if( exists $self->{attr}->{action} and $self->{attr}->{action} eq "modify" and $self->{attr}{id} < 0 )
+ { $self->{attr}->{action} = "create" }
+ if( exists $self->{attr}->{action} )
+ {
+ $self->_process( $self->{attr}->{action}, $self->{entity}, $self->{attr}, $self->{tags}, $self->{members} );
+ }
+ elsif( $self->{attr}{id} < 0 )
+ {
+ $self->_process( "create", $self->{entity}, $self->{attr}, $self->{tags}, $self->{members} );
+ }
+ }
+ $self->{count}++;
+ if( $self->{progress} and ($self->{count}%11) == 1)
+ {
+ $self->{progress}->($self->{count}, $Expat->current_byte()/$self->{input_length} );
+ }
+ $self->{state} = STATE_EXPECT_ENTITY;
+ }
+ return;
+ }
+ elsif( $self->{state} == STATE_EXPECT_ENTITY )
+ {
+ return if $Name eq "bound";
+ if( $self->{filetype} == FILETYPE_OSMCHANGE )
+ {
+ if( $Name eq $self->{command} )
+ {
+ $self->{state} = STATE_EXPECT_COMMAND;
+ }else {die}
+ }
+ else # FILETYPE_OSM
+ {
+ if( $Name eq "osm" )
+ {
+ $self->{state} = STATE_INIT;
+ } else {die}
+ }
+ return;
+ }
+ elsif( $self->{state} == STATE_EXPECT_COMMAND )
+ {
+ if( $Name eq "osmChange" )
+ {
+ $self->{state} = STATE_INIT;
+ }else {die}
+ return;
+ }
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+OsmChangeReaderV6 - Module for reading OpenStreetMap V6 Change XML data files
+
+=head1 SYNOPSIS
+
+ my $OSM = new Geo::OSM::OsmChangeReader(\&process);
+ $OSM->load("Data/changes.osc");
+
+ sub process
+ {
+ my($OSM, $command, $entity) = @_;
+ print "Doing a $command on a $entity ".$entity->id."\n";
+ my $tags = $entity->tags;
+ while( my($k,$v) = splice @{$tags}, 0, 2 )
+ { print " $k: $v\n" }
+ if( $entity->type eq "way" )
+ { print " Nodes: ", join(", ",@{$entity->nodes}),"\n"; }
+ }
+
+=head1 AUTHOR
+
+Martijn van Oosterhout <kleptog@svana.org>
+based on OsmXML.pm written by:
+Oliver White (oliver.white@blibbleblobble.co.uk)
+
+=head1 COPYRIGHT
+
+Copyright 2007, Martijn van Oosterhout
+Copyright 2006, Oliver White
+
+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, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+=cut
diff --git a/navit/script/osm/Geo/OSM/OsmReaderV3.pm b/navit/script/osm/Geo/OSM/OsmReaderV3.pm
new file mode 100644
index 000000000..b01963470
--- /dev/null
+++ b/navit/script/osm/Geo/OSM/OsmReaderV3.pm
@@ -0,0 +1,246 @@
+##################################################################
+## OsmReader.pm - Library for reading OSM files ##
+## By Martijn van Oosterhout <kleptog@svana.org> ##
+## ##
+## Package that reads both OSM file format files. ##
+## The user creates the parse with a callback and the ##
+## loader will call the callback for each detected object. ##
+## Licence: LGPL ##
+##################################################################
+package Geo::OSM::OsmReader;
+
+use strict;
+use warnings;
+
+use Utils::File;
+use Utils::Math;
+use Utils::Debug;
+use XML::Parser;
+use Carp;
+
+use Geo::OSM::EntitiesV3;
+
+use constant STATE_INIT => 1;
+use constant STATE_EXPECT_ENTITY => 3;
+use constant STATE_EXPECT_BODY => 4;
+
+# With this initialiser, your process will get called with instantiated objects
+sub init
+{
+ my $obj = bless{}, shift;
+ my $proc = shift;
+ my $prog = shift;
+ if( ref $proc ne "CODE" )
+ { die "init Geo::OSM::OsmReader requires a sub as argument\n" }
+ $obj->{newproc} = $proc;
+ if( defined $prog )
+ { $obj->{progress} = $prog }
+ return $obj;
+}
+
+sub _process
+{
+ my($self, $entity, $attr, $tags, $members) = @_;
+
+ my $ent;
+ if( $entity eq "node" )
+ {
+ $ent = new Geo::OSM::Node( $attr, $tags );
+ }
+ if( $entity eq "segment" )
+ {
+ $ent = new Geo::OSM::Segment( $attr, $tags );
+ }
+ if( $entity eq "way" )
+ {
+ $ent = new Geo::OSM::Way( $attr, $tags, $members );
+ }
+ croak "Unknown entity '$entity'" if not defined $ent;
+
+ return $self->{newproc}->( $ent );
+}
+
+sub load($)
+{
+ my ($self, $file_name) = @_;
+
+ $self->{state} = STATE_INIT;
+
+ my $start_time = time();
+ my $P = new XML::Parser(Handlers => {Start => sub{ DoStart( $self, @_ )}, End => sub { DoEnd( $self, @_ )}});
+ my $fh = data_open($file_name);
+ die "Cannot open OSM File $file_name\n" unless $fh;
+ $self->{input_length} = -s $fh;
+ $self->{count}=0;
+ eval {
+ $P->parse($fh);
+ };
+ print "\n" if $DEBUG || $VERBOSE;
+ if ( $VERBOSE) {
+ printf "Read and parsed $file_name in %.0f sec\n",time()-$start_time;
+ }
+ if ( $@ ) {
+ warn "$@Error while parsing\n $file_name\n";
+ return;
+ }
+ if (not $P) {
+ warn "WARNING: Could not parse osm data\n";
+ return;
+ }
+}
+
+sub parse($)
+{
+ my ($self, $string) = @_;
+
+ $self->{state} = STATE_INIT;
+
+ my $start_time = time();
+ my $P = new XML::Parser(Handlers => {Start => sub{ DoStart( $self, @_ )}, End => sub { DoEnd( $self, @_ )}});
+ $self->{input_length} = length($string);
+ $self->{count}=0;
+ eval {
+ $P->parse($string);
+ };
+ print "\n" if $DEBUG || $VERBOSE;
+ if ( $VERBOSE) {
+ printf "Read and parsed string in %.0f sec\n",time()-$start_time;
+ }
+ if ( $@ ) {
+ warn "$@Error while parsing\n [$string]\n";
+ return;
+ }
+ if (not $P) {
+ warn "WARNING: Could not parse osm data\n";
+ return;
+ }
+}
+
+# Function is called whenever an XML tag is started
+sub DoStart
+{
+#print @_,"\n";
+ my ($self, $Expat, $Name, %Attr) = @_;
+
+ if( $self->{state} == STATE_INIT )
+ {
+ if($Name eq "osm"){
+ $self->{state} = STATE_EXPECT_ENTITY;
+
+ if( $Attr{version} ne "0.3" and $Attr{version} ne "0.4")
+ { die "OsmReaderV5 can only read 0.3 or 0.4 files, found '$Attr{version}'\n" }
+ } else {
+ die "Expected 'osm' tag, got '$Name'\n";
+ }
+ }
+ elsif( $self->{state} == STATE_EXPECT_ENTITY )
+ {
+ # Pick up the origin attribute from the bound tag
+ if( $Name eq "bound" )
+ {
+ if( exists $Attr{origin} )
+ {
+ $self->{origin} = $Attr{origin};
+ }
+ return;
+ }
+ if($Name eq "node" or $Name eq "segment" or $Name eq "way"){
+ $self->{entity} = $Name;
+ $self->{attr} = {%Attr};
+ $self->{tags} = [];
+ $self->{members} = ($Name ne "node") ? [] : undef;
+ $self->{state} = STATE_EXPECT_BODY;
+ } else {
+ die "Expected entity\n";
+ }
+ }
+ elsif( $self->{state} == STATE_EXPECT_BODY )
+ {
+ if($Name eq "tag"){
+ push @{$self->{tags}}, $Attr{"k"}, $Attr{"v"};
+ }
+ if($Name eq "seg"){
+ push @{$self->{members}}, $Attr{"id"};
+ }
+ }
+}
+
+# Function is called whenever an XML tag is ended
+sub DoEnd
+{
+ my ($self, $Expat, $Name) = @_;
+ if( $self->{state} == STATE_EXPECT_BODY )
+ {
+ if( $Name eq $self->{entity} )
+ {
+ $self->_process( $self->{entity}, $self->{attr}, $self->{tags}, $self->{members} );
+ $self->{count}++;
+ if( $self->{progress} and ($self->{count}%11) == 1)
+ {
+ $self->{progress}->($self->{count}, $self->{input_length} ? $Expat->current_byte()/$self->{input_length} : $Expat->current_byte());
+ }
+ $self->{state} = STATE_EXPECT_ENTITY;
+ }
+ return;
+ }
+ elsif( $self->{state} == STATE_EXPECT_ENTITY )
+ {
+ return if $Name eq "bound";
+ if( $Name eq "osm" )
+ {
+ $self->{state} = STATE_INIT;
+ } else {die}
+ return;
+ }
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+OsmReaderV3 - Module for reading OpenStreetMap V3 XML data files
+
+=head1 SYNOPSIS
+
+ my $OSM = new Geo::OSM::OsmReader(\&process);
+ $OSM->load("Data/changes.osc");
+
+ sub process
+ {
+ my($OSM, $entity) = @_;
+ print "Read $entity ".$entity->id."\n";
+ my $tags = $entity->tags;
+ while( my($k,$v) = splice @{$tags}, 0, 2 )
+ { print " $k: $v\n" }
+ if( $entity->type eq "way" )
+ { print " Segs: ", join(", ",@{$entity->segs}),"\n"; }
+ }
+
+=head1 AUTHOR
+
+Martijn van Oosterhout <kleptog@svana.org>
+based on OsmXML.pm written by:
+Oliver White (oliver.white@blibbleblobble.co.uk)
+
+=head1 COPYRIGHT
+
+Copyright 2007, Martijn van Oosterhout
+Copyright 2006, Oliver White
+
+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, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+=cut
diff --git a/navit/script/osm/Geo/OSM/OsmReaderV5.pm b/navit/script/osm/Geo/OSM/OsmReaderV5.pm
new file mode 100644
index 000000000..37a477b1a
--- /dev/null
+++ b/navit/script/osm/Geo/OSM/OsmReaderV5.pm
@@ -0,0 +1,249 @@
+##################################################################
+## OsmReader.pm - Library for reading OSM files ##
+## By Martijn van Oosterhout <kleptog@svana.org> ##
+## ##
+## Package that reads both OSM file format files. ##
+## The user creates the parse with a callback and the ##
+## loader will call the callback for each detected object. ##
+## Licence: LGPL ##
+##################################################################
+package Geo::OSM::OsmReader;
+
+use strict;
+use warnings;
+
+use Utils::File;
+use Utils::Math;
+use Utils::Debug;
+use XML::Parser;
+use Carp;
+
+use Geo::OSM::EntitiesV5;
+
+use constant STATE_INIT => 1;
+use constant STATE_EXPECT_ENTITY => 3;
+use constant STATE_EXPECT_BODY => 4;
+
+# With this initialiser, your process will get called with instantiated objects
+sub init
+{
+ my $obj = bless{}, shift;
+ my $proc = shift;
+ my $prog = shift;
+ if( ref $proc ne "CODE" )
+ { die "init Geo::OSM::OsmReader requires a sub as argument\n" }
+ $obj->{newproc} = $proc;
+ if( defined $prog )
+ { $obj->{progress} = $prog }
+ return $obj;
+}
+
+sub _process
+{
+ my($self, $entity, $attr, $tags, $members) = @_;
+
+ my $ent;
+ if( $entity eq "node" )
+ {
+ $ent = new Geo::OSM::Node( $attr, $tags );
+ }
+ if( $entity eq "relation" )
+ {
+ $ent = new Geo::OSM::Relation( $attr, $tags, $members );
+ }
+ if( $entity eq "way" )
+ {
+ $ent = new Geo::OSM::Way( $attr, $tags, $members );
+ }
+ croak "Unknown entity '$entity'" if not defined $ent;
+
+ return $self->{newproc}->( $ent );
+}
+
+sub load($)
+{
+ my ($self, $file_name) = @_;
+
+ $self->{state} = STATE_INIT;
+
+ my $start_time = time();
+ my $P = new XML::Parser(Handlers => {Start => sub{ DoStart( $self, @_ )}, End => sub { DoEnd( $self, @_ )}});
+ my $fh = data_open($file_name);
+ die "Cannot open OSM File $file_name\n" unless $fh;
+ $self->{input_length} = -s $fh;
+ $self->{count}=0;
+ eval {
+ $P->parse($fh);
+ };
+ print "\n" if $DEBUG || $VERBOSE;
+ if ( $VERBOSE) {
+ printf "Read and parsed $file_name in %.0f sec\n",time()-$start_time;
+ }
+ if ( $@ ) {
+ warn "$@Error while parsing\n $file_name\n";
+ return;
+ }
+ if (not $P) {
+ warn "WARNING: Could not parse osm data\n";
+ return;
+ }
+}
+
+sub parse($)
+{
+ my ($self, $string) = @_;
+
+ $self->{state} = STATE_INIT;
+
+ my $start_time = time();
+ my $P = new XML::Parser(Handlers => {Start => sub{ DoStart( $self, @_ )}, End => sub { DoEnd( $self, @_ )}});
+ $self->{input_length} = length($string);
+ $self->{count}=0;
+ eval {
+ $P->parse($string);
+ };
+ print "\n" if $DEBUG || $VERBOSE;
+ if ( $VERBOSE) {
+ printf "Read and parsed string in %.0f sec\n",time()-$start_time;
+ }
+ if ( $@ ) {
+ warn "$@Error while parsing\n [$string]\n";
+ return;
+ }
+ if (not $P) {
+ warn "WARNING: Could not parse osm data\n";
+ return;
+ }
+}
+
+# Function is called whenever an XML tag is started
+sub DoStart
+{
+#print @_,"\n";
+ my ($self, $Expat, $Name, %Attr) = @_;
+
+ if( $self->{state} == STATE_INIT )
+ {
+ if($Name eq "osm"){
+ $self->{state} = STATE_EXPECT_ENTITY;
+
+ if( $Attr{version} ne "0.5" )
+ { die "OsmReaderV5 can only read 0.5 files, found '$Attr{version}'\n" }
+ } else {
+ die "Expected 'osm' tag, got '$Name'\n";
+ }
+ }
+ elsif( $self->{state} == STATE_EXPECT_ENTITY )
+ {
+ # Pick up the origin attribute from the bound tag
+ if( $Name eq "bound" )
+ {
+ if( exists $Attr{origin} )
+ {
+ $self->{origin} = $Attr{origin};
+ }
+ return;
+ }
+ if($Name eq "node" or $Name eq "relation" or $Name eq "way"){
+ $self->{entity} = $Name;
+ $self->{attr} = {%Attr};
+ $self->{tags} = [];
+ $self->{members} = ($Name ne "node") ? [] : undef;
+ $self->{state} = STATE_EXPECT_BODY;
+ } else {
+ die "Expected entity\n";
+ }
+ }
+ elsif( $self->{state} == STATE_EXPECT_BODY )
+ {
+ if($Name eq "tag"){
+ push @{$self->{tags}}, $Attr{"k"}, $Attr{"v"};
+ }
+ if($Name eq "nd"){
+ push @{$self->{members}}, $Attr{"ref"};
+ }
+ if($Name eq "member"){
+ push @{$self->{members}}, new Geo::OSM::Relation::Member( \%Attr );
+ }
+ }
+}
+
+# Function is called whenever an XML tag is ended
+sub DoEnd
+{
+ my ($self, $Expat, $Name) = @_;
+ if( $self->{state} == STATE_EXPECT_BODY )
+ {
+ if( $Name eq $self->{entity} )
+ {
+ $self->_process( $self->{entity}, $self->{attr}, $self->{tags}, $self->{members} );
+ $self->{count}++;
+ if( $self->{progress} and ($self->{count}%11) == 1)
+ {
+ $self->{progress}->($self->{count}, $Expat->current_byte()/$self->{input_length} );
+ }
+ $self->{state} = STATE_EXPECT_ENTITY;
+ }
+ return;
+ }
+ elsif( $self->{state} == STATE_EXPECT_ENTITY )
+ {
+ return if $Name eq "bound";
+ if( $Name eq "osm" )
+ {
+ $self->{state} = STATE_INIT;
+ } else {die}
+ return;
+ }
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+OsmReaderV5 - Module for reading OpenStreetMap V5 XML data files
+
+=head1 SYNOPSIS
+
+ my $OSM = new Geo::OSM::OsmReader(\&process);
+ $OSM->load("Data/changes.osc");
+
+ sub process
+ {
+ my($OSM, $entity) = @_;
+ print "Read $entity ".$entity->id."\n";
+ my $tags = $entity->tags;
+ while( my($k,$v) = splice @{$tags}, 0, 2 )
+ { print " $k: $v\n" }
+ if( $entity->type eq "way" )
+ { print " Nodes: ", join(", ",@{$entity->nodes}),"\n"; }
+ }
+
+=head1 AUTHOR
+
+Martijn van Oosterhout <kleptog@svana.org>
+based on OsmXML.pm written by:
+Oliver White (oliver.white@blibbleblobble.co.uk)
+
+=head1 COPYRIGHT
+
+Copyright 2007, Martijn van Oosterhout
+Copyright 2006, Oliver White
+
+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, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+=cut
diff --git a/navit/script/osm/Geo/OSM/OsmReaderV6.pm b/navit/script/osm/Geo/OSM/OsmReaderV6.pm
new file mode 100644
index 000000000..4f6a683d2
--- /dev/null
+++ b/navit/script/osm/Geo/OSM/OsmReaderV6.pm
@@ -0,0 +1,249 @@
+##################################################################
+## OsmReader.pm - Library for reading OSM files ##
+## By Martijn van Oosterhout <kleptog@svana.org> ##
+## ##
+## Package that reads both OSM file format files. ##
+## The user creates the parse with a callback and the ##
+## loader will call the callback for each detected object. ##
+## Licence: LGPL ##
+##################################################################
+package Geo::OSM::OsmReader;
+
+use strict;
+use warnings;
+
+use Utils::File;
+use Utils::Math;
+use Utils::Debug;
+use XML::Parser;
+use Carp;
+
+use Geo::OSM::EntitiesV6;
+
+use constant STATE_INIT => 1;
+use constant STATE_EXPECT_ENTITY => 3;
+use constant STATE_EXPECT_BODY => 4;
+
+# With this initialiser, your process will get called with instantiated objects
+sub init
+{
+ my $obj = bless{}, shift;
+ my $proc = shift;
+ my $prog = shift;
+ if( ref $proc ne "CODE" )
+ { die "init Geo::OSM::OsmReader requires a sub as argument\n" }
+ $obj->{newproc} = $proc;
+ if( defined $prog )
+ { $obj->{progress} = $prog }
+ return $obj;
+}
+
+sub _process
+{
+ my($self, $entity, $attr, $tags, $members) = @_;
+
+ my $ent;
+ if( $entity eq "node" )
+ {
+ $ent = new Geo::OSM::Node( $attr, $tags );
+ }
+ if( $entity eq "relation" )
+ {
+ $ent = new Geo::OSM::Relation( $attr, $tags, $members );
+ }
+ if( $entity eq "way" )
+ {
+ $ent = new Geo::OSM::Way( $attr, $tags, $members );
+ }
+ croak "Unknown entity '$entity'" if not defined $ent;
+
+ return $self->{newproc}->( $ent );
+}
+
+sub load($)
+{
+ my ($self, $file_name) = @_;
+
+ $self->{state} = STATE_INIT;
+
+ my $start_time = time();
+ my $P = new XML::Parser(Handlers => {Start => sub{ DoStart( $self, @_ )}, End => sub { DoEnd( $self, @_ )}});
+ my $fh = data_open($file_name);
+ die "Cannot open OSM File $file_name\n" unless $fh;
+ $self->{input_length} = -s $fh;
+ $self->{count}=0;
+ eval {
+ $P->parse($fh);
+ };
+ print "\n" if $DEBUG || $VERBOSE;
+ if ( $VERBOSE) {
+ printf "Read and parsed $file_name in %.0f sec\n",time()-$start_time;
+ }
+ if ( $@ ) {
+ warn "$@Error while parsing\n $file_name\n";
+ return;
+ }
+ if (not $P) {
+ warn "WARNING: Could not parse osm data\n";
+ return;
+ }
+}
+
+sub parse($)
+{
+ my ($self, $string) = @_;
+
+ $self->{state} = STATE_INIT;
+
+ my $start_time = time();
+ my $P = new XML::Parser(Handlers => {Start => sub{ DoStart( $self, @_ )}, End => sub { DoEnd( $self, @_ )}});
+ $self->{input_length} = length($string);
+ $self->{count}=0;
+ eval {
+ $P->parse($string);
+ };
+ print "\n" if $DEBUG || $VERBOSE;
+ if ( $VERBOSE) {
+ printf "Read and parsed string in %.0f sec\n",time()-$start_time;
+ }
+ if ( $@ ) {
+ warn "$@Error while parsing\n [$string]\n";
+ return;
+ }
+ if (not $P) {
+ warn "WARNING: Could not parse osm data\n";
+ return;
+ }
+}
+
+# Function is called whenever an XML tag is started
+sub DoStart
+{
+#print @_,"\n";
+ my ($self, $Expat, $Name, %Attr) = @_;
+
+ if( $self->{state} == STATE_INIT )
+ {
+ if($Name eq "osm"){
+ $self->{state} = STATE_EXPECT_ENTITY;
+
+ if( $Attr{version} ne "0.6" )
+ { die "OsmReaderV6 can only read 0.6 files, found '$Attr{version}'\n" }
+ } else {
+ die "Expected 'osm' tag, got '$Name'\n";
+ }
+ }
+ elsif( $self->{state} == STATE_EXPECT_ENTITY )
+ {
+ # Pick up the origin attribute from the bound tag
+ if( $Name eq "bounds" )
+ {
+ if( exists $Attr{origin} )
+ {
+ $self->{origin} = $Attr{origin};
+ }
+ return;
+ }
+ if($Name eq "node" or $Name eq "relation" or $Name eq "way"){
+ $self->{entity} = $Name;
+ $self->{attr} = {%Attr};
+ $self->{tags} = [];
+ $self->{members} = ($Name ne "node") ? [] : undef;
+ $self->{state} = STATE_EXPECT_BODY;
+ } else {
+ die "Expected entity\n";
+ }
+ }
+ elsif( $self->{state} == STATE_EXPECT_BODY )
+ {
+ if($Name eq "tag"){
+ push @{$self->{tags}}, $Attr{"k"}, $Attr{"v"};
+ }
+ if($Name eq "nd"){
+ push @{$self->{members}}, $Attr{"ref"};
+ }
+ if($Name eq "member"){
+ push @{$self->{members}}, new Geo::OSM::Relation::Member( \%Attr );
+ }
+ }
+}
+
+# Function is called whenever an XML tag is ended
+sub DoEnd
+{
+ my ($self, $Expat, $Name) = @_;
+ if( $self->{state} == STATE_EXPECT_BODY )
+ {
+ if( $Name eq $self->{entity} )
+ {
+ $self->_process( $self->{entity}, $self->{attr}, $self->{tags}, $self->{members} );
+ $self->{count}++;
+ if( $self->{progress} and ($self->{count}%11) == 1)
+ {
+ $self->{progress}->($self->{count}, $Expat->current_byte()/$self->{input_length} );
+ }
+ $self->{state} = STATE_EXPECT_ENTITY;
+ }
+ return;
+ }
+ elsif( $self->{state} == STATE_EXPECT_ENTITY )
+ {
+ return if $Name eq "bounds";
+ if( $Name eq "osm" )
+ {
+ $self->{state} = STATE_INIT;
+ } else {die}
+ return;
+ }
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+OsmReaderV6 - Module for reading OpenStreetMap V6 XML data files
+
+=head1 SYNOPSIS
+
+ my $OSM = new Geo::OSM::OsmReader(\&process);
+ $OSM->load("Data/changes.osc");
+
+ sub process
+ {
+ my($OSM, $entity) = @_;
+ print "Read $entity ".$entity->id."\n";
+ my $tags = $entity->tags;
+ while( my($k,$v) = splice @{$tags}, 0, 2 )
+ { print " $k: $v\n" }
+ if( $entity->type eq "way" )
+ { print " Nodes: ", join(", ",@{$entity->nodes}),"\n"; }
+ }
+
+=head1 AUTHOR
+
+Martijn van Oosterhout <kleptog@svana.org>
+based on OsmXML.pm written by:
+Oliver White (oliver.white@blibbleblobble.co.uk)
+
+=head1 COPYRIGHT
+
+Copyright 2007, Martijn van Oosterhout
+Copyright 2006, Oliver White
+
+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, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+=cut
diff --git a/navit/script/osm/Geo/OSM/OsmXML.pm b/navit/script/osm/Geo/OSM/OsmXML.pm
new file mode 100644
index 000000000..60f458db7
--- /dev/null
+++ b/navit/script/osm/Geo/OSM/OsmXML.pm
@@ -0,0 +1,161 @@
+package Geo::OSM::OsmXML;
+
+use strict;
+use warnings;
+
+use Utils::File;
+use Utils::Math;
+use Utils::Debug;
+use XML::Parser;
+
+sub new(){ bless{} }
+
+sub load(){
+ my ($self, $file_name) = @_;
+
+ my $start_time = time();
+ my $P = new XML::Parser(Handlers => {Start => \&DoStart, End => \&DoEnd, Char => \&DoChar});
+ my $fh = data_open($file_name);
+ die "Cannot open OSM File $file_name\n" unless $fh;
+ eval {
+ $P->parse($fh);
+ };
+ print "\n" if $DEBUG || $VERBOSE;
+ if ( $VERBOSE) {
+ printf "Read and parsed $file_name in %.0f sec\n",time()-$start_time;
+ }
+ if ( $@ ) {
+ warn "$@Error while parsing\n $file_name\n";
+ return;
+ }
+ if (not $P) {
+ warn "WARNING: Could not parse osm data\n";
+ return;
+ }
+
+}
+sub name(){return($OsmXML::lastName)};
+
+sub bounds(){
+ my ($S,$W,$N,$E) = (1e+6,1e+6,-1e+6,-1e+6); # S,W,N,E
+ foreach my $Node(values %OsmXML::Nodes){
+ $S = $Node->{"lat"} if($Node->{"lat"} < $S);
+ $N = $Node->{"lat"} if($Node->{"lat"} > $N);
+ $W = $Node->{"lon"} if($Node->{"lon"} < $W);
+ $E = $Node->{"lon"} if($Node->{"lon"} > $E);
+ }
+ return($S,$W,$N,$E);
+}
+
+# Function is called whenever an XML tag is started
+sub DoStart()
+{
+ my ($Expat, $Name, %Attr) = @_;
+
+ if($Name eq "node"){
+ undef %OsmXML::Tags;
+ %OsmXML::MainAttr = %Attr;
+ }
+ if($Name eq "segment"){
+ undef %OsmXML::Tags;
+ %OsmXML::MainAttr = %Attr;
+ }
+ if($Name eq "way"){
+ undef %OsmXML::Tags;
+ undef @OsmXML::WaySegments;
+ %OsmXML::MainAttr = %Attr;
+ }
+ if($Name eq "tag"){
+ $OsmXML::Tags{$Attr{"k"}} = $Attr{"v"};
+ }
+ if($Name eq "seg"){
+ push(@OsmXML::WaySegments, $Attr{"id"});
+ }
+}
+
+# Function is called whenever an XML tag is ended
+sub DoEnd(){
+ my ($Expat, $Element) = @_;
+ if($Element eq "node"){
+ my $ID = $OsmXML::MainAttr{"id"};
+ $OsmXML::Nodes{$ID}{"lat"} = $OsmXML::MainAttr{"lat"};
+ $OsmXML::Nodes{$ID}{"lon"} = $OsmXML::MainAttr{"lon"};
+ foreach(keys(%OsmXML::Tags)){
+ $OsmXML::Nodes{$ID}{$_} = $OsmXML::Tags{$_};
+ }
+ }
+ if($Element eq "segment"){
+ my $ID = $OsmXML::MainAttr{"id"};
+ $OsmXML::Segments{$ID}{"from"} = $OsmXML::MainAttr{"from"};
+ $OsmXML::Segments{$ID}{"to"} = $OsmXML::MainAttr{"to"};
+ foreach(keys(%OsmXML::Tags)){
+ $OsmXML::Segments{$ID}{$_} = $OsmXML::Tags{$_};
+ }
+ }
+ if($Element eq "way"){
+ my $ID = $OsmXML::MainAttr{"id"};
+ $OsmXML::Ways{$ID}{"segments"} = join(",",@OsmXML::WaySegments);
+ foreach(keys(%OsmXML::Tags)){
+ $OsmXML::Ways{$ID}{$_} = $OsmXML::Tags{$_};
+ }
+ }
+}
+
+# Function is called whenever text is encountered in the XML file
+sub DoChar(){
+ my ($Expat, $String) = @_;
+}
+
+1;
+
+__END__
+
+=head1 NAME
+
+OsmXML - Module for reading OpenStreetMap XML data files
+
+=head1 SYNOPSIS
+
+ $OSM = new OsmXML();
+ $OSM->load("Data/nottingham.osm");
+
+ foreach $Way(%OsmXML::Ways){
+ @Segments = split(/,/, $Way->{"segments"});
+
+ foreach $SegmentID(@Segments){
+ $Segment = $OsmXML::Segments{$SegmentID};
+
+ $Node1 = $OsmXML::Nodes{$Segment->{"from"}};
+ $Node2 = $OsmXML::Nodes{$Segment->{"to"}};
+
+ printf "Node at %f,%f, named %s, is a %s",
+ $Node2->{"lat"},
+ $Node2->{"lon"},
+ $Node2->{"name"},
+ $Node2->{"highway"};
+ }
+ }
+
+=head1 AUTHOR
+
+Oliver White (oliver.white@blibbleblobble.co.uk)
+
+=head1 COPYRIGHT
+
+Copyright 2006, Oliver White
+
+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, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+=cut
diff --git a/navit/script/osm/Geo/OSM/Planet.pm b/navit/script/osm/Geo/OSM/Planet.pm
new file mode 100644
index 000000000..bedfdffc8
--- /dev/null
+++ b/navit/script/osm/Geo/OSM/Planet.pm
@@ -0,0 +1,336 @@
+##################################################################
+package Geo::OSM::Planet;
+##################################################################
+
+use Exporter;
+@ISA = qw( Exporter );
+use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION);
+@EXPORT = qw( mirror_planet
+ osm_dir
+ planet_dir
+ UTF8sanitize
+ estimated_max_id
+ estimated_max_count
+ );
+
+use strict;
+use warnings;
+
+use HTTP::Request;
+use File::Basename;
+use File::Copy;
+use File::Path;
+use File::Slurp;
+use Getopt::Long;
+use HTTP::Request;
+use Storable ();
+use Data::Dumper;
+
+use Utils::File;
+use Utils::Debug;
+use Utils::LWP::Utils;
+
+
+# As of planet-061220
+my $estimations = {
+ 'way' => {
+ 'count' => 3918624,
+ 'max_id' => 8013668
+ },
+ 'elem' => {
+ 'count' => 312752630,
+ 'max_id' => 312752630
+ },
+ 'seg' => {
+ 'count' => 40992844,
+ 'max_id' => 57261050
+ },
+ 'segment' => {
+ 'count' => 41325764,
+ 'max_id' => 57259818
+ },
+ 'tag' => {
+ 'count' => 186445779,
+ 'max_id' => 1
+ },
+ 'node' => {
+ 'count' => 40069619,
+ 'max_id' => 59943310
+ },
+ 'line' => {
+ 'count' => 388379350,
+ 'max_id' => 312752630
+ }
+};
+
+# ------------------------------------------------------------------
+# This routine estimates the maximum id for way,elem,seg,...
+# The values are taken from older planet.osm Files
+# So they mostly are a little bit to low
+# ARGS:
+# $type: line|way|tag|...
+# RETURNS:
+# $result: number of estimated max_id
+sub estimated_max_id($){
+ my $type= shift;
+ unless ( defined ($estimations->{$type}->{max_id})) {
+ warn("\n estimated_max_id($type): unknown Tag-Type\n");
+ return 0;
+ };
+ return $estimations->{$type}->{max_id};
+}
+
+# ------------------------------------------------------------------
+# This routine estimates the maximim number of elements for way,elem,seg,...
+# The values are taken from older planet.osm Files
+# So they mostly are a little bit to low
+# ARGS:
+# $type: line|way|tag|...
+# RETURNS:
+# $result: number of estimated elements
+sub estimated_max_count($){
+ my $type= shift;
+ unless ( defined ($estimations->{$type}->{count})) {
+ warn("\n estimated_max_id($type): unknown Tag-Type\n");
+ return 0;
+ };
+ return $estimations->{$type}->{count};
+}
+
+# ------------------------------------------------------------------
+# returns the osm main directory for holding data
+sub osm_dir() {
+ # For later these are the defaults
+ # on where we can read/write
+ # ~/osm
+ # /var/data/osm
+ my $dir;
+
+ my $home = $ENV{HOME};
+ unless ( $home ) {
+ $home = `whoami`;
+ chomp $home;
+ $home = "/home/$home";
+ }
+
+ $dir = "$home/osm";
+ return $dir;
+}
+
+# ------------------------------------------------------------------
+# Returns (or sets) the directory where the planet.osm files will be found
+my $PLANET_DIR='';
+sub planet_dir(;$) {
+ my $new_dir=shift;
+
+ if ( $new_dir ) {
+ $PLANET_DIR = $new_dir;
+ } elsif( ! $PLANET_DIR) {
+ my $dir = osm_dir();
+ $PLANET_DIR = "$dir/planet";
+ }
+ return $PLANET_DIR;
+}
+
+
+sub sort_unique(@){
+ my @srt = sort @_;
+ my @erg;
+ my $last_val=undef;
+ for my $val ( @srt ){
+ next if $last_val && $val eq $last_val;
+ $last_val=$val;
+ push (@erg,$val);
+ }
+ return @erg
+}
+
+
+# ------------------------------------------------------------------
+# mirror the newest planet.osm File to
+# ~/osm/planet/planet.osm.bz2
+# and the resulting
+# Filename is returned
+#
+# the file is -----NO LONGER--- Sanitized afterwards
+sub mirror_planet(){
+ my $planet_server="http://planet.openstreetmap.org";
+ my $url = "$planet_server";
+
+ my $mirror_dir=planet_dir();
+ mkdir_if_needed( $mirror_dir );
+
+ my $current_file;
+ if ( !$Utils::LWP::Utils::NO_MIRROR ) {
+ # Get Index.html of Planet.osm.org
+ my $apache_sort_hy_date="?C=M;O=D";
+ my $index_file="$mirror_dir/planet_index.html";
+ my $result = mirror_file("$url/$apache_sort_hy_date",$index_file);
+ if ( $result ) {
+ my $index_content = read_file( $index_file ) ;
+
+ # Get the current planet.osm File
+ my @all_files = ($index_content =~ m/(planet-\d\d\d\d\d\d.osm.bz2|planet-\d\d\d\d\d\d.osm.gz)/g);
+ my ( $current_file1,$current_file2 )
+ = grep { $_ !~ m/planet-061008/ } reverse sort_unique(@all_files);
+ print STDERR " TOP Files: ( $current_file1,$current_file2 ) \n" if $DEBUG;
+ $current_file = $current_file1;
+ $current_file1 =~ s/\.bz2$/\.gz/;
+ if ( $current_file1 eq $current_file2 ) {
+ $current_file = $current_file1
+ };
+ if ( $current_file ) {
+ $url .= "/$current_file";
+ $current_file = "$mirror_dir/$current_file";
+ print STDERR "Mirror OSM Data from $url\n" if $VERBOSE || $DEBUG;
+ $result = mirror_file($url,$current_file);
+ #return undef unless $result;
+ }
+ }
+ }
+
+ my @files= reverse sort_unique( grep { $_ !~ m/planet-061008/ } glob("$mirror_dir/planet-*.osm.{bz2,gz}"));
+ if ( $DEBUG) {
+ print STDERR "Existing Files: \n\t".join("\n\t",@files)."\n";
+ }
+ $current_file = $files[0];
+
+ if ( $DEBUG) {
+ print STDERR "Choosen File: $current_file\n";
+ }
+
+ return undef unless $current_file;
+
+# $current_file = UTF8sanitize($current_file);
+# if ( $DEBUG >2 || $VERBOSE>3) {
+# print STDERR "Sanitized File: $current_file\n";
+# }
+
+ my ($unpacked_file) = ($current_file=~ m/(.*\.osm)/);
+ $current_file = $unpacked_file
+ unless file_needs_re_generation($current_file,$unpacked_file);
+
+ print STDERR "Mirror done, using '$current_file'\n" if $VERBOSE>1 || $DEBUG>1;
+ return $current_file;
+}
+
+# ------------------------------------------------------------------
+# creates a second file with a sanitized Version of planet.osm
+# the resulting file can be found at
+# ~/osm/planet/planet-07XXXX-a.osm.bz2
+# If a recent enought Version is found in ~/osm/planet/
+# nothing is done, but the filename of the file is returned
+# if the routine finds an uncompressed up to date Version
+# ~/osm/planet/planet-07XXXX-a.osm
+# this Filename is returned.
+sub UTF8sanitize($){
+ my $filename = shift;
+ if ( $DEBUG) {
+ print STDERR "UTF8sanitize($filename)\n";
+ }
+ my $start_time=time();
+
+ # the newer Files do not need to be sanitized
+ my ($file_date) = ($filename =~ m/planet-(\d+)/ );
+ return $filename
+ if ($file_date >= 061205) && ( $file_date < 061213);
+
+ my $filename_new= $filename;
+ $filename_new =~ s/\.osm/-a.osm/;
+ my $filename_new_check=newest_unpacked_filename($filename_new);
+
+ # check if planet-070101-a.osm[.bz2] is newer than planet-070101.osm.bz2
+ return $filename_new_check
+ unless file_needs_re_generation($filename,$filename_new_check);
+
+ # We have to create a new one
+ print STDERR "UTF8 Sanitize $filename ... \n";
+ # Uggly Hack, but for now it works
+ my $UTF8sanitizer=`which UTF8sanitizer`;
+ chomp $UTF8sanitizer;
+ unless ( -x $UTF8sanitizer ) {
+ $UTF8sanitizer=find_file_in_perl_path('../planet.osm/C/UTF8sanitizer');
+ }
+ die "Sanitizer not found\n" unless -x $UTF8sanitizer;
+ print STDERR "Sanitizer found at '$UTF8sanitizer'\n" if $DEBUG;
+
+ print STDERR " this may take some time ... \n";
+ my $cmd = "gzip -dc $filename | $UTF8sanitizer | bzip2 >$filename_new.part";
+ print "Command: $cmd" if $DEBUG || $VERBOSE;
+ my $result = `$cmd`;
+ print $result if $DEBUG || $VERBOSE;
+
+ print "Sanitized $filename " if $DEBUG || $VERBOSE;
+ print_time($start_time);
+
+ my $file_size = -s "$filename";
+ my $file_size_new = -s "$filename_new.part";
+ if ( $file_size_new < ($file_size*0.9) ) {
+ die "File Sanitize seems not successfull.\n".
+ "Original Size $file_size\n".
+ "Sanitized Size $file_size_new\n";
+ }
+ rename "$filename_new.part","$filename_new";
+ if ( ! -s $filename_new ) {
+ die "Cannot sanitize $filename\n";
+ }
+ print "now we have a sanitized $filename_new\n" if $DEBUG || $VERBOSE;
+ return $filename_new;
+}
+
+# ------------------------------------------------------------------
+# find a file in the current Perl Search path. For now this was the
+# easiest solution to find programms like UTF8Sanitize
+# ARGS: relative filename (relative to @INC-path
+# RETURNS: Absolute path to file
+sub find_file_in_perl_path($){
+ my $file = shift;
+
+ my $found_file = '';
+ for my $path ( @INC ) {
+ my $filename = "$path/$file";
+ print "find_file_in_perl_path: looking in '$filename'\n" if $DEBUG>2;
+ if ( -s $filename){
+ $found_file = $filename;
+ last;
+ };
+ }
+
+ print "find_file_in_perl_path($file): --> $found_file\n" if $DEBUG;
+ return $found_file;
+}
+
+# ------------------------------------------------------------------
+1;
+
+=head1 NAME
+
+Geo::OSM::Planet
+
+=head1 COPYRIGHT
+
+Copyright 2006, Jörg Ostertag
+
+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, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+=head1 AUTHOR
+
+Jörg Ostertag (planet-count-for-openstreetmap@ostertag.name)
+
+=head1 SEE ALSO
+
+http://www.openstreetmap.org/
+
+=cut
diff --git a/navit/script/osm/Geo/OSM/SegmentList.pm b/navit/script/osm/Geo/OSM/SegmentList.pm
new file mode 100644
index 000000000..0de35ebf5
--- /dev/null
+++ b/navit/script/osm/Geo/OSM/SegmentList.pm
@@ -0,0 +1,520 @@
+##################################################################
+package Geo::OSM::SegmentList;
+##################################################################
+
+use Exporter;
+@ISA = qw( Exporter );
+use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION);
+@EXPORT = qw( LoadOSM_segment_csv
+ reduce_segments_list
+ read_osm_file
+ load_segment_list
+ );
+
+use strict;
+use warnings;
+
+use Math::Trig;
+
+use Data::Dumper;
+use Geo::Geometry;
+use Geo::OSM::Planet;
+use Utils::Debug;
+use Utils::File;
+use Utils::Math;
+use Geo::Filter::Area;
+
+sub load_segment_list($;$){
+ my $do_filter_against_osm = shift;
+ my $bounds = shift;
+
+ my $osm_segments;
+ print STDERR "load_segment_list from: '$do_filter_against_osm'\n";
+ if ( $do_filter_against_osm =~ m/^postgis|mapnik$/ ) {
+ $osm_segments = Geo::OSM::SegmentList::LoadOSM_segment_postgis($bounds);
+ } elsif ( -s $do_filter_against_osm ) {
+ if ( $do_filter_against_osm =~ m/\.csv/ ) {
+ $osm_segments = Geo::OSM::SegmentList::LoadOSM_segment_csv($do_filter_against_osm, $bounds);
+ } elsif ( $do_filter_against_osm =~ m/\.osm/ ) {
+ $osm_segments = Geo::OSM::SegmentList::read_osm_file($do_filter_against_osm, $bounds);
+ } else {
+ die "Unknown Datatype for $do_filter_against_osm\n";
+ }
+ #print Dumper(\$osm_segments ) if $DEBUG;
+ } elsif ( $do_filter_against_osm !~ m/^\d*$/ ) {
+ die "Unknown Datatype for $do_filter_against_osm\n";
+ } else {
+
+ # later we search in:
+ # ~/.osm/data/planet.osm.csv
+ # /var/data/osm/planet.osm.csv
+
+ my $home = $ENV{HOME}|| '~/';
+ my $path= planet_dir();
+ my $osm_filename = "${path}/csv/osm-segments.csv";
+ $osm_filename =~ s,\~/,$home/,;
+ printf STDERR "check $osm_filename for loading\n" if $DEBUG;
+
+ die "Cannot open $osm_filename\n" unless -s $osm_filename;
+ $osm_segments = Geo::OSM::SegmentList::LoadOSM_segment_csv($osm_filename, $bounds);
+ };
+ return $osm_segments
+}
+
+# ------------------------------------------------------------------
+# reduce osm Segments to only those inside the bounding box
+# This make comparison faster
+sub reduce_segments_list($$) {
+ my $all_osm_segments = shift;
+ my $bounds = shift;
+
+ my $start_time=time();
+
+ #printf STDERR "reduce_osm_segments(".Dumper(\$bounds).")\n" if $DEBUG;
+
+ my $osm_segments = [];
+ my $count=0;
+ my $all_count=0;
+ for my $segment ( @{$all_osm_segments} ) {
+ $all_count++;
+ next unless $segment->[0] >= $bounds->{lat_min};
+ next unless $segment->[0] <= $bounds->{lat_max};
+ next unless $segment->[1] >= $bounds->{lon_min};
+ next unless $segment->[1] <= $bounds->{lon_max};
+ next unless $segment->[2] >= $bounds->{lat_min};
+ next unless $segment->[2] <= $bounds->{lat_max};
+ next unless $segment->[3] >= $bounds->{lon_min};
+ next unless $segment->[3] <= $bounds->{lon_max};
+ $count++;
+ push(@{$osm_segments},$segment);
+ }
+ if ( $VERBOSE > 3 || $DEBUG > 3 ) {
+ printf STDERR " Reduced OSM Segment list to $count( $all_count) OSM-Segments ";
+ print_time($start_time);
+ }
+
+ return $osm_segments;
+}
+
+# -------------------------------------------------------
+# Load the csv Version of a segment list
+# Args: $filename, {lat_min=> .., lat_max => ..., lon_min => .., lon_max => .. }
+sub LoadOSM_segment_csv($;$){
+ my $filename = shift;
+ my $bounds = shift;
+ printf STDERR "Reading OSM-Segment-csv File: $filename, ($bounds->{lat_min} ... $bounds->{lat_max} , $bounds->{lon_min} ... $bounds->{lon_max})\n"
+ if $DEBUG || $VERBOSE;
+ my $start_time=time();
+
+ my $segments;
+ my $check_bounds = 1 if defined $bounds;
+ $main::dont_write_osm_storable=1 || $check_bounds;
+ $main::dont_read_osm_storable=1;
+
+ if ( -s "$filename.storable" &&
+ ! file_needs_re_generation($filename,"$filename.storable")
+ && ! $main::dont_read_osm_storable ) {
+ # later we should compare if the file also is newer than the source
+ $filename .= ".storable";
+ printf STDERR "Reading OSM File as storable: $filename\n"
+ if $DEBUG || $VERBOSE;
+ $segments = Storable::retrieve($filename);
+ if ( $VERBOSE >1 || $DEBUG) {
+ printf STDERR "Reading $filename done";
+ print_time($start_time);
+ }
+ } else {
+ my $fh = data_open($filename);
+ my $count=0;
+ my $count_read=0;
+
+ die "Cannot open $filename in LoadOSM_segment_csv.\n".
+ "Please create it first to use the option --osm.\n".
+ "See --help for more info" unless $fh;
+
+ while ( my $line = $fh ->getline() ) {
+ $count++;
+ chomp $line;
+ my @segment;
+ my $dummy;
+ ($segment[0],$segment[1],$segment[2],$segment[3],$segment[4]) = split(/,/,$line,5);
+ #print STDERR Dumper(\@segment);
+
+ if ( $check_bounds ) {
+ next unless $segment[0] >= $bounds->{lat_min};
+ next unless $segment[0] <= $bounds->{lat_max};
+ next unless $segment[1] >= $bounds->{lon_min};
+ next unless $segment[1] <= $bounds->{lon_max};
+ next unless $segment[2] >= $bounds->{lat_min};
+ next unless $segment[2] <= $bounds->{lat_max};
+ next unless $segment[3] >= $bounds->{lon_min};
+ next unless $segment[3] <= $bounds->{lon_max};
+ }
+
+ push (@{$segments},\@segment);
+ $count_read++;
+ }
+ $fh->close();
+ if ( $VERBOSE >1 || $DEBUG) {
+ printf STDERR "Read and parsed $count_read($count) Lines in $filename";
+ print_time($start_time);
+ }
+ if ( ! $main::dont_write_osm_storable ) {
+ $start_time=time();
+ Storable::store($segments ,"$filename.storable");
+ if ( $VERBOSE >1 || $DEBUG) {
+ printf STDERR "Wrote Storable in to $filename.storable";
+ print_time($start_time);
+ }
+ };
+ }
+
+
+ return($segments);
+}
+
+
+
+# -------------------------------------------------------
+# Load the segment list from postgis
+# Args: {lat_min=> .., lat_max => ..., lon_min => .., lon_max => .. }
+# This is a test to see if we can handle all segments of the world
+# with reasonable query times
+sub LoadOSM_segment_postgis($;$){
+ my $bounds = shift;
+ printf STDERR "Reading OSM-Segments form PostGis($bounds->{lat_min} ... $bounds->{lat_max} , $bounds->{lon_min} ... $bounds->{lon_max})\n"
+ if $DEBUG || $VERBOSE;
+ my $start_time=time();
+
+ my $segments;
+ my $check_bounds = 1 if defined $bounds;
+ my @row;
+ my $sth;
+
+ use DBI;
+
+ my $dbname="gis";
+ my $dbhost="/var/run/postgresql";
+ my $dbh = DBI->connect("dbi:Pg:dbname=$dbname;host=$dbhost", "", "", {AutoCommit => 0});
+
+ unless( $dbh) {
+ warn "\n\n!!!!!!!!!!!!!!!! WARNING: Cannot Open Database for reading OSM Segments\n\n";
+ return;
+ };
+
+ # WHERE the_geom && setsrid('BOX(47.36 21.40,51.185 21.53)'::box2d, 42102)
+ # WHERE GeomFromText('POINT(25.3 25.40)', 42102) && the_geom \
+ # AND distance(the_geom, GeomFromText('POINT(25.7 5.3)', 42102)) = 0
+ # WHERE distance(the_geom, setsrid('BOX(4.36 2.3,1.5 2.8)'::box2d, 42102)) = 0
+ # WHERE the_point && setsrid('BOX(295149 2315499, 465992 2163790)'::box2d, -1)
+
+ ##############################
+ # FOR DEBUG
+# $bounds->{lat_min}=10;
+# $bounds->{lon_min}=10;
+# $bounds->{lat_max}=70;
+# $bounds->{lon_max}=70;
+ #
+ ####################################
+
+ my $SRID_WGS84="4326";
+ my $SRID_UNKNOWN="3395";
+ my $SRID_OSM="900913";
+
+ my $polygon_text=sprintf("POLYGON((%.5f %.5f,%.5f %.5f,%.5f %.5f,%.5f %.5f,%.5f %.5f))",
+ $bounds->{lat_min}-0.1 , $bounds->{lon_min}-0.1,
+ $bounds->{lat_max}+0.1 , $bounds->{lon_min}-0.1 ,
+ $bounds->{lat_max}+0.1 , $bounds->{lon_max}+0.1 ,
+ $bounds->{lat_min}-0.1 , $bounds->{lon_max}+0.1 ,
+ $bounds->{lat_min}-0.1 , $bounds->{lon_min}-0.1);
+ my $polygon="transform(GeomFromText('$polygon_text',${SRID_WGS84}),$SRID_OSM)";
+
+ my $select = "select osm_id,highway,name from planet_osm_line where highway is not null and way && ".
+ " $polygon ".
+ "limit 5;";
+ print "\nprepare: $select\n";
+ $sth = $dbh->prepare($select, { pg_server_prepare => 1 });
+ $sth->execute();
+ while ( @row = $sth->fetchrow_array ) {
+ print "postgis ROW: @row\n";
+ }
+ printf STDERR "---------------------------------------------------------------\n" if $DEBUG || $VERBOSE;
+
+
+# $select = "SELECT name ,astext(way),$distance FROM planet_osm_roads WHERE $distance < 500 order by $distance;";
+
+ #SELECT * FROM planet_osm_roads WHERE way in ?",
+ #$select = "SELECT name FROM planet_osm_roads WHERE distance(way,GeomFromText('POINT(856371.58 6683083.41)', 3395)) < 1000;";
+# my $distance="distance(way, GeomFromText('POINT(856371.58 6683083.41)', 3395))";
+ my $point_text=sprintf("POINT(%.5f %.5f)", $bounds->{lat_min} , $bounds->{lon_min});
+ my $point="transform(GeomFromText('$point_text',${SRID_WGS84}),$SRID_OSM)";
+ my $distance="distance(way,$point)";
+
+ $select = "SELECT name FROM planet_osm_line WHERE ${distance} < 1000;";
+ print "\nprepare: $select\n";
+ $sth = $dbh->prepare($select, { pg_server_prepare => 1 });
+ $sth->execute();
+ while ( @row = $sth->fetchrow_array ) {
+ print "postgis ROW: @row\n";
+ }
+ printf STDERR "---------------------------------------------------------------\n" if $DEBUG || $VERBOSE;
+
+ $select = "SELECT name FROM planet_osm_roads WHERE ${distance} < 1000;";
+ print "\nprepare: $select\n";
+ $sth = $dbh->prepare($select, { pg_server_prepare => 1 });
+ $sth->execute();
+ while ( @row = $sth->fetchrow_array ) {
+ print "postgis ROW: @row\n";
+ }
+ printf STDERR "---------------------------------------------------------------\n" if $DEBUG || $VERBOSE;
+
+ $select = "SELECT osm_id,highway,name,asText(transform(way,${SRID_WGS84})) from planet_osm_line where highway is not null limit 5;";
+ print "\nprepare: $select\n";
+ $sth = $dbh->prepare($select, { pg_server_prepare => 1 });
+ $sth->execute();
+ while ( @row = $sth->fetchrow_array ) {
+ print "postgis ROW: @row\n";
+ }
+
+ printf STDERR "---------------------------------------------------------------\n" if $DEBUG || $VERBOSE;
+
+ my $count=0;
+ my $count_read=0;
+ while ( @row = $sth->fetchrow_array ) {
+ print "postgis ROW: @row\n";
+
+ $count++;
+ my $line="";
+ chomp $line;
+ my @segment;
+ my $dummy;
+ ($segment[0],$segment[1],$segment[2],$segment[3],$segment[4]) = split(/,/,$line,5);
+ #print STDERR Dumper(\@segment);
+
+ if ( $check_bounds ) {
+ next unless $segment[0] >= $bounds->{lat_min};
+ next unless $segment[0] <= $bounds->{lat_max};
+ next unless $segment[1] >= $bounds->{lon_min};
+ next unless $segment[1] <= $bounds->{lon_max};
+ next unless $segment[2] >= $bounds->{lat_min};
+ next unless $segment[2] <= $bounds->{lat_max};
+ next unless $segment[3] >= $bounds->{lon_min};
+ next unless $segment[3] <= $bounds->{lon_max};
+ }
+
+ push (@{$segments},\@segment);
+ $count_read++;
+ }
+
+ $dbh->disconnect;
+
+
+ return($segments);
+}
+
+
+# ----------------------
+sub Storable_save($$){
+ my $filename = shift;
+ my $segments = shift;
+ eval{
+ Storable::store($segments ,"$filename.storable");
+ };
+ if ( $@ ) {
+ #warn Dumper(\$segments);
+ die "Storable_save(): $@\n";
+ }
+ printf STDERR "Stored OSM File: $filename as storable\n"
+ if $DEBUG || $VERBOSE;
+}
+
+# ----------------------
+sub Storable_load($){
+ my $filename = shift;
+ $filename .= ".storable";
+ my $segments = Storable::retrieve($filename);
+ printf STDERR "Loaded OSM File: $filename as storable\n"
+ if $DEBUG || $VERBOSE;
+ return $segments;
+}
+
+##################################################################
+# read Segment list from osm File
+##################################################################
+
+#our $read_osm_nodes;
+our $read_osm_segments;
+#our $read_osm_obj;
+our (%MainAttr,$Type,%Tags, @WaySegments);
+# Stats
+our %AllTags;
+# Stored data
+our (%Nodes, %Segments, %Stats);
+our $AREA_FILTER;
+$AREA_FILTER = Geo::Filter::Area->new( area => "world" );
+my $from_node=0;
+
+# Function is called whenever an XML tag is started
+#----------------------------------------------
+sub DoStart()
+{
+ my ($Expat, $Name, %Attr) = @_;
+
+ if($Name eq "node"){
+ undef %Tags;
+ %MainAttr = %Attr;
+ $Type = "n";
+ }
+ if($Name eq "segment"){
+ undef %Tags;
+ %MainAttr = %Attr;
+ $Type = "s";
+ }
+ if($Name eq "way"){
+ undef %Tags;
+ undef @WaySegments;
+ %MainAttr = %Attr;
+ $Type = "w";
+ }
+ if($Name eq "tag"){
+ # TODO: protect against id,from,to,lat,long,etc. being used as tags
+ $Tags{$Attr{"k"}} = $Attr{"v"};
+ $AllTags{$Attr{"k"}}++;
+ $Stats{"tags"}++;
+ }
+ if($Name eq "way"){
+ $from_node=0;
+ }
+ if($Name eq "nd" ) {
+ my $to_node = $Attr{"ref"};
+ if ( $from_node &&
+ defined($Nodes{$from_node}) &&
+ defined($Nodes{$to_node})
+ ) {
+ my ($lat1,$lon1)=split(",",$Nodes{$from_node});
+ my ($lat2,$lon2)=split(",",$Nodes{$to_node});
+ my $angle = angle_north_relative(
+ { lat => $lat1 , lon => $lon1 },
+ { lat => $lat2 , lon => $lon2 });
+ push (@{$read_osm_segments},[$lat1,$lon1,$lat2,$lon2,$angle]);
+ }
+ $from_node = $to_node;
+ }
+}
+
+# Function is called whenever an XML tag is ended
+#----------------------------------------------
+sub DoEnd(){
+ my ($Expat, $Element) = @_;
+ my $ID = $MainAttr{"id"};
+
+ if($Element eq "node"){
+ my $node={};
+ $node->{"lat"} = $MainAttr{"lat"};
+ $node->{"lon"} = $MainAttr{"lon"};
+
+ if ( $AREA_FILTER->inside($node) ) {
+ $Nodes{$ID} = sprintf("%f,%f",$MainAttr{lat}, $MainAttr{lon});
+ foreach(keys(%Tags)){
+ $node->{$_} = $Tags{$_};
+ }
+ }
+ }
+
+ if($Element eq "segment"){
+ my $from = $MainAttr{"from"};
+ my $to = $MainAttr{"to"};
+ if ( defined($Nodes{$from}) && defined($Nodes{$to}) ) {
+ $Segments{$ID}{"from"} = $from;
+ $Segments{$ID}{"to"} = $to;
+ }
+ }
+
+ if($Element eq "way"){
+ if ( @WaySegments ) {
+ foreach my $seg_id( @WaySegments ){ # we only have the needed ones in here
+ }
+ }
+ }
+}
+
+# Function is called whenever text is encountered in the XML file
+#----------------------------------------------
+sub DoChar(){
+ my ($Expat, $String) = @_;
+}
+
+# --------------------------------------------
+sub read_osm_file($;$) { # Insert Segments from osm File
+ my $filename = shift;
+ my $bounds = shift;
+
+ print("Reading OSM Segment from File $filename\n") if $VERBOSE || $DEBUG;
+ if ( file_needs_re_generation($filename,"$filename.storable")) {
+ print "$filename: ".(-s $filename)." Bytes\n" if $DEBUG;
+
+ print STDERR "Parsing file: $filename\n" if $DEBUG;
+ my $p = new XML::Parser( Handlers => {
+ Start => \&DoStart,
+ End => \&DoEnd,
+ Char => \&DoChar,
+ },
+ ErrorContext => 10,
+ );
+
+ my $fh = data_open($filename);
+ if (not $fh) {
+ print STDERR "WARNING: Could not open osm data from $filename\n";
+ return;
+ }
+ my $content;
+ eval {
+ $content = $p->parse($fh);
+ };
+ if (not $p) {
+ print STDERR "WARNING: Could not parse osm data from $filename\n";
+ return;
+ }
+ #warn Dumper(\$read_osm_segments);
+ Storable_save($filename,$read_osm_segments);
+ } else {
+ $read_osm_segments=Storable_load($filename);
+ }
+ return($read_osm_segments);
+}
+
+# -------------------------------------------------------
+
+1;
+
+=head1 NAME
+
+Geo::OSM::SegmentList
+
+=head1 COPYRIGHT
+
+Copyright 2006, Jörg Ostertag
+
+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, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+=head1 AUTHOR
+
+Jörg Ostertag (planet-count-for-openstreetmap@ostertag.name)
+
+=head1 SEE ALSO
+
+http://www.openstreetmap.org/
+
+=cut
diff --git a/navit/script/osm/Geo/OSM/Tracks2OSM.pm b/navit/script/osm/Geo/OSM/Tracks2OSM.pm
new file mode 100644
index 000000000..4016f8c02
--- /dev/null
+++ b/navit/script/osm/Geo/OSM/Tracks2OSM.pm
@@ -0,0 +1,145 @@
+##################################################################
+package Geo::OSM::Tracks2OSM;
+# Functions:
+# tracks2osm:
+# converts a tracks Hash to an OSM Datastructure
+#
+##################################################################
+
+use Exporter;
+@ISA = qw( Exporter );
+use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION);
+@EXPORT = qw( tracks2osm );
+
+use strict;
+use warnings;
+
+use Data::Dumper;
+
+use Geo::Geometry;
+use Geo::Tracks::Tools;
+use Utils::Debug;
+use Utils::File;
+use Utils::Math;
+
+my $first_id = -10000;
+
+my $lat_lon2node={};
+my $next_osm_node_number = $first_id;
+my $osm_nodes_duplicate = {};
+# Check if a node at this position exists
+# if it exists we get the old id; otherwise we create a new one
+sub create_node($$) {
+ my $osm_nodes = shift;
+ my $elem = shift;
+
+ printf STDERR "create_node(): lat or lon undefined : $elem->{lat},$elem->{lon} ".Dumper(\$elem)."\n"
+ unless defined($elem->{lat}) && defined($elem->{lon}) ;
+
+ my $id=0;
+ my $lat_lon = sprintf("%f_%f",$elem->{lat},$elem->{lon});
+ if ( defined( $osm_nodes_duplicate->{$lat_lon} ) ) {
+ $id = $osm_nodes_duplicate->{$lat_lon};
+ printf STDERR "Node already exists as $id pos:$lat_lon\n"
+ if $DEBUG>2;
+ $osm_nodes->{$id}=$elem;
+ # TODO: We have to check that the tags of the old and new nodes don't differ
+ # or we have to merge them
+ } else {
+ $next_osm_node_number--;
+ $id = $next_osm_node_number;
+ $elem->{tag}->{converted_by} = "Track2osm" ;
+ $elem->{node_id} ||= $id;
+ $osm_nodes->{$id}=$elem;
+ $lat_lon2node->{$lat_lon}=$id;
+ $osm_nodes_duplicate->{$lat_lon}=$id;
+ };
+ if ( !$id ) {
+ print STDERR "create_node(): Null node($id,$lat_lon) created\n".
+ Dumper($elem)
+ if $DEBUG;
+ }
+ return $id;
+}
+
+
+my $osm_way_number = $first_id;
+# ------------------------------------------------------------------
+sub tracks2osm($){
+ my $tracks = shift;
+
+
+ my $osm_nodes = {};
+ my $osm_ways = {};
+ my $reference = $tracks->{filename};
+
+ my $last_angle = 999999999;
+ my $angle;
+ my $angle_to_last;
+
+
+ my $count_valid_points_for_ways=0;
+
+ enrich_tracks($tracks);
+
+ for my $track ( @{$tracks->{tracks}} ) {
+
+ # We need at least two elements in track
+ next unless scalar(@{$track})>1;
+
+ $osm_way_number--;
+ $osm_ways->{$osm_way_number}->{tag} = {
+ "converted_by" => "Track2osm",
+ "highway" => "FIXME",
+ "note" => "FIXME",
+ };
+ for my $elem ( @{$track} ) {
+ my $node_id = $elem->{node_id} || create_node($osm_nodes,$elem);
+
+ # -------------------------------------------- Add to Way
+ push(@{$osm_ways->{$osm_way_number}->{nd}},$node_id);
+ $count_valid_points_for_ways++;
+ }
+ }
+
+ my $bounds = GPS::get_bounding_box($tracks);
+ printf STDERR "Track $reference Bounds: ".Dumper(\$bounds) if $DEBUG>5;
+ return { nodes => $osm_nodes,
+ ways => $osm_ways,
+ bounds => $bounds,
+ };
+}
+
+
+
+=head1 NAME
+
+Geo::OSM::Track2OSM
+
+=head1 COPYRIGHT
+
+Copyright 2006, Jörg Ostertag
+
+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, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+=head1 AUTHOR
+
+Jörg Ostertag (planet-count-for-openstreetmap@ostertag.name)
+
+=head1 SEE ALSO
+
+http://www.openstreetmap.org/
+
+=cut
diff --git a/navit/script/osm/Geo/OSM/Upload.pm b/navit/script/osm/Geo/OSM/Upload.pm
new file mode 100644
index 000000000..da18e97ec
--- /dev/null
+++ b/navit/script/osm/Geo/OSM/Upload.pm
@@ -0,0 +1,145 @@
+package osm;
+
+use strict;
+use warnings;
+
+
+use WWW::Curl::easy;
+
+sub new(){bless{}};
+
+sub setup(){
+ my $self = shift();
+ $self->{Username} = shift();
+ $self->{Password} = shift();
+ $self->{UserAgent} = shift();
+}
+
+sub tempfiles(){
+ my $self = shift();
+ $self->{file1} = shift();
+ $self->{file2} = shift();
+}
+
+sub uploadWay(){
+ my ($self, $Tags, @Segments) = @_;
+ $Tags .= sprintf("<tag k=\"created_by\" v=\"%s\"/>", $self->{UserAgent});
+
+ my $Segments = "";
+ foreach $Segment(@Segments){
+ $Segments .= "<seg id=\"$Segment\"/>";
+ }
+
+ my $Way = "<way id=\"0\">$Segments$Tags</way>";
+ my $OSM = "<osm version=\"0.3\">$Way</osm>";
+ my $data = "<?xml version=\"1.0\"?>\n$OSM";
+ my $path = "way/0";
+
+ my ($response, $http_code) = $self->upload($data, $path);
+ return($response);
+}
+
+sub uploadSegment(){
+ my ($self, $Node1,$Node2,$Tags) = @_;
+ $Tags .= sprintf("<tag k=\"created_by\" v=\"%s\"/>", $self->{UserAgent});
+
+ my $Segment = sprintf("<segment id=\"0\" from=\"%d\" to=\"%d\">$Tags</segment>", $Node1,$Node2);
+ my $OSM = "<osm version=\"0.3\">$Segment</osm>";
+ my $data = "<?xml version=\"1.0\"?>\n$OSM";
+ my $path = "segment/0";
+
+ my ($response, $http_code) = $self->upload($data, $path);
+
+
+ return($response);
+}
+
+sub uploadNode(){
+ my ($self, $Lat, $Long, $Tags) = @_;
+ $Tags .= sprintf("<tag k=\"created_by\" v=\"%s\"/>", $self->{UserAgent});
+
+ my $Node = sprintf("<node id=\"0\" lon=\"%f\" lat=\"%f\">$Tags</node>", $Long, $Lat);
+ my $OSM = "<osm version=\"0.3\">$Node</osm>";
+ my $data = "<?xml version=\"1.0\"?>\n$OSM";
+ my $path = "node/0";
+
+ my ($response, $http_code) = $self->upload($data, $path);
+
+ return($response);
+}
+
+sub upload(){
+ my($self, $data, $path) = @_;
+
+ my $curl = new WWW::Curl::easy;
+
+ my $login = sprintf("%s:%s", $self->{Username}, $self->{Password});
+
+ open(my $FileToSend, ">", $self->{file1});
+ print $FileToSend $data;
+ close $FileToSend;
+
+ my $url = "http://www.openstreetmap.org/api/0.3/$path";
+
+ open(my $TxFile, "<", $self->{file1});
+ open(my $RxFile, ">",$self->{file2});
+ $curl->setopt(CURLOPT_URL,$url);
+ $curl->setopt(CURLOPT_RETURNTRANSFER,-1);
+ $curl->setopt(CURLOPT_HEADER,0);
+ $curl->setopt(CURLOPT_USERPWD,$login);
+ $curl->setopt(CURLOPT_PUT,-1);
+ $curl->setopt(CURLOPT_INFILE,$TxFile);
+ $curl->setopt(CURLOPT_INFILESIZE, -s $self->{file1});
+ $curl->setopt(CURLOPT_FILE, $RxFile);
+
+ $curl->perform();
+ my $http_code = $curl->getinfo(CURLINFO_HTTP_CODE);
+ my $err = $curl->errbuf;
+ $curl->close();
+ close $TxFile;
+ close $RxFile;
+
+ open(my $ResponseFile, "<", $self->{file2});
+ my $response = int(<$ResponseFile>);
+ close $ResponseFile;
+
+ print "Code $http_code\n" if($http_code != 200);
+
+ return($response, $http_code);
+}
+
+1;
+
+
+=head1 NAME
+
+Geo::OSM::Upload
+
+=head1 COPYRIGHT
+
+Copyright 2006, Jörg Ostertag
+
+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, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+=head1 AUTHOR
+
+Jörg Ostertag (planet-count-for-openstreetmap@ostertag.name)
+
+=head1 SEE ALSO
+
+http://www.openstreetmap.org/
+
+=cut
+
diff --git a/navit/script/osm/Geo/OSM/Write.pm b/navit/script/osm/Geo/OSM/Write.pm
new file mode 100644
index 000000000..463c2d0cd
--- /dev/null
+++ b/navit/script/osm/Geo/OSM/Write.pm
@@ -0,0 +1,170 @@
+##################################################################
+package Geo::OSM::Write;
+##################################################################
+
+use Exporter;
+@ISA = qw( Exporter );
+use vars qw(@ISA @EXPORT @EXPORT_OK %EXPORT_TAGS $VERSION);
+@EXPORT = qw( write_osm_file );
+
+use strict;
+use warnings;
+
+use Math::Trig;
+use Data::Dumper;
+
+use Geo::Geometry;
+use Utils::Debug;
+use Utils::File;
+use Utils::Math;
+
+
+# ------------------------------------------------------------------
+sub tags2osm($){
+ my $obj = shift;
+
+ my $erg = "";
+ for my $k ( keys %{$obj->{tag}} ) {
+ my $v = $obj->{tag}{$k};
+ if ( ! defined $v ) {
+ warn "incomplete Object: ".Dumper($obj);
+ }
+ #next unless defined $v;
+
+ # character escaping as per http://www.w3.org/TR/REC-xml/
+ $v =~ s/&/&amp;/g;
+ $v =~ s/\'/&apos;/g;
+ $v =~ s/</&lt;/g;
+ $v =~ s/>/&gt;/g;
+ $v =~ s/\"/&quot;/g;
+
+ $erg .= " <tag k=\'$k\' v=\'$v\' />\n";
+ }
+ return $erg;
+}
+
+sub write_osm_file($$) { # Write an osm File
+ my $filename = shift;
+ my $osm = shift;
+
+ my $osm_nodes = $osm->{nodes};
+ my $osm_ways = $osm->{ways};
+
+ $osm->{tool} ||= "OSM-Tool";
+ my $count_nodes = 0;
+ my $count_ways = 0;
+
+ my $generate_ways=$main::generate_ways;
+
+ my $start_time=time();
+
+ printf STDERR ("Writing OSM File $filename\n") if $VERBOSE >1 || $DEBUG>1;
+
+ my $fh;
+ if ( $filename eq "-" ) {
+ $fh = IO::File->new('>&STDOUT');
+ $fh or die("cannot open STDOUT: $!");
+ } else {
+ $fh = IO::File->new(">$filename");
+ }
+ $fh->binmode(':utf8');
+
+ print $fh "<?xml version='1.0' encoding='UTF-8'?>\n";
+ print $fh "<osm version=\'0.5\' generator=\'".$osm->{tool}."\'>\n";
+ if ( defined ( $osm->{bounds} ) ) {
+ my $bounds = $osm->{bounds};
+ my $bounds_sting = "$bounds->{lat_min},$bounds->{lon_min},$bounds->{lat_max},$bounds->{lon_max}";
+ # -90,-180,90,180
+ print $fh " <bound box=\"$bounds_sting\" origin=\"OSM-perl-writer\" />\n";
+
+ }
+
+ # --- Nodes
+ for my $node_id ( sort keys %{$osm_nodes} ) {
+ next unless $node_id;
+ my $node = $osm_nodes->{$node_id};
+ my $lat = $node->{lat};
+ my $lon = $node->{lon};
+ unless ( defined($lat) && defined($lon)){
+ printf STDERR "Node '$node_id' not complete\n";
+ next;
+ }
+ print $fh " <node id=\'$node_id\' ";
+ print $fh " timestamp=\'".$node->{timestamp}."\' "
+ if defined $node->{timestamp};
+ print $fh " changeset=\'".$node->{changeset}."\' "
+ if defined $node->{changeset};
+ print $fh " lat=\'$lat\' ";
+ print $fh " lon=\'$lon\' ";
+ print $fh ">\n";
+ print $fh tags2osm($node);
+ print $fh " </node>\n";
+ $count_nodes++;
+ }
+
+ # --- Ways
+ for my $way_id ( sort keys %{$osm_ways} ) {
+ next unless $way_id;
+ my $way = $osm_ways->{$way_id};
+ next unless scalar( @{$way->{nd}} )>1;
+
+ print $fh " <way id=\'$way_id\'";
+ print $fh " timestamp=\'".$way->{timestamp}."\'"
+ if defined $way->{timestamp};
+ print $fh ">";
+
+ for my $way_nd ( @{$way->{nd}} ) {
+ next unless $way_nd;
+ print $fh " <nd ref=\'$way_nd\' />\n";
+ }
+ print $fh tags2osm($way);
+ print $fh " </way>\n";
+ $count_ways++;
+
+ }
+
+ print $fh "</osm>\n";
+ $fh->close();
+
+ if ( $VERBOSE || $DEBUG ) {
+ printf STDERR "%-35s: ",$filename;
+ printf STDERR " Wrote OSM File ".
+ "($count_nodes Nodes, $count_ways Ways)";
+ print_time($start_time);
+ }
+
+}
+
+1;
+
+=head1 NAME
+
+Geo::OSM::Write
+
+=head1 COPYRIGHT
+
+Copyright 2006, Jörg Ostertag
+
+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, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+=head1 AUTHOR
+
+Jörg Ostertag (planet-count-for-openstreetmap@ostertag.name)
+
+=head1 SEE ALSO
+
+http://www.openstreetmap.org/
+
+=cut
diff --git a/navit/script/osm/osmtool.pl b/navit/script/osm/osmtool.pl
index 30a443fb6..10f50a8ed 100755
--- a/navit/script/osm/osmtool.pl
+++ b/navit/script/osm/osmtool.pl
@@ -1,5 +1,5 @@
#! /usr/bin/perl
-use Geo::OSM::APIClientV5;
+use Geo::OSM::APIClientV6;
use Data::Dumper;
sub print_error
@@ -42,10 +42,18 @@ sub cmd_delete
my($type,$id)=@_;
my($res);
$res=$api->get($type,$id);
+ if (!$api->create_changeset()) {
+ print_error();
+ return 1;
+ }
if (!$api->delete($res)) {
print_error();
return 1;
}
+ if (!$api->close_changeset()) {
+ print_error();
+ return 1;
+ }
return 0;
}
@@ -88,10 +96,18 @@ sub cmd_reload
{
my($type,$id)=@_;
$res=$api->get($type,$id);
+ if (!$api->create_changeset()) {
+ print_error();
+ return 1;
+ }
if (!$api->modify($res)) {
print_error();
return 1;
}
+ if (!$api->close_changeset()) {
+ print_error();
+ return 1;
+ }
return 0;
}
@@ -122,5 +138,5 @@ while (substr($ARGV[0],0,2) eq '--') {
$attr{$key}=$value;
shift;
}
-$api=new Geo::OSM::APIClient(api=>'http://www.openstreetmap.org/api/0.5',%attr);
+$api=new Geo::OSM::APIClient(api=>'http://www.openstreetmap.org/api/0.6',%attr);
command(@ARGV);