2

私はpostgisとrgeoにまったく慣れていません。私は間違った方法で物事に取り組んでいる可能性があると思いますが、いくつかの操作、特に包含と範囲内が球ベースのオブジェクトでは不可能であることを知って少し驚いています。

郵便番号などに基づいてグループ化したい地理的に分散したオブジェクトがたくさんあります。これらのグループごとに境界があり、オブジェクトがその境界内にあるかどうかを確認し、ある境界が別の境界内にあるかどうかも確認したいと考えています。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

現在、境界は Google リバース ジオコード ルックアップから取得されています。北東と南西のバウンディング ボックスの座標は、オブジェクトの作成時にこのメソッドに渡されます。

GEO_FACTORY = RGeo::Geographic.spherical_factory(srid: 4326)

def self.createBoundary(pointOne, pointTwo)
  point1 = GEO_FACTORY.point(pointOne['lat'], pointOne['lng'])
  point2 = GEO_FACTORY.point(pointTwo['lat'], pointTwo['lng'])
  boundingBox = RGeo::Cartesian::BoundingBox.create_from_points(point1,    point2).to_geometry
  boundingBox
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.

次のようなクエリを実行しようとすると(少しばかげていることはわかっています)

 GeoCollectionDefinition.where("ST_Contains(boundary, boundary)")

または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.

掘り下げてみると、このrgeoの問題と、これらの操作が球形のファクトリベースのオブジェクトではサポートされていないという他の証拠が見つかりました

ちょっと思ったんです;

  1. これは間違いないか
  2. 移行で説明した方法で境界とオブジェクトの位置をモデル化することは、私には理にかなっているように思えますが、それについては間違っていると思いますか?
  3. postgis、rgeo、およびアクティブなレコード アダプターを使用して、多数のポイントがポリゴン内にあるかどうかを調べるにはどうすればよいですか?
  4. あるポリゴンが別のポリゴンの中にあるかどうかを確認することはできますか?

編集:

私は傾斜の提案をフォローアップし、データベースで直接いくつかのクエリを実行しました。まず、セットアップを確認するだけです

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...

したがって、含まれていると推測すると、地域では機能しません。私は周りを掘り下げて、st_coversを見つけました

  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 が境界の中心点であるため、これは本当に驚くべきことです。私はかなり混乱していて、かなりばかげたことをしていると確信しています。どんな助けでも大歓迎です

4

2 に答える 2

2

PostGIS のタイプで十分にサポートされているST_DWithinを使用することをお勧めします。geographyradius パラメーターには、0 または 10 を使用できます (つまり、データの精度が 10 m の場合)。

タイプにST_ContainsまたはST_Withinを使用できるようにする予定はありませんgeography

于 2016-09-25T23:28:19.637 に答える
1

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) 

クエリは問題なく実行されましたが、期待していた結果が得られませんでした。これは恥ずかしいビットです

ティルトのアドバイスに従って、ポリゴンを印刷しました

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損傷は、上で概説した方法で行われていました。私は境界定義ポイントを作成し、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

私は恥ずかしくて頭を下げます:)

100 万人の Tilt と Mike に感謝します。ST_DWithin とプロの postgist デバッグのヒントを見つけることができたかどうかはわかりませんが、何時間ものフラストレーションを確実に軽減してくれました。

于 2016-09-26T09:52:03.853 に答える