【问题标题】:Locations in range范围内的位置
【发布时间】:2014-06-21 01:15:26
【问题描述】:

我有一个 Location 模型,其中每个位置都有一个纬度和经度坐标,我试图让一个 Location 实例返回基于 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 的 lat 和 -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

【问题讨论】:

    标签: ruby-on-rails ruby


    【解决方案1】:

    我认为问题出在您没有发布的代码上,特别是to_deg 和to_rad 方法。也许您在这两种方法中的某处写了整数除法而不是浮点除法?请注意,3/2==1 是 Ruby 中的 3/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]
    #   ]
    

    【讨论】:

    • 太棒了,我已经添加了正确修改的有效代码,非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-10-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多