Rails Postgis最近点

时间:2014-08-13 13:36:40

标签: ruby-on-rails geolocation distance postgis

尝试计算某个距离和最近点的最近点。

db / migrate / xxx_create_points.rb中的

“:

    class CreatePoints < ActiveRecord::Migration
      def change
        create_table :points do |t|
          t.point :location, :geographic => true
          t.string :name, :null => false
          t.timestamps
        end
        change_table :points do |t|
          t.index :location, :spatial => true
        end
      end
    end

在config / routes.rb中:

    get 'points/:lat/:lon/:distance', to: 'points#index', :constraints => { :lat => /[^\/]+/, :lon => /[^\/]+/}

在controllers / points_controller.rb中:

    class PointsController < ApplicationController
      def index
        @points= Point.all
        if params[:distance].present? && params[:lat].present? && params[:lon].present?
          @distance = params[:distance].to_i
          @latitude = params[:lat].to_f
          @longitude = params[:lon].to_f
          @points= Point.near(@latitude, @longitude, @distance)
          @near = Point.nearest(@latitude, @longitude, 100).first
        end
    end

在models / point.rb中:

    class Point < ActiveRecord::Base
      set_rgeo_factory_for_column(:location,
                                  RGeo::Geographic.spherical_factory(:srid => 4326))
      attr_accessible :location, :name

      scope :near, lambda { |latitude, longitude, distance|
        where("ST_Distance(location,
                           "+"'POINT(#{latitude} #{longitude})') < #{distance}")}

      scope :nearest, lambda { |latitude, longitude, distance|
        where("ST_Distance(location,
                           "+"'POINT(#{latitude} #{longitude})') < {distance}")
          .order("ST_Distance(location, ST_GeographyFromText('POINT(#{latitude} #{longitude})'))").limit(1)}

    end

在views / points / index.html.erb中:

    <script>
      $.each(response.data, function(i, point) {
        $('#map_canvas').gmap('addMarker', { 
          'position': new google.maps.LatLng(point.latitude, point.longitude), 'bounds': true });
      }
      $('#map_canvas').gmap('addShape', 'Circle', {
        ...
        'center': new google.maps.LatLng(<%= "#{@latitude},#{@longitude}" %>),
        'radius': 1 });
      $('#map_canvas').gmap('addShape', 'Circle', {
        ...
        'center': new google.maps.LatLng(<%= "#{@latitude},#{@longitude}" %>),
        'radius': <%= @distance %> });
      $('#map_canvas').gmap('addShape', 'Circle', {
        ...
        'center': new google.maps.LatLng(<%= "#{@near.location.x},#{@near.location.y}" %>),
        'radius': 2 });
    </script>

浏览器中的结果:http://xxx/points?distance=200&lat=55.7632500&lon=52.442000

我做错了什么?

2 个答案:

答案 0 :(得分:1)

PostGIS始终使用坐标轴顺序(X Y)或(经度纬度)。我在代码中看到了相反的片段:

ST_GeographyFromText('POINT(#{latitude} #{longitude})')

这需要切换:

ST_MakePoint(#{longitude}, #{latitude})::geography

答案 1 :(得分:0)

Google地图使用墨卡托投影,您看到的差异可能是由您在模型中使用的球形投影与墨卡托投影之间的距离计算差异引起的。

尝试在Point类中使用RGeo的simple_mercator_factory,而不是使用spherical_factory。

RGeo's documentation为您提供了有关详细信息。

  # Many popular visualization technologies, such as Google and Bing
  # maps, actually use two coordinate systems. The first is the
  # standard WSG84 lat-long system used by the GPS and represented
  # by EPSG 4326. Most API calls and input-output in these mapping
  # technologies utilize this coordinate system. The second is a
  # Mercator projection based on a "sphericalization" of the WGS84
  # lat-long system. This projection is the basis of the map's screen
  # and tiling coordinates, and has been assigned EPSG 3857.