I'm quite new to postgis and rgeo. I suspect I may be tackling things in the wrong way but I have been a bit surprised to find out a few operations, in particular contains & within, aren't possible on spherical based objects.
I have a bunch of geographically distributed objects which I would like to group together based on things like postcode. For each of of these groupings I have a boundary and I would like to check if an object is inside that boundary and also check if one boundary is inside another. I'm using rails and this is the migration used to set up my collection model
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
Currently the boundary is coming from a google reverse geocode lookup. The NorthEast and SouthWest bounding box coordinates are passed into this method on object creation
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
I have written a few of specs to check that everything is behaving in the way that I expect. The simple distance based tests all pass as expected but there are issues with the ones used to test the boundary functionality. I run into the following
# ------------------
# --- 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.
When I try and run a query like (I know its a bit of a silly one)
GeoCollectionDefinition.where("ST_Contains(boundary, boundary)")
or if I try using the rgeo object directly
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
I get
RGeo::Error::UnsupportedOperation:
Method Geometry#contains? not defined.
Digging around I found this rgeo issue and other evidence that these operations are just not supported for spherical factory based objects
I'm just wondering;
EDIT:
I followed up on tilt's suggestion and ran some queries directly on my db. First, just to verify my set up
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
I also ran some queries;
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 guess contains just won't work on geographies. I dug around and I found 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)
This is really surprising as latlng is the centre point of boundary. I'm pretty confused and sure I'm doing something pretty stupid. Any help would be greatly appreciated
I recommend using ST_DWithin, which is well supported for PostGIS' geography
type. For the radius parameter, you can use 0 or maybe 10 (i.e. if your data has an accuracy of 10 m).
There are not any plans to make ST_Contains or ST_Within available for geography
type.