I am new to working with GIS, and am building a rails app that uses the rgeo gem and PostGIS.

I am trying to use geospatial data to determine the school district for a house. The house is represented by a point, and the school districts are represented by multipolygons. I have successfully plotted both on a map, and all appears to be working correctly, with the point falling inside of one of the polygons.

However, when I try to run the following code to determine which district the house is in, I get back an empty array:

>>  point = @property.coords
>> ES_Zone.where{ st_contains(geometry, point) }
=> #<ActiveRecord::Relation []>

I think that the SRIDs are the same on the points and polygons, because the factories for each show SRID 3785.

>> point.class
=> RGeo::Geos::CAPIPointImpl
>> point.factory
=> #<RGeo::Geos::CAPIFactory:0x860c5838 srid=3785 bufres=1 flags=8>

>> ES_Zone.first.geometry.class
=> RGeo::Geos::CAPIMultiPolygonImpl
>> ES_Zone.first.geometry.factory
=> #<RGeo::Geos::CAPIFactory:0x84889648 srid=3785 bufres=1 flags=8>

Any ideas on why this is happening, and suggestions for how to fix it?

  • you can post an answer to your own question - did you resolve this? – Mapperz Jun 5 '14 at 15:23
  • I'm exploring what @mtn.biker wrote, but so far no luck. – dmanaster Jun 5 '14 at 15:34
  • What does ES_Zone.where{ st_contains(geometry, point) }.to_sql return? – tee Jun 9 '14 at 20:33

Try the && operator:

scope :containing, -> (point) { where("#{self.table_name}.geometry && ?", point) }

From http://postgis.net/docs/manual-1.3/ch03.html:

In general, you will want to use the "intersects operator" (&&) which tests whether the bounding boxes of features intersect. The reason the && operator is useful is because if a spatial index is available to speed up the test, the && operator will make use of this. This can make queries much much faster.

You will also make use of spatial functions, such as Distance(), ST_Intersects(), ST_Contains() and ST_Within(), among others, to narrow down the results of your search. Most spatial queries include both an indexed test and a spatial function test. The index test serves to limit the number of return tuples to only tuples that might meet the condition of interest. The spatial functions are then use to test the condition exactly.

SELECT id, the_geom  FROM thetable
WHERE
the_geom && 'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))'
AND
ST_Contains(the_geom,'POLYGON((0 0, 0 10, 10 10, 10 0, 0 0))');
  • Thanks for taking a look at this, tee. In your example, I assumed that area was a stand-in for the geometry column in my table, so I changed the scope to: scope :containing, -> (point) { where("#{self.table_name}.geometry && ?", point) } However, it still returns an empty array as the result set. – dmanaster Jun 9 '14 at 18:55
  • I updated the example. You may want to try to get it working with raw SQL in psql. – tee Jun 9 '14 at 20:37

ST_Contains() returns a boolean (true/false) whether one geometry falls within another. Suggest you use ST_Intersects() because it's faster and you don't have to be so careful with the order of the arguments. Note:

There are certain subtleties to ST_Contains and ST_Within that are not intuitively obvious. For details check out Subtleties of OGC Covers, Contains, Within

  • Thanks for the answer. I'll use ST_Intersects in the future, but it does not seem to solve the underlying issue of getting back an empty array from my query. – dmanaster Jun 5 '14 at 16:19
  • Yes, I saw some of the comments - your issue doesn't seem to be the where clause of the query. I don't know rails & rgeo, but the next thing I'd look at is defining your point as a geometry. That is, I would think you need to do something like: ST_Intersects(geometry, (ST_SetSRID(ST_MakePoint(point.X, point.Y),3785) ) – mtn.biker Jun 5 '14 at 16:57

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.