geokit 1.8.5 → 1.9.0
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.
- checksums.yaml +7 -0
- data/.travis.yml +0 -1
- data/CHANGELOG.md +7 -0
- data/README.markdown +31 -14
- data/fixtures/vcr_cassettes/geonames_geocode.yml +1 -1
- data/fixtures/vcr_cassettes/geonames_geocode_premium.yml +42 -0
- data/fixtures/vcr_cassettes/google_country_code_biased_result_orly.yml +160 -0
- data/fixtures/vcr_cassettes/google_country_code_biased_result_toledo.yml +111 -0
- data/fixtures/vcr_cassettes/google_result_toledo_default_bias.yml +275 -0
- data/fixtures/vcr_cassettes/google_sublocality.yml +126 -0
- data/fixtures/vcr_cassettes/mapbox_forward_geocode.yml +59 -0
- data/fixtures/vcr_cassettes/mapbox_reverse_geocode.yml +63 -0
- data/fixtures/vcr_cassettes/opencage_city.yml +51 -0
- data/fixtures/vcr_cassettes/opencage_full.yml +65 -0
- data/fixtures/vcr_cassettes/opencage_language_response_es.yml +66 -0
- data/fixtures/vcr_cassettes/opencage_reverse_madrid.yml +51 -0
- data/fixtures/vcr_cassettes/opencage_reverse_prilep.yml +53 -0
- data/geokit.gemspec +5 -3
- data/lib/geokit/bounds.rb +40 -31
- data/lib/geokit/core_ext.rb +1 -1
- data/lib/geokit/geo_loc.rb +63 -41
- data/lib/geokit/geocoders.rb +13 -13
- data/lib/geokit/geocoders/bing.rb +9 -9
- data/lib/geokit/geocoders/ca_geocoder.rb +29 -29
- data/lib/geokit/geocoders/fcc.rb +4 -4
- data/lib/geokit/geocoders/free_geo_ip.rb +6 -7
- data/lib/geokit/geocoders/geo_plugin.rb +5 -6
- data/lib/geokit/geocoders/geocodio.rb +2 -2
- data/lib/geokit/geocoders/geonames.rb +18 -12
- data/lib/geokit/geocoders/google.rb +31 -30
- data/lib/geokit/geocoders/ip.rb +3 -4
- data/lib/geokit/geocoders/mapbox.rb +94 -0
- data/lib/geokit/geocoders/mapquest.rb +5 -5
- data/lib/geokit/geocoders/opencage.rb +93 -0
- data/lib/geokit/geocoders/openstreetmap.rb +9 -6
- data/lib/geokit/geocoders/ripe.rb +3 -3
- data/lib/geokit/geocoders/us_geocoder.rb +10 -9
- data/lib/geokit/geocoders/yahoo.rb +33 -34
- data/lib/geokit/geocoders/yandex.rb +17 -17
- data/lib/geokit/inflectors.rb +4 -10
- data/lib/geokit/lat_lng.rb +50 -26
- data/lib/geokit/mappable.rb +83 -83
- data/lib/geokit/multi_geocoder.rb +25 -20
- data/lib/geokit/net_adapter/net_http.rb +7 -4
- data/lib/geokit/polygon.rb +36 -4
- data/lib/geokit/version.rb +1 -1
- data/test/helper.rb +15 -13
- data/test/test_base_geocoder.rb +6 -7
- data/test/test_bing_geocoder.rb +20 -21
- data/test/test_bounds.rb +26 -28
- data/test/test_ca_geocoder.rb +9 -10
- data/test/test_fcc_geocoder.rb +1 -1
- data/test/test_free_geo_ip_geocoder.rb +1 -1
- data/test/test_geo_plugin_geocoder.rb +9 -9
- data/test/test_geoloc.rb +7 -6
- data/test/test_geonames_geocoder.rb +28 -6
- data/test/test_google_geocoder.rb +210 -176
- data/test/test_inflector.rb +0 -1
- data/test/test_ipgeocoder.rb +17 -18
- data/test/test_latlng.rb +105 -85
- data/test/test_map_quest.rb +18 -21
- data/test/test_mapbox_geocoder.rb +31 -0
- data/test/test_mappable.rb +46 -0
- data/test/test_maxmind_geocoder.rb +1 -3
- data/test/test_multi_geocoder.rb +8 -9
- data/test/test_multi_ip_geocoder.rb +3 -5
- data/test/test_net_adapter.rb +4 -4
- data/test/test_opencage_geocoder.rb +108 -0
- data/test/test_openstreetmap_geocoder.rb +62 -44
- data/test/{test_polygon_contains.rb → test_polygon.rb} +30 -20
- data/test/test_ripe_geocoder.rb +2 -0
- data/test/test_us_geocoder.rb +7 -8
- data/test/test_yahoo_geocoder.rb +20 -21
- data/test/test_yandex_geocoder.rb +34 -35
- metadata +79 -56
- data/fixtures/vcr_cassettes/google_country_code_biased_result.yml +0 -401
data/lib/geokit/mappable.rb
CHANGED
@@ -1,44 +1,43 @@
|
|
1
|
-
#require 'forwardable'
|
1
|
+
# require 'forwardable'
|
2
2
|
|
3
3
|
module Geokit
|
4
|
-
# Contains class and instance methods providing distance calcuation services.
|
5
|
-
# module is meant to be mixed into classes containing lat and lng
|
6
|
-
# distance calculation is desired.
|
4
|
+
# Contains class and instance methods providing distance calcuation services.
|
5
|
+
# This module is meant to be mixed into classes containing lat and lng
|
6
|
+
# attributes where distance calculation is desired.
|
7
7
|
#
|
8
8
|
# At present, two forms of distance calculations are provided:
|
9
9
|
#
|
10
|
-
# * Pythagorean Theory (flat Earth) - which assumes the world is flat and
|
10
|
+
# * Pythagorean Theory (flat Earth) - which assumes the world is flat and
|
11
|
+
# loses accuracy over long distances.
|
11
12
|
# * Haversine (sphere) - which is fairly accurate, but at a performance cost.
|
12
13
|
#
|
13
14
|
# Distance units supported are :miles, :kms, and :nms.
|
14
15
|
module Mappable
|
15
|
-
PI_DIV_RAD = 0.0174
|
16
|
-
KMS_PER_MILE = 1.609
|
17
|
-
NMS_PER_MILE = 0.868976242
|
18
|
-
EARTH_RADIUS_IN_MILES = 3963.19
|
19
|
-
EARTH_RADIUS_IN_KMS = EARTH_RADIUS_IN_MILES * KMS_PER_MILE
|
20
|
-
EARTH_RADIUS_IN_NMS = EARTH_RADIUS_IN_MILES * NMS_PER_MILE
|
21
|
-
MILES_PER_LATITUDE_DEGREE = 69.1
|
22
|
-
KMS_PER_LATITUDE_DEGREE = MILES_PER_LATITUDE_DEGREE * KMS_PER_MILE
|
23
|
-
NMS_PER_LATITUDE_DEGREE = MILES_PER_LATITUDE_DEGREE * NMS_PER_MILE
|
24
|
-
LATITUDE_DEGREES = EARTH_RADIUS_IN_MILES / MILES_PER_LATITUDE_DEGREE
|
25
|
-
|
26
16
|
# Mix below class methods into the includer.
|
27
17
|
def self.included(receiver) # :nodoc:
|
28
18
|
receiver.extend ClassMethods
|
29
19
|
end
|
30
20
|
|
31
21
|
module ClassMethods #:nodoc:
|
22
|
+
PI_DIV_RAD = Math::PI / 180
|
23
|
+
EARTH_RADIUS_IN_METERS = 6376772.71
|
24
|
+
METERS_PER_LATITUDE_DEGREE = 111181.9
|
25
|
+
|
26
|
+
EARTH_RADIUS = {}
|
27
|
+
PER_LATITUDE_DEGREE = {}
|
28
|
+
|
32
29
|
# Returns the distance between two points. The from and to parameters are
|
33
30
|
# required to have lat and lng attributes. Valid options are:
|
34
|
-
# :units - valid values are :miles, :kms, :nms
|
35
|
-
#
|
36
|
-
|
37
|
-
|
38
|
-
|
31
|
+
# :units - valid values are :miles, :kms, :nms
|
32
|
+
# (Geokit::default_units is the default)
|
33
|
+
# :formula - valid values are :flat or :sphere
|
34
|
+
# (Geokit::default_formula is the default)
|
35
|
+
def distance_between(from, to, options = {})
|
36
|
+
from = Geokit::LatLng.normalize(from)
|
37
|
+
to = Geokit::LatLng.normalize(to)
|
39
38
|
return 0.0 if from == to # fixes a "zero-distance" bug
|
40
|
-
units = options[:units] || Geokit
|
41
|
-
formula = options[:formula] || Geokit
|
39
|
+
units = options[:units] || Geokit.default_units
|
40
|
+
formula = options[:formula] || Geokit.default_formula
|
42
41
|
case formula
|
43
42
|
when :sphere then distance_between_sphere(from, to, units)
|
44
43
|
when :flat then distance_between_flat(from, to, units)
|
@@ -56,8 +55,9 @@ module Geokit
|
|
56
55
|
|
57
56
|
def distance_between_flat(from, to, units)
|
58
57
|
lat_length = units_per_latitude_degree(units) * (from.lat - to.lat)
|
59
|
-
lng_length = units_per_longitude_degree(from.lat, units) *
|
60
|
-
|
58
|
+
lng_length = units_per_longitude_degree(from.lat, units) *
|
59
|
+
(from.lng - to.lng)
|
60
|
+
Math.sqrt(lat_length**2 + lng_length**2)
|
61
61
|
end
|
62
62
|
|
63
63
|
# Ruby 1.9 raises {Math::DomainError}, but it is not defined in Ruby 1.8
|
@@ -67,25 +67,26 @@ module Geokit
|
|
67
67
|
end
|
68
68
|
|
69
69
|
# Returns heading in degrees (0 is north, 90 is east, 180 is south, etc)
|
70
|
-
# from the first point to the second point. Typicaly, the instance methods
|
71
|
-
# instead of this method.
|
72
|
-
def heading_between(from,to)
|
73
|
-
from=Geokit::LatLng.normalize(from)
|
74
|
-
to=Geokit::LatLng.normalize(to)
|
75
|
-
|
76
|
-
d_lng=deg2rad(to.lng-from.lng)
|
77
|
-
from_lat=deg2rad(from.lat)
|
78
|
-
to_lat=deg2rad(to.lat)
|
79
|
-
y=Math.sin(d_lng) * Math.cos(to_lat)
|
80
|
-
x=Math.cos(from_lat)*Math.sin(to_lat)-
|
81
|
-
|
70
|
+
# from the first point to the second point. Typicaly, the instance methods
|
71
|
+
# will be used instead of this method.
|
72
|
+
def heading_between(from, to)
|
73
|
+
from = Geokit::LatLng.normalize(from)
|
74
|
+
to = Geokit::LatLng.normalize(to)
|
75
|
+
|
76
|
+
d_lng = deg2rad(to.lng - from.lng)
|
77
|
+
from_lat = deg2rad(from.lat)
|
78
|
+
to_lat = deg2rad(to.lat)
|
79
|
+
y = Math.sin(d_lng) * Math.cos(to_lat)
|
80
|
+
x = Math.cos(from_lat) * Math.sin(to_lat) -
|
81
|
+
Math.sin(from_lat) * Math.cos(to_lat) * Math.cos(d_lng)
|
82
|
+
to_heading(Math.atan2(y, x))
|
82
83
|
end
|
83
84
|
|
84
85
|
# Given a start point, distance, and heading (in degrees), provides
|
85
86
|
# an endpoint. Returns a LatLng instance. Typically, the instance method
|
86
87
|
# will be used instead of this method.
|
87
|
-
def endpoint(start,heading, distance, options={})
|
88
|
-
units = options[:units] || Geokit
|
88
|
+
def endpoint(start, heading, distance, options = {})
|
89
|
+
units = options[:units] || Geokit.default_units
|
89
90
|
ratio = distance.to_f / units_sphere_multiplier(units)
|
90
91
|
start = Geokit::LatLng.normalize(start)
|
91
92
|
lat = deg2rad(start.lat)
|
@@ -103,21 +104,20 @@ module Geokit
|
|
103
104
|
end_lng = lng + Math.atan2(Math.sin(heading) * sin_ratio * cos_lat,
|
104
105
|
cos_ratio - sin_lat * Math.sin(end_lat))
|
105
106
|
|
106
|
-
LatLng.new(rad2deg(end_lat),rad2deg(end_lng))
|
107
|
+
LatLng.new(rad2deg(end_lat), rad2deg(end_lng))
|
107
108
|
end
|
108
109
|
|
109
110
|
# Returns the midpoint, given two points. Returns a LatLng.
|
110
111
|
# Typically, the instance method will be used instead of this method.
|
111
112
|
# Valid option:
|
112
|
-
# :units - valid values are :miles, :kms, or :nms
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
midpoint=from.endpoint(heading,distance/2,options)
|
113
|
+
# :units - valid values are :miles, :kms, or :nms
|
114
|
+
# (:miles is the default)
|
115
|
+
def midpoint_between(from, to, options = {})
|
116
|
+
from = Geokit::LatLng.normalize(from)
|
117
|
+
|
118
|
+
heading = from.heading_to(to)
|
119
|
+
distance = from.distance_to(to, options)
|
120
|
+
from.endpoint(heading, distance / 2, options)
|
121
121
|
end
|
122
122
|
|
123
123
|
# Geocodes a location using the multi geocoder.
|
@@ -139,8 +139,6 @@ module Geokit
|
|
139
139
|
(seconds % 60) # seconds as positive float
|
140
140
|
]
|
141
141
|
end
|
142
|
-
|
143
|
-
protected
|
144
142
|
|
145
143
|
def deg2rad(degrees)
|
146
144
|
degrees.to_f / 180.0 * Math::PI
|
@@ -151,35 +149,34 @@ module Geokit
|
|
151
149
|
end
|
152
150
|
|
153
151
|
def to_heading(rad)
|
154
|
-
(rad2deg(rad)+360)%360
|
152
|
+
(rad2deg(rad) + 360) % 360
|
153
|
+
end
|
154
|
+
|
155
|
+
def self.register_unit(key, in_meters)
|
156
|
+
EARTH_RADIUS[key] = EARTH_RADIUS_IN_METERS * in_meters
|
157
|
+
PER_LATITUDE_DEGREE[key] = METERS_PER_LATITUDE_DEGREE * in_meters
|
155
158
|
end
|
156
159
|
|
160
|
+
register_unit :meters, 1
|
161
|
+
register_unit :kms, 1 / 1000.0
|
162
|
+
register_unit :miles, 1 / 1609.0
|
163
|
+
register_unit :nms, 0.0005400722448725917
|
164
|
+
|
157
165
|
# Returns the multiplier used to obtain the correct distance units.
|
166
|
+
# TODO make more accurate by coping
|
167
|
+
# http://msi.nga.mil/MSISiteContent/StaticFiles/Calculators/degree.html
|
158
168
|
def units_sphere_multiplier(units)
|
159
|
-
|
160
|
-
when :kms; EARTH_RADIUS_IN_KMS
|
161
|
-
when :nms; EARTH_RADIUS_IN_NMS
|
162
|
-
else EARTH_RADIUS_IN_MILES
|
163
|
-
end
|
169
|
+
EARTH_RADIUS[units]
|
164
170
|
end
|
165
171
|
|
166
172
|
# Returns the number of units per latitude degree.
|
167
173
|
def units_per_latitude_degree(units)
|
168
|
-
|
169
|
-
when :kms; KMS_PER_LATITUDE_DEGREE
|
170
|
-
when :nms; NMS_PER_LATITUDE_DEGREE
|
171
|
-
else MILES_PER_LATITUDE_DEGREE
|
172
|
-
end
|
174
|
+
PER_LATITUDE_DEGREE[units]
|
173
175
|
end
|
174
176
|
|
175
177
|
# Returns the number units per longitude degree.
|
176
178
|
def units_per_longitude_degree(lat, units)
|
177
|
-
|
178
|
-
case units
|
179
|
-
when :kms; miles_per_longitude_degree * KMS_PER_MILE
|
180
|
-
when :nms; miles_per_longitude_degree * NMS_PER_MILE
|
181
|
-
else miles_per_longitude_degree
|
182
|
-
end
|
179
|
+
units_sphere_multiplier(units) * Math.cos(lat * PI_DIV_RAD) * PI_DIV_RAD
|
183
180
|
end
|
184
181
|
end
|
185
182
|
|
@@ -189,46 +186,49 @@ module Geokit
|
|
189
186
|
|
190
187
|
# Extracts a LatLng instance. Use with models that are acts_as_mappable
|
191
188
|
def to_lat_lng
|
192
|
-
|
193
|
-
|
194
|
-
|
189
|
+
if instance_of?(Geokit::LatLng) || instance_of?(Geokit::GeoLoc)
|
190
|
+
return self
|
191
|
+
end
|
192
|
+
lat = send(self.class.lat_column_name)
|
193
|
+
lng = send(self.class.lng_column_name)
|
194
|
+
LatLng.new(lat, lng)
|
195
195
|
end
|
196
196
|
|
197
197
|
# Returns the distance from another point. The other point parameter is
|
198
198
|
# required to have lat and lng attributes. Valid options are:
|
199
199
|
# :units - valid values are :miles, :kms, :or :nms (:miles is the default)
|
200
200
|
# :formula - valid values are :flat or :sphere (:sphere is the default)
|
201
|
-
def distance_to(other, options={})
|
201
|
+
def distance_to(other, options = {})
|
202
202
|
self.class.distance_between(self, other, options)
|
203
203
|
end
|
204
204
|
alias distance_from distance_to
|
205
205
|
|
206
|
-
# Returns heading in degrees (0 is north, 90 is east, 180 is south, etc)
|
207
|
-
#
|
206
|
+
# Returns heading in degrees (0 is north, 90 is east, 180 is south, etc) to
|
207
|
+
# the given point. The given point can be a LatLng or a string to be
|
208
|
+
# Geocoded
|
208
209
|
def heading_to(other)
|
209
|
-
self.class.heading_between(self,other)
|
210
|
+
self.class.heading_between(self, other)
|
210
211
|
end
|
211
212
|
|
212
213
|
# Returns heading in degrees (0 is north, 90 is east, 180 is south, etc)
|
213
|
-
# FROM the given point. The given point can be a LatLng or a string to be
|
214
|
+
# FROM the given point. The given point can be a LatLng or a string to be
|
215
|
+
# Geocoded
|
214
216
|
def heading_from(other)
|
215
|
-
self.class.heading_between(other,self)
|
217
|
+
self.class.heading_between(other, self)
|
216
218
|
end
|
217
219
|
|
218
220
|
# Returns the endpoint, given a heading (in degrees) and distance.
|
219
221
|
# Valid option:
|
220
222
|
# :units - valid values are :miles, :kms, or :nms (:miles is the default)
|
221
|
-
def endpoint(heading,distance,options={})
|
222
|
-
self.class.endpoint(self,heading,distance,options)
|
223
|
+
def endpoint(heading, distance, options = {})
|
224
|
+
self.class.endpoint(self, heading, distance, options)
|
223
225
|
end
|
224
226
|
|
225
227
|
# Returns the midpoint, given another point on the map.
|
226
228
|
# Valid option:
|
227
229
|
# :units - valid values are :miles, :kms, or :nms (:miles is the default)
|
228
|
-
def midpoint_to(other, options={})
|
229
|
-
self.class.midpoint_between(self,other,options)
|
230
|
+
def midpoint_to(other, options = {})
|
231
|
+
self.class.midpoint_between(self, other, options)
|
230
232
|
end
|
231
|
-
|
232
233
|
end
|
233
|
-
|
234
234
|
end
|
@@ -1,26 +1,29 @@
|
|
1
1
|
module Geokit
|
2
2
|
module Geocoders
|
3
|
-
#
|
3
|
+
# --------------------------------------------------------------------------
|
4
4
|
# The Multi Geocoder
|
5
|
-
#
|
5
|
+
# --------------------------------------------------------------------------
|
6
6
|
|
7
|
-
# Provides methods to geocode with a variety of geocoding service providers,
|
8
|
-
# among providers in the order you configure. When 2nd
|
9
|
-
# ip location lookup with 'address' as the
|
7
|
+
# Provides methods to geocode with a variety of geocoding service providers,
|
8
|
+
# plus failover among providers in the order you configure. When 2nd
|
9
|
+
# parameter is set 'true', perform ip location lookup with 'address' as the
|
10
|
+
# ip address.
|
10
11
|
#
|
11
12
|
# Goal:
|
12
13
|
# - homogenize the results of multiple geocoders
|
13
14
|
#
|
14
15
|
# Limitations:
|
15
|
-
# - currently only provides the first result. Sometimes geocoders will
|
16
|
+
# - currently only provides the first result. Sometimes geocoders will
|
17
|
+
# return multiple results.
|
16
18
|
# - currently discards the "accuracy" component of the geocoding calls
|
17
19
|
class MultiGeocoder < Geocoder
|
18
|
-
|
19
20
|
private
|
20
|
-
|
21
|
-
#
|
21
|
+
|
22
|
+
# This method will call one or more geocoders in the order specified in
|
23
|
+
# the configuration until one of the geocoders work.
|
22
24
|
#
|
23
|
-
# The failover approach is crucial for production-grade apps, but is
|
25
|
+
# The failover approach is crucial for production-grade apps, but is
|
26
|
+
# rarely used.
|
24
27
|
# 98% of your geocoding calls will be successful with the first call
|
25
28
|
def self.do_geocode(address, *args)
|
26
29
|
provider_order = provider_order_for(address, args)
|
@@ -31,24 +34,26 @@ module Geokit
|
|
31
34
|
res = klass.send :geocode, address, *args
|
32
35
|
return res if res.success?
|
33
36
|
rescue => e
|
34
|
-
logger.error("An error has occurred during geocoding: #{e}\
|
37
|
+
logger.error("An error has occurred during geocoding: #{e}\n" +
|
38
|
+
"Address: #{address}. Provider: #{provider}")
|
35
39
|
end
|
36
40
|
end
|
37
41
|
# If we get here, we failed completely.
|
38
42
|
GeoLoc.new
|
39
43
|
end
|
40
44
|
|
41
|
-
# This method will call one or more geocoders in the order specified in
|
42
|
-
# configuration until one of the geocoders work, only this time it's
|
43
|
-
# to try to reverse geocode a geographical point.
|
45
|
+
# This method will call one or more geocoders in the order specified in
|
46
|
+
# the configuration until one of the geocoders work, only this time it's
|
47
|
+
# going to try to reverse geocode a geographical point.
|
44
48
|
def self.do_reverse_geocode(latlng)
|
45
|
-
Geokit::Geocoders
|
49
|
+
Geokit::Geocoders.provider_order.each do |provider|
|
46
50
|
klass = geocoder(provider)
|
47
51
|
begin
|
48
52
|
res = klass.send :reverse_geocode, latlng
|
49
53
|
return res if res.success?
|
50
54
|
rescue => e
|
51
|
-
logger.error("An error has occurred during geocoding: #{e}\
|
55
|
+
logger.error("An error has occurred during geocoding: #{e}\n" +
|
56
|
+
"Latlng: #{latlng}. Provider: #{provider}")
|
52
57
|
end
|
53
58
|
end
|
54
59
|
# If we get here, we failed completely.
|
@@ -56,7 +61,8 @@ module Geokit
|
|
56
61
|
end
|
57
62
|
|
58
63
|
def self.geocoder(provider)
|
59
|
-
|
64
|
+
class_name = "#{Geokit::Inflector.camelize(provider.to_s)}Geocoder"
|
65
|
+
Geokit::Geocoders.const_get class_name
|
60
66
|
end
|
61
67
|
|
62
68
|
def self.provider_order_for(address, args)
|
@@ -64,13 +70,12 @@ module Geokit
|
|
64
70
|
args.last.delete(:provider_order)
|
65
71
|
else
|
66
72
|
if /^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$/.match(address)
|
67
|
-
Geokit::Geocoders
|
73
|
+
Geokit::Geocoders.ip_provider_order
|
68
74
|
else
|
69
|
-
Geokit::Geocoders
|
75
|
+
Geokit::Geocoders.provider_order
|
70
76
|
end
|
71
77
|
end
|
72
78
|
end
|
73
79
|
end
|
74
80
|
end
|
75
81
|
end
|
76
|
-
|
@@ -6,16 +6,19 @@ module Geokit
|
|
6
6
|
req = Net::HTTP::Get.new(url)
|
7
7
|
req.basic_auth(uri.user, uri.password) if uri.userinfo
|
8
8
|
net_http_args = [uri.host, uri.port]
|
9
|
-
if (proxy_uri_string = Geokit::Geocoders
|
9
|
+
if (proxy_uri_string = Geokit::Geocoders.proxy)
|
10
10
|
proxy_uri = URI.parse(proxy_uri_string)
|
11
|
-
net_http_args += [proxy_uri.host,
|
11
|
+
net_http_args += [proxy_uri.host,
|
12
|
+
proxy_uri.port,
|
13
|
+
proxy_uri.user,
|
14
|
+
proxy_uri.password]
|
12
15
|
end
|
13
|
-
http = Net::HTTP
|
16
|
+
http = Net::HTTP.new(*net_http_args)
|
14
17
|
if uri.scheme == 'https'
|
15
18
|
http.use_ssl = true
|
16
19
|
http.verify_mode = Geokit::Geocoders.ssl_verify_mode
|
17
20
|
end
|
18
|
-
http.start { |
|
21
|
+
http.start { |h| h.request(req) }
|
19
22
|
end
|
20
23
|
|
21
24
|
def self.success?(response)
|
data/lib/geokit/polygon.rb
CHANGED
@@ -1,13 +1,12 @@
|
|
1
1
|
module Geokit
|
2
2
|
# A complex polygon made of multiple points. End point must equal start point to close the poly.
|
3
3
|
class Polygon
|
4
|
-
|
5
4
|
attr_accessor :points
|
6
|
-
|
5
|
+
|
7
6
|
# Pass in an array of Geokit::LatLng
|
8
7
|
def initialize(points)
|
9
8
|
@points = points
|
10
|
-
|
9
|
+
|
11
10
|
# A Polygon must be 'closed', the last point equal to the first point
|
12
11
|
# Append the first point to the array to close the polygon
|
13
12
|
@points << points[0] if points[0] != points[-1]
|
@@ -30,11 +29,44 @@ module Geokit
|
|
30
29
|
oddNodes = !oddNodes
|
31
30
|
end
|
32
31
|
end
|
33
|
-
|
32
|
+
|
34
33
|
last_point = p
|
35
34
|
end
|
36
35
|
|
37
36
|
oddNodes
|
38
37
|
end # contains?
|
38
|
+
|
39
|
+
# A polygon is static and can not be updated with new points, as a result
|
40
|
+
# calculate the centroid once and store it when requested.
|
41
|
+
def centroid
|
42
|
+
@centroid ||= calculate_centroid
|
43
|
+
end # end centroid
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def calculate_centroid
|
48
|
+
centroid_lat = 0.0
|
49
|
+
centroid_lng = 0.0
|
50
|
+
signed_area = 0.0
|
51
|
+
|
52
|
+
# Iterate over each element in the list but the last item as it's
|
53
|
+
# calculated by the i+1 logic
|
54
|
+
@points[0...-1].each_index do |i|
|
55
|
+
x0 = @points[i].lat
|
56
|
+
y0 = @points[i].lng
|
57
|
+
x1 = @points[i + 1].lat
|
58
|
+
y1 = @points[i + 1].lng
|
59
|
+
a = (x0 * y1) - (x1 * y0)
|
60
|
+
signed_area += a
|
61
|
+
centroid_lat += (x0 + x1) * a
|
62
|
+
centroid_lng += (y0 + y1) * a
|
63
|
+
end
|
64
|
+
|
65
|
+
signed_area *= 0.5
|
66
|
+
centroid_lat /= (6.0 * signed_area)
|
67
|
+
centroid_lng /= (6.0 * signed_area)
|
68
|
+
|
69
|
+
Geokit::LatLng.new(centroid_lat, centroid_lng)
|
70
|
+
end # end calculate_centroid
|
39
71
|
end # class Polygon
|
40
72
|
end
|