Skip to content

Instantly share code, notes, and snippets.

@agmcleod
Created September 21, 2011 22:23
Show Gist options
  • Save agmcleod/1233497 to your computer and use it in GitHub Desktop.
Save agmcleod/1233497 to your computer and use it in GitHub Desktop.
require 'mathn'
require 'csv'
def to_rad(angle)
angle/180 * Math::PI
end
def get_distance(from, to)
earth_radius = 6371
dLat = to_rad(to.first - from.first)
dLon = to_rad(to.last - from.last)
lat1 = to_rad(from.first)
lat2 = to_rad(to.first)
a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2)
c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1- a))
earth_radius * c
end
class City
attr_accessor :uid, :latlng, :closest_cities
def initialize(args = {})
self.uid = args[:uid]
self.latlng = args[:latlng]
raise "@latlng must be an array" if self.latlng.class != Array
self.latlng = self.latlng.collect { |c| c.to_f }
self.closest_cities = []
end
def distance_from(point)
get_distance(self.latlng, point)
end
def cities_to_s
raise "Doesnt have 5 cities" if self.closest_cities.size < 5
city_uids = []
self.closest_cities.each do |c|
city_uids << c
end
city_uids.join(" | ")
end
def to_s
"\"#{self.uid}\",#{self.latlng[0]},#{self.latlng[1]},\"#{self.cities_to_s}\""
end
end
cities = []
first = true
CSV.foreach('City.csv') do |row|
if first
first = false
else
cities << City.new(uid: row[5], latlng: row[7..8])
end
end
File.open('cities_out.csv', 'w+') do |f|
f.write("UID,Lat,Lng,Cities\n")
cities.each do |city|
distances = {}
cities.each do |city_to_add|
distances[city.distance_from(city_to_add.latlng)] = city_to_add unless city.uid == city_to_add.uid
end
distances.sort[0..4].each do |d|
city.closest_cities << d[1].uid
end
f.write("#{city.to_s}\n")
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment