Use quadtiling for the node tables.

This commit is contained in:
Tom Hughes 2007-09-21 13:43:43 +00:00
parent 5cd05017a3
commit df31fe13a5
4 changed files with 166 additions and 107 deletions

View file

@ -228,21 +228,19 @@ EOF
" AND node_a=current_nodes.id "+
" AND current_ways.id=current_way_segments.id "+
" AND current_ways.visible=1 "+
" AND (latitude BETWEEN "+ymin.to_s+" AND "+ymax.to_s+") "+
" AND (longitude BETWEEN "+xmin.to_s+" AND "+xmax.to_s+")")
" AND "+OSM.sql_for_area(ymin, xmin, ymax, xmax, "current_nodes."))
ways = waylist.collect {|a| a.wayid.to_i } # get an array of way id's
pointlist =ActiveRecord::Base.connection.select_all("SELECT current_nodes.id,latitude,longitude,current_nodes.tags "+
pointlist = ActiveRecord::Base.connection.select_all("SELECT current_nodes.id,current_nodes.latitude*0.0000001 AS lat,current_nodes.longitude*0.0000001 AS lng,current_nodes.tags "+
" FROM current_nodes "+
" LEFT OUTER JOIN current_segments cs1 ON cs1.node_a=current_nodes.id "+
" LEFT OUTER JOIN current_segments cs2 ON cs2.node_b=current_nodes.id "+
" WHERE (latitude BETWEEN "+ymin.to_s+" AND "+ymax.to_s+") "+
" AND (longitude BETWEEN "+xmin.to_s+" AND "+xmax.to_s+") "+
" WHERE "+OSM.sql_for_area(ymin, xmin, ymax, xmax, "current_nodes.")+
" AND cs1.id IS NULL AND cs2.id IS NULL "+
" AND current_nodes.visible=1")
points = pointlist.collect {|a| [a['id'],long2coord(a['longitude'].to_f,baselong,masterscale),lat2coord(a['latitude'].to_f,basey,masterscale),tag2array(a['tags'])] } # get a list of node ids and their tags
points = pointlist.collect {|a| [a['id'],long2coord(a['lng'].to_f,baselong,masterscale),lat2coord(a['lat'].to_f,basey,masterscale),tag2array(a['tags'])] } # get a list of node ids and their tags
return [ways,points]
end
@ -332,13 +330,16 @@ EOF
tagstr=array2tag(points[i][4])
tagstr=tagstr.gsub(/[\000-\037]/,"")
tagsql="'"+sqlescape(tagstr)+"'"
lat=(ys * 10000000).round
long=(xs * 10000000).round
tile=QuadTile.tile_for_point(ys, xs)
# compare node
if node<0
# new node - create
if renumberednodes[node.to_s].nil?
newnode=ActiveRecord::Base.connection.insert("INSERT INTO current_nodes ( latitude,longitude,timestamp,user_id,visible,tags) VALUES ( #{ys},#{xs},#{db_now},#{uid},1,#{tagsql})")
ActiveRecord::Base.connection.insert("INSERT INTO nodes (id,latitude,longitude,timestamp,user_id,visible,tags) VALUES (#{newnode},#{ys},#{xs},#{db_now},#{uid},1,#{tagsql})")
newnode=ActiveRecord::Base.connection.insert("INSERT INTO current_nodes ( latitude,longitude,timestamp,user_id,visible,tags,tile) VALUES ( #{lat},#{long},#{db_now},#{uid},1,#{tagsql},#{tile})")
ActiveRecord::Base.connection.insert("INSERT INTO nodes (id,latitude,longitude,timestamp,user_id,visible,tags,tile) VALUES (#{newnode},#{lat},#{long},#{db_now},#{uid},1,#{tagsql},#{tile})")
points[i][2]=newnode
renumberednodes[node.to_s]=newnode.to_s
else
@ -347,14 +348,13 @@ EOF
elsif xc.has_key?(node)
# old node from original way - update
if (xs!=xc[node] or (ys/0.0000001).round!=(yc[node]/0.0000001).round or tagstr!=tagc[node])
ActiveRecord::Base.connection.insert("INSERT INTO nodes (id,latitude,longitude,timestamp,user_id,visible,tags) VALUES (#{node},#{ys},#{xs},#{db_now},#{uid},1,#{tagsql})")
ActiveRecord::Base.connection.update("UPDATE current_nodes SET latitude=#{ys},longitude=#{xs},timestamp=#{db_now},user_id=#{uid},tags=#{tagsql},visible=1 WHERE id=#{node}")
if (xs!=xc[node] or ys!=yc[node] or tagstr!=tagc[node])
ActiveRecord::Base.connection.insert("INSERT INTO nodes (id,latitude,longitude,timestamp,user_id,visible,tags,tile) VALUES (#{node},#{lat},#{long},#{db_now},#{uid},1,#{tagsql},#{tile})")
ActiveRecord::Base.connection.update("UPDATE current_nodes SET latitude=#{lat},longitude=#{long},timestamp=#{db_now},user_id=#{uid},tags=#{tagsql},visible=1,tile=#{tile} WHERE id=#{node}")
end
else
# old node, created in another way and now added to this way
end
end
@ -412,8 +412,8 @@ EOF
createuniquenodes(db_uqs,db_uqn) # nodes which appear in this way but no other
sql=<<-EOF
INSERT INTO nodes (id,latitude,longitude,timestamp,user_id,visible)
SELECT DISTINCT cn.id,cn.latitude,cn.longitude,#{db_now},#{uid},0
INSERT INTO nodes (id,latitude,longitude,timestamp,user_id,visible,tile)
SELECT DISTINCT cn.id,cn.latitude,cn.longitude,#{db_now},#{uid},0,cn.tile
FROM current_nodes AS cn,#{db_uqn}
WHERE cn.id=node_id
EOF
@ -486,14 +486,17 @@ EOF
x=coord2long(x.to_f,masterscale,baselong)
y=coord2lat(y.to_f,masterscale,basey)
tagsql="'"+sqlescape(array2tag(tags))+"'"
lat=(y * 10000000).round
long=(x * 10000000).round
tile=QuadTile.tile_for_point(y, x)
if (id>0) then
ActiveRecord::Base.connection.insert("INSERT INTO nodes (id,latitude,longitude,timestamp,user_id,visible,tags) VALUES (#{id},#{y},#{x},#{db_now},#{uid},#{visible},#{tagsql})");
ActiveRecord::Base.connection.update("UPDATE current_nodes SET latitude=#{y},longitude=#{x},timestamp=#{db_now},user_id=#{uid},visible=#{visible},tags=#{tagsql} WHERE id=#{id}");
ActiveRecord::Base.connection.insert("INSERT INTO nodes (id,latitude,longitude,timestamp,user_id,visible,tags,tile) VALUES (#{id},#{lat},#{long},#{db_now},#{uid},#{visible},#{tagsql},#{tile})");
ActiveRecord::Base.connection.update("UPDATE current_nodes SET latitude=#{lat},longitude=#{long},timestamp=#{db_now},user_id=#{uid},visible=#{visible},tags=#{tagsql},tile=#{tile} WHERE id=#{id}");
newid=id
else
newid=ActiveRecord::Base.connection.insert("INSERT INTO current_nodes (latitude,longitude,timestamp,user_id,visible,tags) VALUES (#{y},#{x},#{db_now},#{uid},#{visible},#{tagsql})");
ActiveRecord::Base.connection.update("INSERT INTO nodes (id,latitude,longitude,timestamp,user_id,visible,tags) VALUES (#{newid},#{y},#{x},#{db_now},#{uid},#{visible},#{tagsql})");
newid=ActiveRecord::Base.connection.insert("INSERT INTO current_nodes (latitude,longitude,timestamp,user_id,visible,tags,tile) VALUES (#{lat},#{long},#{db_now},#{uid},#{visible},#{tagsql},#{tile})");
ActiveRecord::Base.connection.update("INSERT INTO nodes (id,latitude,longitude,timestamp,user_id,visible,tags,tile) VALUES (#{newid},#{lat},#{long},#{db_now},#{uid},#{visible},#{tagsql},#{tile})");
end
[id,newid]
end
@ -503,12 +506,12 @@ EOF
def getpoi(args)
id,baselong,basey,masterscale=args; id=id.to_i
poi=ActiveRecord::Base.connection.select_one("SELECT latitude,longitude,tags "+
poi=ActiveRecord::Base.connection.select_one("SELECT latitude*0.0000001 AS lat,longitude*0.0000001 AS lng,tags "+
"FROM current_nodes WHERE visible=1 AND id=#{id}")
if poi.nil? then return [nil,nil,nil,''] end
[id,
long2coord(poi['longitude'].to_f,baselong,masterscale),
lat2coord(poi['latitude'].to_f,basey,masterscale),
long2coord(poi['lng'].to_f,baselong,masterscale),
lat2coord(poi['lat'].to_f,basey,masterscale),
tag2array(poi['tags'])]
end
@ -551,8 +554,8 @@ EOF
createuniquenodes(db_uqs,db_uqn)
sql=<<-EOF
INSERT INTO nodes (id,latitude,longitude,timestamp,user_id,visible)
SELECT DISTINCT cn.id,cn.latitude,cn.longitude,#{db_now},#{uid},0
INSERT INTO nodes (id,latitude,longitude,timestamp,user_id,visible,tile)
SELECT DISTINCT cn.id,cn.latitude,cn.longitude,#{db_now},#{uid},0,cn.tile
FROM current_nodes AS cn,#{db_uqn}
WHERE cn.id=node_id
EOF
@ -601,8 +604,8 @@ def makeway(args)
ys1=yc-0.001; ys2=yc+0.001
sql=<<-EOF
SELECT cn1.latitude AS lat1,cn1.longitude AS lon1,cn1.id AS id1,
cn2.latitude AS lat2,cn2.longitude AS lon2,cn2.id AS id2, cs.id AS segid
SELECT cn1.latitude*0.0000001 AS lat1,cn1.longitude*0.0000001 AS lon1,cn1.id AS id1,
cn2.latitude*0.0000001 AS lat2,cn2.longitude*0.0000001 AS lon2,cn2.id AS id2, cs.id AS segid
FROM current_nodes AS cn1,
current_nodes AS cn2,
current_segments AS cs
@ -667,8 +670,8 @@ def findconnect(id,nodesused,lookfor,toreverse,baselong,basey,masterscale)
# get all segments with 'id' as a point
# (to look for both node_a and node_b, UNION is faster than node_a=id OR node_b=id)!
sql=<<-EOF
SELECT cn1.latitude AS lat1,cn1.longitude AS lon1,cn1.id AS id1,
cn2.latitude AS lat2,cn2.longitude AS lon2,cn2.id AS id2, cs.id AS segid
SELECT cn1.latitude*0.0000001 AS lat1,cn1.longitude*0.0000001 AS lon1,cn1.id AS id1,
cn2.latitude*0.0000001 AS lat2,cn2.longitude*0.0000001 AS lon2,cn2.id AS id2, cs.id AS segid
FROM current_nodes AS cn1,
current_nodes AS cn2,
current_segments AS cs
@ -679,8 +682,8 @@ def findconnect(id,nodesused,lookfor,toreverse,baselong,basey,masterscale)
AND cn2.id=node_b AND cn2.visible=1
AND node_a=#{id}
UNION
SELECT cn1.latitude AS lat1,cn1.longitude AS lon1,cn1.id AS id1,
cn2.latitude AS lat2,cn2.longitude AS lon2,cn2.id AS id2, cs.id AS segid
SELECT cn1.latitude*0.0000001 AS lat1,cn1.longitude*0.0000001 AS lon1,cn1.id AS id1,
cn2.latitude*0.0000001 AS lat2,cn2.longitude*0.0000001 AS lon2,cn2.id AS id2, cs.id AS segid
FROM current_nodes AS cn1,
current_nodes AS cn2,
current_segments AS cs
@ -730,13 +733,13 @@ end
# Support functions for remote calls
def readwayquery(id)
ActiveRecord::Base.connection.select_all "SELECT n1.latitude AS lat1,n1.longitude AS long1,n1.id AS id1,n1.tags as tags1, "+
" n2.latitude AS lat2,n2.longitude AS long2,n2.id AS id2,n2.tags as tags2,segment_id "+
ActiveRecord::Base.connection.select_all "SELECT n1.latitude*0.0000001 AS lat1,n1.longitude*0.0000001 AS long1,n1.id AS id1,n1.tags as tags1, "+
" n2.latitude*0.0000001 AS lat2,n2.longitude*0.0000001 AS long2,n2.id AS id2,n2.tags as tags2,segment_id "+
" FROM current_way_segments,current_segments,current_nodes AS n1,current_nodes AS n2 "+
" WHERE current_way_segments.id=#{id} "+
" AND segment_id=current_segments.id "+
" AND current_segments.visible=1 "+
" AND n1.id=node_a and n2.id=node_b "+
" AND n1.id=node_a AND n2.id=node_b "+
" AND n1.visible=1 AND n2.visible=1 "+
" ORDER BY sequence_id"
end

View file

@ -137,7 +137,7 @@ class ApiController < ApplicationController
end
# get all the nodes
nodes = Node.find(:all, :conditions => ['latitude BETWEEN ? AND ? AND longitude BETWEEN ? AND ? AND visible = 1', min_lat, max_lat, min_lon, max_lon])
nodes = Node.find_by_area(min_lat, min_lon, max_lat, max_lon, :conditions => "visible = 1")
node_ids = nodes.collect {|node| node.id }

View file

@ -10,13 +10,41 @@ class Node < ActiveRecord::Base
has_many :old_nodes, :foreign_key => :id
belongs_to :user
before_save :update_tile
def self.find_by_area(minlat, minlon, maxlat, maxlon, options)
self.with_scope(:find => {:conditions => OSM.sql_for_area(minlat, minlon, maxlat, maxlon)}) do
return self.find(:all, options)
end
end
def update_tile
self.tile = QuadTile.tile_for_point(lat, lon)
end
def lat=(l)
self.latitude = (l * 10000000).round
end
def lon=(l)
self.longitude = (l * 10000000).round
end
def lat
return self.latitude.to_f / 10000000
end
def lon
return self.longitude.to_f / 10000000
end
def validate_position
errors.add_to_base("Node is not in the world") unless in_world?
end
def in_world?
return false if self.latitude < -90 or self.latitude > 90
return false if self.longitude < -180 or self.longitude > 180
return false if self.lat < -90 or self.lat > 90
return false if self.lon < -180 or self.lon > 180
return true
end
@ -29,8 +57,8 @@ class Node < ActiveRecord::Base
node = Node.new
doc.find('//osm/node').each do |pt|
node.latitude = pt['lat'].to_f
node.longitude = pt['lon'].to_f
node.lat = pt['lat'].to_f
node.lon = pt['lon'].to_f
return nil unless node.in_world?
@ -86,8 +114,8 @@ class Node < ActiveRecord::Base
def to_xml_node(user_display_name_cache = nil)
el1 = XML::Node.new 'node'
el1['id'] = self.id.to_s
el1['lat'] = self.latitude.to_s
el1['lon'] = self.longitude.to_s
el1['lat'] = self.lat.to_s
el1['lon'] = self.lon.to_s
user_display_name_cache = {} if user_display_name_cache.nil?

View file

@ -8,13 +8,41 @@ class OldNode < ActiveRecord::Base
belongs_to :user
before_save :update_tile
def self.find_by_area(minlat, minlon, maxlat, maxlon, options)
self.with_scope(:find => {:conditions => OSM.sql_for_area(minlat, minlon, maxlat, maxlon)}) do
return self.find(:all, options)
end
end
def update_tile
self.tile = QuadTile.tile_for_point(lat, lon)
end
def lat=(l)
self.latitude = (l * 10000000).round
end
def lon=(l)
self.longitude = (l * 10000000).round
end
def lat
return self.latitude.to_f / 10000000
end
def lon
return self.longitude.to_f / 10000000
end
def validate_position
errors.add_to_base("Node is not in the world") unless in_world?
end
def in_world?
return false if self.latitude < -90 or self.latitude > 90
return false if self.longitude < -180 or self.longitude > 180
return false if self.lat < -90 or self.lat > 90
return false if self.lon < -180 or self.lon > 180
return true
end
@ -33,8 +61,8 @@ class OldNode < ActiveRecord::Base
def to_xml_node
el1 = XML::Node.new 'node'
el1['id'] = self.id.to_s
el1['lat'] = self.latitude.to_s
el1['lon'] = self.longitude.to_s
el1['lat'] = self.lat.to_s
el1['lon'] = self.lon.to_s
el1['user'] = self.user.display_name if self.user.data_public?
Node.split_tags(el1, self.tags)
el1['visible'] = self.visible.to_s