Ruby on rails 多边形';包含';和其他不支持的几何图形操作

Ruby on rails 多边形';包含';和其他不支持的几何图形操作,ruby-on-rails,activerecord,postgis,rgeo,Ruby On Rails,Activerecord,Postgis,Rgeo,我对postgis和rgeo还不太熟悉。我怀疑我可能用错误的方式处理问题,但我有点惊讶地发现一些操作,特别是contains&inthein,在基于球形的对象上是不可能的 我有一堆地理上分布的对象,我想根据邮政编码之类的东西将它们分组。对于这些分组中的每一个,我都有一个边界,我想检查一个对象是否在该边界内,还想检查一个边界是否在另一个边界内。我使用的是rails,这是用于设置集合模型的迁移 class CreateGeoCollectionDefinition < ActiveRecord

我对postgis和rgeo还不太熟悉。我怀疑我可能用错误的方式处理问题,但我有点惊讶地发现一些操作,特别是contains&inthein,在基于球形的对象上是不可能的

我有一堆地理上分布的对象,我想根据邮政编码之类的东西将它们分组。对于这些分组中的每一个,我都有一个边界,我想检查一个对象是否在该边界内,还想检查一个边界是否在另一个边界内。我使用的是rails,这是用于设置集合模型的迁移

class CreateGeoCollectionDefinition < ActiveRecord::Migration[5.0]
  def change
     create_table :geo_collection_definitions do |t|
       t.string :name
       t.string :geo_place_id
       t.string :geo_place_types, array: true, default: []
       t.st_polygon :boundary, geographic: true
       t.jsonb :boundary_json
       t.st_point :latlng, geographic: true
     end
   end
end
我已经写了一些规范来检查每件事情是否按照我期望的方式运行。简单的基于距离的测试都如预期的那样通过,但用于测试边界功能的测试存在问题。我遇到了以下问题

 # ------------------
 # --- Caused by: ---
 # PG::UndefinedFunction:
 #   ERROR:  function st_contains(geography, geography) does not exist
 #   LINE 1: ...COUNT(*) FROM "geo_collection_definitions" WHERE (ST_Contain...
 #                                                                ^
 #   HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
当我尝试运行这样的查询时(我知道这有点傻)

或者如果我尝试直接使用rgeo对象

it "should be possible to test is points belong in GeoCollection.boundary" do
  factory = RGeo::Geographic.spherical_factory(srid: 4326)
  externalPoint = factory.point(EmptyGeocodeLatLag['lng'], EmptyGeocodeLatLag['lat'])
  expect(someplace_def.boundary.contains?(someplace_def.latlng)).to be_truthy
  expect(someplace_def.boundary.contains?(externalPoint)).to be_falsy
end
我明白了

  RGeo::Error::UnsupportedOperation:
   Method Geometry#contains? not defined.
深入研究后,我发现这一点和其他证据表明,基于球形工厂的对象不支持这些操作

