2016-09-24 3 views
2

Ich bin ziemlich neu in Postgis und RGEO. Ich vermute, dass ich Dinge auf die falsche Art angehen kann, aber ich war ein wenig überrascht, ein paar Operationen zu finden, insbesondere enthält & innerhalb, sind auf sphärischen Objekten nicht möglich.Polygon 'enthält' und andere Operationen auf Geometrien nicht unterstützt

Ich habe eine Reihe von geografisch verteilten Objekten, die ich gerne zusammen gruppieren würde basierend auf Dinge wie Postleitzahl. Für jede dieser Gruppierungen habe ich eine Grenze und ich möchte überprüfen, ob sich ein Objekt innerhalb dieser Grenze befindet und auch prüfen, ob eine Grenze innerhalb einer anderen liegt. Ich bin mit Schienen und dies ist die Migration meiner Sammlung Modell

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 

einzurichten Derzeit ist die Grenze von einem Google kommenden geocode-Reverse-Lookup. Die Nordost- und Südwest Begrenzungsbox Koordinaten werden in diesem Verfahren auf Objekterstellung übergeben

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 

Ich habe ein paar von Spezifikationen geschrieben, dass alles, was zu überprüfen ist in der Art und Weise verhalten, die ich erwarte. Die einfachen entfernungsbasierten Tests werden alle wie erwartet durchgeführt, aber es gibt Probleme mit denen, die zum Testen der Grenzfunktion verwendet werden. Ich laufe in den folgenden

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

Wenn ich versuche, und eine Abfrage wie (ich weiß, es ist ein bisschen eine dumme ein) laufen

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

oder wenn ich versuche, das RGEO-Objekt direkt

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 

ich

RGeo::Error::UnsupportedOperation: 
    Method Geometry#contains? not defined. 

Diggin g ringsherum fand ich diese rgeo issue und andere Beweise, dass diese Operationen nur für sphärische Fabrik basierte Objekte nicht unterstützt werden

Ich frage mich nur;

  1. Ist dies definitiv der Fall
  2. die Grenze und die Lage der Objekte in der Art und Weise in meiner Migration beschrieben Modellierung scheint Sinn für mich zu machen, aber ich nehme an, ich bin falsch daran?
  3. Wie soll ich herausfinden, ob eine Reihe von Punkten innerhalb eines Polygons mit Hilfe von Postgis, Rgeo und dem aktiven Record-Adapter sind?
  4. Ist es möglich zu prüfen, ob ein Polygon in einem anderen liegt?

EDIT:

folgte ich auf Tilt Vorschlag auf und lief auf meinem db einige Anfragen direkt. Zuerst, nur um meine Einrichtung zu überprüfen

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 

Ich habe auch einige Abfragen ausgeführt;

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

So raten enthält nur nicht auf geographies.Ich kramte und ich fand 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) 

Das ist wirklich überraschend, da latlng der Mittelpunkt der Grenze ist. Ich bin ziemlich verwirrt und sicher, dass ich etwas ziemlich dummes mache. Jede Hilfe würde sehr geschätzt

+1

Da das Problem scheint rein postgis basiert, könnte es besser sein, wenn Sie Ihre Frage mit Hilfe von neu formulieren eine SQL-Anweisung anstelle von Rails. Meiner Erfahrung nach ist es immer besser, Ihre Abfragen in reinem SQL zu testen, bevor Sie sie mit einem Framework verbinden. Dies gibt Ihnen eine bessere Kontrolle. – tilt

+0

Hallo Tilt! Tausend Dank für deine Antwort. Ich bin mir sicher, dass es nur etwas Dummes ist, was ich mache. Ich werde prüfen, ob ich proj4 installiert habe. Ich werde dann versuchen, einige Abfragen direkt auf Postgis-DB zu starten, um Dinge zu testen – Conor

+1

Können Sie eine WKT-Ausgabe dieser Grenze geben? (ST_AsText (Grenze)). Sind Sie sicher, dass Sie Geografie weiterhin verwenden möchten? Es macht Sinn, wenn Sie mit großen Datenmengen (über nationale Grenzen hinaus) arbeiten, aber normalerweise ist es besser, in der lokalen Projektion zu arbeiten. Ich bin überrascht, dass Ihre Postleitzahlen sowieso geografisch sind, normalerweise würden sie projiziert werden. – tilt

Antwort

2

Ich empfehle die Verwendung ST_DWithin, die für PostGIS 'geography Typ gut unterstützt wird. Für den Radius-Parameter können Sie 0 oder vielleicht 10 verwenden (d. H. Wenn Ihre Daten eine Genauigkeit von 10 m haben).

Es gibt keine Pläne, ST_Contains oder ST_Within für geography Typ zur Verfügung zu stellen.

1

Mike und Tilt Antworten half mir auf den Grund zu gehen und es ist ein bisschen von einer peinlichen, aber nur für den Fall jede dieser Sachen könnte jemand anderes auf der ganzen Linie helfen ...

ST_DWithin ist definitiv der Weg für mein spezielles Problem und es war großartig, einen Ruf darüber zu bekommen. Ich änderte einige spec-Abfragen, um Dinge wie diese

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) 

Die Abfrage lief gut, was toll war, aber ich war immer noch nicht die Ergebnisse, ich erwartet hatte. Dies ist das peinlich Bit

Nach Tilt Rat, den ich das Polygon

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) 

ausgedruckt und entdeckte schnell, daß Koordinaten, wo die falsche Art und Weise. Der Schaden wurde in der oben beschriebenen Methode createBoundary gemacht. Ich habe die Grenzdefinitionspunkte erstellt und den Lat-Wert anstelle von Ing übergeben und umgekehrt. Ich den Code auf die folgenden aktualisierten

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 

Ich werde meinen Kopf in Scham hängen :)

Dank einer Million Tilt und Mike. Ich bin nicht sicher, dass ich das ST_DWithin gefunden hätte und die Pro-Postgist-Debugging-Tipps haben mir definitiv viele Stunden Frustration erspart

Verwandte Themen