WikiProject Brazil/Brasil 250 Cidades/Scripts
From OpenStreetMap Wiki
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.