1.. _rfc-49:
2
3=======================================================================================
4RFC 49: Curve geometries
5=======================================================================================
6
7Author: Even Rouault
8
9Contact: even dot rouault at spatialys dot com
10
11Status: Adopted, implemented in GDAL 2.0
12
13Summary
14-------
15
16The current geometry model in GDAL 1.X makes use of points, lines,
17polygons and aggregations of them (multipoints, multilines,
18multipolygons and geometry collections). It was modeled from the
19geometry class hierarchy of the "OpenGIS Simple Feature Access Part 1 :
20Common Architecture" (in its 1.1.0 version).
21
22This RFC covers the addition of new geometry types that have been added
23in ISO/IEC 13249 Part 3 Spatial (abbreviated as ISO SQL/MM Part 3):
24
25-  circular string: a circular arc, or a sequence of connected circular
26   arcs, each of them describe by 3 points: the first point of the arc,
27   an intermediate point and the final point
28-  compound curve: a sequence of connected curves, either line strings
29   or circular strings
30-  curve polygon: polygon consisting of one outer ring, and zero or more
31   inner ring. Each ring can be one of the curve implementations: line
32   strings, circular strings, compound curves.
33-  multicurve: a collection of curves (line strings, circular strings,
34   compound curves)
35-  multisurface: a collection of surfaces (polygons, curve polygons)
36
37The scope of this RFC consists in :
38
39-  adding the new geometry classes to the existing geometry class
40   hierarchy, with the corresponding importer and exporter of WKT (Well
41   Known Text) and WKB (Well Known Binary) encodings
42-  adding methods to convert those curve geometries into their
43   approximated linear version, and to do the reverse operation
44-  upgrading some of the drivers that can support such geometries : GML
45   (and indirectly NAS, WFS), PostGIS/PGDump, GeoPackage, SQLite, CSV,
46   VRT.
47
48Reference documents
49-------------------
50
51The following documents have been used for the implementation :
52
53-  `Old draft version of ISO/IEC 13249 Part 3 Spatial, dating from
54   2004-05-09 <http://jtc1sc32.org/doc/N1101-1150/32N1107-WD13249-3--spatial.pdf>`__,
55   a.k.a SQL/MM Part 3 : Caution the WKB codes given at page 137 and
56   following are not the latest ones used. Refer to SFA 1.2.1
57
58-  `OpenGIS Simple Feature Access Part 1 : Common Architecture,v
59   1.2.1 <http://portal.opengeospatial.org/files/?artifact_id=25355>`__,
60   a.k.a. SFA 1.2.1
61
62-  `BNF of WKT
63   encoding <https://github.com/postgis/postgis/blob/svn-trunk/doc/bnf-wkt.txt>`__:
64   extracted from SQL/MM Part 3
65
66-  `BNF of WKB
67   encoding <https://github.com/postgis/postgis/blob/svn-trunk/doc/bnf-wkb.txt>`__:
68   extracted from SQL/MM Part 3
69
70Core changes
71------------
72
73New cass hierarchy
74~~~~~~~~~~~~~~~~~~
75
76The new class hierarchy is the following and is mostly consistent with
77SQL/MM Part 3
78
79.. image:: ../../../images/rfc49/classOGRGeometry.png
80
81The only exceptions are :
82
83-  OGRLinearRing: this class present in GDAL 1.X is kept for backward
84   compatibility and also because it is still present in SFA 1.2.1, even
85   if absent from SQL/MM Part 3
86-  OGRSimpleCurve: this abstract class is an implementation detail in
87   OGR that simplifies the implementation of OGRCircularString, by
88   sharing code with what was in OGRLineString only.
89
90Geometry types
91~~~~~~~~~~~~~~
92
93The OGRwkbGeometryType enumeration has been extended with the following
94values :
95
96::
97
98       wkbCircularString = 8,  /**< one or more circular arc segments connected end to end,
99                                *   ISO SQL/MM Part 3. GDAL >= 2.0 */
100       wkbCompoundCurve = 9,   /**< sequence of contiguous curves, ISO SQL/MM Part 3. GDAL >= 2.0 */
101       wkbCurvePolygon = 10,   /**< planar surface, defined by 1 exterior boundary
102                                *   and zero or more interior boundaries, that are curves.
103                                *    ISO SQL/MM Part 3. GDAL >= 2.0 */
104       wkbMultiCurve = 11,     /**< GeometryCollection of Curves, ISO SQL/MM Part 3. GDAL >= 2.0 */
105       wkbMultiSurface = 12,   /**< GeometryCollection of Surfaces, ISO SQL/MM Part 3. GDAL >= 2.0 */
106
107       wkbCircularStringZ = 1008,  /**< wkbCircularString with Z component. ISO SQL/MM Part 3. GDAL >= 2.0 */
108       wkbCompoundCurveZ = 1009,   /**< wkbCompoundCurve with Z component. ISO SQL/MM Part 3. GDAL >= 2.0 */
109       wkbCurvePolygonZ = 1010,    /**< wkbCurvePolygon with Z component. ISO SQL/MM Part 3. GDAL >= 2.0 */
110       wkbMultiCurveZ = 1011,      /**< wkbMultiCurve with Z component. ISO SQL/MM Part 3. GDAL >= 2.0 */
111       wkbMultiSurfaceZ = 1012,    /**< wkbMultiSurface with Z component. ISO SQL/MM Part 3. GDAL >= 2.0 */
112
113The codes have been taken from SFA 1.2.1, and are consistent with the
114PostGIS 2 implementation. Note that ISO SQL/MM Part 3 allows alternates
115values for wkbCircularString (8 or 1000001) : see Table 15 in the above
116mentioned draft. The values in the range 10000XX probably date back
117from an earlier draft version. OGR will import them, but will use the
118values from SFA 1.2.1 when exporting WKB.
119
120It has been considered if it would worth to modify the enumeration
121values of the existing 2.5D geometries (wkbPoint25D, etc...) to conform
122with the WKB codes of ISO SQL/MM Part 3 / SFA 1.2.1, but there was not a
123clear advantage in doing so, with respect to the impact on existing
124users of OGR API.
125
126Note: the mix of different ways of expression the Z dimension (wkb25DBit
127bit for "old" geometry types, and +1000 for "new" geometry types) has no
128direct impact on the export of geometries as WKB. There is no direct
129coupling between the values of OGRwkbGeometryType and what goes to WKB
130geometries. The exportToWkb() method of OGRGeometry takes a wkbVariant
131parameter to select the variant of WKB that is wished.
132
133The use of the wkb25DBit value (0x8000000) that was sometimes used to
134test if a geometry type was 3D is now clearly deprecated since it will
135not work for the new geometry type. The wkbHasZ() and wkbSetZ() have
136been added to respectively test if a geometry type is 3D, or modify a
137geometry type to be 3D. The wkb25DBit constant is now disabled for all
138code in GDAL (but still accessible by user code) and all drivers have
139been converted to use the new macros.
140
141A new family of functions have been used to operate on geometry types :
142
143::
144
145   OGRwkbGeometryType CPL_DLL OGR_GT_Flatten( OGRwkbGeometryType eType );
146       --> Returns the 2D geometry type corresponding to the passed geometry type.
147
148   OGRwkbGeometryType CPL_DLL OGR_GT_SetZ( OGRwkbGeometryType eType );
149       --> Returns the 3D geometry type corresponding to the passed geometry type.
150
151   OGRwkbGeometryType CPL_DLL OGR_GT_SetModifier( OGRwkbGeometryType eType, int bSetZ, int bSetM );
152       --> Returns a 2D or 3D geometry type depending on parameter.
153
154   int                CPL_DLL OGR_GT_HasZ( OGRwkbGeometryType eType );
155       --> Return if the geometry type is a 3D geometry type.
156
157   int                CPL_DLL OGR_GT_IsSubClassOf( OGRwkbGeometryType eType,
158                                                   OGRwkbGeometryType eSuperType );
159       --> Returns if a type is a subclass of another one
160
161   int                CPL_DLL OGR_GT_IsCurve( OGRwkbGeometryType );
162       -->  Return if a geometry type is an instance of Curve
163           (i.e. wkbLineString, wkbCircularString or wkbCompoundCurve)
164
165   int                CPL_DLL OGR_GT_IsSurface( OGRwkbGeometryType );
166       -->  Return if a geometry type is an instance of Surface
167           (i.e. wkbPolygon or wkbCurvePolygon)
168
169   int                CPL_DLL OGR_GT_IsNonLinear( OGRwkbGeometryType );
170       --> Return if a geometry type is a non-linear geometry type.
171           Such geometry type are wkbCircularString, wkbCompoundCurve, wkbCurvePolygon,
172           wkbMultiCurve, wkbMultiSurface and their 3D variant.
173
174   OGRwkbGeometryType CPL_DLL OGR_GT_GetCollection( OGRwkbGeometryType eType );
175       -->  Returns the collection type that can contain the passed geometry type
176
177   OGRwkbGeometryType CPL_DLL OGR_GT_GetCurve( OGRwkbGeometryType eType );
178       --> Returns the curve geometry type that can contain the passed geometry type.
179           Handled conversions are : wkbPolygon -> wkbCurvePolygon,
180           wkbLineString->wkbCompoundCurve, wkbMultiPolygon->wkbMultiSurface
181           and wkbMultiLineString->wkbMultiCurve.
182
183   OGRwkbGeometryType CPL_DLL OGR_GT_GetLinear( OGRwkbGeometryType eType );
184       --> Returns the non-curve geometry type that can contain the passed geometry type
185           Handled conversions are : wkbCurvePolygon -> wkbPolygon,
186           wkbCircularString->wkbLineString, wkbCompoundCurve->wkbLineString,
187           wkbMultiSurface->wkbMultiPolygon and wkbMultiCurve->wkbMultiLineString.
188
189The existing wkbFlatten() is an alias of OGR_GT_Flatten(), the new
190wkbHasZ() an alias of OGR_GT_HasZ() and wkbSetZ() an alias of
191OGR_GT_SetZ().
192
193New methods
194~~~~~~~~~~~
195
196-  In OGRGeometry class :
197
198::
199
200
201       virtual OGRBoolean hasCurveGeometry(int bLookForNonLinear = FALSE) const;
202
203   /**
204    * \brief Returns if this geometry is or has curve geometry.
205    *
206    * Returns if a geometry is, contains or may contain a CIRCULARSTRING, COMPOUNDCURVE,
207    * CURVEPOLYGON, MULTICURVE or MULTISURFACE.
208    *
209    * If bLookForNonLinear is set to TRUE, it will be actually looked if the
210    * geometry or its subgeometries are or contain a non-linear geometry in them. In which
211    * case, if the method returns TRUE, it means that getLinearGeometry() would
212    * return an approximate version of the geometry. Otherwise, getLinearGeometry()
213    * would do a conversion, but with just converting container type, like
214    * COMPOUNDCURVE -> LINESTRING, MULTICURVE -> MULTILINESTRING or MULTISURFACE -> MULTIPOLYGON,
215    * resulting in a "loss-less" conversion.
216    */
217
218       virtual OGRGeometry* getCurveGeometry(const char* const* papszOptions = NULL) const;
219
220   /**
221    * \brief Return curve version of this geometry.
222    *
223    * Returns a geometry that has possibly CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON,
224    * MULTICURVE or MULTISURFACE in it, by de-approximating curve geometries.
225    *
226    * If the geometry has no curve portion, the returned geometry will be a clone
227    * of it.
228    *
229    * The ownership of the returned geometry belongs to the caller.
230    *
231    * The reverse method is OGRGeometry::getLinearGeometry().
232    *
233    * This function is the same as C function OGR_G_GetCurveGeometry().
234    *
235    * @param papszOptions options as a null-terminated list of strings.
236    *                     Unused for now. Must be set to NULL.
237    */
238
239       virtual OGRGeometry* getLinearGeometry(double dfMaxAngleStepSizeDegrees = 0,
240                                                const char* const* papszOptions = NULL) const;
241
242
243   /**
244    * \brief Return, possibly approximate, non-curve version of this geometry.
245    *
246    * Returns a geometry that has no CIRCULARSTRING, COMPOUNDCURVE, CURVEPOLYGON,
247    * MULTICURVE or MULTISURFACE in it, by approximating curve geometries.
248    *
249    * The ownership of the returned geometry belongs to the caller.
250    *
251    * The reverse method is OGRGeometry::getCurveGeometry().
252    *
253    * This method is the same as the C function OGR_G_GetLinearGeometry().
254    *
255    * @param dfMaxAngleStepSizeDegrees the largest step in degrees along the
256    * arc, zero to use the default setting.
257    * @param papszOptions options as a null-terminated list of strings.
258    *                     See OGRGeometryFactory::curveToLineString() for valid options.
259    */
260
261-  In OGRGeometryFactory class :
262
263::
264
265
266   static OGRLineString* curveToLineString(
267                                               double x0, double y0, double z0,
268                                               double x1, double y1, double z1,
269                                               double x2, double y2, double z2,
270                                               int bHasZ,
271                                               double dfMaxAngleStepSizeDegrees,
272                                               const char*const* papszOptions )
273   /**
274    * \brief Converts an arc circle into an approximate line string
275    *
276    * The arc circle is defined by a first point, an intermediate point and a
277    * final point.
278    *
279    * The provided dfMaxAngleStepSizeDegrees is a hint. The discretization
280    * algorithm may pick a slightly different value.
281    *
282    * So as to avoid gaps when rendering curve polygons that share common arcs,
283    * this method is guaranteed to return a line with reversed vertex if called
284    * with inverted first and final point, and identical intermediate point.
285    *
286    * @param x0 x of first point
287    * @param y0 y of first point
288    * @param z0 z of first point
289    * @param x1 x of intermediate point
290    * @param y1 y of intermediate point
291    * @param z1 z of intermediate point
292    * @param x2 x of final point
293    * @param y2 y of final point
294    * @param z2 z of final point
295    * @param bHasZ TRUE if z must be taken into account
296    * @param dfMaxAngleStepSizeDegrees  the largest step in degrees along the
297    * arc, zero to use the default setting.
298    * @param papszOptions options as a null-terminated list of strings or NULL.
299    * Recognized options:
300    * <ul>
301    * <li>ADD_INTERMEDIATE_POINT=STEALTH/YES/NO (Default to STEALTH).
302    *         Determine if and how the intermediate point must be output in the linestring.
303    *         If set to STEALTH, no explicit intermediate point is added but its
304    *         properties are encoded in low significant bits of intermediate points
305    *         and OGRGeometryFactory::curveFromLineString() can decode them.
306    *         This is the best compromise for round-tripping in OGR and better results
307    *         with PostGIS <a href="http://postgis.org/docs/ST_LineToCurve.html">ST_LineToCurve()</a>
308    *         If set to YES, the intermediate point is explicitly added to the linestring.
309    *         If set to NO, the intermediate point is not explicitly added.
310    * </li>
311    * </ul>
312    */
313
314   --> This method is used by OGRCircularString::getLinearGeometry()
315
316   OGRCurve* OGRGeometryFactory::curveFromLineString(const OGRLineString* poLS,
317                                                     CPL_UNUSED const char*const* papszOptions)
318
319   /**
320    * \brief Try to convert a linestring approximating curves into a curve.
321    *
322    * This method can return a COMPOUNDCURVE, a CIRCULARSTRING or a LINESTRING.
323    *
324    * This method is the reverse of curveFromLineString().
325    *
326    * @param poLS handle to the geometry to convert.
327    * @param papszOptions options as a null-terminated list of strings.
328    *                     Unused for now. Must be set to NULL.
329    */
330
331   --> This method is used by OGRLineString::getCurveGeometry()
332
333
334   OGRGeometry* OGRGeometryFactory::forceTo( OGRGeometry* poGeom,
335                                             OGRwkbGeometryType eTargetType,
336                                             const char*const* papszOptions )
337    *
338    * Tries to force the provided geometry to the specified geometry type.
339    *
340    * It can promote 'single' geometry type to their corresponding collection type
341    * (see OGR_GT_GetCollection()) or the reverse. non-linear geometry type to
342    * their corresponding linear geometry type (see OGR_GT_GetLinear()), by
343    * possibly approximating circular arcs they may contain.
344    * Regarding conversion from linear geometry types to curve geometry types, only
345    * "wrapping" will be done. No attempt to retrieve potential circular arcs by
346    * de-approximating stroking will be done. For that, OGRGeometry::getCurveGeometry()
347    * can be used.
348    *
349    * The passed in geometry is consumed and a new one returned (or potentially the same one).
350    *
351    * @param poGeom the input geometry - ownership is passed to the method.
352    * @param eTargetType target output geometry type.
353    * @param papszOptions options as a null-terminated list of strings or NULL.
354    * @return new geometry.
355    */
356
357   --> This method generalizes the existing forceToPolygon(), forceToLineString(),
358   forceToMultiPolygon(), forceToMultiLineString(), that have been extended to
359   deal with the new geometry types. forceTo() and actually calls them if they
360   can be used for the requested conversion, and also deal with conversion between
361   linear and non-linear geometry types.
362
363Implementation of existing OGRGeometry methods
364~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
365
366As GEOS does not support curve geometries for now, all GEOS related
367operations, the ones returning a boolean value such as Intersects(), or
368the ones returning a new geometry such as Intersection(), have been
369adapted so that non-linear geometries are first converted to their
370linear approximation (this might be revisited if GEOS supports curve
371geometries in the future) When GEOS returns a geometry, and that one of
372the input parameters was a non-linear geometry, the reverse operation is
373done to attempt retrieving as much as possible of the curve geometry. Of
374course, the result will not generally perfect, but it is better than
375nothing.
376
377Simple example doing the union of 2 half-circles that are contiguous:
378
379::
380
381       g1 = ogr.CreateGeometryFromWkt('CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING (0 0,1 1,2 0),(2 0,0 0)))')
382       g2 = ogr.CreateGeometryFromWkt('CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING (0 0,1 -1,2 0),(2 0,0 0)))')
383       g3 = g1.Union(g2)
384       assert g3.ExportToWkt() == 'CURVEPOLYGON (CIRCULARSTRING (0 0,1 1,2 0,1 -1,0 0))'
385
386Or using GetCurveGeometry() explicitly on the result of a buffer
387operation:
388
389::
390
391       g1 = ogr.CreateGeometryFromWkt('POINT(1 2)')
392       g2 = g1.Buffer(0.5)
393       g3 = g2.GetCurveGeometry()
394       assert g3.ExportToWkt() != 'CURVEPOLYGON (CIRCULARSTRING (1.5 2.0,0.5 2.0,1.5 2.0))'
395
396The Length() operation on OGRCircularString (and thus OGRCompoundCurve)
397uses circle geometry to compute the exact length, without falling back
398to linear approximation. The Area() operation on OGRCurvePolygon will
399generally need to go to linear approximation. When operating on a full
400circle, or a curve polygon that is convex, an optimization is done to
401avoid this (by computing the area of the polygon formed with all the
402vertex including in the circular parts of the description, and adding
403the area of the `circular
404segments <http://en.wikipedia.org/wiki/Circular_segment>`__)
405
406C API changes
407~~~~~~~~~~~~~
408
409Deprecation:
410
411-  wkb25DBit still present, but deprecated since incompatible with the
412   new geometry type. Use the wkbFlatten(), wkbHasZ(), wkbSetZ() macros
413   instead
414
415Additions:
416
417-  OGR_GT_xxxx (for Geometry Type): described above
418-  OGRErr OGR_G_ExportToIsoWkb( OGRGeometryH, OGRwkbByteOrder, unsigned
419   char*) : Export geometry as WKB conforming to ISO SQL/MM Part 3.
420-  OGRErr OGR_G_ExportToIsoWkt( OGRGeometryH, char \*\* ) : Export
421   geometry as WKT conforming to ISO SQL/MM Part 3, i.e. 2.5D geometries
422   names are suffixed by " Z", e.g. "POINT Z (1 2 3)".
423-  OGRGeometryH OGR_G_Value( OGRGeometryH, double dfDistance ) : mapping
424   of existing OGRGeometry::Value()
425-  int OGR_G_HasCurveGeometry( OGRGeometryH, int bLookForNonLinear ) :
426   mapping of OGRGeometry::hasCurveGeometry()
427-  OGRGeometryH OGR_G_GetLinearGeometry( OGRGeometryH hGeom, double
428   dfMaxAngleStepSizeDegrees, char*\* papszOptions) : mapping of
429   OGRGeometry::hasCurveGeometry()
430-  OGRGeometryH OGR_G_GetCurveGeometry( OGRGeometryH hGeom, char*\*
431   papszOptions ) : mapping of OGRGeometry::hasCurveGeometry()
432-  void OGRSetNonLinearGeometriesEnabledFlag(int bFlag) : discussed in
433   Backward compatibility section
434-  int OGRGetNonLinearGeometriesEnabledFlag() : discussed in Backward
435   compatibility section
436
437Changes in drivers
438------------------
439
440-  GML geometry importer: Arc, ArcString, ArcByBulge, ArcByCenterPoint,
441   Circle and CircleByCenterPoints GML elements will be returned as
442   circular string OGR geometries. If they are included in other GML
443   elements such as CurveComposite, MultiCurve, Surface, corresponding
444   non-linear OGR geometries will be returned as well. When reading
445   geometries that are made of or consist of Surface, MultiSurface,
446   Curve, MultiCurve, an effort is made to return the OGR geometry class
447   of a linear type as much as possible, i.e. OGRCurvePolygon,
448   OGRCompoundCurve, etc... will only be returned if there's a circular
449   string in the geometry.
450
451-  GML geometry exporter: can generate ArcString and Circle GML elements
452   when passed a geometry with circular string in it.
453
454-  GML driver: Can read/write all the new geometry types. When reading
455   GML3 application schemas, declarations of geometry fields such as
456   CurvePropertyType, SurfacePropertyType, MultiCurvePropertyType or
457   MultiSurfacePropertyType will be also interpreted as being potential
458   non-linear geometries, and corresponding OGR geometry type will be
459   used for the layer geometry type, and the geometries of the feature
460   will also follow that layer geometry type. This can affect the WFS
461   drivers.
462
463-  NAS driver: Can return the new geometry types. NAS layers will use
464   the new geometry types only if the NAS file contains arcs.
465
466-  PG/PostGIS: Can read/write all the new geometry types for both
467   PostGIS 2.X and PostGIS 1.X. For PostGIS 1.X compatibility, special
468   processing must be done in the importFromWkb()/exportToWkb() to deal
469   with the non standard codes used by PostGIS 1.X for curvepolygon,
470   multicurve and multisurface. This is done with a wkbVariantPostGIS1
471   value added to OGRwkbVariant enumeration used by those methods.
472
473-  PGDump: Can write all new geometry types. Above remark related to the
474   differences among version make it important to specify correctly the
475   POSTGIS_VERSION dataset creation option.
476
477-  GeoPackage: Can read/write all the new geometry types. Note: this
478   isn't in the core of the GeoPackage specification, but it is still a
479   registered extension.
480
481-  SQLite: Can read/write all the new geometry types for databases that
482   are NOT Spatialite databases, since Spatialite does no support curve
483   geometry types. However an attempt (well a hack) is done so that the
484   SQLite SQL dialect can still be used. Basically when converting a OGR
485   geometry to Spatialite, if it is of one of the curve geometry type,
486   the resulting blob will first contain the spatialite compatible blob
487   of the linear geometry, and afterwards the WKB of the curve geometry.
488   Spatialite functions, if called with a ST\_ function for example,
489   will ignore the later one. When reading a blob from sqlite, if the
490   added WKB of the curve geometry is still there, it will be used.
491   Otherwise the spatialite geometry blob will be used. So SELECT
492   statement just selecting the geometry column without doing any
493   operation on it should preserve curve geometries.
494
495-  MEM: Can read/write all the new geometry types.
496
497-  CSV: Can read/write all the new geometry types.
498
499-  VRT: Declared as compatible with all the new geometry types. Actual
500   capability will depend on the underlying layers wrapped by the VRT.
501
502Changes in utilities
503--------------------
504
505-  ogr2ogr: the new geometry names (CIRCULARSTRING, etc...) are
506   supported in the -nlt option. "-nlt CONVERT_TO_LINEAR" can also be
507   used to ask curve geometries to be converted into their linear
508   approximation ( what is used to do that is forceTo(xxx,
509   OGR_GT_GetLinear()) ). Note: this isn't strictly necessary as all
510   drivers should be able to deal with the non-linear geometry types
511   with the compatibility mechanism described in Backward compatibility.
512   But this might be useful to produce a PostGIS table or GeoPackage
513   database with linear geometry types even if the source contains
514   non-linear geometries. "-nlt CONVERT_TO_LINEAR" can be combined with
515   "-nlt PROMOTE_TO_MULTI".
516
517Changes in SWIG bindings
518------------------------
519
520Addition of :
521
522-  the new geometry types as ogr.wkbXXXXX
523-  ogr.ForceTo()
524-  Geometry.ExportToIsoWkt()
525-  Geometry.ExportToIsoWkb()
526-  Geometry.HasCurveGeometry(int bLookForCircular = FALSE)
527-  Geometry.GetLinearGeometry(double dfMaxAngleStepSizeDegrees =
528   0.0,char*\* options = NULL)
529-  Geometry.GetCurveGeometry(char*\* options = NULL)
530-  ogr.SetNonLinearGeometriesEnabledFlag(int bFlag)
531-  ogr.GetNonLinearGeometriesEnabledFlag()
532-  ogr.GT_xxxxx functions
533
534Using ogr.wkb25DBit will issue a deprecation warning
535
536Related changes that are *NOT* included in this RFC
537---------------------------------------------------
538
539-  Support for other ISO SQL/MM geometries such as Polyhedral Surface,
540   Triangulated Irregular Network (TIN), Triangle.
541-  Support for the M (Measure) dimension of geometries.
542-  Upgrade of other drivers that could make use of curve geometries :
543   MSSQL Spatial, Oracle Spatial, DXF, DWG, ...
544-  Support for arbitrary new geometry types: Conceptually one could hope
545   that a new class extending OGRCurve (Bezier or Spline curve) for
546   example could be added without touching OGR core. This isn't
547   currently possible: changes in OGRGeometryFactory and the OGR_GT\_
548   functions would be needed to remove a few hardcoded assumptions.
549
550Backward compatibility
551----------------------
552
553Regarding code using GDAL
554~~~~~~~~~~~~~~~~~~~~~~~~~
555
556Many applications will not be able to properly deal with the new
557geometry types that may now be returned by some drivers. If they don't
558want to test the geometry type and explicitly calling the conversion
559function, they can call OGRSetNonLinearGeometriesEnabledFlag(FALSE) (the
560default value is TRUE, i.e. non-linear geometries can be returned). In
561which case, they will be transformed into their closest linear geometry,
562by doing linear approximation, with OGR_G_ForceTo().
563
564This flag has only an effect on the OGR_F_GetGeometryRef(),
565OGR_F_GetGeomFieldRef(), OGR_L_GetGeomType(), OGR_GFld_GetType() and
566OGR_FD_GetGeomType() C API, and corresponding methods in the SWIG
567bindings.
568
569Libraries should generally *not* use that method, since that could
570interfere with other libraries or applications.
571
572Note that it does *not* affect the behavior of the C++ API. It has been
573deemed dangerous/complicated to try doing that at the C++ level as it
574could confuse drivers since they might call GetGeomType() for example.
575
576Regarding OGR drivers
577~~~~~~~~~~~~~~~~~~~~~
578
579Drivers that can deal with the new geometry types SHOULD declare the new
580dataset level ODsCCurveGeometries AND layer level OLCCurveGeometries
581capabilities. The virtual methods CreateFeature() and SetFeature()
582implemented by drivers have been renamed ICreateFeature() and
583ISetFeature(). OGRLayer has now a non-virtual CreateFeature() and
584SetFeature() that checks if the layer has curve geometry capability. If
585it has not, and that the passed feature has non-linear geometries, they
586will be transparently converted to their linear approximation before
587calling the driver ICreateFeature()/ISetFeature() method. Similarly the
588CreateLayer() method at datasource level will convert the passed
589geometry type to a non-linear corresponding type if necessary.
590
591All in-tree drivers have been converted to switch from CreateFeature()
592to ICreateFeature() and SetFeature() to ISetFeature(). Out-of-tree
593drivers will have to be adapted similarly otherwise those methods will
594fails (the now non-virtual methods in OGRLayer class will try to create
595the default implementation of the same class, which will fail).
596
597Documentation
598-------------
599
600All new methods and OGR geometry classes are documented. Driver
601documentation is updated when necessary. MIGRATION_GUIDE.TXT is updated
602with a summary of the text of this RFC.
603
604Testing
605-------
606
607Very few changes have been made so that the existing autotest suite
608still passes. Very comprehensive testing of new geometry classes and
609conversion methods has been added to ogr_geom.py and ogr_gml_geom.py.
610Updated drivers have received new tests also.
611
612Implementation
613--------------
614
615Implementation will be done by Even Rouault. Coordinated with Sourcepole
616(see `QGIS Enhancement 8: Geometry
617redesign <https://github.com/mhugent/QGIS-Enhancement-Proposals/blob/master/QEP-8-geometry_redesign.rst>`__),
618sponsored by Swiss QGIS User Group.
619
620The proposed implementation lies in the "curve_geometries" branch of the
621`https://github.com/rouault/gdal2/tree/curve_geometries <https://github.com/rouault/gdal2/tree/curve_geometries>`__
622repository.
623
624The list of changes :
625`https://github.com/rouault/gdal2/compare/curve_geometries <https://github.com/rouault/gdal2/compare/curve_geometries>`__
626
627Voting history
628--------------
629
630+1 from TamasS, JukkaR and EvenR
631
632