2016-09-24 76 views
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 issue和其他證據表明,這些操作只是不支持球形工廠對象

我只是想知道;

  1. 這是絕對建模我的移民所描述的邊界和方式對象的位置似乎是有道理的我,但我猜我錯了的情況下
  2. 我應該如何查找使用postgis,rgeo和活動記錄適配器的一堆點是否在多邊形內?
  3. 是否可以檢查一個多邊形是否在另一個多邊形內?

編輯:

我跟進傾斜的建議,並直接運行在我的分貝一些查詢。首先,只是爲了驗證我的設置

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是邊界的中心點。我很困惑,並確信我正在做一些非常愚蠢的事情。任何幫助將不勝感激

+1

多小時因爲問題似乎純粹的PostGIS基礎是,如果你的幫助下重新表述您的問題可能會更好一個SQL語句而不是rails。根據我的經驗,在將它們連接到框架之前,在純SQL中測試您的查詢總是更好,這會讓您得到更好的控制。 – tilt

+0

嗨傾斜!非常感謝你的答覆。我確信這只是我正在做的事情。我將考慮確保我安裝了proj4。然後,我會嘗試直接在postgis db上運行一些查詢來測試東西 – Conor

+1

您能給出該邊界的WKT輸出嗎? (ST_AsText(邊界))。另外,你確定你想繼續使用地理?如果你在大範圍(超越國界)數據的情況下工作,這很有意義,但通常情況下,最好在本地投影中工作。無論如何,我很驚訝你的郵政編碼在地理上,通常他們會被預測。 – tilt

回答

2

我推薦使用ST_DWithin,這是很好的支持PostGIS'geography類型。對於半徑參數,可以使用0或10(即,如果數據的精度爲10 m)。

有沒有計劃使ST_ContainsST_Within可用於geography類型。

1

邁克和傾斜的迴應讓我去的這條底線,這是一個有點尷尬的一個,但以防萬一,任何這些東西可以幫助別人了線......

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 

我會羞愧地掛在我的頭上:)

太感謝了傾斜和麥克。我不知道我會發現ST_DWithin和親postgist調試技巧絕對救了我的無奈

相關問題