diff --git a/lib/geocoder.rb b/lib/geocoder.rb index a68acff510cf5d4ac4e2c8fba4a126731be924f5..917a2ad294b3a4aaf28b2aea3ed4d1b8d18aff8e 100644 --- a/lib/geocoder.rb +++ b/lib/geocoder.rb @@ -215,28 +215,28 @@ module Geocoder ## # Compute the geographic center (aka geographic midpoint, center of - # gravity) for an array of [lat,lon] points. + # gravity) for an array of [lat,lon] points. Follows the procedure + # documented at http://www.geomidpoint.com/calculation.html. # def self.geographic_center(points) # convert to Cartesian coordinates - x = []; y = [], z = [] + x = []; y = []; z = [] points.each do |p| - x << cos(p[0]) * cos(p[1]) - y << cos(p[0]) * sin(p[1]) - z << sin(p[0]) + x << Math.cos(p[0]) * Math.cos(p[1]) + y << Math.cos(p[0]) * Math.sin(p[1]) + z << Math.sin(p[0]) end - - # compute average coordinates - avg = [x,y,z].map do |c| - c.inject(0){ |tot,i| tot += i } + + # compute average coordinate values + xa, ya, za = [x,y,z].map do |c| + c.inject(0){ |tot,i| tot += i } / c.size.to_f end # convert back to latitude/longitude - xa, ya, za = avg - lon = atan2(ya, xa) - hyp = sqrt(xa * xa + ya * ya) - lat = atan2(za, hyp) + lon = Math.atan2(ya, xa) + hyp = Math.sqrt(xa * xa + ya * ya) + lat = Math.atan2(za, hyp) [lat,lon] end diff --git a/test/geocoder_test.rb b/test/geocoder_test.rb index b7c18f471362ad136e93730d4fe55eade8d992f3..ce19947dee1360ab1008e956145f6dc4ddc4ea1d 100644 --- a/test/geocoder_test.rb +++ b/test/geocoder_test.rb @@ -15,6 +15,9 @@ class GeocoderTest < Test::Unit::TestCase # sanity check def test_geographic_center - assert_equal 69, Geocoder.geographic_center([[0,0], [0,1]]).round + assert_equal [0.0, 0.5], + Geocoder.geographic_center([[0,0], [0,1]]) + assert_equal [0.0, 1.0], + Geocoder.geographic_center([[0,0], [0,1], [0,2]]) end end