Refactor bounding box code
Moved duplicated code into the BoundingBox class, and pass around BoundingBox objects instead of lists of bounds.
This commit is contained in:
parent
d70fd8ab1a
commit
95d899786a
21 changed files with 581 additions and 247 deletions
|
@ -38,9 +38,6 @@
|
||||||
class AmfController < ApplicationController
|
class AmfController < ApplicationController
|
||||||
include Potlatch
|
include Potlatch
|
||||||
|
|
||||||
# Help methods for checking boundary sanity and area size
|
|
||||||
include MapBoundary
|
|
||||||
|
|
||||||
skip_before_filter :verify_authenticity_token
|
skip_before_filter :verify_authenticity_token
|
||||||
before_filter :check_api_writable
|
before_filter :check_api_writable
|
||||||
|
|
||||||
|
@ -265,15 +262,17 @@ class AmfController < ApplicationController
|
||||||
|
|
||||||
# check boundary is sane and area within defined
|
# check boundary is sane and area within defined
|
||||||
# see /config/application.yml
|
# see /config/application.yml
|
||||||
check_boundaries(xmin, ymin, xmax, ymax)
|
bbox = BoundingBox.new(xmin, ymin, xmax, ymax)
|
||||||
|
bbox.check_boundaries
|
||||||
|
bbox.check_size
|
||||||
|
|
||||||
if POTLATCH_USE_SQL then
|
if POTLATCH_USE_SQL then
|
||||||
ways = sql_find_ways_in_area(xmin, ymin, xmax, ymax)
|
ways = sql_find_ways_in_area(bbox)
|
||||||
points = sql_find_pois_in_area(xmin, ymin, xmax, ymax)
|
points = sql_find_pois_in_area(bbox)
|
||||||
relations = sql_find_relations_in_area_and_ways(xmin, ymin, xmax, ymax, ways.collect {|x| x[0]})
|
relations = sql_find_relations_in_area_and_ways(bbox, ways.collect {|x| x[0]})
|
||||||
else
|
else
|
||||||
# find the way ids in an area
|
# find the way ids in an area
|
||||||
nodes_in_area = Node.bbox(ymin, xmin, ymax, xmax).visible.includes(:ways)
|
nodes_in_area = Node.bbox(bbox).visible.includes(:ways)
|
||||||
ways = nodes_in_area.inject([]) { |sum, node|
|
ways = nodes_in_area.inject([]) { |sum, node|
|
||||||
visible_ways = node.ways.select { |w| w.visible? }
|
visible_ways = node.ways.select { |w| w.visible? }
|
||||||
sum + visible_ways.collect { |w| [w.id,w.version] }
|
sum + visible_ways.collect { |w| [w.id,w.version] }
|
||||||
|
@ -305,9 +304,11 @@ class AmfController < ApplicationController
|
||||||
|
|
||||||
# check boundary is sane and area within defined
|
# check boundary is sane and area within defined
|
||||||
# see /config/application.yml
|
# see /config/application.yml
|
||||||
check_boundaries(xmin, ymin, xmax, ymax)
|
bbox = BoundingBox.new(xmin, ymin, xmax, ymax)
|
||||||
|
bbox.check_boundaries
|
||||||
|
bbox.check_size
|
||||||
|
|
||||||
nodes_in_area = Node.bbox(ymin, xmin, ymax, xmax).joins(:ways_via_history).where(:current_ways => { :visible => false })
|
nodes_in_area = Node.bbox(bbox).joins(:ways_via_history).where(:current_ways => { :visible => false })
|
||||||
way_ids = nodes_in_area.collect { |node| node.ways_via_history.invisible.collect { |way| way.id } }.flatten.uniq
|
way_ids = nodes_in_area.collect { |node| node.ways_via_history.invisible.collect { |way| way.id } }.flatten.uniq
|
||||||
|
|
||||||
[0,'',way_ids]
|
[0,'',way_ids]
|
||||||
|
@ -904,7 +905,7 @@ class AmfController < ApplicationController
|
||||||
# ====================================================================
|
# ====================================================================
|
||||||
# Alternative SQL queries for getway/whichways
|
# Alternative SQL queries for getway/whichways
|
||||||
|
|
||||||
def sql_find_ways_in_area(xmin,ymin,xmax,ymax)
|
def sql_find_ways_in_area(bbox)
|
||||||
sql=<<-EOF
|
sql=<<-EOF
|
||||||
SELECT DISTINCT current_ways.id AS wayid,current_ways.version AS version
|
SELECT DISTINCT current_ways.id AS wayid,current_ways.version AS version
|
||||||
FROM current_way_nodes
|
FROM current_way_nodes
|
||||||
|
@ -912,12 +913,12 @@ class AmfController < ApplicationController
|
||||||
INNER JOIN current_ways ON current_ways.id =current_way_nodes.id
|
INNER JOIN current_ways ON current_ways.id =current_way_nodes.id
|
||||||
WHERE current_nodes.visible=TRUE
|
WHERE current_nodes.visible=TRUE
|
||||||
AND current_ways.visible=TRUE
|
AND current_ways.visible=TRUE
|
||||||
AND #{OSM.sql_for_area(ymin, xmin, ymax, xmax, "current_nodes.")}
|
AND #{OSM.sql_for_area(bbox, "current_nodes.")}
|
||||||
EOF
|
EOF
|
||||||
return ActiveRecord::Base.connection.select_all(sql).collect { |a| [a['wayid'].to_i,a['version'].to_i] }
|
return ActiveRecord::Base.connection.select_all(sql).collect { |a| [a['wayid'].to_i,a['version'].to_i] }
|
||||||
end
|
end
|
||||||
|
|
||||||
def sql_find_pois_in_area(xmin,ymin,xmax,ymax)
|
def sql_find_pois_in_area(bbox)
|
||||||
pois=[]
|
pois=[]
|
||||||
sql=<<-EOF
|
sql=<<-EOF
|
||||||
SELECT current_nodes.id,current_nodes.latitude*0.0000001 AS lat,current_nodes.longitude*0.0000001 AS lon,current_nodes.version
|
SELECT current_nodes.id,current_nodes.latitude*0.0000001 AS lat,current_nodes.longitude*0.0000001 AS lon,current_nodes.version
|
||||||
|
@ -925,7 +926,7 @@ class AmfController < ApplicationController
|
||||||
LEFT OUTER JOIN current_way_nodes cwn ON cwn.node_id=current_nodes.id
|
LEFT OUTER JOIN current_way_nodes cwn ON cwn.node_id=current_nodes.id
|
||||||
WHERE current_nodes.visible=TRUE
|
WHERE current_nodes.visible=TRUE
|
||||||
AND cwn.id IS NULL
|
AND cwn.id IS NULL
|
||||||
AND #{OSM.sql_for_area(ymin, xmin, ymax, xmax, "current_nodes.")}
|
AND #{OSM.sql_for_area(bbox, "current_nodes.")}
|
||||||
EOF
|
EOF
|
||||||
ActiveRecord::Base.connection.select_all(sql).each do |row|
|
ActiveRecord::Base.connection.select_all(sql).each do |row|
|
||||||
poitags={}
|
poitags={}
|
||||||
|
@ -937,7 +938,7 @@ class AmfController < ApplicationController
|
||||||
pois
|
pois
|
||||||
end
|
end
|
||||||
|
|
||||||
def sql_find_relations_in_area_and_ways(xmin,ymin,xmax,ymax,way_ids)
|
def sql_find_relations_in_area_and_ways(bbox,way_ids)
|
||||||
# ** It would be more Potlatchy to get relations for nodes within ways
|
# ** It would be more Potlatchy to get relations for nodes within ways
|
||||||
# during 'getway', not here
|
# during 'getway', not here
|
||||||
sql=<<-EOF
|
sql=<<-EOF
|
||||||
|
@ -945,7 +946,7 @@ class AmfController < ApplicationController
|
||||||
FROM current_relations cr
|
FROM current_relations cr
|
||||||
INNER JOIN current_relation_members crm ON crm.id=cr.id
|
INNER JOIN current_relation_members crm ON crm.id=cr.id
|
||||||
INNER JOIN current_nodes cn ON crm.member_id=cn.id AND crm.member_type='Node'
|
INNER JOIN current_nodes cn ON crm.member_id=cn.id AND crm.member_type='Node'
|
||||||
WHERE #{OSM.sql_for_area(ymin, xmin, ymax, xmax, "cn.")}
|
WHERE #{OSM.sql_for_area(bbox, "cn.")}
|
||||||
EOF
|
EOF
|
||||||
unless way_ids.empty?
|
unless way_ids.empty?
|
||||||
sql+=<<-EOF
|
sql+=<<-EOF
|
||||||
|
|
|
@ -5,9 +5,6 @@ class ApiController < ApplicationController
|
||||||
after_filter :compress_output
|
after_filter :compress_output
|
||||||
around_filter :api_call_handle_error, :api_call_timeout
|
around_filter :api_call_handle_error, :api_call_timeout
|
||||||
|
|
||||||
# Help methods for checking boundary sanity and area size
|
|
||||||
include MapBoundary
|
|
||||||
|
|
||||||
# Get an XML response containing a list of tracepoints that have been uploaded
|
# Get an XML response containing a list of tracepoints that have been uploaded
|
||||||
# within the specified bounding box, and in the specified page.
|
# within the specified bounding box, and in the specified page.
|
||||||
def trackpoints
|
def trackpoints
|
||||||
|
@ -22,25 +19,19 @@ class ApiController < ApplicationController
|
||||||
offset = page * TRACEPOINTS_PER_PAGE
|
offset = page * TRACEPOINTS_PER_PAGE
|
||||||
|
|
||||||
# Figure out the bbox
|
# Figure out the bbox
|
||||||
bbox = params['bbox']
|
|
||||||
unless bbox and bbox.count(',') == 3
|
|
||||||
report_error("The parameter bbox is required, and must be of the form min_lon,min_lat,max_lon,max_lat")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
bbox = bbox.split(',')
|
|
||||||
min_lon, min_lat, max_lon, max_lat = sanitise_boundaries(bbox)
|
|
||||||
# check boundary is sane and area within defined
|
# check boundary is sane and area within defined
|
||||||
# see /config/application.yml
|
# see /config/application.yml
|
||||||
begin
|
begin
|
||||||
check_boundaries(min_lon, min_lat, max_lon, max_lat)
|
bbox = BoundingBox.from_bbox_params(params)
|
||||||
|
bbox.check_boundaries
|
||||||
|
bbox.check_size
|
||||||
rescue Exception => err
|
rescue Exception => err
|
||||||
report_error(err.message)
|
report_error(err.message)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
# get all the points
|
# get all the points
|
||||||
points = Tracepoint.bbox(min_lat, min_lon, max_lat, max_lon).offset(offset).limit(TRACEPOINTS_PER_PAGE).order("gpx_id DESC, trackid ASC, timestamp ASC")
|
points = Tracepoint.bbox(bbox).offset(offset).limit(TRACEPOINTS_PER_PAGE).order("gpx_id DESC, trackid ASC, timestamp ASC")
|
||||||
|
|
||||||
doc = XML::Document.new
|
doc = XML::Document.new
|
||||||
doc.encoding = XML::Encoding::UTF_8
|
doc.encoding = XML::Encoding::UTF_8
|
||||||
|
@ -124,29 +115,18 @@ class ApiController < ApplicationController
|
||||||
# fetched. Finally all the xml is returned.
|
# fetched. Finally all the xml is returned.
|
||||||
def map
|
def map
|
||||||
# Figure out the bbox
|
# Figure out the bbox
|
||||||
bbox = params['bbox']
|
|
||||||
|
|
||||||
unless bbox and bbox.count(',') == 3
|
|
||||||
# alternatively: report_error(TEXT['boundary_parameter_required']
|
|
||||||
report_error("The parameter bbox is required, and must be of the form min_lon,min_lat,max_lon,max_lat")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
bbox = bbox.split(',')
|
|
||||||
|
|
||||||
min_lon, min_lat, max_lon, max_lat = sanitise_boundaries(bbox)
|
|
||||||
|
|
||||||
# check boundary is sane and area within defined
|
# check boundary is sane and area within defined
|
||||||
# see /config/application.yml
|
# see /config/application.yml
|
||||||
begin
|
begin
|
||||||
check_boundaries(min_lon, min_lat, max_lon, max_lat)
|
bbox = BoundingBox.from_bbox_params(params)
|
||||||
|
bbox.check_boundaries
|
||||||
|
bbox.check_size
|
||||||
rescue Exception => err
|
rescue Exception => err
|
||||||
report_error(err.message)
|
report_error(err.message)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
# FIXME um why is this area using a different order for the lat/lon from above???
|
@nodes = Node.bbox(bbox).where(:visible => true).includes(:node_tags).limit(MAX_NUMBER_OF_NODES+1)
|
||||||
@nodes = Node.bbox(min_lat, min_lon, max_lat, max_lon).where(:visible => true).includes(:node_tags).limit(MAX_NUMBER_OF_NODES+1)
|
|
||||||
# get all the nodes, by tag not yet working, waiting for change from NickB
|
# get all the nodes, by tag not yet working, waiting for change from NickB
|
||||||
# need to be @nodes (instance var) so tests in /spec can be performed
|
# need to be @nodes (instance var) so tests in /spec can be performed
|
||||||
#@nodes = Node.search(bbox, params[:tag])
|
#@nodes = Node.search(bbox, params[:tag])
|
||||||
|
@ -164,12 +144,7 @@ class ApiController < ApplicationController
|
||||||
doc = OSM::API.new.get_xml_doc
|
doc = OSM::API.new.get_xml_doc
|
||||||
|
|
||||||
# add bounds
|
# add bounds
|
||||||
bounds = XML::Node.new 'bounds'
|
doc.root << bbox.add_bounds_to(XML::Node.new 'bounds')
|
||||||
bounds['minlat'] = min_lat.to_s
|
|
||||||
bounds['minlon'] = min_lon.to_s
|
|
||||||
bounds['maxlat'] = max_lat.to_s
|
|
||||||
bounds['maxlon'] = max_lon.to_s
|
|
||||||
doc.root << bounds
|
|
||||||
|
|
||||||
# get ways
|
# get ways
|
||||||
# find which ways are needed
|
# find which ways are needed
|
||||||
|
|
|
@ -17,9 +17,6 @@ class ChangesetController < ApplicationController
|
||||||
around_filter :api_call_handle_error, :except => [:list]
|
around_filter :api_call_handle_error, :except => [:list]
|
||||||
around_filter :web_timeout, :only => [:list]
|
around_filter :web_timeout, :only => [:list]
|
||||||
|
|
||||||
# Help methods for checking boundary sanity and area size
|
|
||||||
include MapBoundary
|
|
||||||
|
|
||||||
# Helper methods for checking consistency
|
# Helper methods for checking consistency
|
||||||
include ConsistencyValidations
|
include ConsistencyValidations
|
||||||
|
|
||||||
|
@ -202,11 +199,11 @@ class ChangesetController < ApplicationController
|
||||||
# create the conditions that the user asked for. some or all of
|
# create the conditions that the user asked for. some or all of
|
||||||
# these may be nil.
|
# these may be nil.
|
||||||
changesets = Changeset.scoped
|
changesets = Changeset.scoped
|
||||||
changesets = conditions_bbox(changesets, params['bbox'])
|
changesets, bbox = conditions_bbox(changesets, params)
|
||||||
changesets = conditions_user(changesets, params['user'], params['display_name'])
|
changesets = conditions_user(changesets, params['user'], params['display_name'])
|
||||||
changesets = conditions_time(changesets, params['time'])
|
changesets = conditions_time(changesets, params['time'])
|
||||||
changesets = conditions_open(changesets, params['open'])
|
changesets = conditions_open(changesets, params['open'])
|
||||||
changesets = conditions_closed(changesets, params['closed'])
|
changesets = conditions_closed(changesets, params['closed'])
|
||||||
|
|
||||||
# create the results document
|
# create the results document
|
||||||
results = OSM::API.new.get_xml_doc
|
results = OSM::API.new.get_xml_doc
|
||||||
|
@ -270,15 +267,9 @@ class ChangesetController < ApplicationController
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if params[:bbox]
|
changesets, bbox = conditions_bbox(changesets, params)
|
||||||
bbox = params[:bbox]
|
|
||||||
elsif params[:minlon] and params[:minlat] and params[:maxlon] and params[:maxlat]
|
|
||||||
bbox = params[:minlon] + ',' + params[:minlat] + ',' + params[:maxlon] + ',' + params[:maxlat]
|
|
||||||
end
|
|
||||||
|
|
||||||
if bbox
|
if bbox
|
||||||
changesets = conditions_bbox(changesets, bbox)
|
|
||||||
bbox = BoundingBox.from_s(bbox)
|
|
||||||
bbox_link = render_to_string :partial => "bbox", :object => bbox
|
bbox_link = render_to_string :partial => "bbox", :object => bbox
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -319,22 +310,24 @@ private
|
||||||
#------------------------------------------------------------
|
#------------------------------------------------------------
|
||||||
|
|
||||||
##
|
##
|
||||||
# if a bounding box was specified then parse it and do some sanity
|
# if a bounding box was specified do some sanity checks.
|
||||||
# checks. this is mostly the same as the map call, but without the
|
# restrict changesets to those enclosed by a bounding box
|
||||||
# area restriction.
|
# we need to return both the changesets and the bounding box
|
||||||
def conditions_bbox(changesets, bbox)
|
def conditions_bbox(changesets, params)
|
||||||
unless bbox.nil?
|
if params[:bbox]
|
||||||
raise OSM::APIBadUserInput.new("Bounding box should be min_lon,min_lat,max_lon,max_lat") unless bbox.count(',') == 3
|
bbox = BoundingBox.from_bbox_params(params)
|
||||||
bbox = sanitise_boundaries(bbox.split(/,/))
|
elsif params[:minlon] and params[:minlat] and params[:maxlon] and params[:maxlat]
|
||||||
raise OSM::APIBadUserInput.new("Minimum longitude should be less than maximum.") unless bbox[0] <= bbox[2]
|
bbox = BoundingBox.from_lon_lat_params(params)
|
||||||
raise OSM::APIBadUserInput.new("Minimum latitude should be less than maximum.") unless bbox[1] <= bbox[3]
|
end
|
||||||
|
if bbox
|
||||||
|
bbox.check_boundaries
|
||||||
|
bbox = bbox.to_scaled
|
||||||
return changesets.where("min_lon < ? and max_lon > ? and min_lat < ? and max_lat > ?",
|
return changesets.where("min_lon < ? and max_lon > ? and min_lat < ? and max_lat > ?",
|
||||||
(bbox[2] * GeoRecord::SCALE).to_i,
|
bbox.max_lon.to_i, bbox.min_lon.to_i,
|
||||||
(bbox[0] * GeoRecord::SCALE).to_i,
|
bbox.max_lat.to_i, bbox.min_lat.to_i),
|
||||||
(bbox[3] * GeoRecord::SCALE).to_i,
|
bbox
|
||||||
(bbox[1] * GeoRecord::SCALE).to_i)
|
|
||||||
else
|
else
|
||||||
return changesets
|
return changesets, bbox
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -8,7 +8,7 @@ class ExportController < ApplicationController
|
||||||
|
|
||||||
#When the user clicks 'Export' we redirect to a URL which generates the export download
|
#When the user clicks 'Export' we redirect to a URL which generates the export download
|
||||||
def finish
|
def finish
|
||||||
bbox = BoundingBox.new(params[:minlon], params[:minlat], params[:maxlon], params[:maxlat])
|
bbox = BoundingBox.from_lon_lat_params(params)
|
||||||
format = params[:format]
|
format = params[:format]
|
||||||
|
|
||||||
if format == "osm"
|
if format == "osm"
|
||||||
|
|
|
@ -49,15 +49,16 @@ class SiteController < ApplicationController
|
||||||
@zoom = params['zoom'].to_i
|
@zoom = params['zoom'].to_i
|
||||||
|
|
||||||
elsif params['bbox']
|
elsif params['bbox']
|
||||||
bbox = params['bbox'].split(",")
|
bbox = BoundingBox.from_bbox_params(params)
|
||||||
|
|
||||||
@lon = ( bbox[0].to_f + bbox[2].to_f ) / 2.0
|
@lon = bbox.centre_lon
|
||||||
@lat = ( bbox[1].to_f + bbox[3].to_f ) / 2.0
|
@lat = bbox.centre_lat
|
||||||
@zoom = 16
|
@zoom = 16
|
||||||
|
|
||||||
elsif params['minlon'] and params['minlat'] and params['maxlon'] and params['maxlat']
|
elsif params['minlon'] and params['minlat'] and params['maxlon'] and params['maxlat']
|
||||||
@lon = ( params['maxlon'].to_f + params['minlon'].to_f ) / 2.0
|
bbox = BoundingBox.from_lon_lat_params(params)
|
||||||
@lat = ( params['maxlat'].to_f + params['minlat'].to_f ) / 2.0
|
|
||||||
|
@lon = bbox.centre_lon
|
||||||
|
@lat = bbox.centre_lat
|
||||||
@zoom = 16
|
@zoom = 16
|
||||||
|
|
||||||
elsif params['gpx']
|
elsif params['gpx']
|
||||||
|
|
|
@ -90,21 +90,11 @@ class Changeset < ActiveRecord::Base
|
||||||
# returns the bounding box of the changeset. it is possible that some
|
# returns the bounding box of the changeset. it is possible that some
|
||||||
# or all of the values will be nil, indicating that they are undefined.
|
# or all of the values will be nil, indicating that they are undefined.
|
||||||
def bbox
|
def bbox
|
||||||
@bbox ||= [ min_lon, min_lat, max_lon, max_lat ]
|
@bbox ||= BoundingBox.new(min_lon, min_lat, max_lon, max_lat)
|
||||||
end
|
end
|
||||||
|
|
||||||
def has_valid_bbox?
|
def has_valid_bbox?
|
||||||
not bbox.include? nil
|
bbox.complete?
|
||||||
end
|
|
||||||
|
|
||||||
##
|
|
||||||
# returns area of the changset bbox as a rough comparitive quantity for use of changset displays
|
|
||||||
def area
|
|
||||||
if has_valid_bbox?
|
|
||||||
(max_lon - min_lon) * (max_lat - min_lat)
|
|
||||||
else
|
|
||||||
0
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -112,26 +102,12 @@ class Changeset < ActiveRecord::Base
|
||||||
# expand a little bit more in the direction of the expansion, so that
|
# expand a little bit more in the direction of the expansion, so that
|
||||||
# further expansions may be unnecessary. this is an optimisation
|
# further expansions may be unnecessary. this is an optimisation
|
||||||
# suggested on the wiki page by kleptog.
|
# suggested on the wiki page by kleptog.
|
||||||
def update_bbox!(array)
|
def update_bbox!(bbox_update)
|
||||||
# ensure that bbox is cached and has no nils in it. if there are any
|
bbox.expand!(bbox_update, EXPAND)
|
||||||
# nils, just use the bounding box update to write over them.
|
|
||||||
@bbox = bbox.zip(array).collect { |a, b| a.nil? ? b : a }
|
|
||||||
|
|
||||||
# only try to update the bbox if there is a value for every coordinate
|
|
||||||
# which there will be from the previous line as long as both array and
|
|
||||||
# bbox are all non-nil.
|
|
||||||
if has_valid_bbox? and array.all?
|
|
||||||
# FIXME - this looks nasty and violates DRY... is there any prettier
|
|
||||||
# way to do this?
|
|
||||||
@bbox[0] = [-180 * GeoRecord::SCALE, array[0] + EXPAND * (@bbox[0] - @bbox[2])].max if array[0] < @bbox[0]
|
|
||||||
@bbox[1] = [ -90 * GeoRecord::SCALE, array[1] + EXPAND * (@bbox[1] - @bbox[3])].max if array[1] < @bbox[1]
|
|
||||||
@bbox[2] = [ 180 * GeoRecord::SCALE, array[2] + EXPAND * (@bbox[2] - @bbox[0])].min if array[2] > @bbox[2]
|
|
||||||
@bbox[3] = [ 90 * GeoRecord::SCALE, array[3] + EXPAND * (@bbox[3] - @bbox[1])].min if array[3] > @bbox[3]
|
|
||||||
|
|
||||||
# update active record. rails 2.1's dirty handling should take care of
|
# update active record. rails 2.1's dirty handling should take care of
|
||||||
# whether this object needs saving or not.
|
# whether this object needs saving or not.
|
||||||
self.min_lon, self.min_lat, self.max_lon, self.max_lat = @bbox
|
self.min_lon, self.min_lat, self.max_lon, self.max_lat = @bbox.to_a if bbox.complete?
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
|
@ -237,10 +213,9 @@ class Changeset < ActiveRecord::Base
|
||||||
el1['closed_at'] = self.closed_at.xmlschema unless is_open?
|
el1['closed_at'] = self.closed_at.xmlschema unless is_open?
|
||||||
el1['open'] = is_open?.to_s
|
el1['open'] = is_open?.to_s
|
||||||
|
|
||||||
el1['min_lon'] = (bbox[0].to_f / GeoRecord::SCALE).to_s unless bbox[0].nil?
|
if bbox.complete?
|
||||||
el1['min_lat'] = (bbox[1].to_f / GeoRecord::SCALE).to_s unless bbox[1].nil?
|
bbox.to_unscaled.add_bounds_to(el1, '_')
|
||||||
el1['max_lon'] = (bbox[2].to_f / GeoRecord::SCALE).to_s unless bbox[2].nil?
|
end
|
||||||
el1['max_lat'] = (bbox[3].to_f / GeoRecord::SCALE).to_s unless bbox[3].nil?
|
|
||||||
|
|
||||||
# NOTE: changesets don't include the XML of the changes within them,
|
# NOTE: changesets don't include the XML of the changes within them,
|
||||||
# they are just structures for tagging. to get the osmChange of a
|
# they are just structures for tagging. to get the osmChange of a
|
||||||
|
|
|
@ -44,7 +44,6 @@ class Node < ActiveRecord::Base
|
||||||
# Also adheres to limitations such as within max_number_of_nodes
|
# Also adheres to limitations such as within max_number_of_nodes
|
||||||
#
|
#
|
||||||
def self.search(bounding_box, tags = {})
|
def self.search(bounding_box, tags = {})
|
||||||
min_lon, min_lat, max_lon, max_lat = *bounding_box
|
|
||||||
# @fixme a bit of a hack to search for only visible nodes
|
# @fixme a bit of a hack to search for only visible nodes
|
||||||
# couldn't think of another to add to tags condition
|
# couldn't think of another to add to tags condition
|
||||||
#conditions_hash = tags.merge({ 'visible' => 1 })
|
#conditions_hash = tags.merge({ 'visible' => 1 })
|
||||||
|
@ -59,9 +58,8 @@ class Node < ActiveRecord::Base
|
||||||
#end
|
#end
|
||||||
#conditions = keys.join(' AND ')
|
#conditions = keys.join(' AND ')
|
||||||
|
|
||||||
find_by_area(min_lat, min_lon, max_lat, max_lon,
|
find_by_area(bounding_box, :conditions => {:visible => true},
|
||||||
:conditions => {:visible => true},
|
:limit => MAX_NUMBER_OF_NODES+1)
|
||||||
:limit => MAX_NUMBER_OF_NODES+1)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Read in xml as text and return it's Node object representation
|
# Read in xml as text and return it's Node object representation
|
||||||
|
@ -121,7 +119,7 @@ class Node < ActiveRecord::Base
|
||||||
# the bounding box around a node, which is used for determining the changeset's
|
# the bounding box around a node, which is used for determining the changeset's
|
||||||
# bounding box
|
# bounding box
|
||||||
def bbox
|
def bbox
|
||||||
[ longitude, latitude, longitude, latitude ]
|
BoundingBox.new(longitude, latitude, longitude, latitude)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Should probably be renamed delete_from to come in line with update
|
# Should probably be renamed delete_from to come in line with update
|
||||||
|
|
|
@ -205,7 +205,7 @@ class Way < ActiveRecord::Base
|
||||||
def bbox
|
def bbox
|
||||||
lons = nodes.collect { |n| n.longitude }
|
lons = nodes.collect { |n| n.longitude }
|
||||||
lats = nodes.collect { |n| n.latitude }
|
lats = nodes.collect { |n| n.latitude }
|
||||||
[ lons.min, lats.min, lons.max, lats.max ]
|
BoundingBox.new(lons.min, lats.min, lons.max, lats.max)
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_from(new_way, user)
|
def update_from(new_way, user)
|
||||||
|
|
|
@ -24,23 +24,21 @@
|
||||||
<% unless changeset_details.has_valid_bbox? %>
|
<% unless changeset_details.has_valid_bbox? %>
|
||||||
<td><%= t 'browse.changeset_details.no_bounding_box' %></td>
|
<td><%= t 'browse.changeset_details.no_bounding_box' %></td>
|
||||||
<% else
|
<% else
|
||||||
minlon = changeset_details.min_lon/GeoRecord::SCALE.to_f
|
bbox = changeset_details.bbox.to_unscaled
|
||||||
minlat = changeset_details.min_lat/GeoRecord::SCALE.to_f
|
|
||||||
maxlon = changeset_details.max_lon/GeoRecord::SCALE.to_f
|
|
||||||
maxlat = changeset_details.max_lat/GeoRecord::SCALE.to_f
|
|
||||||
%>
|
%>
|
||||||
<td>
|
<td>
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="3" style="text-align:center"><%=maxlat -%></td>
|
<td colspan="3" style="text-align:center"><%=bbox.max_lat -%></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td><%=minlon -%></td>
|
<td><%=bbox.min_lon -%></td>
|
||||||
<td>(<a href='/?minlon=<%= minlon %>&minlat=<%= minlat %>&maxlon=<%= maxlon %>&maxlat=<%= maxlat %>&box=yes' title='<%= t 'browse.changeset_details.show_area_box' %>'><%= t 'browse.changeset_details.box' %></a>)</td>
|
<td>(<a href='/?minlon=<%= bbox.min_lon %>&minlat=<%= bbox.min_lat %>&maxlon=<%= bbox.max_lon %>&maxlat=<%= bbox.max_lat %>
|
||||||
<td><%=maxlon -%></td>
|
&box=yes' title='<%= t 'browse.changeset_details.show_area_box' %>'><%= t 'browse.changeset_details.box' %></a>)</td>
|
||||||
|
<td><%=bbox.max_lon -%></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td colspan="3" style="text-align:center"><%= minlat -%></td>
|
<td colspan="3" style="text-align:center"><%= bbox.min_lat -%></td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -72,10 +72,11 @@
|
||||||
});
|
});
|
||||||
|
|
||||||
<% if map.instance_of? Changeset %>
|
<% if map.instance_of? Changeset %>
|
||||||
var minlon = <%= map.min_lon / GeoRecord::SCALE.to_f %>;
|
<% bbox = map.bbox.to_unscaled %>
|
||||||
var minlat = <%= map.min_lat / GeoRecord::SCALE.to_f %>;
|
var minlon = <%= bbox.min_lon %>;
|
||||||
var maxlon = <%= map.max_lon / GeoRecord::SCALE.to_f %>;
|
var minlat = <%= bbox.min_lat %>;
|
||||||
var maxlat = <%= map.max_lat / GeoRecord::SCALE.to_f %>;
|
var maxlon = <%= bbox.max_lon %>;
|
||||||
|
var maxlat = <%= bbox.max_lat %>;
|
||||||
var bbox = new OpenLayers.Bounds(minlon, minlat, maxlon, maxlat);
|
var bbox = new OpenLayers.Bounds(minlon, minlat, maxlon, maxlat);
|
||||||
var centre = bbox.getCenterLonLat();
|
var centre = bbox.getCenterLonLat();
|
||||||
|
|
||||||
|
|
|
@ -51,10 +51,11 @@
|
||||||
|
|
||||||
<% @edits.each do |edit| %>
|
<% @edits.each do |edit| %>
|
||||||
<% if edit.has_valid_bbox? %>
|
<% if edit.has_valid_bbox? %>
|
||||||
var minlon = <%= edit.min_lon / GeoRecord::SCALE.to_f %>;
|
<% bbox = edit.bbox.to_unscaled %>
|
||||||
var minlat = <%= edit.min_lat / GeoRecord::SCALE.to_f %>;
|
var minlon = <%= bbox.min_lon %>;
|
||||||
var maxlon = <%= edit.max_lon / GeoRecord::SCALE.to_f %>;
|
var minlat = <%= bbox.min_lat %>;
|
||||||
var maxlat = <%= edit.max_lat / GeoRecord::SCALE.to_f %>;
|
var maxlon = <%= bbox.max_lon %>;
|
||||||
|
var maxlat = <%= bbox.max_lat %>;
|
||||||
var bbox = new OpenLayers.Bounds(minlon, minlat, maxlon, maxlat);
|
var bbox = new OpenLayers.Bounds(minlon, minlat, maxlon, maxlat);
|
||||||
|
|
||||||
bounds.extend(bbox);
|
bounds.extend(bbox);
|
||||||
|
|
|
@ -78,15 +78,12 @@ atom_feed(:language => I18n.locale, :schema_date => 2009,
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
unless changeset.min_lat.nil?
|
if changeset.has_valid_bbox?
|
||||||
minlon = changeset.min_lon/GeoRecord::SCALE.to_f
|
bbox = changeset.bbox.to_unscaled
|
||||||
minlat = changeset.min_lat/GeoRecord::SCALE.to_f
|
|
||||||
maxlon = changeset.max_lon/GeoRecord::SCALE.to_f
|
|
||||||
maxlat = changeset.max_lat/GeoRecord::SCALE.to_f
|
|
||||||
|
|
||||||
# See http://georss.org/Encodings#Geometry
|
# See http://georss.org/Encodings#Geometry
|
||||||
lower_corner = "#{minlat} #{minlon}"
|
lower_corner = "#{bbox.min_lat} #{bbox.min_lon}"
|
||||||
upper_corner = "#{maxlat} #{maxlon}"
|
upper_corner = "#{bbox.max_lat} #{bbox.max_lon}"
|
||||||
|
|
||||||
feed.georss :box, lower_corner + " " + upper_corner
|
feed.georss :box, lower_corner + " " + upper_corner
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,58 +1,113 @@
|
||||||
class BoundingBox
|
class BoundingBox
|
||||||
|
attr_reader :min_lon, :min_lat, :max_lon, :max_lat
|
||||||
|
|
||||||
|
private
|
||||||
|
LON_LIMIT = 180.0
|
||||||
|
LAT_LIMIT = 90.0
|
||||||
|
SCALED_LON_LIMIT = LON_LIMIT * GeoRecord::SCALE
|
||||||
|
SCALED_LAT_LIMIT = LAT_LIMIT * GeoRecord::SCALE
|
||||||
|
|
||||||
|
public
|
||||||
def initialize(min_lon, min_lat, max_lon, max_lat)
|
def initialize(min_lon, min_lat, max_lon, max_lat)
|
||||||
@bbox = [min_lon.to_f, min_lat.to_f, max_lon.to_f, max_lat.to_f]
|
@min_lon = min_lon.to_f unless min_lon.nil?
|
||||||
|
@min_lat = min_lat.to_f unless min_lat.nil?
|
||||||
|
@max_lon = max_lon.to_f unless max_lon.nil?
|
||||||
|
@max_lat = max_lat.to_f unless max_lat.nil?
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.from_s(s)
|
def self.from_s(s)
|
||||||
BoundingBox.new(*s.split(/,/))
|
if s.count(',') == 3
|
||||||
|
BoundingBox.new(*s.split(/,/))
|
||||||
|
else
|
||||||
|
nil
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def min_lon
|
def self.from_bbox_params(params)
|
||||||
@bbox[0]
|
if params[:bbox] and params[:bbox].count(',') == 3
|
||||||
|
bbox_array = params[:bbox].split(',')
|
||||||
|
end
|
||||||
|
from_bbox_array(bbox_array)
|
||||||
end
|
end
|
||||||
|
|
||||||
def min_lon=(min_lon)
|
def self.from_lon_lat_params(params)
|
||||||
@bbox[0] = min_lon
|
if params[:minlon] and params[:minlat] and params[:maxlon] and params[:maxlat]
|
||||||
|
bbox_array = [params[:minlon], params[:minlat], params[:maxlon], params[:maxlat]]
|
||||||
|
end
|
||||||
|
from_bbox_array(bbox_array)
|
||||||
end
|
end
|
||||||
|
|
||||||
def min_lat
|
def expand!(bbox, margin = 0)
|
||||||
@bbox[1]
|
update!(bbox) unless complete?
|
||||||
|
# only try to expand the bbox if there is a value for every coordinate
|
||||||
|
# which there will be from the previous line as long as array does not contain a nil
|
||||||
|
if bbox.complete?
|
||||||
|
@min_lon = [-SCALED_LON_LIMIT,
|
||||||
|
bbox.min_lon + margin * (min_lon - max_lon)].max if bbox.min_lon < min_lon
|
||||||
|
@min_lat = [-SCALED_LAT_LIMIT,
|
||||||
|
bbox.min_lat + margin * (min_lat - max_lat)].max if bbox.min_lat < min_lat
|
||||||
|
@max_lon = [+SCALED_LON_LIMIT,
|
||||||
|
bbox.max_lon + margin * (max_lon - min_lon)].min if bbox.max_lon > max_lon
|
||||||
|
@max_lat = [+SCALED_LAT_LIMIT,
|
||||||
|
bbox.max_lat + margin * (max_lat - min_lat)].min if bbox.max_lat > max_lat
|
||||||
|
end
|
||||||
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
def min_lat=(min_lat)
|
def check_boundaries
|
||||||
@bbox[1] = min_lat
|
# check the bbox is sane
|
||||||
|
if min_lon > max_lon
|
||||||
|
raise OSM::APIBadBoundingBox.new(
|
||||||
|
"The minimum longitude must be less than the maximum longitude, but it wasn't")
|
||||||
|
end
|
||||||
|
if min_lat > max_lat
|
||||||
|
raise OSM::APIBadBoundingBox.new(
|
||||||
|
"The minimum latitude must be less than the maximum latitude, but it wasn't")
|
||||||
|
end
|
||||||
|
if min_lon < -LON_LIMIT || min_lat < -LAT_LIMIT || max_lon > +LON_LIMIT || max_lat > +LAT_LIMIT
|
||||||
|
raise OSM::APIBadBoundingBox.new("The latitudes must be between #{-LAT_LIMIT} and #{LAT_LIMIT}," +
|
||||||
|
" and longitudes between #{-LON_LIMIT} and #{LON_LIMIT}")
|
||||||
|
end
|
||||||
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
def max_lon
|
def check_size
|
||||||
@bbox[2]
|
# check the bbox isn't too large
|
||||||
|
if area > MAX_REQUEST_AREA
|
||||||
|
raise OSM::APIBadBoundingBox.new("The maximum bbox size is " + MAX_REQUEST_AREA.to_s +
|
||||||
|
", and your request was too large. Either request a smaller area, or use planet.osm")
|
||||||
|
end
|
||||||
|
self
|
||||||
end
|
end
|
||||||
|
|
||||||
def max_lon=(max_lon)
|
##
|
||||||
@bbox[2] = max_lon
|
# returns area of the bbox as a rough comparative quantity
|
||||||
|
def area
|
||||||
|
if complete?
|
||||||
|
(max_lon - min_lon) * (max_lat - min_lat)
|
||||||
|
else
|
||||||
|
0
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def max_lat
|
def complete?
|
||||||
@bbox[3]
|
not to_a.include?(nil)
|
||||||
end
|
|
||||||
|
|
||||||
def max_lat=(max_lat)
|
|
||||||
@bbox[3] = max_lat
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def centre_lon
|
def centre_lon
|
||||||
(@bbox[0] + @bbox[2]) / 2.0
|
(min_lon + max_lon) / 2.0
|
||||||
end
|
end
|
||||||
|
|
||||||
def centre_lat
|
def centre_lat
|
||||||
(@bbox[1] + @bbox[3]) / 2.0
|
(min_lat + max_lat) / 2.0
|
||||||
end
|
end
|
||||||
|
|
||||||
def width
|
def width
|
||||||
@bbox[2] - @bbox[0]
|
max_lon - min_lon
|
||||||
end
|
end
|
||||||
|
|
||||||
def height
|
def height
|
||||||
@bbox[3] - @bbox[1]
|
max_lat - min_lat
|
||||||
end
|
end
|
||||||
|
|
||||||
def slippy_width(zoom)
|
def slippy_width(zoom)
|
||||||
|
@ -63,10 +118,64 @@ class BoundingBox
|
||||||
min = min_lat * Math::PI / 180.0
|
min = min_lat * Math::PI / 180.0
|
||||||
max = max_lat * Math::PI / 180.0
|
max = max_lat * Math::PI / 180.0
|
||||||
|
|
||||||
Math.log((Math.tan(max) + 1.0 / Math.cos(max)) / (Math.tan(min) + 1.0 / Math.cos(min))) * 128.0 * 2.0 ** zoom / Math::PI
|
Math.log((Math.tan(max) + 1.0 / Math.cos(max)) /
|
||||||
|
(Math.tan(min) + 1.0 / Math.cos(min))) *
|
||||||
|
(128.0 * 2.0 ** zoom / Math::PI)
|
||||||
|
end
|
||||||
|
|
||||||
|
# there are two forms used for bounds with and without an underscore,
|
||||||
|
# cater for both forms eg minlon and min_lon
|
||||||
|
def add_bounds_to(hash, underscore = "")
|
||||||
|
hash["min#{underscore}lat"] = min_lat.to_s
|
||||||
|
hash["min#{underscore}lon"] = min_lon.to_s
|
||||||
|
hash["max#{underscore}lat"] = max_lat.to_s
|
||||||
|
hash["max#{underscore}lon"] = max_lon.to_s
|
||||||
|
hash
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_scaled
|
||||||
|
BoundingBox.new((min_lon * GeoRecord::SCALE),
|
||||||
|
(min_lat * GeoRecord::SCALE),
|
||||||
|
(max_lon * GeoRecord::SCALE),
|
||||||
|
(max_lat * GeoRecord::SCALE))
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_unscaled
|
||||||
|
BoundingBox.new((min_lon / GeoRecord::SCALE),
|
||||||
|
(min_lat / GeoRecord::SCALE),
|
||||||
|
(max_lon / GeoRecord::SCALE),
|
||||||
|
(max_lat / GeoRecord::SCALE))
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_a
|
||||||
|
[min_lon, min_lat, max_lon, max_lat]
|
||||||
end
|
end
|
||||||
|
|
||||||
def to_s
|
def to_s
|
||||||
return @bbox.join(",")
|
"#{min_lon},#{min_lat},#{max_lon},#{max_lat}"
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def self.from_bbox_array(bbox_array)
|
||||||
|
unless bbox_array
|
||||||
|
raise OSM::APIBadUserInput.new(
|
||||||
|
"The parameter bbox is required, and must be of the form min_lon,min_lat,max_lon,max_lat")
|
||||||
|
end
|
||||||
|
# Take an array of length 4, create a bounding box with min_lon, min_lat, max_lon and
|
||||||
|
# max_lat within their respective boundaries.
|
||||||
|
min_lon = [[bbox_array[0].to_f, -LON_LIMIT].max, +LON_LIMIT].min
|
||||||
|
min_lat = [[bbox_array[1].to_f, -LAT_LIMIT].max, +LAT_LIMIT].min
|
||||||
|
max_lon = [[bbox_array[2].to_f, +LON_LIMIT].min, -LON_LIMIT].max
|
||||||
|
max_lat = [[bbox_array[3].to_f, +LAT_LIMIT].min, -LAT_LIMIT].max
|
||||||
|
BoundingBox.new(min_lon, min_lat, max_lon, max_lat)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update!(bbox)
|
||||||
|
# ensure that bbox has no nils in it. if there are any
|
||||||
|
# nils, just use the bounding box update to write over them.
|
||||||
|
@min_lon = bbox.min_lon if min_lon.nil?
|
||||||
|
@min_lat = bbox.min_lat if min_lat.nil?
|
||||||
|
@max_lon = bbox.max_lon if max_lon.nil?
|
||||||
|
@max_lat = bbox.max_lat if max_lat.nil?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,7 +5,7 @@ module GeoRecord
|
||||||
SCALE = 10000000
|
SCALE = 10000000
|
||||||
|
|
||||||
def self.included(base)
|
def self.included(base)
|
||||||
base.scope :bbox, lambda { |minlat,minlon,maxlat,maxlon| base.where(OSM.sql_for_area(minlat, minlon, maxlat, maxlon)) }
|
base.scope :bbox, lambda { |bbox| base.where(OSM.sql_for_area(bbox)) }
|
||||||
base.before_save :update_tile
|
base.before_save :update_tile
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -1,32 +0,0 @@
|
||||||
module MapBoundary
|
|
||||||
# Take an array of length 4, and return the min_lon, min_lat, max_lon and
|
|
||||||
# max_lat within their respective boundaries.
|
|
||||||
def sanitise_boundaries(bbox)
|
|
||||||
min_lon = [[bbox[0].to_f,-180].max,180].min
|
|
||||||
min_lat = [[bbox[1].to_f,-90].max,90].min
|
|
||||||
max_lon = [[bbox[2].to_f,+180].min,-180].max
|
|
||||||
max_lat = [[bbox[3].to_f,+90].min,-90].max
|
|
||||||
return min_lon, min_lat, max_lon, max_lat
|
|
||||||
end
|
|
||||||
|
|
||||||
def check_boundaries(min_lon, min_lat, max_lon, max_lat)
|
|
||||||
# check the bbox is sane
|
|
||||||
unless min_lon <= max_lon
|
|
||||||
raise OSM::APIBadBoundingBox.new("The minimum longitude must be less than the maximum longitude, but it wasn't")
|
|
||||||
end
|
|
||||||
unless min_lat <= max_lat
|
|
||||||
raise OSM::APIBadBoundingBox.new("The minimum latitude must be less than the maximum latitude, but it wasn't")
|
|
||||||
end
|
|
||||||
unless min_lon >= -180 && min_lat >= -90 && max_lon <= 180 && max_lat <= 90
|
|
||||||
# Due to sanitize_boundaries, it is highly unlikely we'll actually get here
|
|
||||||
raise OSM::APIBadBoundingBox.new("The latitudes must be between -90 and 90, and longitudes between -180 and 180")
|
|
||||||
end
|
|
||||||
|
|
||||||
# check the bbox isn't too large
|
|
||||||
requested_area = (max_lat-min_lat)*(max_lon-min_lon)
|
|
||||||
if requested_area > MAX_REQUEST_AREA
|
|
||||||
raise OSM::APIBadBoundingBox.new("The maximum bbox size is " + MAX_REQUEST_AREA.to_s +
|
|
||||||
", and your request was too large. Either request a smaller area, or use planet.osm")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
12
lib/osm.rb
12
lib/osm.rb
|
@ -497,14 +497,12 @@ module OSM
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return an SQL fragment to select a given area of the globe
|
# Return an SQL fragment to select a given area of the globe
|
||||||
def self.sql_for_area(minlat, minlon, maxlat, maxlon, prefix = nil)
|
def self.sql_for_area(bbox, prefix = nil)
|
||||||
tilesql = QuadTile.sql_for_area(minlat, minlon, maxlat, maxlon, prefix)
|
tilesql = QuadTile.sql_for_area(bbox, prefix)
|
||||||
minlat = (minlat * 10000000).round
|
bbox = bbox.to_scaled
|
||||||
minlon = (minlon * 10000000).round
|
|
||||||
maxlat = (maxlat * 10000000).round
|
|
||||||
maxlon = (maxlon * 10000000).round
|
|
||||||
|
|
||||||
return "#{tilesql} AND #{prefix}latitude BETWEEN #{minlat} AND #{maxlat} AND #{prefix}longitude BETWEEN #{minlon} AND #{maxlon}"
|
return "#{tilesql} AND #{prefix}latitude BETWEEN #{bbox.min_lat} AND #{bbox.max_lat} " +
|
||||||
|
"AND #{prefix}longitude BETWEEN #{bbox.min_lon} AND #{bbox.max_lon}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# Return a spam score for a chunk of text
|
# Return a spam score for a chunk of text
|
||||||
|
|
|
@ -9,11 +9,11 @@ module QuadTile
|
||||||
return tile_for_xy(x, y)
|
return tile_for_xy(x, y)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.tiles_for_area(minlat, minlon, maxlat, maxlon)
|
def self.tiles_for_area(bbox)
|
||||||
minx = ((minlon + 180) * 65535 / 360).round
|
minx = ((bbox.min_lon + 180) * 65535 / 360).round
|
||||||
maxx = ((maxlon + 180) * 65535 / 360).round
|
maxx = ((bbox.max_lon + 180) * 65535 / 360).round
|
||||||
miny = ((minlat + 90) * 65535 / 180).round
|
miny = ((bbox.min_lat + 90) * 65535 / 180).round
|
||||||
maxy = ((maxlat + 90) * 65535 / 180).round
|
maxy = ((bbox.max_lat + 90) * 65535 / 180).round
|
||||||
tiles = []
|
tiles = []
|
||||||
|
|
||||||
minx.upto(maxx) do |x|
|
minx.upto(maxx) do |x|
|
||||||
|
@ -40,8 +40,8 @@ module QuadTile
|
||||||
return t
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.iterate_tiles_for_area(minlat, minlon, maxlat, maxlon)
|
def self.iterate_tiles_for_area(bbox)
|
||||||
tiles = tiles_for_area(minlat, minlon, maxlat, maxlon)
|
tiles = tiles_for_area(bbox)
|
||||||
first = last = nil
|
first = last = nil
|
||||||
|
|
||||||
tiles.sort.each do |tile|
|
tiles.sort.each do |tile|
|
||||||
|
@ -60,11 +60,11 @@ module QuadTile
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.sql_for_area(minlat, minlon, maxlat, maxlon, prefix)
|
def self.sql_for_area(bbox, prefix)
|
||||||
sql = Array.new
|
sql = Array.new
|
||||||
single = Array.new
|
single = Array.new
|
||||||
|
|
||||||
iterate_tiles_for_area(minlat, minlon, maxlat, maxlon) do |first,last|
|
iterate_tiles_for_area(bbox) do |first,last|
|
||||||
if first == last
|
if first == last
|
||||||
single.push(first)
|
single.push(first)
|
||||||
else
|
else
|
||||||
|
|
|
@ -63,12 +63,12 @@ static VALUE tile_for_point(VALUE self, VALUE lat, VALUE lon)
|
||||||
return UINT2NUM(xy2tile(x, y));
|
return UINT2NUM(xy2tile(x, y));
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE tiles_for_area(VALUE self, VALUE minlat, VALUE minlon, VALUE maxlat, VALUE maxlon)
|
static VALUE tiles_for_area(VALUE self, VALUE bbox)
|
||||||
{
|
{
|
||||||
unsigned int minx = lon2x(NUM2DBL(minlon));
|
unsigned int minx = lon2x(NUM2DBL(rb_iv_get(bbox, "@min_lon")));
|
||||||
unsigned int maxx = lon2x(NUM2DBL(maxlon));
|
unsigned int maxx = lon2x(NUM2DBL(rb_iv_get(bbox, "@max_lon")));
|
||||||
unsigned int miny = lat2y(NUM2DBL(minlat));
|
unsigned int miny = lat2y(NUM2DBL(rb_iv_get(bbox, "@min_lat")));
|
||||||
unsigned int maxy = lat2y(NUM2DBL(maxlat));
|
unsigned int maxy = lat2y(NUM2DBL(rb_iv_get(bbox, "@max_lat")));
|
||||||
tilelist_t tl = tilelist_for_area(minx, miny, maxx, maxy);
|
tilelist_t tl = tilelist_for_area(minx, miny, maxx, maxy);
|
||||||
VALUE tiles = rb_ary_new();
|
VALUE tiles = rb_ary_new();
|
||||||
unsigned int t;
|
unsigned int t;
|
||||||
|
@ -88,12 +88,12 @@ static VALUE tile_for_xy(VALUE self, VALUE x, VALUE y)
|
||||||
return UINT2NUM(xy2tile(NUM2UINT(x), NUM2UINT(y)));
|
return UINT2NUM(xy2tile(NUM2UINT(x), NUM2UINT(y)));
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE iterate_tiles_for_area(VALUE self, VALUE minlat, VALUE minlon, VALUE maxlat, VALUE maxlon)
|
static VALUE iterate_tiles_for_area(VALUE self, VALUE bbox)
|
||||||
{
|
{
|
||||||
unsigned int minx = lon2x(NUM2DBL(minlon));
|
unsigned int minx = lon2x(NUM2DBL(rb_iv_get(bbox, "@min_lon")));
|
||||||
unsigned int maxx = lon2x(NUM2DBL(maxlon));
|
unsigned int maxx = lon2x(NUM2DBL(rb_iv_get(bbox, "@max_lon")));
|
||||||
unsigned int miny = lat2y(NUM2DBL(minlat));
|
unsigned int miny = lat2y(NUM2DBL(rb_iv_get(bbox, "@min_lat")));
|
||||||
unsigned int maxy = lat2y(NUM2DBL(maxlat));
|
unsigned int maxy = lat2y(NUM2DBL(rb_iv_get(bbox, "@max_lat")));
|
||||||
tilelist_t tl = tilelist_for_area(minx, miny, maxx, maxy);
|
tilelist_t tl = tilelist_for_area(minx, miny, maxx, maxy);
|
||||||
|
|
||||||
if (tl.tilec > 0)
|
if (tl.tilec > 0)
|
||||||
|
@ -140,9 +140,9 @@ void Init_quad_tile_so(void)
|
||||||
VALUE m = rb_define_module("QuadTile");
|
VALUE m = rb_define_module("QuadTile");
|
||||||
|
|
||||||
rb_define_module_function(m, "tile_for_point", tile_for_point, 2);
|
rb_define_module_function(m, "tile_for_point", tile_for_point, 2);
|
||||||
rb_define_module_function(m, "tiles_for_area", tiles_for_area, 4);
|
rb_define_module_function(m, "tiles_for_area", tiles_for_area, 1);
|
||||||
rb_define_module_function(m, "tile_for_xy", tile_for_xy, 2);
|
rb_define_module_function(m, "tile_for_xy", tile_for_xy, 2);
|
||||||
rb_define_module_function(m, "iterate_tiles_for_area", iterate_tiles_for_area, 4);
|
rb_define_module_function(m, "iterate_tiles_for_area", iterate_tiles_for_area, 1);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -506,7 +506,7 @@ class RelationControllerTest < ActionController::TestCase
|
||||||
def test_tag_modify_bounding_box
|
def test_tag_modify_bounding_box
|
||||||
# in current fixtures, relation 5 contains nodes 3 and 5 (node 3
|
# in current fixtures, relation 5 contains nodes 3 and 5 (node 3
|
||||||
# indirectly via way 3), so the bbox should be [3,3,5,5].
|
# indirectly via way 3), so the bbox should be [3,3,5,5].
|
||||||
check_changeset_modify([3,3,5,5]) do |changeset_id|
|
check_changeset_modify(BoundingBox.new(3,3,5,5)) do |changeset_id|
|
||||||
# add a tag to an existing relation
|
# add a tag to an existing relation
|
||||||
relation_xml = current_relations(:visible_relation).to_xml
|
relation_xml = current_relations(:visible_relation).to_xml
|
||||||
relation_element = relation_xml.find("//osm/relation").first
|
relation_element = relation_xml.find("//osm/relation").first
|
||||||
|
@ -536,7 +536,7 @@ class RelationControllerTest < ActionController::TestCase
|
||||||
current_ways(:used_way),
|
current_ways(:used_way),
|
||||||
current_ways(:way_with_versions)
|
current_ways(:way_with_versions)
|
||||||
].each_with_index do |element, version|
|
].each_with_index do |element, version|
|
||||||
bbox = element.bbox.collect { |x| x / SCALE }
|
bbox = element.bbox.to_unscaled
|
||||||
check_changeset_modify(bbox) do |changeset_id|
|
check_changeset_modify(bbox) do |changeset_id|
|
||||||
relation_xml = Relation.find(relation_id).to_xml
|
relation_xml = Relation.find(relation_id).to_xml
|
||||||
relation_element = relation_xml.find("//osm/relation").first
|
relation_element = relation_xml.find("//osm/relation").first
|
||||||
|
@ -566,7 +566,7 @@ class RelationControllerTest < ActionController::TestCase
|
||||||
# remove a member from a relation and check the bounding box is
|
# remove a member from a relation and check the bounding box is
|
||||||
# only that element.
|
# only that element.
|
||||||
def test_remove_member_bounding_box
|
def test_remove_member_bounding_box
|
||||||
check_changeset_modify([5,5,5,5]) do |changeset_id|
|
check_changeset_modify(BoundingBox.new(5,5,5,5)) do |changeset_id|
|
||||||
# remove node 5 (5,5) from an existing relation
|
# remove node 5 (5,5) from an existing relation
|
||||||
relation_xml = current_relations(:visible_relation).to_xml
|
relation_xml = current_relations(:visible_relation).to_xml
|
||||||
relation_xml.
|
relation_xml.
|
||||||
|
@ -769,10 +769,10 @@ OSM
|
||||||
assert_response :success, "can't re-read changeset for modify test"
|
assert_response :success, "can't re-read changeset for modify test"
|
||||||
assert_select "osm>changeset", 1, "Changeset element doesn't exist in #{@response.body}"
|
assert_select "osm>changeset", 1, "Changeset element doesn't exist in #{@response.body}"
|
||||||
assert_select "osm>changeset[id=#{changeset_id}]", 1, "Changeset id=#{changeset_id} doesn't exist in #{@response.body}"
|
assert_select "osm>changeset[id=#{changeset_id}]", 1, "Changeset id=#{changeset_id} doesn't exist in #{@response.body}"
|
||||||
assert_select "osm>changeset[min_lon=#{bbox[0].to_f}]", 1, "Changeset min_lon wrong in #{@response.body}"
|
assert_select "osm>changeset[min_lon=#{bbox.min_lon}]", 1, "Changeset min_lon wrong in #{@response.body}"
|
||||||
assert_select "osm>changeset[min_lat=#{bbox[1].to_f}]", 1, "Changeset min_lat wrong in #{@response.body}"
|
assert_select "osm>changeset[min_lat=#{bbox.min_lat}]", 1, "Changeset min_lat wrong in #{@response.body}"
|
||||||
assert_select "osm>changeset[max_lon=#{bbox[2].to_f}]", 1, "Changeset max_lon wrong in #{@response.body}"
|
assert_select "osm>changeset[max_lon=#{bbox.max_lon}]", 1, "Changeset max_lon wrong in #{@response.body}"
|
||||||
assert_select "osm>changeset[max_lat=#{bbox[3].to_f}]", 1, "Changeset max_lat wrong in #{@response.body}"
|
assert_select "osm>changeset[max_lat=#{bbox.max_lat}]", 1, "Changeset max_lat wrong in #{@response.body}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
316
test/unit/bounding_box_test.rb
Normal file
316
test/unit/bounding_box_test.rb
Normal file
|
@ -0,0 +1,316 @@
|
||||||
|
require File.dirname(__FILE__) + '/../test_helper'
|
||||||
|
|
||||||
|
class BoundingBoxTest < ActiveSupport::TestCase
|
||||||
|
def setup
|
||||||
|
@size_error_message = "The maximum bbox size is 0.25, and your request was too large. Either request a smaller area, or use planet.osm"
|
||||||
|
@malformed_error_message = "The parameter bbox is required, and must be of the form min_lon,min_lat,max_lon,max_lat"
|
||||||
|
@lon_order_error_message = "The minimum longitude must be less than the maximum longitude, but it wasn't"
|
||||||
|
@lat_order_error_message = "The minimum latitude must be less than the maximum latitude, but it wasn't"
|
||||||
|
@bbox_out_of_limits_error_message = "The latitudes must be between -90.0 and 90.0, and longitudes between -180.0 and 180.0"
|
||||||
|
@nil_error_message = "Should not contain nil"
|
||||||
|
|
||||||
|
@bbox_from_nils = BoundingBox.new(nil, nil, nil, nil)
|
||||||
|
@bbox_expand = BoundingBox.new(0,0,0,0)
|
||||||
|
@bbox_expand_ten = BoundingBox.new(10,10,10,10)
|
||||||
|
@bbox_expand_minus_two = BoundingBox.new(-2,-2,-2,-2)
|
||||||
|
@bbox_from_string = BoundingBox.from_s("1,2,3,4")
|
||||||
|
@min_lon = 1.0
|
||||||
|
@min_lat = 2.0
|
||||||
|
@max_lon = 3.0
|
||||||
|
@max_lat = 4.0
|
||||||
|
|
||||||
|
@bad_positive_boundary_bbox = %w{ 181,91,0,0 0,0,181,91 }
|
||||||
|
@bad_negative_boundary_bbox = %w{ -181,-91,0,0 0,0,-181,-91 }
|
||||||
|
@bad_big_bbox = %w{ -0.1,-0.1,1.1,1.1 10,10,11,11 }
|
||||||
|
@bad_malformed_bbox = %w{ -0.1 hello 10N2W10.1N2.1W }
|
||||||
|
@bad_lat_mixed_bbox = %w{ 0,0.1,0.1,0 -0.1,80,0.1,70 0.24,54.34,0.25,54.33 }
|
||||||
|
@bad_lon_mixed_bbox = %w{ 80,-0.1,70,0.1 54.34,0.24,54.33,0.25 }
|
||||||
|
@bad_limit_bbox = %w{ -180.1,-90,180,90 -180,-90.1,180,90 -180,-90,180.1,90 -180,-90,180,90.1}
|
||||||
|
@good_bbox = %w{ -0.1,-0.1,0.1,0.1 51.1,-0.1,51.2,0 -0.1,%20-0.1,%200.1,%200.1
|
||||||
|
-0.1edcd,-0.1d,0.1,0.1 -0.1E,-0.1E,0.1S,0.1N S0.1,W0.1,N0.1,E0.1}
|
||||||
|
|
||||||
|
@expand_min_lon_array = %w{ 2,10,10,10 1,10,10,10 0,10,10,10 -1,10,10,10 -2,10,10,10 -8,10,10,10 }
|
||||||
|
@expand_min_lat_array = %w{ 10,2,10,10 10,1,10,10 10,0,10,10 10,-1,10,10 10,-2,10,10 10,-8,10,10 }
|
||||||
|
@expand_max_lon_array = %w{ -2,-2,-1,-2 -2,-2,0,-2 -2,-2,1,-2 -2,-2,2,-2 }
|
||||||
|
@expand_max_lat_array = %w{ -2,-2,-2,-1 -2,-2,-2,0 -2,-2,-2,1 -2,-2,-2,2 }
|
||||||
|
@expand_min_lon_margin_response = [[2,10,10,10], [-7,10,10,10], [-7,10,10,10], [-7,10,10,10], [-7,10,10,10], [-25,10,10,10]]
|
||||||
|
@expand_min_lat_margin_response = [[10,2,10,10], [10,-7,10,10], [10,-7,10,10], [10,-7,10,10], [10,-7,10,10], [10,-25,10,10]]
|
||||||
|
@expand_max_lon_margin_response = [[-2,-2,-1,-2], [-2,-2,1,-2], [-2,-2,1,-2], [-2,-2,5,-2]]
|
||||||
|
@expand_max_lat_margin_response = [[-2,-2,-2,-1], [-2,-2,-2,1], [-2,-2,-2,1], [-2,-2,-2,5]]
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_good_bbox_from_string
|
||||||
|
@good_bbox.each do |string|
|
||||||
|
bbox = BoundingBox.from_s(string)
|
||||||
|
array = string.split(',').collect {|s| s.to_f}
|
||||||
|
check_bbox(bbox, array)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_bbox_from_s_malformed
|
||||||
|
@bad_malformed_bbox.each do |bbox_string|
|
||||||
|
bbox = BoundingBox.from_s(bbox_string)
|
||||||
|
assert_nil bbox
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_good_bbox_from_params
|
||||||
|
@good_bbox.each do |string|
|
||||||
|
bbox = BoundingBox.from_bbox_params({:bbox => string})
|
||||||
|
array = string.split(',').collect {|s| s.to_f}
|
||||||
|
check_bbox(bbox, array)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_good_bbox_from_lon_lat_params
|
||||||
|
@good_bbox.each do |string|
|
||||||
|
array = string.split(',')
|
||||||
|
bbox = BoundingBox.from_lon_lat_params({:minlon => array[0], :minlat => array[1], :maxlon => array[2], :maxlat => array[3]})
|
||||||
|
check_bbox(bbox, array.collect {|s| s.to_f})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_bbox_from_params_malformed
|
||||||
|
@bad_malformed_bbox.each do |bbox_string|
|
||||||
|
exception = assert_raise(OSM::APIBadUserInput) {BoundingBox.from_bbox_params({:bbox => bbox_string})}
|
||||||
|
assert_equal(@malformed_error_message, exception.message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_good_bbox_from_new
|
||||||
|
@good_bbox.each do |string|
|
||||||
|
array = string.split(',')
|
||||||
|
bbox = BoundingBox.new(array[0], array[1], array[2], array[3])
|
||||||
|
check_bbox(bbox, array.collect {|s| s.to_f})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_creation_from_new_with_nils
|
||||||
|
check_bbox(@bbox_from_nils, [nil, nil, nil, nil])
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_expand_min_lon_boundary
|
||||||
|
@bbox_expand.expand!(BoundingBox.new(-1810000000,0,0,0))
|
||||||
|
check_expand(@bbox_expand, "-1800000000,0,0,0")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_expand_min_lat_boundary
|
||||||
|
@bbox_expand.expand!(BoundingBox.new(0,-910000000,0,0))
|
||||||
|
check_expand(@bbox_expand, "0,-900000000,0,0")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_expand_max_lon_boundary
|
||||||
|
@bbox_expand.expand!(BoundingBox.new(0,0,1810000000,0))
|
||||||
|
check_expand(@bbox_expand, "0,0,1800000000,0")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_expand_max_lat_boundary
|
||||||
|
@bbox_expand.expand!(BoundingBox.new(0,0,0,910000000))
|
||||||
|
check_expand(@bbox_expand, "0,0,0,900000000")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_expand_min_lon_without_margin
|
||||||
|
@expand_min_lon_array.each {|array_string| check_expand(@bbox_expand_ten, array_string)}
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_expand_min_lon_with_margin
|
||||||
|
@expand_min_lon_array.each_with_index do |array_string, index|
|
||||||
|
check_expand(@bbox_expand_ten, array_string, 1, @expand_min_lon_margin_response[index])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_expand_min_lat_without_margin
|
||||||
|
@expand_min_lat_array.each {|array_string| check_expand(@bbox_expand_ten, array_string)}
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_expand_min_lat_with_margin
|
||||||
|
@expand_min_lat_array.each_with_index do |array_string, index|
|
||||||
|
check_expand(@bbox_expand_ten, array_string, 1, @expand_min_lat_margin_response[index])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_expand_max_lon_without_margin
|
||||||
|
@expand_max_lon_array.each {|array_string| check_expand(@bbox_expand_minus_two, array_string)}
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_expand_max_lon_with_margin
|
||||||
|
@expand_max_lon_array.each_with_index do |array_string, index|
|
||||||
|
check_expand(@bbox_expand_minus_two, array_string, 1, @expand_max_lon_margin_response[index])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_expand_max_lat_without_margin
|
||||||
|
@expand_max_lat_array.each {|array_string| check_expand(@bbox_expand_minus_two, array_string)}
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_expand_max_lat_with_margin
|
||||||
|
bbox = @bbox_expand
|
||||||
|
@expand_max_lat_array.each_with_index do |array_string, index|
|
||||||
|
check_expand(@bbox_expand_minus_two, array_string, 1, @expand_max_lat_margin_response[index])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_good_bbox_boundaries
|
||||||
|
@good_bbox.each do |bbox_string|
|
||||||
|
assert_nothing_raised(OSM::APIBadBoundingBox) {BoundingBox.from_s(bbox_string).check_boundaries}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_from_params_with_positive_out_of_boundary
|
||||||
|
@bad_positive_boundary_bbox.each do |bbox_string|
|
||||||
|
bbox = BoundingBox.from_bbox_params({:bbox => bbox_string})
|
||||||
|
array = bbox.to_a
|
||||||
|
assert_equal 180, [array[0], array[2]].max
|
||||||
|
assert_equal 90, [array[1], array[3]].max
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_from_params_with_negative_out_of_boundary
|
||||||
|
@bad_negative_boundary_bbox.each do |bbox_string|
|
||||||
|
bbox = BoundingBox.from_bbox_params({:bbox => bbox_string})
|
||||||
|
array = bbox.to_a
|
||||||
|
assert_equal -180, [array[0], array[2]].min
|
||||||
|
assert_equal -90, [array[1], array[3]].min
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_boundaries_mixed_lon
|
||||||
|
@bad_lon_mixed_bbox.each do |bbox_string|
|
||||||
|
exception = assert_raise(OSM::APIBadBoundingBox) {BoundingBox.from_s(bbox_string).check_boundaries}
|
||||||
|
assert_equal(@lon_order_error_message, exception.message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_boundaries_mixed_lat
|
||||||
|
@bad_lat_mixed_bbox.each do |bbox_string|
|
||||||
|
exception = assert_raise(OSM::APIBadBoundingBox) {BoundingBox.from_s(bbox_string).check_boundaries}
|
||||||
|
assert_equal(@lat_order_error_message, exception.message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_boundaries_out_of_limits
|
||||||
|
@bad_limit_bbox.each do |bbox_string|
|
||||||
|
exception = assert_raise(OSM::APIBadBoundingBox) {BoundingBox.from_s(bbox_string).check_boundaries}
|
||||||
|
assert_equal(@bbox_out_of_limits_error_message, exception.message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_good_bbox_size
|
||||||
|
@good_bbox.each do |bbox_string|
|
||||||
|
assert_nothing_raised(OSM::APIBadBoundingBox) {BoundingBox.from_s(bbox_string).check_size}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_size_to_big
|
||||||
|
@bad_big_bbox.each do |bbox_string|
|
||||||
|
bbox = nil
|
||||||
|
assert_nothing_raised(OSM::APIBadBoundingBox) {bbox = BoundingBox.from_bbox_params({:bbox => bbox_string}).check_boundaries}
|
||||||
|
exception = assert_raise(OSM::APIBadBoundingBox) {bbox.check_size}
|
||||||
|
assert_equal(@size_error_message, exception.message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_bbox_area
|
||||||
|
@good_bbox.each do |string|
|
||||||
|
bbox = BoundingBox.from_s(string)
|
||||||
|
array = string.split(',')
|
||||||
|
assert_equal ((array[2].to_f - array[0].to_f) * (array[3].to_f - array[1].to_f)), bbox.area
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_complete
|
||||||
|
assert !@bbox_from_nils.complete?, "should contain a nil"
|
||||||
|
assert @bbox_from_string.complete?, "should not contain a nil"
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_centre_lon
|
||||||
|
@good_bbox.each do |bbox_string|
|
||||||
|
array = bbox_string.split(',')
|
||||||
|
assert_equal ((array[0].to_f + array[2].to_f) / 2.0), BoundingBox.from_s(bbox_string).centre_lon
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_centre_lat
|
||||||
|
@good_bbox.each do |bbox_string|
|
||||||
|
array = bbox_string.split(',')
|
||||||
|
assert_equal ((array[1].to_f + array[3].to_f) / 2.0), BoundingBox.from_s(bbox_string).centre_lat
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_width
|
||||||
|
@good_bbox.each do |bbox_string|
|
||||||
|
array = bbox_string.split(',')
|
||||||
|
assert_equal (array[2].to_f - array[0].to_f), BoundingBox.from_s(bbox_string).width
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_height
|
||||||
|
@good_bbox.each do |bbox_string|
|
||||||
|
array = bbox_string.split(',')
|
||||||
|
assert_equal (array[3].to_f - array[1].to_f), BoundingBox.from_s(bbox_string).height
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_slippy_width
|
||||||
|
assert_in_delta 5.68888888888889, @bbox_from_string.slippy_width(2), 0.000000000000001
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_slippy_height
|
||||||
|
assert_in_delta 5.69698684268433, @bbox_from_string.slippy_height(2), 0.000000000000001
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_add_bounds_to_no_underscore
|
||||||
|
bounds = @bbox_from_string.add_bounds_to({})
|
||||||
|
assert_equal 4, bounds.size
|
||||||
|
assert_equal @min_lon.to_s, bounds['minlon']
|
||||||
|
assert_equal @min_lat.to_s, bounds['minlat']
|
||||||
|
assert_equal @max_lon.to_s, bounds['maxlon']
|
||||||
|
assert_equal @max_lat.to_s, bounds['maxlat']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_add_bounds_to_with_underscore
|
||||||
|
bounds = @bbox_from_string.add_bounds_to({}, '_')
|
||||||
|
assert_equal 4, bounds.size
|
||||||
|
assert_equal @min_lon.to_s, bounds['min_lon']
|
||||||
|
assert_equal @min_lat.to_s, bounds['min_lat']
|
||||||
|
assert_equal @max_lon.to_s, bounds['max_lon']
|
||||||
|
assert_equal @max_lat.to_s, bounds['max_lat']
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_to_scaled
|
||||||
|
bbox = @bbox_from_string.to_scaled
|
||||||
|
assert_equal @min_lon * GeoRecord::SCALE, bbox.min_lon
|
||||||
|
assert_equal @min_lat * GeoRecord::SCALE, bbox.min_lat
|
||||||
|
assert_equal @max_lon * GeoRecord::SCALE, bbox.max_lon
|
||||||
|
assert_equal @max_lat * GeoRecord::SCALE, bbox.max_lat
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_to_unscaled
|
||||||
|
scale = GeoRecord::SCALE
|
||||||
|
bbox = BoundingBox.new(1.0 * scale, 2.0 * scale, 3.0 * scale, 4.0 * scale).to_unscaled
|
||||||
|
check_bbox(bbox, [@min_lon, @min_lat, @max_lon, @max_lat])
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_to_a
|
||||||
|
assert_equal [1.0,2.0,3.0,4.0], @bbox_from_string.to_a
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_to_string
|
||||||
|
assert_equal "#{@min_lon},#{@min_lat},#{@max_lon},#{@max_lat}", @bbox_from_string.to_s
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def check_expand(bbox, array_string, margin = 0, result = nil)
|
||||||
|
array = array_string.split(',').collect {|s| s.to_f}
|
||||||
|
result = array unless result
|
||||||
|
bbox.expand!(BoundingBox.new(array[0], array[1], array[2], array[3]), margin)
|
||||||
|
check_bbox(bbox, result)
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_bbox(bbox, result)
|
||||||
|
assert_equal result[0], bbox.min_lon, 'min_lon'
|
||||||
|
assert_equal result[1], bbox.min_lat, 'min_lat'
|
||||||
|
assert_equal result[2], bbox.max_lon, 'max_lon'
|
||||||
|
assert_equal result[3], bbox.max_lat, 'max_lat'
|
||||||
|
end
|
||||||
|
end
|
|
@ -15,7 +15,10 @@ class WayTest < ActiveSupport::TestCase
|
||||||
:invisible_way,
|
:invisible_way,
|
||||||
:used_way ].each do |way_symbol|
|
:used_way ].each do |way_symbol|
|
||||||
way = current_ways(way_symbol)
|
way = current_ways(way_symbol)
|
||||||
assert_equal node.bbox, way.bbox
|
assert_equal node.bbox.min_lon, way.bbox.min_lon, 'min_lon'
|
||||||
|
assert_equal node.bbox.min_lat, way.bbox.min_lat, 'min_lat'
|
||||||
|
assert_equal node.bbox.max_lon, way.bbox.max_lon, 'max_lon'
|
||||||
|
assert_equal node.bbox.max_lat, way.bbox.max_lat, 'max_lat'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue