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