andre-geokit 1.2.0 → 1.2.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/Manifest.txt CHANGED
@@ -1,17 +1,17 @@
1
- .loadpath
2
1
  .project
3
2
  Manifest.txt
4
3
  README.markdown
5
4
  Rakefile
6
5
  geokit.gemspec
7
- lib/geokit/geocoders.rb
8
6
  lib/geokit.rb
7
+ lib/geokit/geocoders.rb
9
8
  lib/geokit/mappable.rb
10
9
  test/test_base_geocoder.rb
11
10
  test/test_bounds.rb
12
11
  test/test_ca_geocoder.rb
13
12
  test/test_geoloc.rb
14
13
  test/test_google_geocoder.rb
14
+ test/test_google_reverse_geocoder.rb
15
15
  test/test_ipgeocoder.rb
16
16
  test/test_latlng.rb
17
17
  test/test_multi_geocoder.rb
data/README.markdown CHANGED
@@ -1,12 +1,13 @@
1
1
  # Geokit gem
2
2
 
3
- [http://geokit.rubyforge.org](http://geokit.rubyforge.org)
3
+ * Geokit Documentation at Rubyforge [http://geokit.rubyforge.org](http://geokit.rubyforge.org).
4
+ * Repository at Github: [http://github.com/andre/geokit-gem/tree/master](http://github.com/andre/geokit-gem/tree/master).
4
5
 
5
6
  ## DESCRIPTION:
6
7
 
7
8
  The Geokit gem provides the following:
8
9
 
9
- * Distance calculations between two points on the earth. Calculate the distance in miles or KM, with all the trigonometry abstracted away by GeoKit.
10
+ * Distance calculations between two points on the earth. Calculate the distance in miles, kilometers, or nautical miles, with all the trigonometry abstracted away by GeoKit.
10
11
  * Geocoding from multiple providers. It currently supports Google, Yahoo, Geocoder.us, and Geocoder.ca geocoders, and it provides a uniform response structure from all of them. It also provides a fail-over mechanism, in case your input fails to geocode in one service.
11
12
  * Rectangular bounds calculations: is a point within a given rectangular bounds?
12
13
  * Heading and midpoint calculations
@@ -36,10 +37,12 @@ Combine this with gem with the [geokit-rails plugin](http://github.com/andre/geo
36
37
 
37
38
  FYI, that `.ll` method means "latitude longitude".
38
39
 
40
+ See the RDOC more more ... there is also operations on rectangular bounds (e.g., determining if a point is within bounds, find the center, etc).
41
+
39
42
  ## INSTALL:
40
43
 
41
44
  * gem sources -a http://gems.github.com
42
- * sudo gem install andre-geokit-gem
45
+ * sudo gem install andre-geokit
43
46
 
44
47
  ## Configuration
45
48
 
data/Rakefile CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'hoe'
5
- require './lib/geokit.rb'
5
+ require './lib/geokit'
6
6
 
7
7
  Hoe.new('Geokit', Geokit::VERSION) do |p|
8
8
  # p.rubyforge_name = 'Geokitx' # if different than lowercase project name
data/lib/geokit.rb CHANGED
@@ -25,6 +25,4 @@ require 'geokit/geocoders'
25
25
  require 'geokit/mappable'
26
26
 
27
27
  # make old-style module name "GeoKit" equivilent to new-style "Geokit"
28
- module GeoKit
29
- include Geokit
30
- end
28
+ GeoKit=Geokit
@@ -95,6 +95,14 @@ module Geokit
95
95
  return res.success ? res : GeoLoc.new
96
96
  end
97
97
 
98
+ # Main method which calls the do_reverse_geocode template method which subclasses
99
+ # are responsible for implementing. Returns a populated GeoLoc or an
100
+ # empty one with a failed success code.
101
+ def self.reverse_geocode(latlng)
102
+ res = do_reverse_geocode(latlng)
103
+ return res.success ? res : GeoLoc.new
104
+ end
105
+
98
106
  # Call the geocoder service using the timeout if configured.
99
107
  def self.call_geocoder_service(url)
100
108
  timeout(Geokit::Geocoders::timeout) { return self.do_get(url) } if Geokit::Geocoders::timeout
@@ -103,6 +111,13 @@ module Geokit
103
111
  return nil
104
112
  end
105
113
 
114
+ # Not all geocoders can do reverse geocoding. So, unless the subclass explicitly overrides this method,
115
+ # a call to reverse_geocode will return an empty GeoLoc. If you happen to be using MultiGeocoder,
116
+ # this will cause it to failover to the next geocoder, which will hopefully be one which supports reverse geocoding.
117
+ def self.do_reverse_geocode(latlng)
118
+ return GeoLoc.new
119
+ end
120
+
106
121
  protected
107
122
 
108
123
  def self.logger()
@@ -193,6 +208,16 @@ module Geokit
193
208
  class GoogleGeocoder < Geocoder
194
209
 
195
210
  private
211
+
212
+ # Template method which does the reverse-geocode lookup.
213
+ def self.do_reverse_geocode(latlng)
214
+ res = self.call_geocoder_service("http://maps.google.com/maps/geo?ll=#{Geokit::Inflector::url_escape(latlng)}&output=xml&key=#{Geokit::Geocoders::google}&oe=utf-8")
215
+ # res = Net::HTTP.get_response(URI.parse("http://maps.google.com/maps/geo?ll=#{Geokit::Inflector::url_escape(address_str)}&output=xml&key=#{Geokit::Geocoders::google}&oe=utf-8"))
216
+ return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
217
+ xml = res.body
218
+ logger.debug "Google reverse-geocoding. LL: #{latlng}. Result: #{xml}"
219
+ return self.xml2GeoLoc(xml)
220
+ end
196
221
 
197
222
  # Template method which does the geocode lookup.
198
223
  def self.do_geocode(address)
@@ -200,8 +225,12 @@ module Geokit
200
225
  res = self.call_geocoder_service("http://maps.google.com/maps/geo?q=#{Geokit::Inflector::url_escape(address_str)}&output=xml&key=#{Geokit::Geocoders::google}&oe=utf-8")
201
226
  # res = Net::HTTP.get_response(URI.parse("http://maps.google.com/maps/geo?q=#{Geokit::Inflector::url_escape(address_str)}&output=xml&key=#{Geokit::Geocoders::google}&oe=utf-8"))
202
227
  return GeoLoc.new if !res.is_a?(Net::HTTPSuccess)
203
- xml=res.body
228
+ xml = res.body
204
229
  logger.debug "Google geocoding. Address: #{address}. Result: #{xml}"
230
+ return self.xml2GeoLoc(xml)
231
+ end
232
+
233
+ def self.xml2GeoLoc(xml)
205
234
  doc=REXML::Document.new(xml)
206
235
 
207
236
  if doc.elements['//kml/Response/Status/code'].text == '200'
@@ -211,7 +240,7 @@ module Geokit
211
240
  #basics
212
241
  res.lat=coordinates[1]
213
242
  res.lng=coordinates[0]
214
- res.country_code=doc.elements['//CountryNameCode'].text
243
+ res.country_code=doc.elements['//CountryNameCode'].text if doc.elements['//CountryNameCode']
215
244
  res.provider='google'
216
245
 
217
246
  #extended -- false if not not available
@@ -9,14 +9,17 @@ module Geokit
9
9
  # * Pythagorean Theory (flat Earth) - which assumes the world is flat and loses accuracy over long distances.
10
10
  # * Haversine (sphere) - which is fairly accurate, but at a performance cost.
11
11
  #
12
- # Distance units supported are :miles and :kms.
12
+ # Distance units supported are :miles, :kms, and :nms.
13
13
  module Mappable
14
14
  PI_DIV_RAD = 0.0174
15
15
  KMS_PER_MILE = 1.609
16
+ NMS_PER_MILE = 0.868976242
16
17
  EARTH_RADIUS_IN_MILES = 3963.19
17
18
  EARTH_RADIUS_IN_KMS = EARTH_RADIUS_IN_MILES * KMS_PER_MILE
19
+ EARTH_RADIUS_IN_NMS = EARTH_RADIUS_IN_MILES * NMS_PER_MILE
18
20
  MILES_PER_LATITUDE_DEGREE = 69.1
19
21
  KMS_PER_LATITUDE_DEGREE = MILES_PER_LATITUDE_DEGREE * KMS_PER_MILE
22
+ NMS_PER_LATITUDE_DEGREE = MILES_PER_LATITUDE_DEGREE * NMS_PER_MILE
20
23
  LATITUDE_DEGREES = EARTH_RADIUS_IN_MILES / MILES_PER_LATITUDE_DEGREE
21
24
 
22
25
  # Mix below class methods into the includer.
@@ -27,7 +30,7 @@ module Geokit
27
30
  module ClassMethods #:nodoc:
28
31
  # Returns the distance between two points. The from and to parameters are
29
32
  # required to have lat and lng attributes. Valid options are:
30
- # :units - valid values are :miles or :kms (Geokit::default_units is the default)
33
+ # :units - valid values are :miles, :kms, :nms (Geokit::default_units is the default)
31
34
  # :formula - valid values are :flat or :sphere (Geokit::default_formula is the default)
32
35
  def distance_between(from, to, options={})
33
36
  from=Geokit::LatLng.normalize(from)
@@ -36,11 +39,15 @@ module Geokit
36
39
  units = options[:units] || Geokit::default_units
37
40
  formula = options[:formula] || Geokit::default_formula
38
41
  case formula
39
- when :sphere
40
- units_sphere_multiplier(units) *
41
- Math.acos( Math.sin(deg2rad(from.lat)) * Math.sin(deg2rad(to.lat)) +
42
- Math.cos(deg2rad(from.lat)) * Math.cos(deg2rad(to.lat)) *
43
- Math.cos(deg2rad(to.lng) - deg2rad(from.lng)))
42
+ when :sphere
43
+ begin
44
+ units_sphere_multiplier(units) *
45
+ Math.acos( Math.sin(deg2rad(from.lat)) * Math.sin(deg2rad(to.lat)) +
46
+ Math.cos(deg2rad(from.lat)) * Math.cos(deg2rad(to.lat)) *
47
+ Math.cos(deg2rad(to.lng) - deg2rad(from.lng)))
48
+ rescue Errno::EDOM
49
+ 0.0
50
+ end
44
51
  when :flat
45
52
  Math.sqrt((units_per_latitude_degree(units)*(from.lat-to.lat))**2 +
46
53
  (units_per_longitude_degree(from.lat, units)*(from.lng-to.lng))**2)
@@ -67,7 +74,11 @@ module Geokit
67
74
  # will be used instead of this method.
68
75
  def endpoint(start,heading, distance, options={})
69
76
  units = options[:units] || Geokit::default_units
70
- radius = units == :miles ? EARTH_RADIUS_IN_MILES : EARTH_RADIUS_IN_KMS
77
+ radius = case units
78
+ when :kms: EARTH_RADIUS_IN_KMS
79
+ when :nms: EARTH_RADIUS_IN_NMS
80
+ else EARTH_RADIUS_IN_MILES
81
+ end
71
82
  start=Geokit::LatLng.normalize(start)
72
83
  lat=deg2rad(start.lat)
73
84
  lng=deg2rad(start.lng)
@@ -86,7 +97,7 @@ module Geokit
86
97
  # Returns the midpoint, given two points. Returns a LatLng.
87
98
  # Typically, the instance method will be used instead of this method.
88
99
  # Valid option:
89
- # :units - valid values are :miles or :kms (:miles is the default)
100
+ # :units - valid values are :miles, :kms, or :nms (:miles is the default)
90
101
  def midpoint_between(from,to,options={})
91
102
  from=Geokit::LatLng.normalize(from)
92
103
 
@@ -120,18 +131,30 @@ module Geokit
120
131
 
121
132
  # Returns the multiplier used to obtain the correct distance units.
122
133
  def units_sphere_multiplier(units)
123
- units == :miles ? EARTH_RADIUS_IN_MILES : EARTH_RADIUS_IN_KMS
134
+ case units
135
+ when :kms: EARTH_RADIUS_IN_KMS
136
+ when :nms: EARTH_RADIUS_IN_NMS
137
+ else EARTH_RADIUS_IN_MILES
138
+ end
124
139
  end
125
140
 
126
141
  # Returns the number of units per latitude degree.
127
142
  def units_per_latitude_degree(units)
128
- units == :miles ? MILES_PER_LATITUDE_DEGREE : KMS_PER_LATITUDE_DEGREE
143
+ case units
144
+ when :kms: KMS_PER_LATITUDE_DEGREE
145
+ when :nms: NMS_PER_LATITUDE_DEGREE
146
+ else MILES_PER_LATITUDE_DEGREE
147
+ end
129
148
  end
130
149
 
131
150
  # Returns the number units per longitude degree.
132
151
  def units_per_longitude_degree(lat, units)
133
152
  miles_per_longitude_degree = (LATITUDE_DEGREES * Math.cos(lat * PI_DIV_RAD)).abs
134
- units == :miles ? miles_per_longitude_degree : miles_per_longitude_degree * KMS_PER_MILE
153
+ case units
154
+ when :kms: miles_per_longitude_degree * KMS_PER_MILE
155
+ when :nms: miles_per_longitude_degree * NMS_PER_MILE
156
+ else miles_per_longitude_degree
157
+ end
135
158
  end
136
159
  end
137
160
 
@@ -143,12 +166,12 @@ module Geokit
143
166
  def to_lat_lng
144
167
  return self if instance_of?(Geokit::LatLng) || instance_of?(Geokit::GeoLoc)
145
168
  return LatLng.new(send(self.class.lat_column_name),send(self.class.lng_column_name)) if self.class.respond_to?(:acts_as_mappable)
146
- return nil
169
+ nil
147
170
  end
148
171
 
149
172
  # Returns the distance from another point. The other point parameter is
150
173
  # required to have lat and lng attributes. Valid options are:
151
- # :units - valid values are :miles or :kms (:miles is the default)
174
+ # :units - valid values are :miles, :kms, :or :nms (:miles is the default)
152
175
  # :formula - valid values are :flat or :sphere (:sphere is the default)
153
176
  def distance_to(other, options={})
154
177
  self.class.distance_between(self, other, options)
@@ -169,14 +192,14 @@ module Geokit
169
192
 
170
193
  # Returns the endpoint, given a heading (in degrees) and distance.
171
194
  # Valid option:
172
- # :units - valid values are :miles or :kms (:miles is the default)
195
+ # :units - valid values are :miles, :kms, or :nms (:miles is the default)
173
196
  def endpoint(heading,distance,options={})
174
197
  self.class.endpoint(self,heading,distance,options)
175
198
  end
176
199
 
177
200
  # Returns the midpoint, given another point on the map.
178
201
  # Valid option:
179
- # :units - valid values are :miles or :kms (:miles is the default)
202
+ # :units - valid values are :miles, :kms, or :nms (:miles is the default)
180
203
  def midpoint_to(other, options={})
181
204
  self.class.midpoint_between(self,other,options)
182
205
  end
data/test/test_bounds.rb CHANGED
@@ -55,7 +55,7 @@ class BoundsTest < Test::Unit::TestCase #:nodoc: all
55
55
 
56
56
  def test_center
57
57
  assert_in_delta 32.939828,@bounds.center.lat,0.00005
58
- assert_in_delta -96.9511763,@bounds.center.lng,0.00005
58
+ assert_in_delta(-96.9511763,@bounds.center.lng,0.00005)
59
59
  end
60
60
 
61
61
  def test_center_cross_meridian
data/test/test_latlng.rb CHANGED
@@ -24,6 +24,11 @@ class LatLngTest < Test::Unit::TestCase #:nodoc: all
24
24
  assert_equal 0, @loc_a.distance_to(@loc_a, :units => :kms, :formula => :flat)
25
25
  end
26
26
 
27
+ def test_distance_between_same_with_nms_and_flat
28
+ assert_equal 0, Geokit::LatLng.distance_between(@loc_a, @loc_a, :units => :nms, :formula => :flat)
29
+ assert_equal 0, @loc_a.distance_to(@loc_a, :units => :nms, :formula => :flat)
30
+ end
31
+
27
32
  def test_distance_between_same_with_miles_and_sphere
28
33
  assert_equal 0, Geokit::LatLng.distance_between(@loc_a, @loc_a, :units => :miles, :formula => :sphere)
29
34
  assert_equal 0, @loc_a.distance_to(@loc_a, :units => :miles, :formula => :sphere)
@@ -34,6 +39,11 @@ class LatLngTest < Test::Unit::TestCase #:nodoc: all
34
39
  assert_equal 0, @loc_a.distance_to(@loc_a, :units => :kms, :formula => :sphere)
35
40
  end
36
41
 
42
+ def test_distance_between_same_with_nms_and_sphere
43
+ assert_equal 0, Geokit::LatLng.distance_between(@loc_a, @loc_a, :units => :nms, :formula => :sphere)
44
+ assert_equal 0, @loc_a.distance_to(@loc_a, :units => :nms, :formula => :sphere)
45
+ end
46
+
37
47
  def test_distance_between_diff_using_defaults
38
48
  assert_in_delta 3.97, Geokit::LatLng.distance_between(@loc_a, @loc_e), 0.01
39
49
  assert_in_delta 3.97, @loc_a.distance_to(@loc_e), 0.01
@@ -49,6 +59,11 @@ class LatLngTest < Test::Unit::TestCase #:nodoc: all
49
59
  assert_in_delta 6.39, @loc_a.distance_to(@loc_e, :units => :kms, :formula => :flat), 0.4
50
60
  end
51
61
 
62
+ def test_distance_between_diff_with_nms_and_flat
63
+ assert_in_delta 3.334, Geokit::LatLng.distance_between(@loc_a, @loc_e, :units => :nms, :formula => :flat), 0.4
64
+ assert_in_delta 3.334, @loc_a.distance_to(@loc_e, :units => :nms, :formula => :flat), 0.4
65
+ end
66
+
52
67
  def test_distance_between_diff_with_miles_and_sphere
53
68
  assert_in_delta 3.97, Geokit::LatLng.distance_between(@loc_a, @loc_e, :units => :miles, :formula => :sphere), 0.01
54
69
  assert_in_delta 3.97, @loc_a.distance_to(@loc_e, :units => :miles, :formula => :sphere), 0.01
@@ -59,12 +74,18 @@ class LatLngTest < Test::Unit::TestCase #:nodoc: all
59
74
  assert_in_delta 6.39, @loc_a.distance_to(@loc_e, :units => :kms, :formula => :sphere), 0.01
60
75
  end
61
76
 
77
+ def test_distance_between_diff_with_nms_and_sphere
78
+ assert_in_delta 3.454, Geokit::LatLng.distance_between(@loc_a, @loc_e, :units => :nms, :formula => :sphere), 0.01
79
+ assert_in_delta 3.454, @loc_a.distance_to(@loc_e, :units => :nms, :formula => :sphere), 0.01
80
+ end
81
+
62
82
  def test_manually_mixed_in
63
83
  assert_equal 0, Geokit::LatLng.distance_between(@point, @point)
64
84
  assert_equal 0, @point.distance_to(@point)
65
85
  assert_equal 0, @point.distance_to(@loc_a)
66
86
  assert_in_delta 3.97, @point.distance_to(@loc_e, :units => :miles, :formula => :flat), 0.2
67
87
  assert_in_delta 6.39, @point.distance_to(@loc_e, :units => :kms, :formula => :flat), 0.4
88
+ assert_in_delta 3.334, @point.distance_to(@loc_e, :units => :nms, :formula => :flat), 0.4
68
89
  end
69
90
 
70
91
  def test_heading_between
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: andre-geokit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.0
4
+ version: 1.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andre Lewis and Bill Eisenhauer
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-11-30 00:00:00 -08:00
12
+ date: 2009-02-01 00:00:00 -08:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -52,7 +52,7 @@ homepage: http://geokit.rubyforge.org
52
52
  post_install_message:
53
53
  rdoc_options:
54
54
  - --main
55
- - README.txt
55
+ - README.markdown
56
56
  require_paths:
57
57
  - lib
58
58
  required_ruby_version: !ruby/object:Gem::Requirement