module Asari::Geography

Public: This module contains helper methods that serialize and deserialize latitudes and longitudes to store on Cloudsearch. For more information, see:

docs.aws.amazon.com/cloudsearch/latest/developerguide/geosearch.html

Constants

EARTH_RADIUS
METERS_PER_DEGREE_OF_LATITUDE

Public Class Methods

coordinate_box(options) click to toggle source

Public: Calculates a range of integers to search within from a point and a distance in meters. This is used to search a certain distance from a point in Cloudsearch.

options - the options hash requires:
  meters: an Integer
  lat: a Float
  lng: a Float

Examples:

Asari::GeographyConversion.coordinate_box(lat: 25062714160, lng: 1112993466, miles: 5)
#=> {:lat=>25062714160, :lng=>1112993466}

Returns: a Hash containing :lat and :lng keys with Range values

# File lib/asari/geography.rb, line 69
def coordinate_box(options)
  latitude = options[:lat]
  longitude = options[:lng]

  earth_radius_at_latitude = EARTH_RADIUS * Math.cos(latitude * ( Math::PI / 180 ))

  change_in_latitude = ( options[:meters].to_f / EARTH_RADIUS ) * ( 180 / Math::PI )
  change_in_longitude = ( options[:meters].to_f / earth_radius_at_latitude ) * ( 180 / Math::PI )

  bottom = latitude_to_int(latitude - change_in_latitude)
  top = latitude_to_int(latitude + change_in_latitude)
  if((latitude - change_in_latitude).abs < (latitude + change_in_latitude).abs)
    left = longitude_to_int(longitude - change_in_longitude, latitude - change_in_latitude)
    right = longitude_to_int(longitude + change_in_longitude, latitude - change_in_latitude)
  else
    left = longitude_to_int(longitude - change_in_longitude, latitude + change_in_latitude)
    right = longitude_to_int(longitude + change_in_longitude, latitude + change_in_latitude)
  end

  { lat: (bottom.round..top.round), lng: (left.round..right.round) }
end
degrees_to_int(options) click to toggle source

Public: Converts coordinates to unsigned integers that store up to two place values.

options - the options hash requires:
  lat: a Float
  lng: a Float

Examples:

Asari::GeographyConversion.degrees_to_int(45.52, 122.6819)
#=> {:lat=>25062714160, :lng=>1112993466}

Returns: a Hash containing :lat and :lng keys with Integer values

# File lib/asari/geography.rb, line 27
def degrees_to_int(options)
  latitude = latitude_to_int(options[:lat])
  longitude = longitude_to_int(options[:lng], options[:lat])
  { lat: latitude, lng: longitude }
end
int_to_degrees(options) click to toggle source

Public: Converts unsigned integers created with `degrees_to_int` back to the standard Geographic Coordinate System.

options - the options hash requires:
  lat: an Integer
  lng: an Integer

Examples:

Asari::GeographyConversion.int_to_degrees(lat: 25062714160, lng: 1112993466)
#=> {:lat=>45.52, :lng=>-122.682}

Returns: a Hash containing :lat and :lng keys with Float values

# File lib/asari/geography.rb, line 47
def int_to_degrees(options)
  latitude = latitude_to_degrees(options[:lat])
  longitude = longitude_to_degrees(options[:lng], latitude)
  { lat: latitude, lng: longitude }
end

Private Class Methods

latitude_to_degrees(int) click to toggle source
# File lib/asari/geography.rb, line 97
def latitude_to_degrees(int)
  ((int / METERS_PER_DEGREE_OF_LATITUDE / 100.0) - 180).round(3)
end
latitude_to_int(degrees) click to toggle source
# File lib/asari/geography.rb, line 93
def latitude_to_int(degrees)
  ((degrees + 180) * METERS_PER_DEGREE_OF_LATITUDE * 100).round
end
longitude_to_degrees(int, latitude_in_degrees) click to toggle source
# File lib/asari/geography.rb, line 106
def longitude_to_degrees(int, latitude_in_degrees)
  meters = meters_per_degree_of_longitude(latitude_in_degrees)
  ((int / meters / 100.0) - 180).round(3)
end
longitude_to_int(degrees, latitude) click to toggle source
# File lib/asari/geography.rb, line 101
def longitude_to_int(degrees, latitude)
  meters = meters_per_degree_of_longitude(latitude)
  ((degrees + 180) * meters * 100).round
end
meters_per_degree_of_longitude(latitude) click to toggle source
# File lib/asari/geography.rb, line 111
def meters_per_degree_of_longitude(latitude)
  METERS_PER_DEGREE_OF_LATITUDE * Math.cos(latitude  * ( Math::PI / 180 ))
end