Permalink
Browse files

initial commit

  • Loading branch information...
1 parent 34570e1 commit 46c69f71297a5f82e3c0e4c15ca636c2d21e1ac8 @kristianmandrup committed Jan 12, 2011
Showing with 165 additions and 7 deletions.
  1. +1 −1 Gemfile
  2. +28 −0 Gemfile.lock
  3. +4 −1 README.rdoc
  4. +3 −2 Rakefile
  5. +109 −0 lib/haversine.rb
  6. +20 −3 spec/haversine_spec.rb
View
@@ -6,7 +6,7 @@ source "http://rubygems.org"
# Add dependencies to develop your gem here.
# Include everything needed to run rake, tests, features, etc.
group :development do
- gem "rspec", "~> 2.3.0"
+ gem "rspec", ">= 2.3.0"
gem "bundler", "~> 1.0.0"
gem "jeweler", "~> 1.5.2"
gem "rcov", ">= 0"
View
@@ -0,0 +1,28 @@
+GEM
+ remote: http://rubygems.org/
+ specs:
+ diff-lcs (1.1.2)
+ git (1.2.5)
+ jeweler (1.5.2)
+ bundler (~> 1.0.0)
+ git (>= 1.2.5)
+ rake
+ rake (0.8.7)
+ rcov (0.9.9)
+ rspec (2.4.0)
+ rspec-core (~> 2.4.0)
+ rspec-expectations (~> 2.4.0)
+ rspec-mocks (~> 2.4.0)
+ rspec-core (2.4.0)
+ rspec-expectations (2.4.0)
+ diff-lcs (~> 1.1.2)
+ rspec-mocks (2.4.0)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ bundler (~> 1.0.0)
+ jeweler (~> 1.5.2)
+ rcov
+ rspec (>= 2.3.0)
View
@@ -1,6 +1,9 @@
= haversine
-Description goes here.
+Calculates the haversine distance between two locations using longitude and latitude.
+This is done using Math formulas without resorting to Active Record or SQL DB functionality
+
+This is meant to ba a replacement for all those geocode and geolocation utils out there that use built in SQL DB functionality for their calculations!
== Contributing to haversine
View
@@ -15,8 +15,9 @@ Jeweler::Tasks.new do |gem|
gem.name = "haversine"
gem.homepage = "http://github.com/kristianmandrup/haversine"
gem.license = "MIT"
- gem.summary = %Q{TODO: one-line summary of your gem}
- gem.description = %Q{TODO: longer description of your gem}
+ gem.summary = %Q{Calculates the haversine distance between two locations using longitude and latitude}
+ gem.description = %Q{Calculates the haversine distance between two locations using longitude and latitude.
+This is done using Math formulas without resorting to Active Record or SQL DB functionality}
gem.email = "kmandrup@gmail.com"
gem.authors = ["Kristian Mandrup"]
# Include your dependencies below. Runtime dependencies are required when using your gem,
View
@@ -0,0 +1,109 @@
+#
+# haversine formula to compute the great circle distance between two points given their latitude and longitudes
+#
+# Copyright (C) 2008, 360VL, Inc
+# Copyright (C) 2008, Landon Cox
+#
+# http://www.esawdust.com (Landon Cox)
+# contact:
+# http://www.esawdust.com/blog/businesscard/businesscard.html
+#
+# LICENSE: GNU Affero GPL v3
+# The ruby implementation of the Haversine formula is free software: you can redistribute it and/or modify
+# it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation.
+#
+# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
+# License version 3 for more details. http://www.gnu.org/licenses/
+#
+# Landon Cox - 9/25/08
+#
+# Notes:
+#
+# translated into Ruby based on information contained in:
+# http://mathforum.org/library/drmath/view/51879.html Doctors Rick and Peterson - 4/20/99
+# http://www.movable-type.co.uk/scripts/latlong.html
+# http://en.wikipedia.org/wiki/Haversine_formula
+#
+# This formula can compute accurate distances between two points given latitude and longitude, even for
+# short distances.
+
+# PI = 3.1415926535
+
+class Haversine
+
+ RAD_PER_DEG = 0.017453293 # PI/180
+
+ # the great circle distance d will be in whatever units R is in
+
+ Rmiles = 3956 # radius of the great circle in miles
+ Rkm = 6371 # radius in kilometers...some algorithms use 6367
+ Rfeet = Rmiles * 5282 # radius in feet
+ Rmeters = Rkm * 1000 # radius in meters
+
+ # this is global because if computing lots of track point distances, it didn't make
+ # sense to new a Hash each time over potentially 100's of thousands of points
+
+ class Distance
+ class << self
+
+ [:miles, :km, :feet, :meters].each do |unit|
+ class_eval %{
+ def in_#{unit} number
+ Unit.new :#{unit}, number
+ end
+ }
+ end
+ end
+
+ class Unit
+ attr_accessor :name, :number
+
+ def initialize name, number = 0
+ @name = name
+ @number = number
+ end
+
+ def to_s
+ "#{number} #{name}"
+ end
+ end
+ end
+
+ def self.distances
+ @distances ||= Hash.new
+ end
+
+ # given two lat/lon points, compute the distance between the two points using the haversine formula
+ # the result will be a Hash of distances which are key'd by 'mi','km','ft', and 'm'
+
+ def self.distance( lat1, lon1, lat2, lon2 )
+ dlon = lon2 - lon1
+ dlat = lat2 - lat1
+
+ dlon_rad = dlon * RAD_PER_DEG
+ dlat_rad = dlat * RAD_PER_DEG
+
+ lat1_rad = lat1 * RAD_PER_DEG
+ lon1_rad = lon1 * RAD_PER_DEG
+
+ lat2_rad = lat2 * RAD_PER_DEG
+ lon2_rad = lon2 * RAD_PER_DEG
+
+ # puts "dlon: #{dlon}, dlon_rad: #{dlon_rad}, dlat: #{dlat}, dlat_rad: #{dlat_rad}"
+
+ a = (Math.sin(dlat_rad/2))**2 + Math.cos(lat1_rad) * Math.cos(lat2_rad) * (Math.sin(dlon_rad/2))**2
+ c = 2 * Math.atan2( Math.sqrt(a), Math.sqrt(1-a))
+
+ dMi = Rmiles * c # delta between the two points in miles
+ dKm = Rkm * c # delta in kilometers
+ dFeet = Rfeet * c # delta in feet
+ dMeters = Rmeters * c # delta in meters
+
+ distances[:miles] = Distance.in_miles dMi
+ distances[:km] = Distance.in_km dKm
+ distances[:feet] = Distance.in_feet dFeet
+ distances[:meters] = Distance.in_meters dMeters
+ distances
+ end
+end
View
@@ -1,7 +1,24 @@
-require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
+require 'spec_helper'
describe "Haversine" do
- it "fails" do
- fail "hey buddy, you should probably rename this file and start specing for real"
+ it "should work" do
+ lon1 = -104.88544
+ lat1 = 39.06546
+
+ lon2 = -104.80
+ lat2 = lat1
+
+ dist = Haversine.distance( lat1, lon1, lat2, lon2 )
+
+ puts "the distance from #{lat1}, #{lon1} to #{lat2}, #{lon2} is:"
+
+ puts dist[:meters].number
+
+ puts "#{dist[:miles]}"
+ puts "#{dist[:km]}"
+ puts "#{dist[:feet]}"
+ puts "#{dist[:meters]}"
+
+ dist[:km].to_s.should match(/7\.376*/)
end
end

0 comments on commit 46c69f7

Please sign in to comment.