module GeoFaker

Constants

BASE_URL
VERSION

Public Class Methods

around(query, radius_in_km:) click to toggle source
# File lib/geo_faker.rb, line 36
def self.around(query, radius_in_km:)
  data = geo_data(query)
  lat = data['lat'].to_f
  lon = data['lon'].to_f

  angle = 2 * Math::PI * rand()
  distance = nil
  loop do
    distance = radius_in_km * gaussian_rand()
    break if distance.abs < 3 * radius_in_km
  end

  delta_lat = GeoTransform.km_to_degree_lat(distance * Math.cos(angle))
  delta_lon = GeoTransform.km_to_degree_lon(distance * Math.sin(angle), lat)

  Point.new(
    lat: lat + delta_lat,
    lon: lon + delta_lon,
  )
end
gaussian_rand() click to toggle source
# File lib/geo_faker.rb, line 57
def self.gaussian_rand
  theta = 2 * Math::PI * rand
  rho = Math.sqrt(-2 * Math.log(1 - rand))
  x = rho * Math.cos(theta)
  #y = rho * Math.sin(theta)
  x
end
geo_data(query, with_polygon: false) click to toggle source
# File lib/geo_faker.rb, line 13
def self.geo_data(query, with_polygon: false)
  @@geo_data[query] ||= load_geo_data(query, with_polygon: with_polygon)
  if with_polygon && !@@geo_data[query].key?('geojson')
    @@geo_data[query] = load_geo_data(query, with_polygon: with_polygon)
  end
  @@geo_data[query]
end
load_geo_data(query, with_polygon: false) click to toggle source
# File lib/geo_faker.rb, line 21
def self.load_geo_data(query, with_polygon: false)
  response = RestClient.get(BASE_URL, params: {
    q: query,
    format: 'json',
    limit: 1,
    polygon_geojson: with_polygon ? '1' : '0',
  })

  raise "API error: #{response.code}" unless response.code == 200

  data = JSON.parse(response.body)
  raise "No matching result." if data.empty?
  data.first
end
point_in_poly(poly, point) click to toggle source
# File lib/geo_faker.rb, line 103
def self.point_in_poly(poly, point)
  last_point = poly[-1]
  oddNodes = false
  y = point.lon
  x = point.lat

  poly.each do |p|
    yi = p[0]
    xi = p[1]
    yj = last_point[0]
    xj = last_point[1]
    if yi < y && yj >= y ||
        yj < y && yi >= y
      oddNodes = !oddNodes if xi + (y - yi) / (yj - yi) * (xj - xi) < x
    end
    last_point = p
  end

  oddNodes
end
within(query) click to toggle source
# File lib/geo_faker.rb, line 80
def self.within(query)
  data = geo_data(query, with_polygon: true)

  bounds = data['boundingbox'].map(&:to_f)
  south = bounds[0]
  north = bounds[1]
  west = bounds[2]
  east = bounds[3]

  geojson = data['geojson']
  raise 'geojson is not Polygon' unless geojson['type'] == 'Polygon'
  outer_poly = geojson['coordinates'][0]

  loop do
    point = Point.new(
      lat: rand(south..north),
      lon: rand(west..east),
    )

    return point if point_in_poly(outer_poly, point)
  end
end
within_bounds(query) click to toggle source
# File lib/geo_faker.rb, line 65
def self.within_bounds(query)
  data = geo_data(query)
  bounds = data['boundingbox'].map(&:to_f)

  south = bounds[0]
  north = bounds[1]
  west = bounds[2]
  east = bounds[3]

  Point.new(
    lat: rand(south..north),
    lon: rand(west..east),
  )
end