Ruby Rails Postgis - 查找多边形中的所有点

nod*_*rog 6 ruby sql postgis ruby-on-rails

我想在构建用于带有activerecord-postgis-adapter的rails的sql查询时提供一些帮助.我一直在做相当多的阅读,但现在有点卡住了,任何帮助都会非常感激.

我有两个模型事件和领域:

事件具有"几何"列,其类型为Point

class Event < ActiveRecord::Base
  self.rgeo_factory_generator = RGeo::Geos.factory_generator    
end

t.spatial  "geometry", :limit => {:srid=>4326, :type=>"polygon", :geographic=>true}
Run Code Online (Sandbox Code Playgroud)

区域有一个"几何"列,其类型为Polygon

class Area < ActiveRecord::Base 
  self.rgeo_factory_generator = RGeo::Geos.factory_generator
end

t.spatial  "geometry", :limit => {:srid=>4326, :type=>"point", :geographic=>true}
Run Code Online (Sandbox Code Playgroud)

我可以在谷歌地图上创建和绘制事件和区域,并通过单击地图并保存到数据库来创建区域.

我希望能够执行以下2个查询:

  1. @ area.events - 显示区域中的所有事件
  2. @ event.areas - 显示单个事件所在的所有区域

我知道我可能会在这里问一点,但任何帮助都会非常感激

非常感谢

Dan*_*uma 6

这是一个快速的方法来做到这一点.这些只会返回ActiveRecord对象的数组.

class Area
  def events
    Event.joins("INNER JOIN areas ON areas.id=#{id} AND st_contains(areas.geometry, events.geometry)").all
  end
end

class Event
  def areas
    Area.joins("INNER JOIN events ON events.id=#{id} AND st_contains(areas.geometry, events.geometry)").all
  end
end
Run Code Online (Sandbox Code Playgroud)

您可能应该记住(缓存结果),这样每次调用方法时都不会查询数据库.那应该是直截了当的; 我将它作为练习留给读者.

可能是可能得到复杂,在一个真正的Rails协会代理包装这件事(这样你就可以得到所有的Rails协会好吃的东西).我没有看过这个.在任何情况下它都不是标准的Rails关联,因为你没有存储ID.

第十二是正确的:您应该为两个表创建空间索引.Activerecord-postgis-adapter应该可以在迁移中轻松完成.

change_table :events do |t|
  t.index :geometry, :spatial => true
end

change_table :areas do |t|
  t.index :geometry, :spatial => true
end
Run Code Online (Sandbox Code Playgroud)

如果您在安装postgis时遇到问题,我最近就这些内容写了一堆博客文章.查看http://www.daniel-azuma.com/blog/archives/category/tech/georails.我也是rgeo和activerecord-postgis-adapter本身的作者,所以如果你遇到困难我很乐意提供帮助.

  • 谢谢丹尼尔,这真的很好,是的,我正确安装了postgis因为我认为我的专栏应该是地理位置的错误所在...你的宝石顺便说一句,非常感谢你投入的所有工作他们. (2认同)

Twe*_*fth 3

这个答案对您来说将是一项正在进行的工作。我对 ruby​​ on Rails 不太了解,但我应该能够帮助您完成数据库部分。

您有两个表,包含多边形的区域和将事件保存为单个点的事件(如果事件也是一个区域并且您试图挑选出重叠区域...如果事件是单个点,则情况会更复杂点这有效)。

Select *
from area a inner join event e on 1=1
Run Code Online (Sandbox Code Playgroud)

这将创建加入每个事件的每个区域的列表...如果您有 500 个事件和 20 个区域,则此查询将返回 10'000 行。现在您想要过滤此事件,以便仅过滤它们所加入的区域内的事件。我们可以使用 st_contains 作为 st_contains(polygon,point):

where st_contains(a.polygon,e.point) = 't'
Run Code Online (Sandbox Code Playgroud)

如果你运行这个,它应该给你一个。,e。对于区域内的所有活动。现在只要数你想数的就可以了。

select a.id, count(1)
from area a inner join event e on 1=1
where st_contains(a.polygon,e.point) = 't'
group by 1
Run Code Online (Sandbox Code Playgroud)

这将为您提供所有区域的列表(按 ID)以及其中的事件计数。用 e.id 替换 a.id 将给出事件 id 的列表以及它们所在的数字区域。

不幸的是,我不知道如何在 Ruby 中表达这些查询,但是您需要的数据库概念都在这里......

出于速度考虑,您应该查看 Postgres 的 GIStree 索引...索引多边形的性能呈指数级提高。

编辑:

PostGIS 是 Postgres 附带的一个 contrib 文件,但标准安装中不存在...您需要找到此 contrib 文件。这些将在您的数据库中安装一系列 GIS 功能,包括 ST_Contains。(函数驻留在数据库中,因此请确保将函数安装在您正在使用的数据库中)

PostGIS contrib 文件安装的第二件事是 template_postGIS 数据库,该数据库是几何数据类型所需的(在安装此数据库之前,geom 作为数据类型将不存在)。