我對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 issue和其他證據表明,這些操作只是不支持球形工廠對象
我只是想知道;
- 這是絕對建模我的移民所描述的邊界和方式對象的位置似乎是有道理的我,但我猜我錯了的情況下
- ?
- 我應該如何查找使用postgis,rgeo和活動記錄適配器的一堆點是否在多邊形內?
- 是否可以檢查一個多邊形是否在另一個多邊形內?
編輯:
我跟進傾斜的建議,並直接運行在我的分貝一些查詢。首先,只是爲了驗證我的設置
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是邊界的中心點。我很困惑,並確信我正在做一些非常愚蠢的事情。任何幫助將不勝感激
多小時因爲問題似乎純粹的PostGIS基礎是,如果你的幫助下重新表述您的問題可能會更好一個SQL語句而不是rails。根據我的經驗,在將它們連接到框架之前,在純SQL中測試您的查詢總是更好,這會讓您得到更好的控制。 – tilt
嗨傾斜!非常感謝你的答覆。我確信這只是我正在做的事情。我將考慮確保我安裝了proj4。然後,我會嘗試直接在postgis db上運行一些查詢來測試東西 – Conor
您能給出該邊界的WKT輸出嗎? (ST_AsText(邊界))。另外,你確定你想繼續使用地理?如果你在大範圍(超越國界)數據的情況下工作,這很有意義,但通常情況下,最好在本地投影中工作。無論如何,我很驚訝你的郵政編碼在地理上,通常他們會被預測。 – tilt