Opened 5 months ago

Last modified 42 hours ago

#37173 assigned New feature

Support for curved geometry types

Reported by: Matthias Kuhn Owned by: Matthias Kuhn
Component: GIS Version: dev
Severity: Normal Keywords:
Cc: Triage Stage: Accepted
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

GeoDjango has support for various geometry types (Point, Line, Polygon and their Multi types), the gdal component also supports curves but geos and the db mapping do not yet have support for curved types.

Support for the following types should be added for supporting curved types:

CircularString,
CompoundCurve,
CurvePolygon,
MultiCurve,
MultiSurface

We have been working on libgeos to introduce basic support for curves in version 3.13 ​https://github.com/libgeos/geos/releases/tag/3.13.0, the support is gradually improved in the algorithms in 3.14 and upcoming 3.15.

Postgis allows for storing curved types for a long time already.

We will be happy to work on support for this.

Change History (3)

comment:1 by David Smith, 5 months ago

Owner: set to Matthias Kuhn
Status: new → assigned
Triage Stage: Unreviewed → Accepted

Thanks for the ticket. Adding support for curved geometries to GEOS / database would be a good next step in this area. #34406 was the ticket that resulted in GDAL support for curved geometries being added.

#36849 was a sidequest from when I speculatively looked at this (Nov-2024). GEOS raised many error messages (or at least 3.13 did) as many functions did not support curved geometries. Django currently crashes with an unintuitive GEOSException in this scenario with the underlying GEOS message not easily visible. That ticket/patch aim to improve that.

A patch would be very welcome. I'll set yourself as the owner of the ticket.

comment:2 by Matthias Kuhn, 4 months ago

Thanks for the additional information.

Note: 3.15 also comes with the possibility to automatically segmentize curves if the underlying operations do not support curves, this would avoid exceptions at the expense of potentially lossy operations.

​https://github.com/libgeos/geos/pull/1382

comment:3 by suricactus, 42 hours ago

With some coordination with Matthias, who opened the ticket, I have prepared a patch with the proposed changes, which includes:

  • form fields for curved geoms.
  • model fields for curved geoms.
  • curved geom classes in django.contrib.gis.geos .
  • extensive test suite.

Those changes are more or less straighforward.

All tested with GEOS 3.12.3 to 3.15.0, but for better use of the curved geoms 3.15.0+ is required. There is still a lot of work going on around curved geoms in GEOS, so the situation will only improve in the future.

However, without passing GEOSContext_setCurveToLineParams_r and GEOSContext_setLineToCurveParams_r (​https://github.com/libgeos/geos/blob/75c538dc1841a905f0cc771230ce67e405343fb9/capi/geos_c.h.in#L549-L579) using curved geometries is a minefield whether the function is supported or not. Functions such as isValid_r and equals_r are not yet supported in GEOS 3.15.0.

So I would propose we add a new context manager, that allows configuring the automatic curve to line and line to curve conversions. A sample usage in a test:

geom = CircularString((2, 5), (8, 5), (2, 5))
obj = CircularStringModel.objects.create(geom=geom)

if geos_version_tuple() >= (3, 15, 0):
    with geos_curve_conversion(curve_to_line_params=GEOSCurveToLineParams()):
        self.assertTrue(obj.geom.equals(geom)) # without the context manager raises `Error encountered on GEOS C predicate function ...`

The idea is anyone can write a Django middleware to enable such conversion if they want.

I also considered adding new global setting such a GEOS_CURVE_TO_LINE: bool or GEOS_CURVE_TO_LINE: dict {max_step_degrees, max_deviation}, but it's a bit trickier to deal with it. Also there is a way to set the CurveToLine and LineToCurve conversion, but you cannot read the currently configured parameters from Python.

So my question would be: shall 1) I open a new ticket to propose the context manager and then a follow-up PR, or 2) shall I do a two commit PR with the basic changes requested in this ticket and then introducing the context manager, both prefixed with "Fixed #37173", or 3) just put everything in one gigantic commit "Fixed #37173"? Sorry for the question, my first upstream django contribution, and I want to keep things simple enough for review too.

Note: See TracTickets for help on using tickets.
Back to Top