Merge changes from trunk 7673:8632.
This commit is contained in:
commit
5f8ab9e924
62 changed files with 1456 additions and 373 deletions
|
@ -1,60 +0,0 @@
|
|||
class GeoRecord < ActiveRecord::Base
|
||||
before_save :update_tile
|
||||
|
||||
# This is a scaling factor for going between the lat and lon via the API
|
||||
# and the longitude and latitude that is stored in the database
|
||||
SCALE = 10000000
|
||||
|
||||
# Is this node within -90 <= latitude <= 90 and -180 <= longitude <= 180
|
||||
# * returns true/false
|
||||
def in_world?
|
||||
return false if self.lat < -90 or self.lat > 90
|
||||
return false if self.lon < -180 or self.lon > 180
|
||||
return true
|
||||
end
|
||||
|
||||
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 * SCALE).round
|
||||
end
|
||||
|
||||
def lon=(l)
|
||||
self.longitude = (l * SCALE).round
|
||||
end
|
||||
|
||||
# Return WGS84 latitude
|
||||
def lat
|
||||
return self.latitude.to_f / SCALE
|
||||
end
|
||||
|
||||
# Return WGS84 longitude
|
||||
def lon
|
||||
return self.longitude.to_f / SCALE
|
||||
end
|
||||
|
||||
# Potlatch projections
|
||||
def lon_potlatch(baselong,masterscale)
|
||||
(self.lon-baselong)*masterscale
|
||||
end
|
||||
|
||||
def lat_potlatch(basey,masterscale)
|
||||
-(lat2y(self.lat)-basey)*masterscale
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def lat2y(a)
|
||||
180/Math::PI * Math.log(Math.tan(Math::PI/4+a*(Math::PI/180)/2))
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
class Node < GeoRecord
|
||||
class Node < ActiveRecord::Base
|
||||
require 'xml/libxml'
|
||||
|
||||
include GeoRecord
|
||||
|
||||
set_table_name 'current_nodes'
|
||||
|
||||
validates_presence_of :user_id, :timestamp
|
||||
|
@ -8,21 +10,21 @@ class Node < GeoRecord
|
|||
validates_numericality_of :latitude, :longitude
|
||||
validate :validate_position
|
||||
|
||||
has_many :old_nodes, :foreign_key => :id
|
||||
has_many :way_nodes
|
||||
has_many :node_tags, :foreign_key => :id
|
||||
belongs_to :user
|
||||
|
||||
|
||||
has_many :old_nodes, :foreign_key => :id
|
||||
|
||||
has_many :way_nodes
|
||||
has_many :ways, :through => :way_nodes
|
||||
|
||||
has_many :containing_relation_members, :class_name => "RelationMember", :as => :member
|
||||
has_many :containing_relations, :class_name => "Relation", :through => :containing_relation_members, :source => :relation, :extend => ObjectFinder
|
||||
|
||||
# Sanity check the latitude and longitude and add an error if it's broken
|
||||
def validate_position
|
||||
errors.add_to_base("Node is not in the world") unless in_world?
|
||||
end
|
||||
|
||||
def in_world?
|
||||
return false if self.lat < -90 or self.lat > 90
|
||||
return false if self.lon < -180 or self.lon > 180
|
||||
return true
|
||||
end
|
||||
|
||||
#
|
||||
# Search for nodes matching tags within bounding_box
|
||||
#
|
||||
|
@ -55,109 +57,64 @@ class Node < GeoRecord
|
|||
p = XML::Parser.new
|
||||
p.string = xml
|
||||
doc = p.parse
|
||||
|
||||
node = Node.new
|
||||
|
||||
doc.find('//osm/node').each do |pt|
|
||||
return Node.from_xml_node(pt, create)
|
||||
node.lat = pt['lat'].to_f
|
||||
node.lon = pt['lon'].to_f
|
||||
|
||||
return nil unless node.in_world?
|
||||
|
||||
unless create
|
||||
if pt['id'] != '0'
|
||||
node.id = pt['id'].to_i
|
||||
end
|
||||
end
|
||||
|
||||
node.visible = pt['visible'] and pt['visible'] == 'true'
|
||||
|
||||
if create
|
||||
node.timestamp = Time.now
|
||||
else
|
||||
if pt['timestamp']
|
||||
node.timestamp = Time.parse(pt['timestamp'])
|
||||
end
|
||||
end
|
||||
|
||||
tags = []
|
||||
|
||||
pt.find('tag').each do |tag|
|
||||
tags << [tag['k'],tag['v']]
|
||||
end
|
||||
|
||||
node.tags = Tags.join(tags)
|
||||
end
|
||||
rescue
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
def self.from_xml_node(pt, create=false)
|
||||
node = Node.new
|
||||
|
||||
node.version = pt['version']
|
||||
node.lat = pt['lat'].to_f
|
||||
node.lon = pt['lon'].to_f
|
||||
|
||||
return nil unless node.in_world?
|
||||
|
||||
unless create
|
||||
if pt['id'] != '0'
|
||||
node.id = pt['id'].to_i
|
||||
end
|
||||
end
|
||||
|
||||
node.visible = pt['visible'] and pt['visible'] == 'true'
|
||||
|
||||
if create
|
||||
node.timestamp = Time.now
|
||||
else
|
||||
if pt['timestamp']
|
||||
node.timestamp = Time.parse(pt['timestamp'])
|
||||
end
|
||||
end
|
||||
|
||||
tags = []
|
||||
|
||||
pt.find('tag').each do |tag|
|
||||
node.add_tag_key_val(tag['k'],tag['v'])
|
||||
node = nil
|
||||
end
|
||||
|
||||
return node
|
||||
end
|
||||
|
||||
# Save this node with the appropriate OldNode object to represent it's history.
|
||||
def save_with_history!
|
||||
t = Time.now
|
||||
Node.transaction do
|
||||
self.version += 1
|
||||
self.timestamp = t
|
||||
self.timestamp = Time.now
|
||||
self.save!
|
||||
|
||||
# Create a NodeTag
|
||||
tags = self.tags
|
||||
NodeTag.delete_all(['id = ?', self.id])
|
||||
tags.each do |k,v|
|
||||
tag = NodeTag.new
|
||||
tag.k = k
|
||||
tag.v = v
|
||||
tag.id = self.id
|
||||
tag.save!
|
||||
end
|
||||
|
||||
# Create an OldNode
|
||||
old_node = OldNode.from_node(self)
|
||||
old_node.timestamp = t
|
||||
old_node.save_with_dependencies!
|
||||
old_node.save!
|
||||
end
|
||||
end
|
||||
|
||||
def delete_with_history(user)
|
||||
if self.visible
|
||||
if WayNode.find(:first, :joins => "INNER JOIN current_ways ON current_ways.id = current_way_nodes.id", :conditions => [ "current_ways.visible = 1 AND current_way_nodes.node_id = ?", self.id ])
|
||||
raise OSM::APIPreconditionFailedError.new
|
||||
elsif RelationMember.find(:first, :joins => "INNER JOIN current_relations ON current_relations.id=current_relation_members.id", :conditions => [ "visible = 1 AND member_type='node' and member_id=?", self.id])
|
||||
raise OSM::APIPreconditionFailedError.new
|
||||
else
|
||||
self.user_id = user.id
|
||||
self.visible = 0
|
||||
save_with_history!
|
||||
end
|
||||
else
|
||||
raise OSM::APIAlreadyDeletedError.new
|
||||
end
|
||||
end
|
||||
|
||||
def update_from(new_node, user)
|
||||
if new_node.version != version
|
||||
raise OSM::APIVersionMismatchError.new(new_node.version, version)
|
||||
end
|
||||
|
||||
self.user_id = user.id
|
||||
self.latitude = new_node.latitude
|
||||
self.longitude = new_node.longitude
|
||||
self.tags = new_node.tags
|
||||
self.visible = true
|
||||
save_with_history!
|
||||
end
|
||||
|
||||
# Turn this Node in to a complete OSM XML object with <osm> wrapper
|
||||
def to_xml
|
||||
doc = OSM::API.new.get_xml_doc
|
||||
doc.root << to_xml_node()
|
||||
return doc
|
||||
end
|
||||
|
||||
# Turn this Node in to an XML Node without the <osm> wrapper.
|
||||
def to_xml_node(user_display_name_cache = nil)
|
||||
el1 = XML::Node.new 'node'
|
||||
el1['id'] = self.id.to_s
|
||||
|
@ -176,7 +133,7 @@ class Node < GeoRecord
|
|||
|
||||
el1['user'] = user_display_name_cache[self.user_id] unless user_display_name_cache[self.user_id].nil?
|
||||
|
||||
self.tags.each do |k,v|
|
||||
Tags.split(self.tags) do |k,v|
|
||||
el2 = XML::Node.new('tag')
|
||||
el2['k'] = k.to_s
|
||||
el2['v'] = v.to_s
|
||||
|
@ -185,33 +142,15 @@ class Node < GeoRecord
|
|||
|
||||
el1['visible'] = self.visible.to_s
|
||||
el1['timestamp'] = self.timestamp.xmlschema
|
||||
el1['version'] = self.version.to_s
|
||||
return el1
|
||||
end
|
||||
|
||||
# Return the node's tags as a Hash of keys and their values
|
||||
def tags_as_hash
|
||||
return tags
|
||||
end
|
||||
|
||||
def tags
|
||||
unless @tags
|
||||
@tags = {}
|
||||
self.node_tags.each do |tag|
|
||||
@tags[tag.k] = tag.v
|
||||
end
|
||||
hash = {}
|
||||
Tags.split(self.tags) do |k,v|
|
||||
hash[k] = v
|
||||
end
|
||||
@tags
|
||||
hash
|
||||
end
|
||||
|
||||
def tags=(t)
|
||||
@tags = t
|
||||
end
|
||||
|
||||
def add_tag_key_val(k,v)
|
||||
@tags = Hash.new unless @tags
|
||||
@tags[k] = v
|
||||
end
|
||||
|
||||
|
||||
|
||||
end
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
class OldNode < GeoRecord
|
||||
class OldNode < ActiveRecord::Base
|
||||
include GeoRecord
|
||||
|
||||
set_table_name 'nodes'
|
||||
|
||||
validates_presence_of :user_id, :timestamp
|
||||
|
@ -27,15 +29,8 @@ class OldNode < GeoRecord
|
|||
old_node.timestamp = node.timestamp
|
||||
old_node.user_id = node.user_id
|
||||
old_node.id = node.id
|
||||
old_node.version = node.version
|
||||
return old_node
|
||||
end
|
||||
|
||||
def to_xml
|
||||
doc = OSM::API.new.get_xml_doc
|
||||
doc.root << to_xml_node()
|
||||
return doc
|
||||
end
|
||||
|
||||
def to_xml_node
|
||||
el1 = XML::Node.new 'node'
|
||||
|
@ -44,7 +39,7 @@ class OldNode < GeoRecord
|
|||
el1['lon'] = self.lon.to_s
|
||||
el1['user'] = self.user.display_name if self.user.data_public?
|
||||
|
||||
self.tags.each do |k,v|
|
||||
Tags.split(self.tags) do |k,v|
|
||||
el2 = XML::Node.new('tag')
|
||||
el2['k'] = k.to_s
|
||||
el2['v'] = v.to_s
|
||||
|
@ -53,41 +48,24 @@ class OldNode < GeoRecord
|
|||
|
||||
el1['visible'] = self.visible.to_s
|
||||
el1['timestamp'] = self.timestamp.xmlschema
|
||||
el1['version'] = self.version.to_s
|
||||
return el1
|
||||
end
|
||||
|
||||
def save_with_dependencies!
|
||||
save!
|
||||
#not sure whats going on here
|
||||
clear_aggregation_cache
|
||||
clear_association_cache
|
||||
#ok from here
|
||||
@attributes.update(OldNode.find(:first, :conditions => ['id = ? AND timestamp = ?', self.id, self.timestamp]).instance_variable_get('@attributes'))
|
||||
|
||||
self.tags.each do |k,v|
|
||||
tag = OldNodeTag.new
|
||||
tag.k = k
|
||||
tag.v = v
|
||||
tag.id = self.id
|
||||
tag.version = self.version
|
||||
tag.save!
|
||||
|
||||
def tags_as_hash
|
||||
hash = {}
|
||||
Tags.split(self.tags) do |k,v|
|
||||
hash[k] = v
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
def tags
|
||||
unless @tags
|
||||
@tags = Hash.new
|
||||
OldNodeTag.find(:all, :conditions => ["id = ? AND version = ?", self.id, self.version]).each do |tag|
|
||||
@tags[tag.k] = tag.v
|
||||
end
|
||||
end
|
||||
@tags = Hash.new unless @tags
|
||||
@tags
|
||||
# Pretend we're not in any ways
|
||||
def ways
|
||||
return []
|
||||
end
|
||||
|
||||
def tags=(t)
|
||||
@tags = t
|
||||
end
|
||||
|
||||
# Pretend we're not in any relations
|
||||
def containing_relation_members
|
||||
return []
|
||||
end
|
||||
end
|
||||
|
|
|
@ -109,5 +109,20 @@ class OldRelation < ActiveRecord::Base
|
|||
el1 << e
|
||||
end
|
||||
return el1
|
||||
end
|
||||
end
|
||||
|
||||
# Temporary method to match interface to nodes
|
||||
def tags_as_hash
|
||||
return self.tags
|
||||
end
|
||||
|
||||
# Temporary method to match interface to relations
|
||||
def relation_members
|
||||
return self.old_members
|
||||
end
|
||||
|
||||
# Pretend we're not in any relations
|
||||
def containing_relation_members
|
||||
return []
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
class OldRelationMember < ActiveRecord::Base
|
||||
belongs_to :user
|
||||
|
||||
set_table_name 'relation_members'
|
||||
|
||||
end
|
||||
|
|
|
@ -1,6 +1,3 @@
|
|||
class OldRelationTag < ActiveRecord::Base
|
||||
belongs_to :user
|
||||
|
||||
set_table_name 'relation_tags'
|
||||
|
||||
end
|
||||
|
|
|
@ -110,5 +110,20 @@ class OldWay < ActiveRecord::Base
|
|||
el1 << e
|
||||
end
|
||||
return el1
|
||||
end
|
||||
end
|
||||
|
||||
# Temporary method to match interface to nodes
|
||||
def tags_as_hash
|
||||
return self.tags
|
||||
end
|
||||
|
||||
# Temporary method to match interface to ways
|
||||
def way_nodes
|
||||
return self.old_nodes
|
||||
end
|
||||
|
||||
# Pretend we're not in any relations
|
||||
def containing_relation_members
|
||||
return []
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
class Relation < ActiveRecord::Base
|
||||
require 'xml/libxml'
|
||||
|
||||
set_table_name 'current_relations'
|
||||
|
||||
belongs_to :user
|
||||
|
||||
has_many :old_relations, :foreign_key => 'id', :order => 'version'
|
||||
|
||||
has_many :relation_members, :foreign_key => 'id'
|
||||
has_many :relation_tags, :foreign_key => 'id'
|
||||
|
||||
has_many :old_relations, :foreign_key => 'id', :order => 'version'
|
||||
|
||||
set_table_name 'current_relations'
|
||||
has_many :containing_relation_members, :class_name => "RelationMember", :as => :member
|
||||
has_many :containing_relations, :class_name => "Relation", :through => :containing_relation_members, :source => :relation, :extend => ObjectFinder
|
||||
|
||||
def self.from_xml(xml, create=false)
|
||||
begin
|
||||
|
@ -109,29 +112,6 @@ class Relation < ActiveRecord::Base
|
|||
return el1
|
||||
end
|
||||
|
||||
|
||||
# collect relationships. currently done in one big block at the end;
|
||||
# may need to move this upwards if people want automatic completion of
|
||||
# relationships, i.e. deliver referenced objects like we do with ways...
|
||||
# FIXME: rip out the fucking SQL
|
||||
def self.find_for_nodes_and_ways(node_ids, way_ids)
|
||||
relations = []
|
||||
|
||||
if node_ids.length > 0
|
||||
relations += Relation.find_by_sql("select e.* from current_relations e,current_relation_members em where " +
|
||||
"e.visible=1 and " +
|
||||
"em.id = e.id and em.member_type='node' and em.member_id in (#{node_ids.join(',')})")
|
||||
end
|
||||
if way_ids.length > 0
|
||||
relations += Relation.find_by_sql("select e.* from current_relations e,current_relation_members em where " +
|
||||
"e.visible=1 and " +
|
||||
"em.id = e.id and em.member_type='way' and em.member_id in (#{way_ids.join(',')})")
|
||||
end
|
||||
|
||||
relations # if you don't do this then it returns nil and not []
|
||||
end
|
||||
|
||||
|
||||
# FIXME is this really needed?
|
||||
def members
|
||||
unless @members
|
||||
|
@ -236,22 +216,49 @@ class Relation < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def preconditions_ok?
|
||||
# These are hastables that store an id in the index of all
|
||||
# the nodes/way/relations that have already been added.
|
||||
# Once we know the id of the node/way/relation exists
|
||||
# we check to see if it is already existing in the hashtable
|
||||
# if it does, then we return false. Otherwise
|
||||
# we add it to the relevant hash table, with the value true..
|
||||
# Thus if you have nodes with the ids of 50 and 1 already in the
|
||||
# relation, then the hash table nodes would contain:
|
||||
# => {50=>true, 1=>true}
|
||||
nodes = Hash.new
|
||||
ways = Hash.new
|
||||
relations = Hash.new
|
||||
self.members.each do |m|
|
||||
if (m[0] == "node")
|
||||
n = Node.find(:first, :conditions => ["id = ?", m[1]])
|
||||
unless n and n.visible
|
||||
return false
|
||||
end
|
||||
if nodes[m[1]]
|
||||
return false
|
||||
else
|
||||
nodes[m[1]] = true
|
||||
end
|
||||
elsif (m[0] == "way")
|
||||
w = Way.find(:first, :conditions => ["id = ?", m[1]])
|
||||
unless w and w.visible and w.preconditions_ok?
|
||||
return false
|
||||
end
|
||||
if ways[m[1]]
|
||||
return false
|
||||
else
|
||||
ways[m[1]] = true
|
||||
end
|
||||
elsif (m[0] == "relation")
|
||||
e = Relation.find(:first, :conditions => ["id = ?", m[1]])
|
||||
unless e and e.visible and e.preconditions_ok?
|
||||
return false
|
||||
end
|
||||
if relations[m[1]]
|
||||
return false
|
||||
else
|
||||
relations[m[1]] = true
|
||||
end
|
||||
else
|
||||
return false
|
||||
end
|
||||
|
@ -261,4 +268,8 @@ class Relation < ActiveRecord::Base
|
|||
return false
|
||||
end
|
||||
|
||||
# Temporary method to match interface to nodes
|
||||
def tags_as_hash
|
||||
return self.tags
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,30 +1,23 @@
|
|||
class RelationMember < ActiveRecord::Base
|
||||
set_table_name 'current_relation_members'
|
||||
|
||||
# problem with RelationMember is that it may link to any one
|
||||
# object (a node, a way, another relation), and belongs_to is
|
||||
# not flexible enough for that. So we do this, which is ugly,
|
||||
# but fortunately rails won't actually run the SQL behind that
|
||||
# unless someone really accesses .node, .way, or
|
||||
# .relation - which is what we do below based on member_type.
|
||||
# (and no: the :condition on belongs_to doesn't work here as
|
||||
# it is a condition on the *referenced* object not the
|
||||
# *referencing* object!)
|
||||
|
||||
belongs_to :node, :foreign_key => "member_id"
|
||||
belongs_to :way, :foreign_key => "member_id"
|
||||
belongs_to :relation, :foreign_key => "member_id"
|
||||
belongs_to :member, :polymorphic => true, :foreign_type => :member_class
|
||||
belongs_to :relation, :foreign_key => :id
|
||||
|
||||
# so we define this "member" function that returns whatever it
|
||||
# is.
|
||||
|
||||
def member()
|
||||
return (member_type == "node") ? node : (member_type == "way") ? way : relation
|
||||
def after_find
|
||||
self[:member_class] = self.member_type.capitalize
|
||||
end
|
||||
|
||||
# NOTE - relations are SUBJECTS of memberships. The fact that nodes,
|
||||
# ways, and relations can be the OBJECT of a membership,
|
||||
# i.e. a node/way/relation can be referenced throgh a
|
||||
# RelationMember object, is NOT modelled in rails, i.e. these links
|
||||
# have to be resolved manually, on demand.
|
||||
def after_initialize
|
||||
self[:member_class] = self.member_type.capitalize
|
||||
end
|
||||
|
||||
def before_save
|
||||
self.member_type = self[:member_class].downcase
|
||||
end
|
||||
|
||||
def member_type=(type)
|
||||
self[:member_type] = type
|
||||
self[:member_class] = type.capitalize
|
||||
end
|
||||
end
|
||||
|
|
|
@ -183,7 +183,7 @@ class Trace < ActiveRecord::Base
|
|||
# If there are any existing points for this trace then delete
|
||||
# them - we check for existing points first to avoid locking
|
||||
# the table in the common case where there aren't any.
|
||||
if Tracepoint.exists?(['gpx_id = ?', self.id])
|
||||
if Tracepoint.find(:first, :conditions => ['gpx_id = ?', self.id])
|
||||
Tracepoint.delete_all(['gpx_id = ?', self.id])
|
||||
end
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
class Tracepoint < GeoRecord
|
||||
class Tracepoint < ActiveRecord::Base
|
||||
include GeoRecord
|
||||
|
||||
set_table_name 'gps_points'
|
||||
|
||||
validates_numericality_of :trackid, :only_integer => true
|
||||
|
|
|
@ -1,15 +1,19 @@
|
|||
class Way < ActiveRecord::Base
|
||||
require 'xml/libxml'
|
||||
|
||||
belongs_to :user
|
||||
set_table_name 'current_ways'
|
||||
|
||||
has_many :nodes, :through => :way_nodes, :order => 'sequence_id'
|
||||
has_many :way_nodes, :foreign_key => 'id', :order => 'sequence_id'
|
||||
has_many :way_tags, :foreign_key => 'id'
|
||||
belongs_to :user
|
||||
|
||||
has_many :old_ways, :foreign_key => 'id', :order => 'version'
|
||||
|
||||
set_table_name 'current_ways'
|
||||
has_many :way_nodes, :foreign_key => 'id', :order => 'sequence_id'
|
||||
has_many :nodes, :through => :way_nodes, :order => 'sequence_id'
|
||||
|
||||
has_many :way_tags, :foreign_key => 'id'
|
||||
|
||||
has_many :containing_relation_members, :class_name => "RelationMember", :as => :member
|
||||
has_many :containing_relations, :class_name => "Relation", :through => :containing_relation_members, :source => :relation, :extend => ObjectFinder
|
||||
|
||||
def self.from_xml(xml, create=false)
|
||||
begin
|
||||
|
@ -270,4 +274,9 @@ class Way < ActiveRecord::Base
|
|||
self.delete_with_history(user)
|
||||
|
||||
end
|
||||
|
||||
# Temporary method to match interface to nodes
|
||||
def tags_as_hash
|
||||
return self.tags
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue