geodistance 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/README.markdown +3 -0
- data/Rakefile +1 -0
- data/geodistance.gemspec +22 -0
- data/lib/geodistance.rb +82 -0
- data/lib/geodistance/version.rb +3 -0
- data/spec/geodistance_spec.rb +129 -0
- metadata +67 -0
data/Gemfile
ADDED
data/README.markdown
ADDED
data/Rakefile
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'bundler/gem_tasks'
|
data/geodistance.gemspec
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
|
3
|
+
require "geodistance/version"
|
|
4
|
+
|
|
5
|
+
Gem::Specification.new do |s|
|
|
6
|
+
s.name = "geodistance"
|
|
7
|
+
s.version = Geodistance::VERSION
|
|
8
|
+
s.authors = ["Dennis Suratna"]
|
|
9
|
+
s.email = ["denniss@cal.berkeley.edu"]
|
|
10
|
+
s.homepage = ""
|
|
11
|
+
s.summary = %q{These are helper methods for doing any geolocation operation}
|
|
12
|
+
s.description = %q{Helper methods for calculating geolocation distance based on longitude and latitude. It will also have other methods that I feel are tedious and boring to re-write}
|
|
13
|
+
|
|
14
|
+
s.rubyforge_project = "geodistance"
|
|
15
|
+
|
|
16
|
+
s.files = `git ls-files`.split("\n")
|
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
19
|
+
s.require_paths = ["lib"]
|
|
20
|
+
|
|
21
|
+
s.add_development_dependency "rspec"
|
|
22
|
+
end
|
data/lib/geodistance.rb
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
require "geodistance/version"
|
|
2
|
+
|
|
3
|
+
module Geodistance
|
|
4
|
+
UNITS_OF_DISTANCE = [:mile, :kilometer]
|
|
5
|
+
EARTH_RADIUS_IN_MILE = 3959
|
|
6
|
+
EARTH_RADIUS_IN_KILOMETER = 6371
|
|
7
|
+
|
|
8
|
+
def haversine_distance(lon, lat)
|
|
9
|
+
distance_in_unit(haversine(lon, lat))
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def distance(lon, lat)
|
|
13
|
+
distance_in_unit(spherical_law_of_cosines(lon, lat))
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def distance_in_unit(delta_sigma_hat)
|
|
17
|
+
case __unit
|
|
18
|
+
when :mile
|
|
19
|
+
EARTH_RADIUS_IN_MILE * delta_sigma_hat
|
|
20
|
+
else
|
|
21
|
+
EARTH_RADIUS_IN_KILOMETER * delta_sigma_hat
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def haversine(lon, lat)
|
|
26
|
+
phi_s = to_rad __latitude
|
|
27
|
+
lambda_s = to_rad __longitude
|
|
28
|
+
phi_f = to_rad lat
|
|
29
|
+
lambda_f = to_rad lon
|
|
30
|
+
delta_lambda = (lambda_f - lambda_s).abs
|
|
31
|
+
delta_phi = (phi_f - phi_s).abs
|
|
32
|
+
|
|
33
|
+
a = Math.sin(delta_phi/2)**2
|
|
34
|
+
b = Math.cos(phi_s) * Math.cos(phi_f) * Math.sin(delta_lambda/2)**2
|
|
35
|
+
2 * Math.asin(Math.sqrt(a + b)) #delta sigma hat
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def spherical_law_of_cosines(lon, lat)
|
|
39
|
+
phi_s = to_rad __latitude
|
|
40
|
+
lambda_s = to_rad __longitude
|
|
41
|
+
phi_f = to_rad lat
|
|
42
|
+
lambda_f = to_rad lon
|
|
43
|
+
delta_lambda = (lambda_f - lambda_s).abs
|
|
44
|
+
|
|
45
|
+
Math.acos(Math.sin(phi_s) * Math.sin(phi_f) + Math.cos(phi_s) * Math.cos(phi_f) * Math.cos(delta_lambda))
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def __longitude
|
|
49
|
+
self.instance_variable_get("@#{self.class.instance_variable_get(:@longitude_attr)}".to_sym)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def __latitude
|
|
53
|
+
self.instance_variable_get("@#{self.class.instance_variable_get(:@latitude_attr)}".to_sym)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def __unit
|
|
57
|
+
self.class.instance_variable_get(:@unit_of_distance)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
module ClassMethods
|
|
61
|
+
def longitude_attr(name)
|
|
62
|
+
@longitude_attr = name
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def latitude_attr(name)
|
|
66
|
+
@latitude_attr = name
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def unit_of_distance(name)
|
|
70
|
+
raise "Unrecognize unit of distance #{name}. Use one of these: #{UNITS_OF_DISTANCE} " unless UNITS_OF_DISTANCE.include? name.to_sym
|
|
71
|
+
@unit_of_distance = name
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def self.included(base)
|
|
76
|
+
base.extend(ClassMethods)
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def to_rad(angle)
|
|
80
|
+
angle/180 * Math::PI
|
|
81
|
+
end
|
|
82
|
+
end
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
require File.expand_path('../../lib/geodistance.rb', __FILE__)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
describe Geodistance do
|
|
5
|
+
describe ".longitude_attr" do
|
|
6
|
+
it "should set the attribute to get the longitude" do
|
|
7
|
+
class TestClass
|
|
8
|
+
include Geodistance
|
|
9
|
+
longitude_attr :lon
|
|
10
|
+
end
|
|
11
|
+
TestClass.instance_variable_get(:@longitude_attr).should == :lon
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
describe ".latitude_attr" do
|
|
16
|
+
it "should set the attribute to get the latitude" do
|
|
17
|
+
class TestClass
|
|
18
|
+
include Geodistance
|
|
19
|
+
latitude_attr :lat
|
|
20
|
+
end
|
|
21
|
+
TestClass.instance_variable_get(:@latitude_attr).should == :lat
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
describe ".unit_of_distance" do
|
|
26
|
+
context "with invalid unit of distance" do
|
|
27
|
+
it "raises an error" do
|
|
28
|
+
lambda { Class.new do
|
|
29
|
+
include Geodistance
|
|
30
|
+
unit_of_distance :rofl
|
|
31
|
+
end }.should raise_error
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
context "with valid unit of distance" do
|
|
36
|
+
it "sets the instance variable with the right unit" do
|
|
37
|
+
class TestClass
|
|
38
|
+
include Geodistance
|
|
39
|
+
unit_of_distance :mile
|
|
40
|
+
end
|
|
41
|
+
TestClass.instance_variable_get(:@unit_of_distance).should == :mile
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
describe "longitude and latitude and unit" do
|
|
47
|
+
before do
|
|
48
|
+
class DummyClass
|
|
49
|
+
include Geodistance
|
|
50
|
+
latitude_attr :lat
|
|
51
|
+
longitude_attr :lon
|
|
52
|
+
unit_of_distance :mile
|
|
53
|
+
|
|
54
|
+
def initialize(lon, lat)
|
|
55
|
+
@lon = lon
|
|
56
|
+
@lat = lat
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
@dummy = DummyClass.new(30, 20)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "longitude returns the longitude" do
|
|
64
|
+
@dummy.__longitude.should == 30
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "latitude returns the latitude" do
|
|
68
|
+
@dummy.__latitude.should == 20
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
it "unit returns unit of distance" do
|
|
72
|
+
@dummy.__unit.should == :mile
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
describe "haversine_distance" do
|
|
77
|
+
before do
|
|
78
|
+
class DummyClass
|
|
79
|
+
include Geodistance
|
|
80
|
+
latitude_attr :lat
|
|
81
|
+
longitude_attr :lon
|
|
82
|
+
unit_of_distance :kilometer
|
|
83
|
+
|
|
84
|
+
def initialize(lon, lat)
|
|
85
|
+
@lon = lon
|
|
86
|
+
@lat = lat
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
lon_s = -22.534 #22 32 2 W
|
|
90
|
+
lat_s = 40.512 #40 30 43 N
|
|
91
|
+
|
|
92
|
+
@dummy = DummyClass.new(lon_s, lat_s)
|
|
93
|
+
|
|
94
|
+
@lon_f = 53.456 #53 27 22 E
|
|
95
|
+
@lat_f = 62.123 #62 7 23 N
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
it "gives right distance" do
|
|
99
|
+
@dummy.haversine_distance(@lon_f, @lat_f).should be_within(1).of(5413)
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
describe "distance" do
|
|
104
|
+
before do
|
|
105
|
+
class DummyClass
|
|
106
|
+
include Geodistance
|
|
107
|
+
latitude_attr :lat
|
|
108
|
+
longitude_attr :lon
|
|
109
|
+
unit_of_distance :kilometer
|
|
110
|
+
|
|
111
|
+
def initialize(lon, lat)
|
|
112
|
+
@lon = lon
|
|
113
|
+
@lat = lat
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
lon_s = -86.67
|
|
117
|
+
lat_s = 36.12
|
|
118
|
+
|
|
119
|
+
@dummy = DummyClass.new(lon_s, lat_s)
|
|
120
|
+
|
|
121
|
+
@lon_f = -118.40
|
|
122
|
+
@lat_f = 33.94
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "gives right distance" do
|
|
126
|
+
@dummy.distance(@lon_f, @lat_f).should be_within(1).of(2887)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: geodistance
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.0.1
|
|
5
|
+
prerelease:
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- Dennis Suratna
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2012-01-31 00:00:00.000000000Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: rspec
|
|
16
|
+
requirement: &2152693500 !ruby/object:Gem::Requirement
|
|
17
|
+
none: false
|
|
18
|
+
requirements:
|
|
19
|
+
- - ! '>='
|
|
20
|
+
- !ruby/object:Gem::Version
|
|
21
|
+
version: '0'
|
|
22
|
+
type: :development
|
|
23
|
+
prerelease: false
|
|
24
|
+
version_requirements: *2152693500
|
|
25
|
+
description: Helper methods for calculating geolocation distance based on longitude
|
|
26
|
+
and latitude. It will also have other methods that I feel are tedious and boring
|
|
27
|
+
to re-write
|
|
28
|
+
email:
|
|
29
|
+
- denniss@cal.berkeley.edu
|
|
30
|
+
executables: []
|
|
31
|
+
extensions: []
|
|
32
|
+
extra_rdoc_files: []
|
|
33
|
+
files:
|
|
34
|
+
- .gitignore
|
|
35
|
+
- Gemfile
|
|
36
|
+
- README.markdown
|
|
37
|
+
- Rakefile
|
|
38
|
+
- geodistance.gemspec
|
|
39
|
+
- lib/geodistance.rb
|
|
40
|
+
- lib/geodistance/version.rb
|
|
41
|
+
- spec/geodistance_spec.rb
|
|
42
|
+
homepage: ''
|
|
43
|
+
licenses: []
|
|
44
|
+
post_install_message:
|
|
45
|
+
rdoc_options: []
|
|
46
|
+
require_paths:
|
|
47
|
+
- lib
|
|
48
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
49
|
+
none: false
|
|
50
|
+
requirements:
|
|
51
|
+
- - ! '>='
|
|
52
|
+
- !ruby/object:Gem::Version
|
|
53
|
+
version: '0'
|
|
54
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
55
|
+
none: false
|
|
56
|
+
requirements:
|
|
57
|
+
- - ! '>='
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: '0'
|
|
60
|
+
requirements: []
|
|
61
|
+
rubyforge_project: geodistance
|
|
62
|
+
rubygems_version: 1.8.15
|
|
63
|
+
signing_key:
|
|
64
|
+
specification_version: 3
|
|
65
|
+
summary: These are helper methods for doing any geolocation operation
|
|
66
|
+
test_files:
|
|
67
|
+
- spec/geodistance_spec.rb
|