#34406: Add support for curved geometries in GeoDjango
-------------------------------------+-------------------------------------
               Reporter:  Fabien Le  |          Owner:  nobody
  Frapper                            |
                   Type:  New        |         Status:  new
  feature                            |
              Component:  GIS        |        Version:  4.1
               Severity:  Normal     |       Keywords:  geodjango gdal
           Triage Stage:             |      Has patch:  0
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 I tried ingesting curved geometries in a `GeometryField` in GeoDjango.

 At first I encountered some errors as these are not officially supported
 in GeoDjango, but I noticed that `gdal` is able to go from a geometry to
 another using converters :
 - Currently supported geometries
 
https://github.com/django/django/blob/main/django/contrib/gis/gdal/geometries.py#L727
 - Corresponding geometries in `gdal`
 https://gdal.org/doxygen/ogr__core_8h.html#a800236a0d460ef66e687b7b65610f12a

 I successfully ingested the following geometries for a project :
 - 9: "CompoundCurve"
 - 10: "CurvePolygon"
 - 11: "MultiCurve"
 - 12: "MultiSurface"

 ----

 Below is a code snippet I used, subclassing `OGRGeometry` and
 `OGRGeomType` in order to bypass existing GeoDjango validation to add
 support for more geometries :
 - Link to the snippet with syntax highlighting
 https://gist.github.com/fabienheureux/2dd4dad8f7c4fedef708154eea1470f9
 - It mainly adds keys for new geometries and classes inheriting for
 `OGRGeometry` to handle these in GeoDjango
 - It shows how we could make these geometries backward compatible (from
 curved geometries to more standard geometries) using a simple call to
 existing gdal methods

 **Is there a reason why it is not supported at the moment in GeoDjango ?
 Would you consider a pull request adding support for these geometries ?**

 I could suggest a patch based on the snippet above, but I am not sure how
 to treat the `transform` part of it.
 Should we keep this part ?
 It seems that Postgis can handle these polygons
 https://postgis.net/docs/using_postgis_dbmanagement.html#CircularString

 ----

 Here is the same snippet but without syntax highlighting

 {{{
 from django.contrib.gis.gdal.geometries import GEO_CLASSES, OGRGeometry
 from django.contrib.gis.gdal.geomtype import OGRGeomType
 from django.contrib.gis.gdal.libgdal import lgdal
 from django.contrib.gis.gdal.prototypes import ds as capi
 from django.contrib.gis.gdal.prototypes import geom as geom_api


 class ExtendedOGRGeometry(OGRGeometry):
     def __init__(self, geom_input, srs=None):
         try:
             super().__init__(geom_input, srs)
         except KeyError:
             if (
                 not isinstance(geom_input, self.ptr_type)
                 and self.geom_type.num not in gdal_transform.keys()
             ):
                 raise

              self.__class__ = EXTENDED_GEO_CLASSES[self.geom_type.num]

     @property
     def geom_type(self):
         "Return the Type for this Geometry."
         return ExtendedOGRGeomType(geom_api.get_geom_type(self.ptr))

 class CurvePolygon(ExtendedOGRGeometry):
     pass

 class CompoundCurve(ExtendedOGRGeometry):
     pass

 class MultiSurface(ExtendedOGRGeometry):
     pass

 class MultiCurve(ExtendedOGRGeometry):
     pass

 EXTENDED_GEO_CLASSES = {
     **GEO_CLASSES,
     9: CompoundCurve,
     10: CurvePolygon,
     11: MultiCurve,
     12: MultiSurface,
 }

 class ExtendedOGRGeomType(OGRGeomType):
     # Copy paste of original types dictionnary from GeoDjango
 implementation
     #
 
https://github.com/django/django/blob/main/django/contrib/gis/gdal/geomtype.py#L9
     _types = {
         0: "Unknown",
         1: "Point",
         2: "LineString",
         3: "Polygon",
         4: "MultiPoint",
         5: "MultiLineString",
         6: "MultiPolygon",
         7: "GeometryCollection",
         100: "None",
         101: "LinearRing",
         102: "PointZ",
         1 + OGRGeomType.wkb25bit: "Point25D",
         2 + OGRGeomType.wkb25bit: "LineString25D",
         3 + OGRGeomType.wkb25bit: "Polygon25D",
         4 + OGRGeomType.wkb25bit: "MultiPoint25D",
         5 + OGRGeomType.wkb25bit: "MultiLineString25D",
         6 + OGRGeomType.wkb25bit: "MultiPolygon25D",
         7 + OGRGeomType.wkb25bit: "GeometryCollection25D",
         # Extended geometry types
         9: "CompoundCurve",
         10: "CurvePolygon",
         11: "MultiCurve",
         12: "MultiSurface",
     }


 # New bindings to existing GDAL methods
 force_to_polygon = geom_output(lgdal.OGR_G_ForceToPolygon, [c_void_p])
 force_to_multi_polygon = geom_output(lgdal.OGR_G_ForceToMultiPolygon,
 [c_void_p])
 force_to_line = geom_output(lgdal.OGR_G_ForceToLineString, [c_void_p])
 force_to_multi_line = geom_output(lgdal.OGR_G_ForceToMultiLineString,
 [c_void_p])

 # The functions below need to be called on the corresponding geometry type
 # before saving it in the database to prevent errors in geodjango.
 gdal_transform = {
     9: force_to_line,
     10: force_to_polygon,
     11: force_to_multi_line,
     12: force_to_multi_polygon,
 }

 def ingest_curved_geometry(geom_ptr):
     transform = gdal_transform[geom.geom_type.num]
     geom = ExtendedOGRGeometry(transform(geom_api.clone_geom(geom_ptr)))

     # FIXME: for a yet unknown reason, the initial SRID is not kept when
 using ExtendedOGRGeometry
     geom.srid = 3857
     geom.transform(4326)
 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/34406>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/01070186d03f5c52-e4b29872-3e21-4c1b-853e-83106e7f979a-000000%40eu-central-1.amazonses.com.

Reply via email to