范围内的位置

时间:2014-06-19 22:22:01

标签: ruby-on-rails ruby

我有一个位置模型,其中每个位置都有一个以度为单位的纬度和经度坐标,我试图让一个位置实例返回基于http://www.mullie.eu/geographic-searches/的指定距离范围内的所有位置:

  def in_range(distance)
    earth_radius = 3958.75587

    maxlat = self.lat + to_deg(distance / earth_radius)
    minlat = self.lat - to_deg(distance / earth_radius)
    maxlon = self.lon + to_deg(distance / earth_radius / Math::cos(to_rad(self.lat)))
    minlon = self.lon - to_deg(distance / earth_radius / Math::cos(to_rad(self.lat)))

    Location.where("lat > ? AND lat < ? AND lon > ? AND lon < ?",minlat,maxlat,minlon,maxlon)
  end

当我创建位置并请求范围时:

l1 = Location.find_by_post_code("SW11")

这会返回一个51.4663的纬度和一个-0.165543的lon,当我要求时,我的maxlat,minlat,maxlon,minlon值太小了:

l1.in_range(10)

maxlat = 51.466344087822264
minlat = 51.46625591217773
maxlon = -0.1654722301720378
minlon = -0.1656137698279622

所以我认为这些值的计算是错误的,但是在找到这方面的资源时遇到了麻烦,有没有人知道获取最大和最小坐标值的正确方法?


编辑 - 随后回答,完整的工作代码如下:

class Location < ActiveRecord::Base

  EARTH_RADIUS = 3958.75587

  def in_range(distance)
    maxlat = self.lat + rad2deg(distance / EARTH_RADIUS)
    minlat = self.lat - rad2deg(distance / EARTH_RADIUS)
    maxlon = self.lon + rad2deg(distance / EARTH_RADIUS / Math.cos(deg2rad(self.lat)))
    minlon = self.lon - rad2deg(distance / EARTH_RADIUS / Math.cos(deg2rad(self.lat)))

    locations = Location.where("lat > ? AND lat < ? AND lon > ? AND lon < ?",minlat,maxlat,minlon,maxlon).to_a
    locations.each do |location|
      if self.distance_to(location) > distance
        locations.delete(location)
      end
    end
    locations
  end

  def distance_to(location)
    lat_source_rad = deg2rad(self.lat)
    lat_destination_rad = deg2rad(location.lat)
    lat_delta = deg2rad(location.lat - self.lat)
    lon_delta = deg2rad(location.lon - self.lon)

    a = Math::sin(lat_delta/2.0) * Math::sin(lat_delta/2.0) +
        Math::cos(lat_source_rad) * Math::cos(lat_destination_rad) *
        Math::sin(lon_delta/2.0) * Math::sin(lon_delta/2.0)
    b = 2 * Math::atan2(Math::sqrt(a), Math::sqrt(1.0-a))
    c = EARTH_RADIUS * b
  end

  private

  def rad2deg(rad)
    rad / Math::PI * 180.0
  end

  def deg2rad(deg)
    deg / 180.0 * Math::PI
  end
end

1 个答案:

答案 0 :(得分:0)

我认为问题在于您没有发布的代码,特别是to_degto_rad方法。也许你在两种方法中的某处写过整数除法而不是浮点除法?请注意Ruby中的3/2==13/2.0==1.5

class Location
  RADIUS = 3958.75587
  attr_accessor :lat, :lng

  def initialize(lat, lng)
    @lat = lat
    @lng = lng
  end

  def ranges(distance)
    maxlat = @lat + rad2deg(distance / RADIUS)
    minlat = @lat - rad2deg(distance / RADIUS)

    maxlng = @lng + rad2deg(distance / RADIUS / Math.cos(deg2rad(@lat)))
    minlng = @lng - rad2deg(distance / RADIUS / Math.cos(deg2rad(@lat)))

    [[minlat, maxlat], [minlng, maxlng]]
  end

  private
  def rad2deg(rad)
    rad / Math::PI * 180.0
  end

  def deg2rad(deg)
    deg / 180.0 * Math::PI
  end
end

l = Location.new(51.4663, -0.165543)
p l.ranges(10)
#=> [
#     [51.32156821710003, 51.611031782899964],
#     [-0.39786664062357346, 0.06678064062357347]
#   ]