geokit 1.8.5 → 1.9.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|