geo-distance 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ lib/**/*.rb
2
+ bin/*
3
+ -
4
+ features/**/*.feature
5
+ LICENSE.txt
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+ # Add dependencies required to use your gem here.
3
+ # Example:
4
+ # gem "activesupport", ">= 2.3.5"
5
+
6
+ # Add dependencies to develop your gem here.
7
+ # Include everything needed to run rake, tests, features, etc.
8
+ group :development do
9
+ gem "rspec", ">= 2.3.0"
10
+ gem "bundler", "~> 1.0.0"
11
+ gem "jeweler", "~> 1.5.2"
12
+ gem "rcov", ">= 0"
13
+ end
data/Gemfile.lock ADDED
@@ -0,0 +1,28 @@
1
+ GEM
2
+ remote: http://rubygems.org/
3
+ specs:
4
+ diff-lcs (1.1.2)
5
+ git (1.2.5)
6
+ jeweler (1.5.2)
7
+ bundler (~> 1.0.0)
8
+ git (>= 1.2.5)
9
+ rake
10
+ rake (0.8.7)
11
+ rcov (0.9.9)
12
+ rspec (2.4.0)
13
+ rspec-core (~> 2.4.0)
14
+ rspec-expectations (~> 2.4.0)
15
+ rspec-mocks (~> 2.4.0)
16
+ rspec-core (2.4.0)
17
+ rspec-expectations (2.4.0)
18
+ diff-lcs (~> 1.1.2)
19
+ rspec-mocks (2.4.0)
20
+
21
+ PLATFORMS
22
+ ruby
23
+
24
+ DEPENDENCIES
25
+ bundler (~> 1.0.0)
26
+ jeweler (~> 1.5.2)
27
+ rcov
28
+ rspec (>= 2.3.0)
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Kristian Mandrup
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.textile ADDED
@@ -0,0 +1,63 @@
1
+ h1. GeoDistance - geo distance calculations
2
+
3
+ Calculates the Geo distance between two locations using longitude and latitude.
4
+ This is done using "pure" Math formulas without resorting to Active Record or SQL DB functionality
5
+
6
+ This gem is meant to be a replacement for those geo distance utils out there that use built in SQL DB functionality for their calculations!
7
+
8
+ The formulas curently supported are
9
+
10
+ * _Haversine_
11
+ * _Spherical_
12
+ * _Vincenty_
13
+
14
+ h2. Install & Usage
15
+
16
+ <pre>require 'geo-distance'
17
+
18
+ it "should work" do
19
+ lon1 = -104.88544
20
+ lat1 = 39.06546
21
+
22
+ lon2 = -104.80
23
+ lat2 = lat1
24
+
25
+ dist = GeoDistance::Haversine.distance( lat1, lon1, lat2, lon2 )
26
+
27
+ puts "the distance from #{lat1}, #{lon1} to #{lat2}, #{lon2} is: #{dist[:meters].number} meters"
28
+
29
+ puts "#{dist[:feet]}"
30
+ puts "#{dist.meters}"
31
+ puts "#{dist[:km]}"
32
+ puts "#{dist[:miles]}"
33
+ dist[:km].to_s.should match(/7\.376*/)
34
+ end
35
+ </pre>
36
+
37
+ h3. Setting default algorithm
38
+
39
+ You can also set a default algorithm to use...
40
+ The following will use the _Haversine_ algorithm:
41
+
42
+ <pre>
43
+ GeoDistance.default_algorithm = :haversine
44
+ dist = GeoDistance.distance( lat1, lon1, lat2, lon2 )
45
+ </pre>
46
+
47
+ GeoDistance is used in the "geo_magic":https://github.com/kristianmandrup/geo_magic gem
48
+
49
+ h2. Contributing to geo-distance
50
+
51
+ * Check out the specs and add specs to spec any added features or changes!
52
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
53
+ * Fork the project
54
+ * Start a feature/bugfix branch
55
+ * Commit and push until you are happy with your contribution
56
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
57
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
58
+
59
+ h2. Copyright
60
+
61
+ Copyright (c) 2011 Kristian Mandrup. See LICENSE.txt for
62
+ further details.
63
+
data/Rakefile ADDED
@@ -0,0 +1,51 @@
1
+ require 'rubygems'
2
+ require 'bundler'
3
+ begin
4
+ Bundler.setup(:default, :development)
5
+ rescue Bundler::BundlerError => e
6
+ $stderr.puts e.message
7
+ $stderr.puts "Run `bundle install` to install missing gems"
8
+ exit e.status_code
9
+ end
10
+ require 'rake'
11
+
12
+ require 'jeweler'
13
+ Jeweler::Tasks.new do |gem|
14
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
15
+ gem.name = "geo-distance"
16
+ gem.homepage = "http://github.com/kristianmandrup/geo-distance"
17
+ gem.license = "MIT"
18
+ gem.summary = %Q{Calculates the geo distance between two locations using longitude and latitude, using Haversine, Speherical or Vincenty formula}
19
+ gem.description = %Q{Calculates the geo distance between two locations using longitude and latitude using Haversine, Speherical or Vincenty formula.
20
+ This is done using Math formulas without resorting to Active Record or SQL DB functionality}
21
+ gem.email = "kmandrup@gmail.com"
22
+ gem.authors = ["Kristian Mandrup"]
23
+ # Include your dependencies below. Runtime dependencies are required when using your gem,
24
+ # and development dependencies are only needed for development (ie running rake tasks, tests, etc)
25
+ # gem.add_runtime_dependency 'jabber4r', '> 0.1'
26
+ # gem.add_development_dependency 'rspec', '> 1.2.3'
27
+ end
28
+ Jeweler::RubygemsDotOrgTasks.new
29
+
30
+ require 'rspec/core'
31
+ require 'rspec/core/rake_task'
32
+ RSpec::Core::RakeTask.new(:spec) do |spec|
33
+ spec.pattern = FileList['spec/**/*_spec.rb']
34
+ end
35
+
36
+ RSpec::Core::RakeTask.new(:rcov) do |spec|
37
+ spec.pattern = 'spec/**/*_spec.rb'
38
+ spec.rcov = true
39
+ end
40
+
41
+ task :default => :spec
42
+
43
+ require 'rake/rdoctask'
44
+ Rake::RDocTask.new do |rdoc|
45
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
46
+
47
+ rdoc.rdoc_dir = 'rdoc'
48
+ rdoc.title = "geo-distance #{version}"
49
+ rdoc.rdoc_files.include('README*')
50
+ rdoc.rdoc_files.include('lib/**/*.rb')
51
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.2
@@ -0,0 +1,79 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{geo-distance}
8
+ s.version = "0.1.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Kristian Mandrup"]
12
+ s.date = %q{2011-01-14}
13
+ s.description = %q{Calculates the geo distance between two locations using longitude and latitude using Haversine, Speherical or Vincenty formula.
14
+ This is done using Math formulas without resorting to Active Record or SQL DB functionality}
15
+ s.email = %q{kmandrup@gmail.com}
16
+ s.extra_rdoc_files = [
17
+ "LICENSE.txt",
18
+ "README.textile"
19
+ ]
20
+ s.files = [
21
+ ".document",
22
+ ".rspec",
23
+ "Gemfile",
24
+ "Gemfile.lock",
25
+ "LICENSE.txt",
26
+ "README.textile",
27
+ "Rakefile",
28
+ "VERSION",
29
+ "geo-distance.gemspec",
30
+ "lib/geo-distance.rb",
31
+ "lib/geo-distance/core_ext.rb",
32
+ "lib/geo-distance/formula.rb",
33
+ "lib/geo-distance/haversine.rb",
34
+ "lib/geo-distance/spherical.rb",
35
+ "lib/geo-distance/vincenty.rb",
36
+ "spec/core_ext_spec.rb",
37
+ "spec/dist_default_spec.rb",
38
+ "spec/dist_haversine_spec.rb",
39
+ "spec/dist_spherical_spec.rb",
40
+ "spec/dist_vincenty_spec.rb",
41
+ "spec/spec_helper.rb"
42
+ ]
43
+ s.homepage = %q{http://github.com/kristianmandrup/geo-distance}
44
+ s.licenses = ["MIT"]
45
+ s.require_paths = ["lib"]
46
+ s.rubygems_version = %q{1.3.7}
47
+ s.summary = %q{Calculates the geo distance between two locations using longitude and latitude, using Haversine, Speherical or Vincenty formula}
48
+ s.test_files = [
49
+ "spec/core_ext_spec.rb",
50
+ "spec/dist_default_spec.rb",
51
+ "spec/dist_haversine_spec.rb",
52
+ "spec/dist_spherical_spec.rb",
53
+ "spec/dist_vincenty_spec.rb",
54
+ "spec/spec_helper.rb"
55
+ ]
56
+
57
+ if s.respond_to? :specification_version then
58
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
59
+ s.specification_version = 3
60
+
61
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
62
+ s.add_development_dependency(%q<rspec>, [">= 2.3.0"])
63
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
64
+ s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
65
+ s.add_development_dependency(%q<rcov>, [">= 0"])
66
+ else
67
+ s.add_dependency(%q<rspec>, [">= 2.3.0"])
68
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
69
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
70
+ s.add_dependency(%q<rcov>, [">= 0"])
71
+ end
72
+ else
73
+ s.add_dependency(%q<rspec>, [">= 2.3.0"])
74
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
75
+ s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
76
+ s.add_dependency(%q<rcov>, [">= 0"])
77
+ end
78
+ end
79
+
@@ -0,0 +1,136 @@
1
+ module GeoDistance
2
+ # this is global because if computing lots of track point distances, it didn't make
3
+ # sense to new a Hash each time over potentially 100's of thousands of points
4
+
5
+ class << self
6
+ # radius of the great circle in miles
7
+ # radius in kilometers...some algorithms use 6367
8
+ def earth_radius
9
+ {:km => 6371, :miles => 3956, :feet => 20895592, :meters => 6371000}
10
+ end
11
+
12
+ def radians_per_degree
13
+ 0.017453293 # PI/180
14
+ end
15
+
16
+ def units
17
+ [:miles, :km, :feet, :meters]
18
+ end
19
+
20
+ def radians_ratio unit
21
+ GeoDistance.radians_per_degree * earth_radius[unit]
22
+ end
23
+
24
+ def default_algorithm= name
25
+ raise ArgumentError, "Not a valid algorithm. Must be one of: #{algorithms}" if !algorithms.include?(name.to_sym)
26
+ @default_algorithm = name
27
+ end
28
+
29
+ def distance( lat1, lon1, lat2, lon2)
30
+ klass = case default_algorithm
31
+ when :haversine
32
+ GeoDistance::Haversine
33
+ when :spherical
34
+ GeoDistance::Spherical
35
+ when :vincenty
36
+ GeoDistance::Vincenty
37
+ else
38
+ raise ArgumentError, "Not a valid algorithm. Must be one of: #{algorithms}"
39
+ end
40
+ klass.distance lat1, lon1, lat2, lon2
41
+ end
42
+
43
+ def default_algorithm
44
+ @default_algorithm || :haversine
45
+ end
46
+
47
+ protected
48
+
49
+ def algorithms
50
+ [:haversine, :spherical, :vincenty]
51
+ end
52
+ end
53
+
54
+ class Distance
55
+ attr_reader :distance, :unit
56
+
57
+ def initialize distance, unit = nil
58
+ @distance = distance
59
+ return if !unit
60
+
61
+ raise ArgumentError, "Invalid unit: #{unit} - must be one of #{GeoDistance.units}" if !GeoDistance.units.include?(unit.to_sym)
62
+ @unit = unit.to_sym
63
+ end
64
+
65
+ def [] key
66
+ method = :"delta_#{key}"
67
+ raise ArgumentError, "Invalid unit key #{key}" if !respond_to? method
68
+ Distance.send "in_#{key}", send(method)
69
+ end
70
+
71
+ GeoDistance.units.each do |unit|
72
+ class_eval %{
73
+ def #{unit}
74
+ self[:#{unit}]
75
+ end
76
+ }
77
+ end
78
+
79
+ protected
80
+
81
+ # delta between the two points in miles
82
+ GeoDistance.units.each do |unit|
83
+ class_eval %{
84
+ def delta_#{unit}
85
+ GeoDistance.earth_radius[:#{unit}] * distance
86
+ end
87
+ }
88
+ end
89
+
90
+ class << self
91
+ GeoDistance.units.each do |unit|
92
+ class_eval %{
93
+ def in_#{unit} number
94
+ Unit.new :#{unit}, number
95
+ end
96
+ }
97
+ end
98
+ end
99
+
100
+ class Unit
101
+ attr_accessor :name, :number
102
+
103
+ def initialize name, number = 0
104
+ @name = name
105
+ @number = number
106
+ end
107
+
108
+ def number
109
+ @number.round_to(precision[name])
110
+ end
111
+
112
+ def to_s
113
+ "#{number} #{name}"
114
+ end
115
+
116
+ private
117
+
118
+ def precision
119
+ {
120
+ :feet => 0,
121
+ :meters => 2,
122
+ :km => 4,
123
+ :miles => 4
124
+ }
125
+ end
126
+ end
127
+ end
128
+
129
+ def self.wants? unit_opts, unit
130
+ unit_opts == unit || unit_opts[unit]
131
+ end
132
+ end
133
+
134
+ require 'geo-distance/haversine'
135
+ require 'geo-distance/spherical'
136
+ require 'geo-distance/vincenty'
@@ -0,0 +1,31 @@
1
+ class Float
2
+ def round_to(x)
3
+ (self * 10**x).round.to_f / 10**x
4
+ end
5
+
6
+ def ceil_to(x)
7
+ (self * 10**x).ceil.to_f / 10**x
8
+ end
9
+
10
+ def floor_to(x)
11
+ (self * 10**x).floor.to_f / 10**x
12
+ end
13
+
14
+ def rpd
15
+ self * GeoDistance.radians_per_degree
16
+ end
17
+ alias_method :to_radians, :rpd
18
+ end
19
+
20
+ require 'geo-distance'
21
+
22
+ class Integer
23
+ ::GeoDistance.units.each do |unit|
24
+ class_eval %{
25
+ def #{unit}
26
+ GeoDistance::Distance.new(self, :#{unit})
27
+ end
28
+ }
29
+ end
30
+ end
31
+
@@ -0,0 +1,16 @@
1
+ module GeoDistance
2
+ EARTH_RADIUS = { :kilometers => 6378.135, :miles => 3963.1676 }
3
+ # WGS-84 numbers
4
+ EARTH_MAJOR_AXIS_RADIUS = { :kilometers => 6378.137, :miles => 3963.19059 }
5
+ EARTH_MINOR_AXIS_RADIUS = { :kilometers => 6356.7523142, :miles => 3949.90276 }
6
+
7
+ class DistanceFormula
8
+ include Math
9
+ extend Math
10
+
11
+ def initialize
12
+ raise NotImplementedError
13
+ end
14
+ end
15
+ end
16
+
@@ -0,0 +1,56 @@
1
+ #
2
+ # haversine formula to compute the great circle distance between two points given their latitude and longitudes
3
+ #
4
+ # Copyright (C) 2008, 360VL, Inc
5
+ # Copyright (C) 2008, Landon Cox
6
+ #
7
+ # http://www.esawdust.com (Landon Cox)
8
+ # contact:
9
+ # http://www.esawdust.com/blog/businesscard/businesscard.html
10
+ #
11
+ # LICENSE: GNU Affero GPL v3
12
+ # The ruby implementation of the Haversine formula is free software: you can redistribute it and/or modify
13
+ # it under the terms of the GNU Affero General Public License version 3 as published by the Free Software Foundation.
14
+ #
15
+ # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the
16
+ # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
17
+ # License version 3 for more details. http://www.gnu.org/licenses/
18
+ #
19
+ # Landon Cox - 9/25/08
20
+ #
21
+ # Notes:
22
+ #
23
+ # translated into Ruby based on information contained in:
24
+ # http://mathforum.org/library/drmath/view/51879.html Doctors Rick and Peterson - 4/20/99
25
+ # http://www.movable-type.co.uk/scripts/latlong.html
26
+ # http://en.wikipedia.org/wiki/Haversine_formula
27
+ #
28
+ # This formula can compute accurate distances between two points given latitude and longitude, even for
29
+ # short distances.
30
+
31
+ # PI = 3.1415926535
32
+
33
+ require 'geo-distance/core_ext'
34
+ require 'geo-distance/formula'
35
+
36
+ module GeoDistance
37
+ class Haversine < DistanceFormula
38
+ # given two lat/lon points, compute the distance between the two points using the haversine formula
39
+ # the result will be a Hash of distances which are key'd by 'mi','km','ft', and 'm'
40
+
41
+ def self.distance( lat1, lon1, lat2, lon2)
42
+ dlon = lon2 - lon1
43
+ dlat = lat2 - lat1
44
+
45
+ a = calc(dlat, lat1, lat2, dlon)
46
+ c = 2 * Math.atan2( Math.sqrt(a), Math.sqrt(1-a))
47
+
48
+ GeoDistance::Distance.new c
49
+ end
50
+
51
+ def self.calc dlat, lat1, lat2, dlon
52
+ (Math.sin(dlat.rpd/2))**2 + Math.cos(lat1.rpd) * Math.cos((lat2.rpd)) * (Math.sin(dlon.rpd/2))**2
53
+ end
54
+ end
55
+
56
+ end
@@ -0,0 +1,24 @@
1
+ require 'geo-distance/core_ext'
2
+ require 'geo-distance/formula'
3
+
4
+ module GeoDistance
5
+ class Spherical < DistanceFormula
6
+ def self.distance( lat1, lon1, lat2, lon2)
7
+ from_longitude = lon1.to_radians
8
+ from_latitude = lat1.to_radians
9
+ to_longitude = lon2.to_radians
10
+ to_latitude = lat2.to_radians
11
+
12
+ c = Math.acos(
13
+ Math.sin(from_latitude) *
14
+ Math.sin(to_latitude) +
15
+
16
+ Math.cos(from_latitude) *
17
+ Math.cos(to_latitude) *
18
+ Math.cos(to_longitude - from_longitude)
19
+ ) #* EARTH_RADIUS[units.to_sym]
20
+
21
+ GeoDistance::Distance.new c
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,79 @@
1
+ require 'geo-distance/core_ext'
2
+ require 'geo-distance/formula'
3
+
4
+ module GeoDistance
5
+ class Vincenty < DistanceFormula
6
+
7
+ # Calculate the distance between two Locations using the Vincenty formula
8
+ #
9
+ # Graticule::Distance::Vincenty.distance(
10
+ # Graticule::Location.new(:latitude => 42.7654, :longitude => -86.1085),
11
+ # Graticule::Location.new(:latitude => 41.849838, :longitude => -87.648193)
12
+ # )
13
+ # #=> 101.070118000159
14
+ #
15
+ def self.distance(lat1, lon1, lat2, lon2)
16
+ from_longitude = lon1.to_radians
17
+ from_latitude = lat1.to_radians
18
+ to_longitude = lon2.to_radians
19
+ to_latitude = lat2.to_radians
20
+
21
+ earth_major_axis_radius = EARTH_MAJOR_AXIS_RADIUS[:kilometers]
22
+ earth_minor_axis_radius = EARTH_MINOR_AXIS_RADIUS[:kilometers]
23
+
24
+ f = (earth_major_axis_radius - earth_minor_axis_radius) / earth_major_axis_radius
25
+
26
+ l = to_longitude - from_longitude
27
+ u1 = atan((1-f) * tan(from_latitude))
28
+ u2 = atan((1-f) * tan(to_latitude))
29
+ sin_u1 = sin(u1)
30
+ cos_u1 = cos(u1)
31
+ sin_u2 = sin(u2)
32
+ cos_u2 = cos(u2)
33
+
34
+ lambda = l
35
+ lambda_p = 2 * PI
36
+ iteration_limit = 20
37
+ while (lambda-lambda_p).abs > 1e-12 && (iteration_limit -= 1) > 0
38
+ sin_lambda = sin(lambda)
39
+ cos_lambda = cos(lambda)
40
+ sin_sigma = sqrt((cos_u2*sin_lambda) * (cos_u2*sin_lambda) +
41
+ (cos_u1*sin_u2-sin_u1*cos_u2*cos_lambda) * (cos_u1*sin_u2-sin_u1*cos_u2*cos_lambda))
42
+ return 0 if sin_sigma == 0 # co-incident points
43
+ cos_sigma = sin_u1*sin_u2 + cos_u1*cos_u2*cos_lambda
44
+ sigma = atan2(sin_sigma, cos_sigma)
45
+ sin_alpha = cos_u1 * cos_u2 * sin_lambda / sin_sigma
46
+ cosSqAlpha = 1 - sin_alpha*sin_alpha
47
+ cos2SigmaM = cos_sigma - 2*sin_u1*sin_u2/cosSqAlpha
48
+
49
+ cos2SigmaM = 0 if cos2SigmaM.nan? # equatorial line: cosSqAlpha=0 (§6)
50
+
51
+ c = f/16*cosSqAlpha*(4+f*(4-3*cosSqAlpha))
52
+ lambda_p = lambda
53
+ lambda = l + (1-c) * f * sin_alpha *
54
+ (sigma + c*sin_sigma*(cos2SigmaM+c*cos_sigma*(-1+2*cos2SigmaM*cos2SigmaM)))
55
+ end
56
+ # formula failed to converge (happens on antipodal points)
57
+ # We'll call Haversine formula instead.
58
+ return Haversine.distance(from, to, units) if iteration_limit == 0
59
+
60
+ uSq = cosSqAlpha * (earth_major_axis_radius**2 - earth_minor_axis_radius**2) / (earth_minor_axis_radius**2)
61
+ a = 1 + uSq/16384*(4096+uSq*(-768+uSq*(320-175*uSq)))
62
+ b = uSq/1024 * (256+uSq*(-128+uSq*(74-47*uSq)))
63
+ delta_sigma = b*sin_sigma*(cos2SigmaM+b/4*(cos_sigma*(-1+2*cos2SigmaM*cos2SigmaM)-
64
+ b/6*cos2SigmaM*(-3+4*sin_sigma*sin_sigma)*(-3+4*cos2SigmaM*cos2SigmaM)))
65
+
66
+ c = earth_minor_axis_radius * a * (sigma-delta_sigma)
67
+
68
+ GeoDistance::Distance.new(c / unkilometer)
69
+ end
70
+
71
+ private
72
+
73
+ def self.unkilometer
74
+ 6378.135
75
+ end
76
+
77
+
78
+ end
79
+ end
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe "GeoDistance core extensions" do
4
+ it "should work" do
5
+ 5.km.should be_kind_of GeoDistance::Distance
6
+ 5.km.distance.should == 5
7
+ 5.km.unit.should == :km
8
+ end
9
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe "GeoDistance default" do
4
+ it "should work" do
5
+ lon1 = -104.88544
6
+ lat1 = 39.06546
7
+
8
+ lon2 = -104.80
9
+ lat2 = lat1
10
+
11
+ GeoDistance.default_algorithm = :haversine
12
+
13
+ dist = GeoDistance.distance( lat1, lon1, lat2, lon2 )
14
+
15
+ puts "the distance from #{lat1}, #{lon1} to #{lat2}, #{lon2} is: #{dist[:meters].number} meters"
16
+
17
+ puts "#{dist[:feet]}"
18
+ puts "#{dist.meters}"
19
+ puts "#{dist[:km]}"
20
+ puts "#{dist[:miles]}"
21
+ dist[:km].to_s.should match(/7\.376*/)
22
+ end
23
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe "GeoDistance::Haversine" do
4
+ it "should work" do
5
+ lon1 = -104.88544
6
+ lat1 = 39.06546
7
+
8
+ lon2 = -104.80
9
+ lat2 = lat1
10
+
11
+ dist = GeoDistance::Haversine.distance( lat1, lon1, lat2, lon2 )
12
+
13
+ puts "the distance from #{lat1}, #{lon1} to #{lat2}, #{lon2} is: #{dist[:meters].number} meters"
14
+
15
+ puts "#{dist[:feet]}"
16
+ puts "#{dist.meters}"
17
+ puts "#{dist[:km]}"
18
+ puts "#{dist[:miles]}"
19
+ dist[:km].to_s.should match(/7\.376*/)
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe "GeoDistance::Spherical" do
4
+ it "should work" do
5
+ lon1 = -104.88544
6
+ lat1 = 39.06546
7
+
8
+ lon2 = -104.80
9
+ lat2 = lat1
10
+
11
+ dist = GeoDistance::Spherical.distance( lat1, lon1, lat2, lon2 )
12
+
13
+ puts "the distance from #{lat1}, #{lon1} to #{lat2}, #{lon2} is: #{dist[:meters].number} meters"
14
+
15
+ puts "#{dist[:feet]}"
16
+ puts "#{dist.meters}"
17
+ puts "#{dist[:km]}"
18
+ puts "#{dist[:miles]}"
19
+ dist[:km].to_s.should match(/7\.376*/)
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ describe "GeoDistance::Vincenty" do
4
+ it "should work" do
5
+ lon1 = -104.88544
6
+ lat1 = 39.06546
7
+
8
+ lon2 = -104.80
9
+ lat2 = lat1
10
+
11
+ dist = GeoDistance::Vincenty.distance( lat1, lon1, lat2, lon2 )
12
+
13
+ puts "the distance from #{lat1}, #{lon1} to #{lat2}, #{lon2} is: #{dist[:meters].number} meters"
14
+
15
+ puts "#{dist[:feet]}"
16
+ puts "#{dist.meters}"
17
+ puts "#{dist[:km]}"
18
+ puts "#{dist[:miles]}"
19
+ dist[:km].to_s.should match(/7\.38*/)
20
+ end
21
+ end
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
3
+ require 'rspec'
4
+ require 'geo-distance'
5
+
6
+ # Requires supporting files with custom matchers and macros, etc,
7
+ # in ./support/ and its subdirectories.
8
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
9
+
10
+ RSpec.configure do |config|
11
+
12
+ end
metadata ADDED
@@ -0,0 +1,150 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: geo-distance
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 2
9
+ version: 0.1.2
10
+ platform: ruby
11
+ authors:
12
+ - Kristian Mandrup
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2011-01-14 00:00:00 +01:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rspec
22
+ requirement: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 2
29
+ - 3
30
+ - 0
31
+ version: 2.3.0
32
+ type: :development
33
+ prerelease: false
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: bundler
37
+ requirement: &id002 !ruby/object:Gem::Requirement
38
+ none: false
39
+ requirements:
40
+ - - ~>
41
+ - !ruby/object:Gem::Version
42
+ segments:
43
+ - 1
44
+ - 0
45
+ - 0
46
+ version: 1.0.0
47
+ type: :development
48
+ prerelease: false
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: jeweler
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ none: false
54
+ requirements:
55
+ - - ~>
56
+ - !ruby/object:Gem::Version
57
+ segments:
58
+ - 1
59
+ - 5
60
+ - 2
61
+ version: 1.5.2
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ name: rcov
67
+ requirement: &id004 !ruby/object:Gem::Requirement
68
+ none: false
69
+ requirements:
70
+ - - ">="
71
+ - !ruby/object:Gem::Version
72
+ segments:
73
+ - 0
74
+ version: "0"
75
+ type: :development
76
+ prerelease: false
77
+ version_requirements: *id004
78
+ description: |-
79
+ Calculates the geo distance between two locations using longitude and latitude using Haversine, Speherical or Vincenty formula.
80
+ This is done using Math formulas without resorting to Active Record or SQL DB functionality
81
+ email: kmandrup@gmail.com
82
+ executables: []
83
+
84
+ extensions: []
85
+
86
+ extra_rdoc_files:
87
+ - LICENSE.txt
88
+ - README.textile
89
+ files:
90
+ - .document
91
+ - .rspec
92
+ - Gemfile
93
+ - Gemfile.lock
94
+ - LICENSE.txt
95
+ - README.textile
96
+ - Rakefile
97
+ - VERSION
98
+ - geo-distance.gemspec
99
+ - lib/geo-distance.rb
100
+ - lib/geo-distance/core_ext.rb
101
+ - lib/geo-distance/formula.rb
102
+ - lib/geo-distance/haversine.rb
103
+ - lib/geo-distance/spherical.rb
104
+ - lib/geo-distance/vincenty.rb
105
+ - spec/core_ext_spec.rb
106
+ - spec/dist_default_spec.rb
107
+ - spec/dist_haversine_spec.rb
108
+ - spec/dist_spherical_spec.rb
109
+ - spec/dist_vincenty_spec.rb
110
+ - spec/spec_helper.rb
111
+ has_rdoc: true
112
+ homepage: http://github.com/kristianmandrup/geo-distance
113
+ licenses:
114
+ - MIT
115
+ post_install_message:
116
+ rdoc_options: []
117
+
118
+ require_paths:
119
+ - lib
120
+ required_ruby_version: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ">="
124
+ - !ruby/object:Gem::Version
125
+ hash: 1850876785159146324
126
+ segments:
127
+ - 0
128
+ version: "0"
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ none: false
131
+ requirements:
132
+ - - ">="
133
+ - !ruby/object:Gem::Version
134
+ segments:
135
+ - 0
136
+ version: "0"
137
+ requirements: []
138
+
139
+ rubyforge_project:
140
+ rubygems_version: 1.3.7
141
+ signing_key:
142
+ specification_version: 3
143
+ summary: Calculates the geo distance between two locations using longitude and latitude, using Haversine, Speherical or Vincenty formula
144
+ test_files:
145
+ - spec/core_ext_spec.rb
146
+ - spec/dist_default_spec.rb
147
+ - spec/dist_haversine_spec.rb
148
+ - spec/dist_spherical_spec.rb
149
+ - spec/dist_vincenty_spec.rb
150
+ - spec/spec_helper.rb