From 7020a51ecc1ee714f9910016596bf036334e21a2 Mon Sep 17 00:00:00 2001 From: Dmitry Platonov Date: Fri, 30 Apr 2010 21:41:46 +0400 Subject: [PATCH] Import --- src/basic-osm-converter/import.sh | 15 ++ src/basic-osm-converter/import_osm.pl | 164 ++++++++++++++ src/basic-osm-converter/maketiles.pl | 149 ++++++++++++ src/basic-osm-converter/navigator_lib.pm | 14 ++ src/basic-osm-converter/osm.sql | 111 +++++++++ src/basic-osm-converter/spatial.sql | 16 ++ src/kothic.py | 277 +++++++++++++++++++++++ 7 files changed, 746 insertions(+) create mode 100755 src/basic-osm-converter/import.sh create mode 100755 src/basic-osm-converter/import_osm.pl create mode 100755 src/basic-osm-converter/maketiles.pl create mode 100644 src/basic-osm-converter/navigator_lib.pm create mode 100644 src/basic-osm-converter/osm.sql create mode 100644 src/basic-osm-converter/spatial.sql create mode 100755 src/kothic.py diff --git a/src/basic-osm-converter/import.sh b/src/basic-osm-converter/import.sh new file mode 100755 index 0000000..862d0fa --- /dev/null +++ b/src/basic-osm-converter/import.sh @@ -0,0 +1,15 @@ +#! /bin/bash + +rm -f $1 +cat osm.sql | grep -vi "CREATE INDEX" | sqlite3 $1 +cat spatial.sql | sqlite3 $1 +echo "Importing $2 into $1" +./import_osm.pl $1 < $2 +echo "Creating indexes" +cat osm.sql | grep -i "CREATE INDEX" | sqlite3 $1 +echo 'Analyzing' +sqlite3 $1 'analyze' +echo 'Creating spatial index' +sqlite3 $1 'insert into way_index (id,minLat,maxLat,minLon,maxLon) select way_id,min(lat),max(lat),min(lon),max(lon) from way_node,node where way_node.node_id=node.id group by way_id' +echo 'Creating way coords' +sqlite3 $1 'insert into way_coord_text (id,lat,lon) select way_id,group_concat(lat),group_concat(lon) from (select way_id,lat,lon from way_node,node where node_id=id order by way_id,node_number) group by way_id' diff --git a/src/basic-osm-converter/import_osm.pl b/src/basic-osm-converter/import_osm.pl new file mode 100755 index 0000000..cc8eab9 --- /dev/null +++ b/src/basic-osm-converter/import_osm.pl @@ -0,0 +1,164 @@ +#! /usr/bin/perl -w + +use XML::Parser; +use DBI; +use strict; + +my $dbname = shift; +my $count = 0; + +my $parser = new XML::Parser(ErrorContext => 2); + +$parser->setHandlers(Char => \&char_handler, + Start => \&start_handler, + End => \&end_handler); +# Default => \&default_handler); + +my $file = shift; + +my $dbargs = {AutoCommit => 0, + PrintError => 1, + }; + +my $dbh = DBI->connect("dbi:SQLite:dbname=$dbname","","",$dbargs); +$dbh->do("PRAGMA synchronous = OFF"); +if ($dbh->err()) { die "$DBI::errstr\n"; } + +print "*\n"; + +if(defined $file and -f $file){ + $parser->parsefile($file); +} +else{ + $parser->parse(\*STDIN); +} + +$dbh->commit(); +$dbh->disconnect(); + +################ +## End of main +################ + +my $id; +my %tags; +my %node_attrs; +my $node_count = 0; +my $node_id; +my $relation_count = 0; +my $sequence; +my $node_count; +my $way_count; +my $relation_count; +my $way_id; +my $relation_id; +my $node_number; + +sub start_handler +{ + my( $parseinst, $element, %attrs ) = @_; + SWITCH: { + if ($element eq "node") { + $dbh->do("insert into node (id, lat, lon) values ($attrs{id},$attrs{lat},$attrs{lon})"); + if ($dbh->err()) { die "$DBI::errstr\n"; } + $node_count += 1; + if($node_count % 1000 == 0){ + print "nodes: ",$node_count,"\n"; + } + $node_id = $attrs{id}; + if($node_count % 100000 == 0){ + $dbh->commit(); + if ($dbh->err()) { die "$DBI::errstr\n"; } +# $dbh->begin(); +# if ($dbh->err()) { die "$DBI::errstr\n"; } + } + + last SWITCH; + } + if ($element eq "way") { + $dbh->do("insert into way (id) values ($attrs{id})"); + if ($dbh->err()) { die "$DBI::errstr\n"; } + $way_id = $attrs{id}; + $node_number = 0; + $way_count += 1; + if($way_count % 1000 == 0){ + print "ways: ",$way_count,"\n"; + } + last SWITCH; + } + if ($element eq "relation") { + $dbh->do("insert into relation (id) values ($attrs{id})"); + if ($dbh->err()) { die "$DBI::errstr\n"; } + $relation_id = $attrs{id}; + $relation_count += 1; + $sequence = 0; + if($relation_count % 1000 == 0){ + print "relations: ",$relation_count,"\n"; + } + last SWITCH; + } + if ($element eq "nd" and defined $way_id) { + $dbh->do("insert into way_node (way_id,node_id,node_number) values ($way_id,$attrs{ref},$node_number)"); + if ($dbh->err()) { die "$DBI::errstr\n"; } + $node_number += 1; + last SWITCH; + } + if ($element eq "tag" ) { + if(defined $way_id){ + my $q = "insert into way_tag (id,key,value) values ($way_id,".$dbh->quote($attrs{k}).",".$dbh->quote($attrs{v}).")"; + $dbh->do("$q"); + if ($dbh->err()) { print $q,"\n"; die "$DBI::errstr\n"; } + } + elsif(defined $node_id){ + my $q = "insert into node_tag (id,key,value) values ($node_id,".$dbh->quote($attrs{k}).",".$dbh->quote($attrs{v}).")"; + $dbh->do("$q"); + if ($dbh->err()) { print $q,"\n"; die "$DBI::errstr\n"; } + } + elsif(defined $relation_id){ + my $q = "insert into relation_tag (id,key,value) values ($relation_id,".$dbh->quote($attrs{k}).",".$dbh->quote($attrs{v}).")"; + $dbh->do("$q"); + if ($dbh->err()) { print $q,"\n"; die "$DBI::errstr\n"; } + } + last SWITCH; + } + if ($element eq "member" ) { + my $q; + if($attrs{type} eq 'node'){ + $q = "insert into relation_member_node (id,node_id,role,sequence_number) values ($relation_id,".$dbh->quote($attrs{ref}).",".$dbh->quote($attrs{role}).",$sequence)"; + } + if($attrs{type} eq 'way'){ + $q = "insert into relation_member_way (id,way_id,role,sequence_number) values ($relation_id,".$dbh->quote($attrs{ref}).",".$dbh->quote($attrs{role}).",$sequence)"; + } + if($attrs{type} eq 'relation'){ + $q = "insert into relation_member_relation (id,relation_id,role,sequence_number) values ($relation_id,".$dbh->quote($attrs{ref}).",".$dbh->quote($attrs{role}).",$sequence)"; + } + $sequence += 1; + if(defined $q){ + $dbh->do("$q"); + if ($dbh->err()) { print $q,"\n"; die "$DBI::errstr\n"; } + } + } + + } + return; +} + +sub end_handler +{ + my( $parseinst, $element ) = @_; + if($element eq 'way'){ + undef $way_id; + }elsif($element eq 'node'){ + undef $node_id; + }elsif($element eq 'relation'){ + undef $relation_id; + } + return; +} + +sub char_handler +{ + # This is just here to reduce the noise seen by + # the default handler + return; +} # End of char_handler diff --git a/src/basic-osm-converter/maketiles.pl b/src/basic-osm-converter/maketiles.pl new file mode 100755 index 0000000..88ec4a4 --- /dev/null +++ b/src/basic-osm-converter/maketiles.pl @@ -0,0 +1,149 @@ +#!/usr/bin/perl -w +use DBI; +use Time::HiRes qw(gettimeofday tv_interval); +use strict; +use File::Spec; +use navigator_lib; + +my $dbname = $ARGV[0] or die "Usage: ./maketiles.pl database.db"; +my $dbargs = {AutoCommit => 0, + PrintError => 1, +}; + + +my $latmin; +my $latmax; +my $lonmin; +my $lonmax; + +my $latcenter = 55.75; +my $loncenter = 37.62; +#lat=55.7543&lon=37.6211 +#my ( $width, $height ) = ( 240, 320 ); +#my ( $width, $height ) = ( 640,480 ); +#my $zoom = $width/0.02; + +my $dbh = DBI->connect("dbi:SQLite:dbname=$dbname","","",$dbargs); +#$dbh->do("PRAGMA synchronous = OFF"); +if ($dbh->err()) { die "$DBI::errstr\n"; } + +my $i; +my $j; +my $n = 50; +my $tile_step = 0.01; +for($i=-$n;$i<=$n;$i+=1){ +for($j=-$n;$j<=$n;$j+=1){ + $latmin = $latcenter + $i*$tile_step; + $latmax = $latmin + $tile_step; + $lonmin = $loncenter + $j*$tile_step; + $lonmax = $lonmin + $tile_step; + my $filename = latlon_to_filename($latmin, $lonmin); + my ($vol, $dir, $fname) = File::Spec->splitpath($filename); +# print $vol,$dir," xxx\n"; + my $p = '.'; + foreach my $cd (File::Spec->splitdir($dir)){ + $p = File::Spec->catdir($p, $cd); + mkdir $p; + } + open my $file, '>', $filename or die "create map file: $!"; + my $q = 'select way_coord_text.id,lat,lon,key,value from way_index,way_tag,way_coord_text where maxLat >= '.$latmin.' and minLat <= '.$latmax.' and maxLon >= '.$lonmin.' and minLon <= '.$lonmax.' and way_index.id=way_coord_text.id and way_coord_text.id = way_tag.id and (key like \'highway\' or key = \'natural\' or key = \'landuse\'or key=\'building\' or key=\'waterway\' or key=\'leisure\' )'; + print $q,"\n"; + my $t0 = [gettimeofday]; + my $res = $dbh->selectall_arrayref($q); + my $el1 = tv_interval ( $t0, [gettimeofday]); + if ($dbh->err()) { die "$DBI::errstr\n"; } + my $r; + my $way_count=0; + my $node_count=0; + foreach $r (@$res){ + my @wlat = split(',', $r->[1]); + my @wlon = split(',', $r->[2]); + my @coord; + $way_count += 1; + while(@wlat){ + my ($sx, $sy) = ((shift @wlat), (shift @wlon)); + push @coord, $sx, $sy; + $node_count += 1; + } + my $k = $r->[3]; + my $v = $r->[4]; + if($k eq 'highway' and ($v eq 'primary' or $v eq 'motorway' or $v eq 'trunk')){ + line1($file, $r->[0], 1, @coord); + } + elsif($k eq 'highway' and ($v eq 'motorway_link' or $v eq 'trunk_link' or $v eq 'primary_link')){ + line1($file, $r->[0], 2, @coord); + } + elsif($k eq 'highway' and $v eq 'secondary'){ + line1($file, $r->[0], 3, @coord); + } + elsif($k eq 'highway' and ($v eq 'tertiary' or $v eq 'residential' or $v eq 'living_street')){ + line1($file, $r->[0], 4, @coord); + } + elsif($k eq 'highway' and ($v eq 'service' or $v eq 'unclassified')){ + line1($file, $r->[0], 5, @coord); + } + elsif($k eq 'building' and $v eq 'yes'){ + poly($file, $r->[0], 6, @coord); + } + elsif($k eq 'highway' and $v eq 'footway' or $v eq 'path' or $v eq 'track'){ + } + elsif(($k eq 'natural' and $v eq 'wood') or ($k eq 'landuse' and $v eq 'forest') or ($k eq 'leisure' and $v eq 'park')){ + poly($file, $r->[0], 7, @coord); + } + elsif($k eq 'highway'){ + line1($file, $r->[0], 8, @coord); + } + elsif($k eq 'landuse' and $v eq 'industrial'){ + poly($file, $r->[0], 9, @coord); + } + elsif(($k eq 'natural' and $v eq 'water') or ($k eq 'waterway' and $v eq 'riverbank')){ + poly($file, $r->[0], 10, @coord); + } + elsif($k eq 'landuse' and $v eq 'residential'){ + poly($file, $r->[0], 11, @coord); + } + elsif(($k eq 'waterway' and $v eq 'river')){ + line1($file, $r->[0], 12, @coord); + } + elsif(($k eq 'waterway' and $v eq 'stream')){ + line1($file, $r->[0], 13, @coord); + } + elsif(($k eq 'landuse' and $v eq 'allotments')){ + poly($file, $r->[0], 14, @coord); + } + elsif(($k eq 'landuse')){ + poly($file, $r->[0], 15, @coord); + } + } + my $el2 = tv_interval ( $t0, [gettimeofday]); + print "Ways: $way_count nodes: $node_count\n"; + print "SQL: $el1 draw: ",$el2-$el1,"\n"; + close $file; +} +} + +sub line1{ + my $a; + my $f = shift; + my $id = shift; + my $t = shift; + print $f "L $id $t"; + foreach $a (@_){ + print $f " $a"; + } + print $f "\n"; + return 0; +} + +sub poly{ + my $a; + my $f = shift; + my $id = shift; + my $t = shift; + print $f "P $id $t"; + foreach $a (@_){ + print $f " $a"; + } + print $f "\n"; + return 0; +} diff --git a/src/basic-osm-converter/navigator_lib.pm b/src/basic-osm-converter/navigator_lib.pm new file mode 100644 index 0000000..c45cf3a --- /dev/null +++ b/src/basic-osm-converter/navigator_lib.pm @@ -0,0 +1,14 @@ +package navigator_lib; +use Exporter; +use base Exporter; + +@EXPORT = qw(latlon_to_filename); + +sub latlon_to_filename{ + my ($i, $j) = @_; + $i = int($i*100+0.5); + $j = int($j*100+0.5); + return "data/".int($i/100).'/'.int($j/100).'/'.($i%100).'/'.($j%100).'.map'; +} + +1; diff --git a/src/basic-osm-converter/osm.sql b/src/basic-osm-converter/osm.sql new file mode 100644 index 0000000..4fe79c4 --- /dev/null +++ b/src/basic-osm-converter/osm.sql @@ -0,0 +1,111 @@ +create table node ( + id INTEGER PRIMARY KEY, + lat FLOAT, + lon FLOAT +); + +create table way( + id INTEGER PRIMARY KEY +); + +create table way_node ( + node_number INTEGER, + way_id INTEGER, + node_id INTEGER, + FOREIGN KEY(way_id) REFERENCES way(id), + FOREIGN KEY(node_id) REFERENCES node(id) +); + +CREATE INDEX way_node_way_id_idx on way_node (way_id); +CREATE INDEX way_node_node_id_idx on way_node (node_id); + +create table way_tag( + id INTEGER, + key VARCHAR(20), + value VARCHAR(20), + FOREIGN KEY(id) REFERENCES way(id) +); + +CREATE INDEX way_tag_id_idx on way_tag (id); +CREATE INDEX way_tag_key_idx on way_tag (key); +CREATE INDEX way_tag_value_idx on way_tag (value); +CREATE INDEX way_tag_key_value_idx on way_tag (key,value); + +create table node_tag( + id INTEGER, + key VARCHAR(20), + value VARCHAR(20), + FOREIGN KEY(id) REFERENCES node(id) +); + +CREATE INDEX node_tag_id_idx on node_tag (id); +CREATE INDEX node_tag_key_idx on node_tag (key); +CREATE INDEX node_tag_value_idx on node_tag (value); +CREATE INDEX node_tag_key_value_idx on node_tag (key,value); + +create table relation( + id INTEGER PRIMARY KEY +); + +create table relation_tag( + id INTEGER, + key VARCHAR(20), + value VARCHAR(20), + FOREIGN KEY(id) REFERENCES relation(id) +); + +CREATE INDEX relation_tag_id_idx on relation_tag (id); +CREATE INDEX relation_tag_key_idx on relation_tag (key); +CREATE INDEX relation_tag_value_idx on relation_tag (value); +CREATE INDEX relation_tag_key_value_idx on relation_tag (key,value); + +create table relation_member_node( + id INTEGER, + node_id INTEGER, + sequence_number INTEGER NOT NULL, + role VARCHAR(20) NOT NULL, + FOREIGN KEY(id) REFERENCES relation(id) + FOREIGN KEY(node_id) REFERENCES node(id) +); + +CREATE INDEX relation_member_node_id_idx on relation_member_node (id); +CREATE INDEX relation_member_node_node_id_idx on relation_member_node (node_id); +CREATE INDEX relation_member_node_role_idx on relation_member_node (role); + +create table relation_member_way( + id INTEGER, + way_id INTEGER, + sequence_number INTEGER NOT NULL, + role VARCHAR(20) NOT NULL, + FOREIGN KEY(id) REFERENCES relation(id) + FOREIGN KEY(way_id) REFERENCES way(id) +); + +CREATE INDEX relation_member_way_id_idx on relation_member_way (id); +CREATE INDEX relation_member_way_way_id_idx on relation_member_way (way_id); +CREATE INDEX relation_member_way_role_idx on relation_member_way (role); + +create table relation_member_relation( + id INTEGER, + relation_id INTEGER, + sequence_number INTEGER NOT NULL, + role VARCHAR(20) NOT NULL, + FOREIGN KEY(id) REFERENCES relation(id) + FOREIGN KEY(relation_id) REFERENCES relation(id) +); + +CREATE INDEX relation_member_relation_id_idx on relation_member_relation (id); +CREATE INDEX relation_member_relation_relation_id_idx on relation_member_relation (relation_id); +CREATE INDEX relation_member_relation_role_idx on relation_member_relation (role); + +-- CREATE VIEW pt_route AS SELECT id,value AS type FROM relation_tag WHERE key = 'route' AND value IN ('bus', 'trolleybus', 'tram'); +create view pt_route as select id,value as type from relation_tag where key = 'route' and value in ('bus', 'trolleybus', 'tram') and id in (select id from relation_tag where key = 'type' and value = 'route'); +-- create view pt_route_ref as select pt_route.id as id, pt_route.type as type,value as ref from pt_route,relation_tag where pt_route.id = relation_tag.id and key='ref'; +create view pt_route_ref as select pt_route.id as id, pt_route.type as type,value as ref from pt_route,relation_tag where relation_tag.id in (select id from pt_route) and pt_route.id = relation_tag.id and key='ref'; +-- create view pt_way as select distinct way_id as id,type,ref from relation_member_way,pt_route_ref where relation_member_way.id = pt_route_ref.id; +create view pt_way_ref as select distinct way_id as id,type,ref from pt_route_ref,relation_member_way where relation_member_way.id = pt_route_ref.id; +create view pt_way_id as select distinct way_id as id from pt_route_ref,relation_member_way where relation_member_way.id = pt_route_ref.id; +--create view pt_way_node as select way_id,node_id from way_node where way_id in (select id from pt_way_id); +create view pt_way_node as select way_id,node_id,node_number from way_node where way_id in (select id from pt_way_id); +create view pt_stop as select distinct id,node_id from relation_member_node where id in (select id from pt_route) and role in ('forward:stop','backward:stop','stop'); +create view pt_stop_ref as select distinct node_id as id,type,ref from pt_route_ref,relation_member_node where relation_member_node.id = pt_route_ref.id; diff --git a/src/basic-osm-converter/spatial.sql b/src/basic-osm-converter/spatial.sql new file mode 100644 index 0000000..f9e5920 --- /dev/null +++ b/src/basic-osm-converter/spatial.sql @@ -0,0 +1,16 @@ +CREATE VIRTUAL TABLE way_index USING rtree( + id, -- Integer primary key + minLat, maxLat, -- Minimum and maximum X coordinate + minLon, maxLon -- Minimum and maximum Y coordinate + ); + +CREATE TABLE way_coord( + id INTEGER PRIMARY KEY, + coord BLOB +); + +CREATE TABLE way_coord_text( + id INTEGER PRIMARY KEY, + lat TEXT, + lon TEXT +); diff --git a/src/kothic.py b/src/kothic.py new file mode 100755 index 0000000..c65819c --- /dev/null +++ b/src/kothic.py @@ -0,0 +1,277 @@ +#!/usr/bin/env python +#use Cairo; +#import cairo +#use Gtk2 '-init'; +import pygtk +pygtk.require('2.0') +import gtk +import cairo +import math +import string +import threading +import time +import Queue + +#use Glib qw(TRUE FALSE); +#use Time::HiRes qw(gettimeofday tv_interval); +#use strict; +#use POSIX qw(ceil floor); +#use style qw(@style); +#use navigator_lib; + +#my $dbname = "moscow.db"; +#my $dbargs = {AutoCommit => 0, +# PrintError => 1, +#}; +# + +#my $latmin; +#my $latmax; +#my $lonmin; +#my $lonmax; + +#my $latcenter = 55.6304; +#my $loncenter = 37.49305; + +class Renderer(threading.Thread): + def __init__(self, comm): + self.comm = comm + threading.Thread.__init__(self) + def run(self): + print ("Thread started") + self.tc = {} + while(True): + while(True): + request = self.comm[0].get() + if(self.comm[0].empty): + break + print (" got request:", request) + res = RasterTile(request[2][0], request[2][1]) + res.update_surface(request[0][0], request[0][1], request[1], self.tc, request[3]) + print (" render complete") + comm[1].put(res) + +class Navigator: + def __init__(self, comm): + self.comm = comm + self.lat_c = 55.6304 + self.lon_c = 37.49305 + self.width, self.height = 640, 480 + self.zoom = self.width/0.02; + self.window = gtk.Window(gtk.WINDOW_TOPLEVEL) + self.dx = 0 + self.dy = 0 + self.drag = False + self.tilecache = {} + self.border = 200 + self.rastertile = None + self.f = True + undef = None + self.style = [ +[None, None, None, 0], +[undef, [6.0, [0,0,0]], [4.0, [1, 1, .7]], 1], +[undef, [4.5, [0,0,0]], [2.5, [1, 1, .7]], 2], +[undef, [3.5, [0,0,0]], [2.5, [1, 1, .7]], 3], +[undef, [2.8, [0,0,0]], [2.0, [1, 1, 1]], 4], +[undef, undef, [1.0, [1, 1, 1]], 5], +[undef, [0, [0.7, 0.4, 0.4]], undef, 6], +[[1, [0.30, 0.5, 0.30]], undef, undef, 7], +[undef, undef, [2, [1, 0.3, 0.3]], 8], +[[0, [0.7, 0.6, 0.6]], undef, undef, 9], +[[0, [0.4, 0.4, 1.0]], undef, undef, 10], +[[0, [0.6, 0.6, 0.6]], undef, undef, 11], +[undef, [3.5, [0.4, 0.4, 1.0]], undef, 12], +[undef, [2, [0.4, 0.4, 1.0]], undef, 13], +[[0, [0.72, 0.51, 0.32]], undef, undef, 14], +[[0, [1, 0.0, 0.0]], undef, undef, 0] #unknown landuse +] + da = gtk.DrawingArea() + da.add_events(gtk.gdk.BUTTON1_MOTION_MASK) + da.add_events(gtk.gdk.POINTER_MOTION_MASK) + da.add_events(gtk.gdk.BUTTON_PRESS_MASK) + da.add_events(gtk.gdk.BUTTON_RELEASE_MASK) +# self.window.add_events(gtk.gdk.BUTTON1_MOTION_MASK) + da.connect("expose_event",self.expose_ev) + da.connect("motion_notify_event",self.motion_ev) + da.connect("button_press_event",self.press_ev) + da.connect("button_release_event",self.release_ev) + self.da = da +# self.surface = cairo.ImageSurfaceicreate(gtk.RGB24, self.width, self.height) + self.window.set_size_request(self.width, self.height) + self.window.add(da) + self.window.connect("delete_event", self.delete_ev) + def motion_ev(self, widget, event): +# print("Motion") + if self.drag: + self.dx = event.x - self.drag_x + self.dy = event.y - self.drag_y + if((abs(self.dx) > 100 or abs(self.dy) > 100) and self.f): + self.comm[0].put((self.rastertile.screen2latlon(self.rastertile.w/2 - self.dx, self.rastertile.h/2 - self.dy), self.zoom, (self.width + self.border*2, self.height + self.border*2), self.style)) + self.request_d = (self.dx, self.dy) + self.f = False + if not self.comm[1].empty(): + self.rastertile = self.comm[1].get() + self.f = True + self.drag_x += self.request_d[0] + self.drag_y += self.request_d[1] + self.dx = event.x - self.drag_x + self.dy = event.y - self.drag_y + widget.queue_draw() + def delete_ev(self, widget, event): + gtk.main_quit() + def press_ev(self, widget, event): + print("Start drag") + self.drag = True + self.drag_x = event.x + self.drag_y = event.y + def release_ev(self, widget, event): + print("Stop drag") + self.drag = False +# print("ll:", self.latcenter, self.loncenter) + print("LL before: ",self.lat_c, self.lon_c) + print("dd: ",self.dx, self.dy) + self.lat_c, self.lon_c = self.rastertile.screen2latlon(self.rastertile.w/2 - self.dx, self.rastertile.h/2 - self.dy); + self.dx = self.dy = 0 + self.f = True + print("LL after: ",self.lat_c, self.lon_c) +# self.rastertile.update_surface( self.lat_c, self.lon_c, self.zoom, self.tilecache, self.style) + self.comm[0].put(((self.lat_c, self.lon_c), self.zoom, (self.width + self.border*2, self.height + self.border*2), self.style)) + widget.queue_draw() + def expose_ev(self, widget, event): +# print("Expose") + if(widget.allocation.width != self.width): + print("Rrresize!") + self.width = widget.allocation.width + self.height = widget.allocation.height + self.rastertile = None + if self.rastertile is None: + self.rastertile = RasterTile(self.width + self.border*2, self.height + self.border*2) + self.rastertile.update_surface(self.lat_c, self.lon_c, self.zoom, self.tilecache, self.style) + cr = widget.window.cairo_create() + cr.set_source_surface(self.rastertile.surface, self.dx-self.border, self.dy - self.border) + cr.paint() +# cr. + + def main(self): + self.window.show_all() + gtk.main() + +def line(cr, c): + cr.move_to(c[0], c[1]) + for k in range(2, len(c), 2): + cr.line_to(c[k], c[k + 1]) + cr.stroke() + +def poly(cr, c): + cr.move_to(c[0], c[1]) + for k in range(2, len(c), 2): + cr.line_to(c[k], c[k + 1]) + cr.fill() + +def ways(t): +# return [y for x in t.itervalues() for y in x.itervalues()] + r = {} + for i in t.values(): + r.update(i) + return r.values() + +def load_tile(k): + print("loading tile: ", k) + f = open(key_to_filename(k)) + t = {} + while True: + str = f.readline() + if str is None or str == "": + break + str = str.rstrip("\n") + a = str.split(" ") + w = Way(a[0], int(a[1]), int(a[2]), map(lambda x: float(x), a[3:])) + t[w.id] = w + f.close() + return t + +class RasterTile: + def __init__(self, width, height): + self.w = width + self.h = height + self.surface = cairo.ImageSurface(cairo.FORMAT_RGB24, self.w, self.h) + self.x_offset = 0 + self.y_offset = 0 + self.lat_c = None + self.lon_c = None + self.zoom = None + def screen2latlon(self, x, y): + return -(y - self.h/2)/self.zoom + self.lat_c, (x - self.w/2)/(math.cos(self.lat_c*math.pi/180)*self.zoom) + self.lon_c + def latlon2screen(self, lat, lon, lcc): + return (lon - self.lon_c)*lcc*self.zoom + self.w/2, -(lat - self.lat_c)*self.zoom + self.h/2 + def update_surface(self, lat, lon, zoom, tilecache, style): + self.zoom = zoom + self.lat_c = lat + self.lon_c = lon + cr = cairo.Context(self.surface) + cr.rectangle(0, 0, self.w, self.h) + cr.set_source_rgb(0.7, 0.7, 0.7) + cr.fill() + latmin, lonmin = self.screen2latlon(0, self.h) + latmax, lonmax = self.screen2latlon(self.w, 0) + latkey_min = int(latmin*100) + latkey_max = int(latmax*100) + lonkey_min = int(lonmin*100) + lonkey_max = int(lonmax*100) + print(latmin, lonmin, latmax, lonmax) + print( latkey_min, latkey_max, lonkey_min, lonkey_max) +#FIXME: add time + active_tile = set([(i,j) for i in range(latkey_min, latkey_max+1) for j in range(lonkey_min, lonkey_max+1)]) + print(active_tile) + for k in tilecache.keys(): + if k not in active_tile: + del tilecache[k] + print("del tile:", k) + for k in active_tile: + if k not in tilecache: + tilecache[k] = load_tile(k) + #FIXME add time2 + ww = ways(tilecache) + print("ways: ", len(ww)) + + ww.sort(key=lambda x: style[x.style][3]) + lcc = math.cos(self.lat_c*math.pi/180) + for w in ww: + cs = [] + for k in range(0, len(w.coords), 2): + x, y = self.latlon2screen(w.coords[k], w.coords[k+1], lcc); + cs.append(x) + cs.append(y) + w.cs = cs + for passn in range(1, 4): + print("pass ",passn) + for w in ww: + stn = w.style + if stn < len(style) and style[stn] is not None and style[stn][passn-1] is not None: + st = style[w.style][passn-1] + cr.set_line_width(st[0]) + cr.set_source_rgb(st[1][0], st[1][1], st[1][2]) + if w.type == "L": + line(cr, w.cs) + elif w.type == "P": + poly(cr, w.cs) + +class Way: + def __init__(self, type, id, style, coords): + self.type = type + self.id = id + self.coords = coords + self.style = style + self.cs = None + +def key_to_filename(k): + return "data/" + str(k[0]//100) + "/" + str(k[1]//100) + "/" + str(k[0]%100) + "/" + str(k[1]%100) + ".map" + +if __name__ == "__main__": + comm = (Queue.Queue(), Queue.Queue()) + gtk.gdk.threads_init() + nav = Navigator(comm) + r = Renderer(comm) + r.daemon = True + r.start() + nav.main()