rgeo-geojson
rgeo-geojson copied to clipboard
Fail to decode polygons with overlapping areas
I've noticed a problem when trying to decode areas with "bowtie" like shapes:
geojson = '{"type":"Polygon","coordinates":[[[40.1605224609375,50.48547354578499],[41.890869140625,49.75642885858046],[41.8963623046875,50.447011182312195],[40.1495361328125,50.025387620270244],[40.1605224609375,50.48547354578499]]]}'
polygon = RGeo::GeoJSON.decode(geojson, json_parser: :json)
# => returns nil
And, as you can see here, this is a valid Geo JSON Polygon.
Debugging the code, we could check that lib/rgeo/geo_json/coder.rb @ line 246
calls
ring = @geo_factory.linear_ring(points)
Which actually raises an RGeo::Error::InvalidGeometry: LinearRing failed ring test
and returns nil
.
Version tested: 0.4.3
+1 here
+1 Version 2.1.1 problem still exists
I could indeed reproduce this issue by forcing the simple_factory
(the geos based one does not reproduce).
geojson = '{"type":"Polygon","coordinates":[[[40.1605224609375,50.48547354578499],[41.890869140625,49.75642885858046],[41.8963623046875,50.447011182312195],[40.1495361328125,50.025387620270244],[40.1605224609375,50.48547354578499]]]}'
polygon = RGeo::GeoJSON.decode(geojson, geo_factory: RGeo::Cartesian.simple_factory)
With that said, it looks like a geojson accepts complex polygons (https://tools.ietf.org/html/rfc7946#section-3.1.6). Hence we may considere setting uses_lenient_assertions for the coder geo_factory. This would make the polygon not compliant with OGC as mentioned in rgeo. However, I don't know yet enough about RGeo's codebase to make that decision globally. @keithdoggett what is your opinion on that one ?
Locally, a quick fix is:
geojson = <<~JSON
{
"type":"Polygon",
"coordinates": [[
[40.1605224609375,50.48547354578499],
[41.890869140625,49.75642885858046],
[41.8963623046875,50.447011182312195],
[40.1495361328125,50.025387620270244],
[40.1605224609375,50.48547354578499]
]]
}
JSON
polygon = RGeo::GeoJSON.decode(geojson, geo_factory: RGeo::Cartesian.simple_factory(uses_lenient_assertions: true))
puts polygon
And for convenience:
# in some init file
GEOJSON_CODER = RGeo::GeoJSON.coder(geo_factory: RGeo::Cartesian.simple_factory(uses_lenient_assertions: true))
# later
geojson = <<~JSON
{
"type":"Polygon",
"coordinates": [[
[40.1605224609375,50.48547354578499],
[41.890869140625,49.75642885858046],
[41.8963623046875,50.447011182312195],
[40.1495361328125,50.025387620270244],
[40.1605224609375,50.48547354578499]
]]
}
JSON
GEOJSON_CODER.decode(geojson)
This might as well be a bit related with rgeo/rgeo#228, since it depends on the is_simple?
method. However, the fact that geos is giving varying behaviors for the is_simple?
method is already tracked in https://github.com/rgeo/rgeo/issues/218.
EDIT: sorry for the quick close/reopen, but I think we may be able to handle this issue here