我只是想知道

  • 真的是这样吗
  • 以迁移中描述的方式对对象的边界和位置进行建模对我来说似乎是有意义的,但我猜我错了
  • 我应该如何使用postgis、rgeo和active record适配器来确定一组点是否位于多边形内
  • 是否可以检查一个多边形是否在另一个多边形内
  • 编辑:

    我跟进了tilt的建议,并直接在db上运行了一些查询。首先,只是为了验证我的设置

    SELECT PostGIS_full_version();
    
     NOTICE:  Function postgis_topology_scripts_installed() not found. Is topology support enabled and topology.sql installed?                                  postgis_full_version
    
     POSTGIS="2.1.7 r13414" GEOS="3.5.0-CAPI-1.9.0 r4084" PROJ="Rel.   4.9.2, 08 September 2015" GDAL="GDAL 1.11.5, released 2016/07/01" LIBXML="2.9.2" LIBJSON="UNKNOWN" RASTER
    
    我还问了一些问题

      SELECT name  FROM geo_collection_definitions WHERE st_contains(latlng, boundary);
     ERROR:  function st_contains(geography, geography) does not exist
     LINE 1: ...ELECT name  FROM geo_collection_definitions WHERE   st_contain...
    
    所以guess contains在地理上不起作用。我四处翻找,发现了圣母院的盖子

      SELECT name  FROM geo_collection_definitions WHERE st_covers(boundary, latlng);
      name
      ------
      (0 rows)
    
     SELECT name  FROM geo_collection_definitions WHERE st_covers(boundary, ST_GeomFromText('POINT(12.9549709 55.5563043)', 4326));
      name
      ------
      (0 rows)
    
    这确实令人惊讶,因为latlng是边界的中心点。我很困惑,我肯定我在做一些很愚蠢的事情。非常感谢您提供的任何帮助

    我推荐使用,这是PostGIS的地理类型所支持的。对于半径参数,可以使用0或10(即,如果数据的精度为10 m)


    没有任何关于地理类型的计划。

    Mike和Tilt的回答帮助我弄清了问题的真相,这有点令人尴尬,但只是为了以防万一,这些东西可能会帮助其他人

    ST_DWithin绝对是解决我特殊问题的方法,能听到关于这一点的大喊真是太好了。我将一些规范查询更改为如下内容

      collectionDefs = GeoCollectionDefinition.where("ST_DWithin(boundary, '#{someplace.latlng}', 10)")
      expect(collectionDefs.count).to eq(2)
      collectionDefs = GeoCollectionDefinition.where("ST_DWithin(boundary, 'Point(0.0 0.0)', 10)")
      expect(collectionDefs.count).to eq(0) 
    
    查询运行得很好,这很好,但我仍然没有得到我期望的结果。这是令人尴尬的一点

    按照Tilt的建议,我打印出了多边形

    POLYGON((55.4965351 12.8894595,55.6445967 12.8894595,55.6445967 13.151087,55.4965351 13.151087,55.4965351 12.8894595)) and the centre point is POINT(13.0108705 55.5790534)
    
    很快发现了错误方向的坐标。损害是在我上面概述的
    createBoundary
    方法中造成的。我正在创建边界定义点,并通过lat值代替lng,反之亦然。我将代码更新为以下内容

     def self.createBoundary(pointOne, pointTwo)
        point1 = GEO_FACTORY.point(pointOne['lng'], pointOne['lat'])
        point2 = GEO_FACTORY.point(pointTwo['lng'], pointTwo['lat'])
        boundingBox =    RGeo::Cartesian::BoundingBox.create_from_points(point1, point2).to_geometry
       boundingBox
     end
    
    我会羞愧地低下头:)


    非常感谢你和迈克。我不确定我是否会发现ST_DWithin和pro postgist调试技巧确实让我省去了很多时间的挫折

    因为这个问题似乎完全是基于postgis的,如果你用SQL语句而不是rails来重新表述你的问题可能会更好。根据我的经验,在将查询连接到框架之前,最好先用纯SQL测试查询,这样可以更好地控制查询。您好!非常感谢你的回复。我肯定这只是我在做的傻事。我将调查是否安装了proj4。然后,我将尝试直接在postgis数据库上运行一些查询来测试东西扫描您是否给出该边界的WKT输出?(ST_AsText(边界))。另外,您确定要继续使用地理信息吗?如果你处理大规模(超越国界)的数据,这是有意义的,但通常情况下,最好是在本地投影中进行。我很惊讶你们的邮政编码是地理上的,通常是投影的。没问题,倾斜。这里是边界多边形的多边形((55.4965351 12.8894595,55.6445967 12.8894595,55.6445967 13.151087,55.4965351 13.151087,55.4965351 12.8894595)),中心点是点(13.0108705 55.5790534)啊!!多边形坐标是反向的!谢谢你!
    POLYGON((55.4965351 12.8894595,55.6445967 12.8894595,55.6445967 13.151087,55.4965351 13.151087,55.4965351 12.8894595)) and the centre point is POINT(13.0108705 55.5790534)
    
     def self.createBoundary(pointOne, pointTwo)
        point1 = GEO_FACTORY.point(pointOne['lng'], pointOne['lat'])
        point2 = GEO_FACTORY.point(pointTwo['lng'], pointTwo['lat'])
        boundingBox =    RGeo::Cartesian::BoundingBox.create_from_points(point1, point2).to_geometry
       boundingBox
     end