Brazil/Brasil 250 Cidades/Scripts
< Brazil | Brasil 250 Cidades
Jump to navigation
Jump to search
Os scripts foram gentilmente cedidos por Matt Amos.
Arquivo exemplo usa_extract.yml, com a lista das cidades.
--- Los Angeles, California: - 34.05 - -118.25 Tempe, Arizona: - 33.41463 - -111.90938 Kansas City, Kansas: - 39.09947 - -94.58133 Costa Mesa, California: - 33.66978 - -117.90432 Peoria, Illinois: - 40.69365 - -89.58899
Arquivo routes.rb, que gera as distâncias entre as cidades. Um arquivo .yml, como o de acima, deverá ser passado como parâmetro na linha de comando.
require 'rubygems'
require 'cloudmade'
require 'yaml'
include CloudMade
API_KEY='' # PUT YOUR API KEY HERE
CITIES = YAML::load_file(ARGV[0])
CM = Client.from_parameters(API_KEY)
def route_or_nil(from, to)
backoff = 60
loop do
begin
# To calculate the distance using the 'fastest' route:
# return CM.routing.route(Point.new(CITIES[from]), Point.new(CITIES[to]))
# To calculate the distance using the 'shortest' route:
return CM.routing.route(Point.new(CITIES[from]), Point.new(CITIES[to]), nil, "car", "en", "shortest")
rescue Timeout::Error
STDERR.puts "[#{Time.now}] Timeout, retrying..."
sleep(backoff)
backoff = [60 * 30, backoff * 2].min
rescue HTTPError => e
STDERR.puts "[#{Time.now}] HTTP error: #{e}, retrying..."
sleep(backoff)
backoff = [60 * 30, backoff * 2].min
rescue
STDERR.puts "[#{Time.now}] Other error: #{e}, retrying..."
sleep(backoff)
backoff = [60 * 30, backoff * 2].min
end
end
rescue RouteNotFound
nil
end
num_cities = CITIES.keys.length
CITIES.keys.sort.each do |i|
CITIES.keys.sort.each do |j|
r = route_or_nil(i, j)
if r.nil?
puts "#{i};#{j};NO ROUTE"
else
puts "#{i};#{j};#{r.summary.total_distance}"
end
end
end
Arquivo to_html.rb, que gera, a partir do resultado do routes.rb, uma página html com as distâncias e links.
require 'rubygems'
require 'yaml'
CITIES = YAML::load_file(ARGV[0])
# average radius of the earth
RADIUS = 6371010.0
# ratio of route to great circle distance to be considered "bad". this will
# vary regionally (i.e: much higher in the mountains), so should be found by
# experiment.
FACTOR = 1.5
# calculate the great circle distance
# from wikipedia:
# arctan(sqrt((cos(phi_f) * sin(Delta_lambda))^2 +
# (cos(phi_s) * sin(phi_f) - sin(phi_s) * cos(phi_f) * cos(Delta_lambda)^2)) /
# (sin(phi_s) * sin(phi_f) + cos(phi_s) * cos(phi_f) * cos(Delta_lambda)))
def great_circle(a, b)
lambda = Math::PI * (a[1] - b[1]) / 180.0
phi_s = Math::PI * a[0] / 180.0
phi_f = Math::PI * b[0] / 180.0
sin_phi_s = Math::sin(phi_s)
sin_phi_f = Math::sin(phi_f)
sin_lambda = Math::sin(lambda)
cos_phi_s = Math::cos(phi_s)
cos_phi_f = Math::cos(phi_f)
cos_lambda = Math::cos(lambda)
sigma = Math::atan2(Math::sqrt((cos_phi_f * sin_lambda)**2 + (cos_phi_s * sin_phi_f - sin_phi_s * cos_phi_f * cos_lambda)**2),
sin_phi_s * sin_phi_f + cos_phi_s * cos_phi_f * cos_lambda)
return RADIUS * sigma
end
# define this as the success test - whether something worked or
# not. return a :symbol, which will be used as the CSS class for
# the table cell.
def css_class(from, to, dist)
if dist.nil?
return :fail
else
if dist > FACTOR * great_circle(CITIES[from], CITIES[to])
return :bad
elsif dist > 0.0
return :success
else
return :zero
end
end
end
city_dist = {}
File.readlines(ARGV[1]).each do |line|
from, to, dist = line.split(/;/)
if dist == "S/ ROTA"
dist = nil
else
dist = dist.to_f
end
if city_dist[from].nil?
city_dist[from] = { to => dist }
else
city_dist[from][to] = dist
end
end
city_names = CITIES.keys.sort
puts <<END
<html><head><title>Distancias</title>
<style type="text/css">
a.success { color: green; }
a.fail { color: red; }
a.zero { color: #888; }
a.bad { color: #fa0; }
</style>
</head><body>
END
puts "<table><tr><th></th>"
city_names.each do |to|
to_pos = CITIES[to]
# url to 'fastest' routing
# url = "http://maps.cloudmade.com/?lat=#{to_pos[0]}&lng=#{to_pos[1]}&zoom=6"
# url to 'shortest' routing
url = "http://maps.cloudmade.com/?lat=#{to_pos[0]}&lng=#{to_pos[1]}&zoom=6&travel=car/shortest"
puts "<th><a href=\"#{url}\">#{to}</a></th>"
end
puts "</tr>"
counters = {}
city_names.each do |from|
from_pos = CITIES[from]
# url to 'fastest' routing
# url = "http://maps.cloudmade.com/?lat=#{from_pos[0]}&lng=#{from_pos[1]}&zoom=6"
# url to 'shortest' routing
url = "http://maps.cloudmade.com/?lat=#{from_pos[0]}&lng=#{from_pos[1]}&zoom=6&travel=car/shortest"
puts "<tr><td><a href=\"#{url}\">#{from}</a></td>"
city_names.each do |to|
to_pos = CITIES[to]
dist = city_dist[from][to]
cc = css_class(from, to, dist)
counters[cc] = (counters[cc] || 0) + 1
# url to 'fastest' routing
# url = "http://maps.cloudmade.com/?directions=#{[from_pos,to_pos].flatten.join(',')}&lat=#{0.5*(from_pos[0]+to_pos[0])}&lng=#{0.5*(from_pos[1]+to_pos[1])}&zoom=6"
# url to 'shortest' routing
url = "http://maps.cloudmade.com/?directions=#{[from_pos,to_pos].flatten.join(',')}&lat=#{0.5*(from_pos[0]+to_pos[0])}&lng=#{0.5*(from_pos[1]+to_pos[1])}&zoom=6&travel=car/shortest"
if from == to
puts "<td>X</td>"
elsif dist.nil? or dist == 0
puts "<td><a href='#{url}' class='#{cc}'>Falhou</a></td>"
else
title_pretty_dist = dist.round.to_s.gsub(/(\d)(\d{3})$/, '\1.\2')
pretty_dist = title_pretty_dist.to_i.to_s
puts "<td><a href='#{url}' title='(#{from}) #{title_pretty_dist} km (#{to})' class='#{cc}'>#{pretty_dist} km</a></td>"
end
end
puts "</tr>"
end
puts "</table>"
total = city_names.length ** 2
counters.each do |cc, n|
puts "<!--p>Class #{cc}: #{n} of #{total} (#{(100.0*n)/total}%)</p-->"
end
puts "</body></html>"
Arquivo gerargrid.bat, para rodar os scripts no windows:
@echo off echo Buscando distancias... ruby routes.rb cidades.yml >cidades-distancias.csv echo Gerando html... ruby to_html.rb cidades.yml cidades-distancias.csv > cidades-distancias.html echo Script finalizado.