= RFC 61 : Support for measured geometries = Author: Ari Jolma[[BR]] Contact: ari.jolma at gmail.com[[BR]] Status: Draft[[BR]] Implementation version: 2.1 or 2.2 == Summary == This RFC defines how to implement measured geometries (geometries, where the points have M coordinate, i.e., they are XYM or XYZM). == Rationale == M coordinate is in the OGC simple feature model and it is used in many vector data formats. == Changes == Changes are required into the C++ API and the C API needs to be enhanced. Several drivers need to be changed to take advantage of this enhancement but also due to the changes in the C++ API. === Common API === New OGRwkbGeometryType values are needed - that is a rather complex system due to history. SFSQL 1.2 and ISO SQL/MM Part 3 will be used, i.e., 2D type + 2000 for M and 2D type + 3000 for ZM. (Also types such as Tin and !PolyhedralSurface types can be added for completeness, even if unimplemented currently) === C++ API === The property int nCoordinateDimension in class OGRGeometry will be replaced by int flags. It may have the following flags: {{{ #define OGR_G_NOT_EMPTY 0x1 #define OGR_G_3D 0x2 #define OGR_G_MEASURED 0x4 }}} Currently hacks such as nCoordDimension == -2 are used to denote empty geometries. This implies many changes to drivers etc. which get or set nCoordinateDimension. !IsEmpty = !(flags & OGR_G_NOT_EMPTY), Is3D = flags & OGR_G_3D, !IsMeasured = flags & OGR_G_MEASURED. Keep (with original semantics, i.e., coordinate dimension is 2 or 3), but deprecate {{{ getCoordinateDimension(); setCoordinateDimension(); }}} class OGRGeometry: {{{ //Possibly add methods (SF Common Architecture): int Dimension(); // -1 for empty geometries, 0 for points, 1 for curves, 2 for surfaces, max of components for collections int CoordinateDimension(); // 2 if not 3D and not measured, 3 if 3D or measured, 4 if 3D and measured int SpatialDimension(); // ?? char *GeometryType(); // calls OGRToOGCGeomType (which needs to be enhanced) //Add methods (SF Common Architecture): OGRBoolean Is3D(); OGRBoolean IsMeasured(); //Add methods (non-standard, may cause internal changes, e.g., allocate memory for Z or M values): virtual void set3D(OGRBoolean bIs3D); virtual void setMeasured(OGRBoolean bIsMeasured); //Add now or later methods: virtual OGRGeometry *LocateAlong(double mValue); virtual OGRGeometry *LocateBetween(double mStart, double mEnd); }}} int !CoordinateDimension() should have the new semantics. The method name in simple features documents actually is without prefix get. Similarly, Add property double m to class OGRPoint. Add constructor, getters, and setters for it. Add property double *padfM to class OGRSimpleCurce. Add constructor, getters, and setters for it. The getters and setters can take advantage of the flags to determine whether Z or M is to be set in some of them. For backwards compatibility Z is preferred. Override methods set3D and setMeasured in those classes where setCoordinateDimension is overridden. === C API === ogr_core.h: {{{ OGRwkbGeometryType CPL_DLL OGR_GT_SetM( OGRwkbGeometryType eType ); int CPL_DLL OGR_GT_HasM( OGRwkbGeometryType eType ); }}} ogr_api.h: (new versions of some functions are needed, use postfix M) {{{ void CPL_DLL OGR_G_Is3D( OGRGeometryH ); void CPL_DLL OGR_G_IsMeasured( OGRGeometryH ); void CPL_DLL OGR_G_Set3D( OGRGeometryH, int ); void CPL_DLL OGR_G_SetMeasured( OGRGeometryH, int ); int CPL_DLL OGR_G_GetPointsM( OGRGeometryH hGeom, void* pabyX, int nXStride, void* pabyY, int nYStride, void* pabyZ, int nZStride, void* pabyM, int nMStride); double CPL_DLL OGR_G_GetM( OGRGeometryH, int ); void CPL_DLL OGR_G_GetPointM( OGRGeometryH, int iPoint, double *, double *, double *, double * ); void CPL_DLL OGR_G_SetPointM( OGRGeometryH, int iPoint, double, double, double, double ); void CPL_DLL OGR_G_AddPointM( OGRGeometryH, double, double, double, double ); void CPL_DLL OGR_G_SetPointsM( OGRGeometryH hGeom, int nPointsIn, void* pabyX, int nXStride, void* pabyY, int nYStride, void* pabyZ, int nZStride, void* pabyM, int nMStride ); }}} ogr_p.g {{{ const char CPL_DLL * OGRWktReadPointsM( const char * pszInput, OGRRawPoint **ppaoPoints, double **ppadfZ, double **ppadfM, int * pnMaxPoints, int * pnReadPoints ); void CPL_DLL OGRMakeWktCoordinateM( char *, double, double, double, double, int ); }}} pggeometry.h is internal, so we can change the function prototype {{{ void OGRCreateFromMultiPatchPart(OGRMultiPolygon *poMP, OGRPolygon*& poLastPoly, int nPartType, int nPartPoints, double* padfX, double* padfY, double* padfZ, double* padfM); }}} == SWIG bindings (Python / Java / C# / Perl) changes == The new C API functions need to be exposed through swig. Further changes depend on whether the language bindings are aware of coordinates. At least Python and Perl are. == Drivers == Drivers that are probably affected by the C++ changes are at least (these use the !CoordinateDimension API) pg, mssqlspatial, sqlite, db2, mysql, gml, pgdump, geojson, libkml, gpkg, wasp, gpx, filegdb, vfk, bna, dxf. == Utilities == to do == Documentation == All new methods/functions are documented. == Test Suite == to do == Compatibility Issues == Many drivers (actually datasets and layers) which support measures need to have the support added. Support should be advertised using {{{ #define ODsCMeasuredGeometries "MeasuredGeometries" #define OLCMeasuredGeometries "MeasuredGeometries" }}} ICreateLayer, which all(?) drivers implement, have geometry type as an argument. The method should call CPLError() with CPLE_NotSupported and return NULL if the driver does not support measures. Similarly for ICreateFeature and ISetFeature. == Related tickets == https://trac.osgeo.org/gdal/ticket/6063 https://trac.osgeo.org/gdal/ticket/6331 == Implementation == The implementation will be done by Ari Jolma. The proposed implementation will be in https://github.com/ajolma/GDAL-XYZM == Voting history