text: /******************************************************************************
   * $Id: ogr_geometry.h 62c2ef9b70dfd1a0e087c7a27df0bfd375997093 2018-04-10 15:25:06 +0200 Even Rouault $
   *
   * Project:  OpenGIS Simple Features Reference Implementation
   * Purpose:  Classes for manipulating simple features that is not specific
   *           to a particular interface technology.
   * Author:   Frank Warmerdam, warmerdam@pobox.com
   *
   ******************************************************************************
   * Copyright (c) 1999, Frank Warmerdam
   * Copyright (c) 2008-2014, Even Rouault <even dot rouault at mines-paris dot org>
   *
   * Permission is hereby granted, free of charge, to any person obtaining a
   * copy of this software and associated documentation files (the "Software"),
   * to deal in the Software without restriction, including without limitation
   * the rights to use, copy, modify, merge, publish, distribute, sublicense,
   * and/or sell copies of the Software, and to permit persons to whom the
   * Software is furnished to do so, subject to the following conditions:
   *
   * The above copyright notice and this permission notice shall be included
   * in all copies or substantial portions of the Software.
   *
   * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   * DEALINGS IN THE SOFTWARE.
   ****************************************************************************/
  
  #ifndef OGR_GEOMETRY_H_INCLUDED
  #define OGR_GEOMETRY_H_INCLUDED
  
  #include "cpl_conv.h"
  #include "cpl_json.h"
  #include "ogr_core.h"
  #include "ogr_spatialref.h"
  
  #include <memory>
  
  /**
   * \file ogr_geometry.h
   *
   * Simple feature geometry classes.
   */
  
  /*! @cond Doxygen_Suppress */
  #ifndef DEFINEH_OGRGeometryH
  #define DEFINEH_OGRGeometryH
  #ifdef DEBUG
  typedef struct OGRGeometryHS *OGRGeometryH;
  #else
  typedef void *OGRGeometryH;
  #endif
  #endif /* DEFINEH_OGRGeometryH */
  /*! @endcond */
  
  
  /**
   * Simple container for a position.
   */
  class OGRRawPoint
  {
    public:
            /** Constructor */
            OGRRawPoint() : x(0.0), y(0.0) {}
  
            /** Constructor */
            OGRRawPoint(double xIn, double yIn) : x(xIn), y(yIn) {}
  
      /** x */
      double      x;
      /** y */
      double      y;
  };
  
  /** GEOS geometry type */
  typedef struct GEOSGeom_t *GEOSGeom;
  /** GEOS context handle type */
  typedef struct GEOSContextHandle_HS *GEOSContextHandle_t;
  /** SFCGAL geometry type */
  typedef void sfcgal_geometry_t;
  
  class OGRPoint;
  class OGRCurve;
  class OGRCompoundCurve;
  class OGRSimpleCurve;
  class OGRLinearRing;
  class OGRLineString;
  class OGRCircularString;
  class OGRSurface;
  class OGRCurvePolygon;
  class OGRPolygon;
  class OGRMultiPoint;
  class OGRMultiSurface;
  class OGRMultiPolygon;
  class OGRMultiCurve;
  class OGRMultiLineString;
  class OGRGeometryCollection;
  class OGRTriangle;
  class OGRPolyhedralSurface;
  class OGRTriangulatedSurface;
  
  //! @cond Doxygen_Suppress
  typedef OGRLineString* (*OGRCurveCasterToLineString)(OGRCurve*);
  typedef OGRLinearRing* (*OGRCurveCasterToLinearRing)(OGRCurve*);
  
  typedef OGRPolygon*      (*OGRSurfaceCasterToPolygon)(OGRSurface*);
  typedef OGRCurvePolygon* (*OGRSurfaceCasterToCurvePolygon)(OGRSurface*);
  typedef OGRMultiPolygon* (*OGRPolyhedralSurfaceCastToMultiPolygon)(OGRPolyhedralSurface*);
  //! @endcond
  
  /** OGRGeometry visitor interface.
   * @since GDAL 2.3
   */
  class CPL_DLL IOGRGeometryVisitor
  {
      public:
          /** Destructor/ */
          virtual ~IOGRGeometryVisitor() = default;
  
          /** Visit OGRPoint. */
          virtual void visit(OGRPoint*) = 0;
          /** Visit OGRLineString. */
          virtual void visit(OGRLineString*) = 0;
          /** Visit OGRLinearRing. */
          virtual void visit(OGRLinearRing*) = 0;
          /** Visit OGRPolygon. */
          virtual void visit(OGRPolygon*) = 0;
          /** Visit OGRMultiPoint. */
          virtual void visit(OGRMultiPoint*) = 0;
          /** Visit OGRMultiLineString. */
          virtual void visit(OGRMultiLineString*) = 0;
          /** Visit OGRMultiPolygon. */
          virtual void visit(OGRMultiPolygon*) = 0;
          /** Visit OGRGeometryCollection. */
          virtual void visit(OGRGeometryCollection*) = 0;
          /** Visit OGRCircularString. */
          virtual void visit(OGRCircularString*) = 0;
          /** Visit OGRCompoundCurve. */
          virtual void visit(OGRCompoundCurve*) = 0;
          /** Visit OGRCurvePolygon. */
          virtual void visit(OGRCurvePolygon*) = 0;
          /** Visit OGRMultiCurve. */
          virtual void visit(OGRMultiCurve*) = 0;
          /** Visit OGRMultiSurface. */
          virtual void visit(OGRMultiSurface*) = 0;
          /** Visit OGRTriangle. */
          virtual void visit(OGRTriangle*) = 0;
          /** Visit OGRPolyhedralSurface. */
          virtual void visit(OGRPolyhedralSurface*) = 0;
          /** Visit OGRTriangulatedSurface. */
          virtual void visit(OGRTriangulatedSurface*) = 0;
  };
  
  /** OGRGeometry visitor default implementation.
   *
   * This default implementation will recurse down to calling
   * visit(OGRPoint*) on each point.
   *
   * @since GDAL 2.3
   */
  class CPL_DLL OGRDefaultGeometryVisitor: public IOGRGeometryVisitor
  {
          void _visit(OGRSimpleCurve* poGeom);
  
      public:
  
          void visit(OGRPoint*) override {}
          void visit(OGRLineString*) override;
          void visit(OGRLinearRing*) override;
          void visit(OGRPolygon*) override;
          void visit(OGRMultiPoint*) override;
          void visit(OGRMultiLineString*) override;
          void visit(OGRMultiPolygon*) override;
          void visit(OGRGeometryCollection*) override;
          void visit(OGRCircularString*) override;
          void visit(OGRCompoundCurve*) override;
          void visit(OGRCurvePolygon*) override;
          void visit(OGRMultiCurve*) override;
          void visit(OGRMultiSurface*) override;
          void visit(OGRTriangle*) override;
          void visit(OGRPolyhedralSurface*) override;
          void visit(OGRTriangulatedSurface*) override;
  };
  
  /** OGRGeometry visitor interface.
   * @since GDAL 2.3
   */
  class CPL_DLL IOGRConstGeometryVisitor
  {
      public:
          /** Destructor/ */
          virtual ~IOGRConstGeometryVisitor() = default;
  
          /** Visit OGRPoint. */
          virtual void visit(const OGRPoint*) = 0;
          /** Visit OGRLineString. */
          virtual void visit(const OGRLineString*) = 0;
          /** Visit OGRLinearRing. */
          virtual void visit(const OGRLinearRing*) = 0;
          /** Visit OGRPolygon. */
          virtual void visit(const OGRPolygon*) = 0;
          /** Visit OGRMultiPoint. */
          virtual void visit(const OGRMultiPoint*) = 0;
          /** Visit OGRMultiLineString. */
          virtual void visit(const OGRMultiLineString*) = 0;
          /** Visit OGRMultiPolygon. */
          virtual void visit(const OGRMultiPolygon*) = 0;
          /** Visit OGRGeometryCollection. */
          virtual void visit(const OGRGeometryCollection*) = 0;
          /** Visit OGRCircularString. */
          virtual void visit(const OGRCircularString*) = 0;
          /** Visit OGRCompoundCurve. */
          virtual void visit(const OGRCompoundCurve*) = 0;
          /** Visit OGRCurvePolygon. */
          virtual void visit(const OGRCurvePolygon*) = 0;
          /** Visit OGRMultiCurve. */
          virtual void visit(const OGRMultiCurve*) = 0;
          /** Visit OGRMultiSurface. */
          virtual void visit(const OGRMultiSurface*) = 0;
          /** Visit OGRTriangle. */
          virtual void visit(const OGRTriangle*) = 0;
          /** Visit OGRPolyhedralSurface. */
          virtual void visit(const OGRPolyhedralSurface*) = 0;
          /** Visit OGRTriangulatedSurface. */
          virtual void visit(const OGRTriangulatedSurface*) = 0;
  };
  
  /** OGRGeometry visitor default implementation.
   *
   * This default implementation will recurse down to calling
   * visit(const OGRPoint*) on each point.
   *
   * @since GDAL 2.3
   */
  class CPL_DLL OGRDefaultConstGeometryVisitor: public IOGRConstGeometryVisitor
  {
          void _visit(const OGRSimpleCurve* poGeom);
  
      public:
  
          void visit(const OGRPoint*) override {}
          void visit(const OGRLineString*) override;
          void visit(const OGRLinearRing*) override;
          void visit(const OGRPolygon*) override;
          void visit(const OGRMultiPoint*) override;
          void visit(const OGRMultiLineString*) override;
          void visit(const OGRMultiPolygon*) override;
          void visit(const OGRGeometryCollection*) override;
          void visit(const OGRCircularString*) override;
          void visit(const OGRCompoundCurve*) override;
          void visit(const OGRCurvePolygon*) override;
          void visit(const OGRMultiCurve*) override;
          void visit(const OGRMultiSurface*) override;
          void visit(const OGRTriangle*) override;
          void visit(const OGRPolyhedralSurface*) override;
          void visit(const OGRTriangulatedSurface*) override;
  };
  
  /************************************************************************/
  /*                             OGRGeometry                              */
  /************************************************************************/
  
  /**
   * Abstract base class for all geometry classes.
   *
   * Some spatial analysis methods require that OGR is built on the GEOS library
   * to work properly. The precise meaning of methods that describe spatial
   * relationships between geometries is described in the SFCOM, or other simple
   * features interface specifications, like "OpenGIS® Implementation
   * Specification for Geographic information - Simple feature access - Part 1:
   * Common architecture":
   * <a href="http://www.opengeospatial.org/standards/sfa">OGC 06-103r4</a>
   *
   * In GDAL 2.0, the hierarchy of classes has been extended with
   * <a href="https://portal.opengeospatial.org/files/?artifact_id=32024">
   * (working draft) ISO SQL/MM Part 3 (ISO/IEC 13249-3)</a> curve geometries :
   * CIRCULARSTRING (OGRCircularString), COMPOUNDCURVE (OGRCompoundCurve),
   * CURVEPOLYGON (OGRCurvePolygon), MULTICURVE (OGRMultiCurve) and
   * MULTISURFACE (OGRMultiSurface).
   *
   */
  
  class CPL_DLL OGRGeometry
  {
    private:
      OGRSpatialReference * poSRS;                // may be NULL
  
    protected:
  //! @cond Doxygen_Suppress
      friend class OGRCurveCollection;
  
      unsigned int flags;
  
      OGRErr       importPreambleFromWkt( const char ** ppszInput,
                                           int* pbHasZ, int* pbHasM,
                                           bool* pbIsEmpty );
      OGRErr       importCurveCollectionFromWkt(
                       const char ** ppszInput,
                       int bAllowEmptyComponent,
                       int bAllowLineString,
                       int bAllowCurve,
                       int bAllowCompoundCurve,
                       OGRErr (*pfnAddCurveDirectly)(OGRGeometry* poSelf,
                                                     OGRCurve* poCurve) );
      OGRErr       importPreambleFromWkb( const unsigned char * pabyData,
                                           int nSize,
                                           OGRwkbByteOrder& eByteOrder,
                                           OGRwkbVariant eWkbVariant );
      OGRErr       importPreambleOfCollectionFromWkb(
                       const unsigned char * pabyData,
                       int& nSize,
                       int& nDataOffset,
                       OGRwkbByteOrder& eByteOrder,
                       int nMinSubGeomSize,
                       int& nGeomCount,
                       OGRwkbVariant eWkbVariant );
      OGRErr       PointOnSurfaceInternal( OGRPoint * poPoint ) const;
      OGRBoolean   IsSFCGALCompatible() const;
  
      void         HomogenizeDimensionalityWith( OGRGeometry* poOtherGeom );
  
  //! @endcond
  
    public:
  
  /************************************************************************/
  /*                   Bit flags for OGRGeometry                          */
  /*          The OGR_G_NOT_EMPTY_POINT is used *only* for points.        */
  /*          Do not use these outside of the core.                       */
  /*          Use Is3D, IsMeasured, set3D, and setMeasured instead        */
  /************************************************************************/
  
  //! @cond Doxygen_Suppress
      static const unsigned int OGR_G_NOT_EMPTY_POINT = 0x1;
      static const unsigned int OGR_G_3D = 0x2;
      static const unsigned int OGR_G_MEASURED = 0x4;
  //! @endcond
  
                  OGRGeometry();
                  OGRGeometry( const OGRGeometry& other );
      virtual     ~OGRGeometry();
  
      OGRGeometry& operator=( const OGRGeometry& other );
  
      /** Returns if two geometries are equal. */
      bool operator==( const OGRGeometry& other ) const { return CPL_TO_BOOL(Equals(&other)); }
  
      /** Returns if two geometries are different. */
      bool operator!=( const OGRGeometry& other ) const { return !CPL_TO_BOOL(Equals(&other)); }
  
      // Standard IGeometry.
      virtual int getDimension() const = 0;
      virtual int getCoordinateDimension() const;
      int CoordinateDimension() const;
      virtual OGRBoolean  IsEmpty() const = 0;
      virtual OGRBoolean  IsValid() const;
      virtual OGRBoolean  IsSimple() const;
      /*! Returns whether the geometry has a Z component. */
      OGRBoolean  Is3D() const { return flags & OGR_G_3D; }
      /*! Returns whether the geometry has a M component. */
      OGRBoolean  IsMeasured() const { return flags & OGR_G_MEASURED; }
      virtual OGRBoolean  IsRing() const;
      virtual void        empty() = 0;
      virtual OGRGeometry *clone() const CPL_WARN_UNUSED_RESULT = 0;
      virtual void getEnvelope( OGREnvelope * psEnvelope ) const = 0;
      virtual void getEnvelope( OGREnvelope3D * psEnvelope ) const = 0;
  
      // IWks Interface.
      virtual int WkbSize() const = 0;
      OGRErr importFromWkb( const GByte*, int=-1,
                                    OGRwkbVariant=wkbVariantOldOgc );
      virtual OGRErr importFromWkb( const unsigned char *,
                                    int,
                                    OGRwkbVariant,
                                    int& nBytesConsumedOut ) = 0;
      virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *,
                                  OGRwkbVariant=wkbVariantOldOgc ) const = 0;
      virtual OGRErr importFromWkt( const char ** ppszInput ) = 0;
  
      /** Deprecated.
       * @deprecated in GDAL 2.3
       */
      OGRErr importFromWkt( char ** ppszInput ) CPL_WARN_DEPRECATED("Use importFromWkt(const char**) instead")
      {
          return importFromWkt( const_cast<const char**>(ppszInput) );
      }
  
      virtual OGRErr exportToWkt( char ** ppszDstText,
                                  OGRwkbVariant=wkbVariantOldOgc ) const = 0;
  
      // Non-standard.
      virtual OGRwkbGeometryType getGeometryType() const = 0;
      OGRwkbGeometryType    getIsoGeometryType() const;
      virtual const char *getGeometryName() const = 0;
      virtual void   dumpReadable( FILE *, const char * = nullptr
                                   , char** papszOptions = nullptr ) const;
      virtual void   flattenTo2D() = 0;
      virtual char * exportToGML( const char* const * papszOptions = nullptr ) const;
      virtual char * exportToKML() const;
      virtual char * exportToJson() const;
  
      /** Accept a visitor. */
      virtual void accept(IOGRGeometryVisitor* visitor) = 0;
  
      /** Accept a visitor. */
      virtual void accept(IOGRConstGeometryVisitor* visitor) const = 0;
  
      static GEOSContextHandle_t createGEOSContext();
      static void freeGEOSContext( GEOSContextHandle_t hGEOSCtxt );
      virtual GEOSGeom exportToGEOS( GEOSContextHandle_t hGEOSCtxt )
          const CPL_WARN_UNUSED_RESULT;
      virtual OGRBoolean hasCurveGeometry(int bLookForNonLinear = FALSE) const;
      virtual OGRGeometry* getCurveGeometry(
          const char* const* papszOptions = nullptr ) const CPL_WARN_UNUSED_RESULT;
      virtual OGRGeometry* getLinearGeometry(
          double dfMaxAngleStepSizeDegrees = 0,
          const char* const* papszOptions = nullptr ) const CPL_WARN_UNUSED_RESULT;
  
      // SFCGAL interfacing methods.
  //! @cond Doxygen_Suppress
      static sfcgal_geometry_t* OGRexportToSFCGAL( const OGRGeometry *poGeom );
      static OGRGeometry* SFCGALexportToOGR( const sfcgal_geometry_t* _geometry );
  //! @endcond
      virtual void closeRings();
  
      virtual void setCoordinateDimension( int nDimension );
      virtual void set3D( OGRBoolean bIs3D );
      virtual void setMeasured( OGRBoolean bIsMeasured );
  
      virtual void    assignSpatialReference( OGRSpatialReference * poSR );
      OGRSpatialReference *getSpatialReference( void ) const { return poSRS; }
  
      virtual OGRErr  transform( OGRCoordinateTransformation *poCT ) = 0;
      OGRErr  transformTo( OGRSpatialReference *poSR );
  
      virtual void segmentize(double dfMaxLength);
  
      // ISpatialRelation
      virtual OGRBoolean  Intersects( const OGRGeometry * ) const;
      virtual OGRBoolean  Equals( const OGRGeometry * ) const = 0;
      virtual OGRBoolean  Disjoint( const OGRGeometry * ) const;
      virtual OGRBoolean  Touches( const OGRGeometry * ) const;
      virtual OGRBoolean  Crosses( const OGRGeometry * ) const;
      virtual OGRBoolean  Within( const OGRGeometry * ) const;
      virtual OGRBoolean  Contains( const OGRGeometry * ) const;
      virtual OGRBoolean  Overlaps( const OGRGeometry * ) const;
  //    virtual OGRBoolean  Relate( const OGRGeometry *, const char * ) const;
  //    virtual OGRGeometry *LocateAlong( double mValue ) const;
  //    virtual OGRGeometry *LocateBetween( double mStart, double mEnd ) const;
  
      virtual OGRGeometry *Boundary() const CPL_WARN_UNUSED_RESULT;
      virtual double  Distance( const OGRGeometry * ) const ;
      virtual OGRGeometry *ConvexHull() const CPL_WARN_UNUSED_RESULT;
      virtual OGRGeometry *Buffer( double dfDist, int nQuadSegs = 30 )
          const CPL_WARN_UNUSED_RESULT;
      virtual OGRGeometry *Intersection( const OGRGeometry *)
          const CPL_WARN_UNUSED_RESULT;
      virtual OGRGeometry *Union( const OGRGeometry * )
          const CPL_WARN_UNUSED_RESULT;
      virtual OGRGeometry *UnionCascaded() const CPL_WARN_UNUSED_RESULT;
      virtual OGRGeometry *Difference( const OGRGeometry * )
          const CPL_WARN_UNUSED_RESULT;
      virtual OGRGeometry *SymDifference( const OGRGeometry * )
          const CPL_WARN_UNUSED_RESULT;
      virtual OGRErr       Centroid( OGRPoint * poPoint ) const;
      virtual OGRGeometry *Simplify(double dTolerance)
          const CPL_WARN_UNUSED_RESULT;
      OGRGeometry *SimplifyPreserveTopology(double dTolerance)
          const CPL_WARN_UNUSED_RESULT;
      virtual OGRGeometry *DelaunayTriangulation(
          double dfTolerance, int bOnlyEdges ) const CPL_WARN_UNUSED_RESULT;
  
      virtual OGRGeometry *Polygonize() const CPL_WARN_UNUSED_RESULT;
  
      virtual double Distance3D( const OGRGeometry *poOtherGeom ) const;
  
  //! @cond Doxygen_Suppress
      // backward compatibility to non-standard method names.
      OGRBoolean  Intersect( OGRGeometry * )
          const CPL_WARN_DEPRECATED("Non standard method. "
                                    "Use Intersects() instead");
      OGRBoolean  Equal( OGRGeometry * )
          const CPL_WARN_DEPRECATED("Non standard method. "
                                    "Use Equals() instead");
      OGRGeometry *SymmetricDifference( const OGRGeometry * )
          const CPL_WARN_DEPRECATED("Non standard method. "
                                    "Use SymDifference() instead");
      OGRGeometry *getBoundary()
          const CPL_WARN_DEPRECATED("Non standard method. "
                                    "Use Boundary() instead");
  //! @endcond
  
  //! @cond Doxygen_Suppress
      // Special HACK for DB2 7.2 support
      static int bGenerate_DB2_V72_BYTE_ORDER;
  //! @endcond
  
      virtual void        swapXY();
  //! @cond Doxygen_Suppress
      static OGRGeometry* CastToIdentity( OGRGeometry* poGeom ) { return poGeom; }
      static OGRGeometry* CastToError( OGRGeometry* poGeom );
  //! @endcond
  
      /** Convert a OGRGeometry* to a OGRGeometryH.
       * @since GDAL 2.3
       */
      static inline OGRGeometryH ToHandle(OGRGeometry* poGeom)
          { return reinterpret_cast<OGRGeometryH>(poGeom); }
  
      /** Convert a OGRGeometryH to a OGRGeometry*.
       * @since GDAL 2.3
       */
      static inline OGRGeometry* FromHandle(OGRGeometryH hGeom)
          { return reinterpret_cast<OGRGeometry*>(hGeom); }
  
      /** Down-cast to OGRPoint*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbPoint.
       * @since GDAL 2.3
       */
      inline OGRPoint* toPoint()
          { return cpl::down_cast<OGRPoint*>(this); }
  
      /** Down-cast to OGRPoint*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbPoint.
       * @since GDAL 2.3
       */
      inline const OGRPoint* toPoint() const
          { return cpl::down_cast<const OGRPoint*>(this); }
  
      /** Down-cast to OGRCurve*.
       * Implies prior checking that OGR_GT_IsSubClass(getGeometryType(), wkbCurve).
       * @since GDAL 2.3
       */
      inline OGRCurve* toCurve()
          { return cpl::down_cast<OGRCurve*>(this); }
  
      /** Down-cast to OGRCurve*.
       * Implies prior checking that OGR_GT_IsSubClass(getGeometryType(), wkbCurve).
       * @since GDAL 2.3
       */
      inline const OGRCurve* toCurve() const
          { return cpl::down_cast<const OGRCurve*>(this); }
  
      /** Down-cast to OGRSimpleCurve*.
       * Implies prior checking that getGeometryType() is wkbLineString, wkbCircularString or a derived type.
       * @since GDAL 2.3
       */
      inline OGRSimpleCurve* toSimpleCurve()
          { return cpl::down_cast<OGRSimpleCurve*>(this); }
  
      /** Down-cast to OGRSimpleCurve*.
       * Implies prior checking that getGeometryType() is wkbLineString, wkbCircularString or a derived type.
       * @since GDAL 2.3
       */
      inline const OGRSimpleCurve* toSimpleCurve() const
          { return cpl::down_cast<const OGRSimpleCurve*>(this); }
  
      /** Down-cast to OGRLineString*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbLineString.
       * @since GDAL 2.3
       */
      inline OGRLineString* toLineString()
          { return cpl::down_cast<OGRLineString*>(this); }
  
      /** Down-cast to OGRLineString*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbLineString.
       * @since GDAL 2.3
       */
      inline const OGRLineString* toLineString() const
          { return cpl::down_cast<const OGRLineString*>(this); }
  
      /** Down-cast to OGRLinearRing*.
       * Implies prior checking that EQUAL(getGeometryName(), "LINEARRING").
       * @since GDAL 2.3
       */
      inline OGRLinearRing* toLinearRing()
          { return cpl::down_cast<OGRLinearRing*>(this); }
  
      /** Down-cast to OGRLinearRing*.
       * Implies prior checking that EQUAL(getGeometryName(), "LINEARRING").
       * @since GDAL 2.3
       */
      inline const OGRLinearRing* toLinearRing() const
          { return cpl::down_cast<const OGRLinearRing*>(this); }
  
      /** Down-cast to OGRCircularString*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbCircularString.
       * @since GDAL 2.3
       */
      inline OGRCircularString* toCircularString()
          { return cpl::down_cast<OGRCircularString*>(this); }
  
      /** Down-cast to OGRCircularString*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbCircularString.
       * @since GDAL 2.3
       */
      inline const OGRCircularString* toCircularString() const
          { return cpl::down_cast<const OGRCircularString*>(this); }
  
      /** Down-cast to OGRCompoundCurve*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbCompoundCurve.
       * @since GDAL 2.3
       */
      inline OGRCompoundCurve* toCompoundCurve()
          { return cpl::down_cast<OGRCompoundCurve*>(this); }
  
      /** Down-cast to OGRCompoundCurve*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbCompoundCurve.
       * @since GDAL 2.3
       */
      inline const OGRCompoundCurve* toCompoundCurve() const
          { return cpl::down_cast<const OGRCompoundCurve*>(this); }
  
      /** Down-cast to OGRSurface*.
       * Implies prior checking that OGR_GT_IsSubClass(getGeometryType(), wkbSurface).
       * @since GDAL 2.3
       */
      inline OGRSurface* toSurface()
          { return cpl::down_cast<OGRSurface*>(this); }
  
      /** Down-cast to OGRSurface*.
       * Implies prior checking that OGR_GT_IsSubClass(getGeometryType(), wkbSurface).
       * @since GDAL 2.3
       */
      inline const OGRSurface* toSurface() const
          { return cpl::down_cast<const OGRSurface*>(this); }
  
      /** Down-cast to OGRPolygon*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbPolygon or wkbTriangle.
       * @since GDAL 2.3
       */
      inline OGRPolygon* toPolygon()
          { return cpl::down_cast<OGRPolygon*>(this); }
  
      /** Down-cast to OGRPolygon*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbPolygon or wkbTriangle.
       * @since GDAL 2.3
       */
      inline const OGRPolygon* toPolygon() const
          { return cpl::down_cast<const OGRPolygon*>(this); }
  
      /** Down-cast to OGRTriangle*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbTriangle.
       * @since GDAL 2.3
       */
      inline OGRTriangle* toTriangle()
          { return cpl::down_cast<OGRTriangle*>(this); }
  
      /** Down-cast to OGRTriangle*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbTriangle.
       * @since GDAL 2.3
       */
      inline const OGRTriangle* toTriangle() const
          { return cpl::down_cast<const OGRTriangle*>(this); }
  
      /** Down-cast to OGRCurvePolygon*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbCurvePolygon or wkbPolygon or wkbTriangle.
       * @since GDAL 2.3
       */
      inline OGRCurvePolygon* toCurvePolygon()
          { return cpl::down_cast<OGRCurvePolygon*>(this); }
  
      /** Down-cast to OGRCurvePolygon*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbCurvePolygon or wkbPolygon or wkbTriangle.
       * @since GDAL 2.3
       */
      inline const OGRCurvePolygon* toCurvePolygon() const
          { return cpl::down_cast<const OGRCurvePolygon*>(this); }
  
      /** Down-cast to OGRGeometryCollection*.
       * Implies prior checking that OGR_GT_IsSubClass(getGeometryType(), wkbGeometryCollection).
       * @since GDAL 2.3
       */
      inline OGRGeometryCollection* toGeometryCollection()
          { return cpl::down_cast<OGRGeometryCollection*>(this); }
  
      /** Down-cast to OGRGeometryCollection*.
       * Implies prior checking that OGR_GT_IsSubClass(getGeometryType(), wkbGeometryCollection).
       * @since GDAL 2.3
       */
      inline const OGRGeometryCollection* toGeometryCollection() const
          { return cpl::down_cast<const OGRGeometryCollection*>(this); }
  
      /** Down-cast to OGRMultiPoint*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbMultiPoint.
       * @since GDAL 2.3
       */
      inline OGRMultiPoint* toMultiPoint()
          { return cpl::down_cast<OGRMultiPoint*>(this); }
  
      /** Down-cast to OGRMultiPoint*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbMultiPoint.
       * @since GDAL 2.3
       */
      inline const OGRMultiPoint* toMultiPoint() const
          { return cpl::down_cast<const OGRMultiPoint*>(this); }
  
      /** Down-cast to OGRMultiLineString*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbMultiLineString.
       * @since GDAL 2.3
       */
      inline OGRMultiLineString* toMultiLineString()
          { return cpl::down_cast<OGRMultiLineString*>(this); }
  
      /** Down-cast to OGRMultiLineString*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbMultiLineString.
       * @since GDAL 2.3
       */
      inline const OGRMultiLineString* toMultiLineString() const
          { return cpl::down_cast<const OGRMultiLineString*>(this); }
  
      /** Down-cast to OGRMultiPolygon*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbMultiPolygon.
       * @since GDAL 2.3
       */
      inline OGRMultiPolygon* toMultiPolygon()
          { return cpl::down_cast<OGRMultiPolygon*>(this); }
  
      /** Down-cast to OGRMultiPolygon*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbMultiPolygon.
       * @since GDAL 2.3
       */
      inline const OGRMultiPolygon* toMultiPolygon() const
          { return cpl::down_cast<const OGRMultiPolygon*>(this); }
  
      /** Down-cast to OGRMultiCurve*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbMultiCurve and derived types.
       * @since GDAL 2.3
       */
      inline OGRMultiCurve* toMultiCurve()
          { return cpl::down_cast<OGRMultiCurve*>(this); }
  
      /** Down-cast to OGRMultiCurve*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbMultiCurve and derived types.
       * @since GDAL 2.3
       */
      inline const OGRMultiCurve* toMultiCurve() const
          { return cpl::down_cast<const OGRMultiCurve*>(this); }
  
      /** Down-cast to OGRMultiSurface*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbMultiSurface and derived types.
       * @since GDAL 2.3
       */
      inline OGRMultiSurface* toMultiSurface()
          { return cpl::down_cast<OGRMultiSurface*>(this); }
  
      /** Down-cast to OGRMultiSurface*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbMultiSurface and derived types.
       * @since GDAL 2.3
       */
      inline const OGRMultiSurface* toMultiSurface() const
          { return cpl::down_cast<const OGRMultiSurface*>(this); }
  
      /** Down-cast to OGRPolyhedralSurface*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbPolyhedralSurface or wkbTIN.
       * @since GDAL 2.3
       */
      inline OGRPolyhedralSurface* toPolyhedralSurface()
          { return cpl::down_cast<OGRPolyhedralSurface*>(this); }
  
      /** Down-cast to OGRPolyhedralSurface*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbPolyhedralSurface or wkbTIN.
       * @since GDAL 2.3
       */
      inline const OGRPolyhedralSurface* toPolyhedralSurface() const
          { return cpl::down_cast<const OGRPolyhedralSurface*>(this); }
  
      /** Down-cast to OGRTriangulatedSurface*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbTIN.
       * @since GDAL 2.3
       */
      inline OGRTriangulatedSurface* toTriangulatedSurface()
          { return cpl::down_cast<OGRTriangulatedSurface*>(this); }
  
      /** Down-cast to OGRTriangulatedSurface*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbTIN.
       * @since GDAL 2.3
       */
      inline const OGRTriangulatedSurface* toTriangulatedSurface() const
          { return cpl::down_cast<const OGRTriangulatedSurface*>(this); }
  
  };
  
  //! @cond Doxygen_Suppress
  struct CPL_DLL OGRGeometryUniquePtrDeleter
  {
      void operator()(OGRGeometry*) const;
  };
  //! @endcond
  
  /** Unique pointer type for OGRGeometry.
   * @since GDAL 2.3
   */
  typedef std::unique_ptr<OGRGeometry, OGRGeometryUniquePtrDeleter> OGRGeometryUniquePtr;
  
  /************************************************************************/
  /*                               OGRPoint                               */
  /************************************************************************/
  
  /**
   * Point class.
   *
   * Implements SFCOM IPoint methods.
   */
  
  class CPL_DLL OGRPoint : public OGRGeometry
  {
      double      x;
      double      y;
      double      z;
      double      m;
  
    public:
      OGRPoint();
      OGRPoint( double x, double y );
      OGRPoint( double x, double y, double z );
      OGRPoint( double x, double y, double z, double m );
      OGRPoint( const OGRPoint& other );
      ~OGRPoint() override;
  
      OGRPoint& operator=( const OGRPoint& other );
  
      // IWks Interface
      int WkbSize() const override;
      OGRErr importFromWkb( const unsigned char *,
                            int,
                            OGRwkbVariant,
                            int& nBytesConsumedOut ) override;
      OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *,
                          OGRwkbVariant=wkbVariantOldOgc )
          const override;
      using OGRGeometry::importFromWkt; /** deprecated */
      OGRErr importFromWkt( const char ** ) override;
      OGRErr exportToWkt( char ** ppszDstText,
                          OGRwkbVariant=wkbVariantOldOgc )
          const override;
  
      // IGeometry
      virtual int getDimension() const override;
      virtual OGRGeometry *clone() const override;
      virtual void empty() override;
      virtual void getEnvelope( OGREnvelope * psEnvelope ) const override;
      virtual void getEnvelope( OGREnvelope3D * psEnvelope ) const override;
      virtual OGRBoolean  IsEmpty() const override
          { return !(flags & OGR_G_NOT_EMPTY_POINT); }
  
      // IPoint
      /** Return x */
      double      getX() const { return x; }
      /** Return y */
      double      getY() const { return y; }
      /** Return z */
      double      getZ() const { return z; }
      /** Return m */
      double      getM() const { return m; }
  
      // Non standard
      virtual void setCoordinateDimension( int nDimension ) override;
      /** Set x
       * @param xIn x
       */
      void        setX( double xIn ) { x = xIn; flags |= OGR_G_NOT_EMPTY_POINT; }
      /** Set y
       * @param yIn y
       */
      void        setY( double yIn ) { y = yIn; flags |= OGR_G_NOT_EMPTY_POINT; }
      /** Set z
       * @param zIn z
       */
      void        setZ( double zIn )
          { z = zIn; flags |= (OGR_G_NOT_EMPTY_POINT | OGR_G_3D); }
      /** Set m
       * @param mIn m
       */
      void        setM( double mIn )
          { m = mIn; flags |= (OGR_G_NOT_EMPTY_POINT | OGR_G_MEASURED); }
  
      // ISpatialRelation
      virtual OGRBoolean  Equals( const OGRGeometry * ) const override;
      virtual OGRBoolean  Intersects( const OGRGeometry * ) const override;
      virtual OGRBoolean  Within( const OGRGeometry * ) const override;
  
      // Non standard from OGRGeometry
      virtual const char *getGeometryName() const override;
      virtual OGRwkbGeometryType getGeometryType() const override;
      virtual OGRErr  transform( OGRCoordinateTransformation *poCT ) override;
      virtual void flattenTo2D() override;
      virtual void accept(IOGRGeometryVisitor* visitor) override { visitor->visit(this); }
      virtual void accept(IOGRConstGeometryVisitor* visitor) const override { visitor->visit(this); }
  
      virtual void        swapXY() override;
  };
  
  /************************************************************************/
  /*                            OGRPointIterator                          */
  /************************************************************************/
  
  /**
   * Interface for a point iterator.
   *
   * @since GDAL 2.0
   */
  
  class CPL_DLL OGRPointIterator
  {
      public:
          virtual ~OGRPointIterator();
          virtual OGRBoolean getNextPoint( OGRPoint* p ) = 0;
  
          static void destroy( OGRPointIterator* );
  };
  
  /************************************************************************/
  /*                               OGRCurve                               */
  /************************************************************************/
  
  /**
   * Abstract curve base class for OGRLineString, OGRCircularString and
   * OGRCompoundCurve
   */
  
  class CPL_DLL OGRCurve : public OGRGeometry
  {
    protected:
  //! @cond Doxygen_Suppress
              OGRCurve();
              OGRCurve( const OGRCurve& other );
  
      virtual OGRCurveCasterToLineString GetCasterToLineString() const = 0;
      virtual OGRCurveCasterToLinearRing GetCasterToLinearRing() const = 0;
  
      friend class OGRCurvePolygon;
      friend class OGRCompoundCurve;
  //! @endcond
      virtual int ContainsPoint( const OGRPoint* p ) const;
      virtual int IntersectsPoint( const OGRPoint* p ) const;
      virtual double get_AreaOfCurveSegments() const = 0;
  
      private:
  
          class CPL_DLL ConstIterator
          {
                  struct Private;
                  std::unique_ptr<Private> m_poPrivate;
              public:
                  ConstIterator(const OGRCurve* poSelf, bool bStart);
                  ConstIterator(ConstIterator&& oOther); // declared but not defined. Needed for gcc 5.4 at least
                  ~ConstIterator();
                  const OGRPoint& operator*() const;
                  ConstIterator& operator++();
                  bool operator!=(const ConstIterator& it) const;
          };
  
          friend inline ConstIterator begin(const OGRCurve*);
          friend inline ConstIterator end(const OGRCurve*);
  
    public:
      ~OGRCurve() override;
  
  //! @cond Doxygen_Suppress
      OGRCurve& operator=( const OGRCurve& other );
  //! @endcond
  
      /** Type of child elements. */
      typedef OGRPoint ChildType;
  
      /** Return begin of a point iterator.
       *
       * Using this iterator for standard range-based loops is safe, but
       * due to implementation limitations, you shouldn't try to access
       * (dereference) more than one iterator step at a time, since you will get
       * a reference to the same OGRPoint& object.
       * @since GDAL 2.3
       */
      ConstIterator begin() const;
      /** Return end of a point iterator. */
      ConstIterator end() const;
  
      // ICurve methods
      virtual double get_Length() const = 0;
      virtual void StartPoint( OGRPoint * ) const = 0;
      virtual void EndPoint( OGRPoint * ) const = 0;
      virtual int  get_IsClosed() const;
      virtual void Value( double, OGRPoint * ) const = 0;
      virtual OGRLineString* CurveToLine( double dfMaxAngleStepSizeDegrees = 0,
                                          const char* const* papszOptions = nullptr)
          const = 0;
      virtual int getDimension() const override;
  
      // non standard
      virtual int getNumPoints() const = 0;
      virtual OGRPointIterator* getPointIterator() const = 0;
      virtual OGRBoolean IsConvex() const;
      virtual double get_Area() const = 0;
  
      /** Down-cast to OGRSimpleCurve*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbLineString or wkbCircularString. */
      inline OGRSimpleCurve* toSimpleCurve()
          { return cpl::down_cast<OGRSimpleCurve*>(this); }
  
      /** Down-cast to OGRSimpleCurve*.
       * Implies prior checking that wkbFlatten(getGeometryType()) == wkbLineString or wkbCircularString. */
      inline const OGRSimpleCurve* toSimpleCurve() const
          { return cpl::down_cast<const OGRSimpleCurve*>(this); }
  
      static OGRCompoundCurve* CastToCompoundCurve( OGRCurve* puCurve );
      static OGRLineString*    CastToLineString( OGRCurve* poCurve );
      static OGRLinearRing*    CastToLinearRing( OGRCurve* poCurve );
  };
  
  //! @cond Doxygen_Suppress
  /** @see OGRCurve::begin() const */
  inline OGRCurve::ConstIterator begin(const OGRCurve* poCurve) { return poCurve->begin(); }
  /** @see OGRCurve::end() const */
  inline OGRCurve::ConstIterator end(const OGRCurve* poCurve) { return poCurve->end(); }
  //! @endcond
  
  /************************************************************************/
  /*                             OGRSimpleCurve                           */
  /************************************************************************/
  
  /**
   * Abstract curve base class for OGRLineString and OGRCircularString
   *
   * Note: this class does not exist in SQL/MM standard and exists for
   * implementation convenience.
   *
   * @since GDAL 2.0
   */
  
  class CPL_DLL OGRSimpleCurve: public OGRCurve
  {
    protected:
  //! @cond Doxygen_Suppress
      friend class OGRGeometry;
  
      int         nPointCount;
      OGRRawPoint *paoPoints;
      double      *padfZ;
      double      *padfM;
  
      void        Make3D();
      void        Make2D();
      void        RemoveM();
      void        AddM();
  
      OGRErr      importFromWKTListOnly( const char ** ppszInput, int bHasZ, int bHasM,
                                         OGRRawPoint*& paoPointsIn,
                                         int& nMaxPoints,
                                         double*& padfZIn );
  
  //! @endcond
  
      virtual double get_LinearArea() const;
  
                  OGRSimpleCurve();
                  OGRSimpleCurve( const OGRSimpleCurve& other );
  
    private:
          class CPL_DLL Iterator
          {
                  struct Private;
                  std::unique_ptr<Private> m_poPrivate;
                  void update();
              public:
                  Iterator(OGRSimpleCurve* poSelf, int nPos);
                  Iterator(Iterator&& oOther); // declared but not defined. Needed for gcc 5.4 at least
                  ~Iterator();
                  OGRPoint& operator*();
                  Iterator& operator++();
                  bool operator!=(const Iterator& it) const;
          };
  
          friend inline Iterator begin(OGRSimpleCurve*);
          friend inline Iterator end(OGRSimpleCurve*);
  
          class CPL_DLL ConstIterator
          {
                  struct Private;
                  std::unique_ptr<Private> m_poPrivate;
              public:
                  ConstIterator(const OGRSimpleCurve* poSelf, int nPos);
                  ConstIterator(ConstIterator&& oOther); // declared but not defined. Needed for gcc 5.4 at least
                  ~ConstIterator();
                  const OGRPoint& operator*() const;
                  ConstIterator& operator++();
                  bool operator!=(const ConstIterator& it) const;
          };
  
          friend inline ConstIterator begin(const OGRSimpleCurve*);
          friend inline ConstIterator end(const OGRSimpleCurve*);
  
    public:
      ~OGRSimpleCurve() override;
  
      OGRSimpleCurve& operator=( const OGRSimpleCurve& other );
  
      /** Type of child elements. */
      typedef OGRPoint ChildType;
  
      /** Return begin of point iterator. 
       *
       * Using this iterator for standard range-based loops is safe, but
       * due to implementation limitations, you shouldn't try to access
       * (dereference) more than one iterator step at a time, since you will get
       * a reference to the same OGRPoint& object.
       * @since GDAL 2.3
       */
      Iterator begin();
      /** Return end of point iterator. */
      Iterator end();
      /** Return begin of point iterator.
       *
       * Using this iterator for standard range-based loops is safe, but
       * due to implementation limitations, you shouldn't try to access
       * (dereference) more than one iterator step at a time, since you will get
       * a reference to the same OGRPoint& object.
       * @since GDAL 2.3
       */
      ConstIterator begin() const;
      /** Return end of point iterator. */
      ConstIterator end() const;
  
      // IWks Interface.
      virtual int WkbSize() const override;
      virtual OGRErr importFromWkb( const unsigned char *,
                                    int,
                                    OGRwkbVariant,
                                    int& nBytesConsumedOut ) override;
      virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *,
                                  OGRwkbVariant=wkbVariantOldOgc )
          const override;
      using OGRGeometry::importFromWkt; /** deprecated */
      OGRErr importFromWkt( const char ** ) override;
      virtual OGRErr exportToWkt( char ** ppszDstText,
                                  OGRwkbVariant=wkbVariantOldOgc )
          const override;
  
      // IGeometry interface.
      virtual OGRGeometry *clone() const override;
      virtual void empty() override;
      virtual void getEnvelope( OGREnvelope * psEnvelope ) const override;
      virtual void getEnvelope( OGREnvelope3D * psEnvelope ) const override;
      virtual OGRBoolean  IsEmpty() const override;
  
      // ICurve methods.
      virtual double get_Length() const override;
      virtual void StartPoint( OGRPoint * ) const override;
      virtual void EndPoint( OGRPoint * ) const override;
      virtual void Value( double, OGRPoint * ) const override;
      virtual double Project( const OGRPoint * ) const;
      virtual OGRLineString* getSubLine( double, double, int ) const;
  
      // ILineString methods.
      virtual int getNumPoints() const override { return nPointCount; }
      void        getPoint( int, OGRPoint * ) const;
      double      getX( int i ) const { return paoPoints[i].x; }
      double      getY( int i ) const { return paoPoints[i].y; }
      double      getZ( int i ) const;
      double      getM( int i ) const;
  
      // ISpatialRelation
      virtual OGRBoolean  Equals( const OGRGeometry * ) const override;
  
      // non standard.
      virtual void setCoordinateDimension( int nDimension ) override;
      virtual void set3D( OGRBoolean bIs3D ) override;
      virtual void setMeasured( OGRBoolean bIsMeasured ) override;
      void        setNumPoints( int nNewPointCount,
                                int bZeroizeNewContent = TRUE );
      void        setPoint( int, OGRPoint * );
      void        setPoint( int, double, double );
      void        setZ( int, double );
      void        setM( int, double );
      void        setPoint( int, double, double, double );
      void        setPointM( int, double, double, double );
      void        setPoint( int, double, double, double, double );
      void        setPoints( int, const OGRRawPoint *, const double * = nullptr );
      void        setPointsM( int, const OGRRawPoint *, const double * );
      void        setPoints( int, const OGRRawPoint *, const double *, const double * );
      void        setPoints( int, const double * padfX, const double * padfY,
                             const double *padfZIn = nullptr );
      void        setPointsM( int, const double * padfX, const double * padfY,
                              const double *padfMIn = nullptr );
      void        setPoints( int, const double * padfX, const double * padfY,
                             const double *padfZIn, const double *padfMIn );
      void        addPoint( const OGRPoint * );
      void        addPoint( double, double );
      void        addPoint( double, double, double );
      void        addPointM( double, double, double );
      void        addPoint( double, double, double, double );
  
      void        getPoints( OGRRawPoint *, double * = nullptr ) const;
      void        getPoints( void* pabyX, int nXStride,
                             void* pabyY, int nYStride,
                             void* pabyZ = nullptr, int nZStride = 0 ) const;
      void        getPoints( void* pabyX, int nXStride,
                             void* pabyY, int nYStride,
                             void* pabyZ, int nZStride,
                             void* pabyM, int nMStride ) const;
  
      void        addSubLineString( const OGRLineString *,
                                    int nStartVertex = 0, int nEndVertex = -1 );
      void        reversePoints( void );
      virtual OGRPointIterator* getPointIterator() const override;
  
      // non-standard from OGRGeometry
      virtual OGRErr  transform( OGRCoordinateTransformation *poCT ) override;
      virtual void flattenTo2D() override;
      virtual void segmentize(double dfMaxLength) override;
  
      virtual void        swapXY() override;
  };
  
  //! @cond Doxygen_Suppress
  /** @see OGRSimpleCurve::begin() */
  inline OGRSimpleCurve::Iterator begin(OGRSimpleCurve* poCurve) { return poCurve->begin(); }
  /** @see OGRSimpleCurve::end() */
  inline OGRSimpleCurve::Iterator end(OGRSimpleCurve* poCurve) { return poCurve->end(); }
  
  /** @see OGRSimpleCurve::begin() const */
  inline OGRSimpleCurve::ConstIterator begin(const OGRSimpleCurve* poCurve) { return poCurve->begin(); }
  /** @see OGRSimpleCurve::end() const */
  inline OGRSimpleCurve::ConstIterator end(const OGRSimpleCurve* poCurve) { return poCurve->end(); }
  //! @endcond
  
  /************************************************************************/
  /*                            OGRLineString                             */
  /************************************************************************/
  
  /**
   * Concrete representation of a multi-vertex line.
   *
   * Note: for implementation convenience, we make it inherit from OGRSimpleCurve
   * whereas SFSQL and SQL/MM only make it inherits from OGRCurve.
   */
  
  class CPL_DLL OGRLineString : public OGRSimpleCurve
  {
      static OGRLinearRing*          CasterToLinearRing(OGRCurve* poCurve);
  
    protected:
  //! @cond Doxygen_Suppress
      static OGRLineString* TransferMembersAndDestroy(
                                              OGRLineString* poSrc,
                                              OGRLineString* poDst);
  
      virtual OGRCurveCasterToLineString GetCasterToLineString()
          const override;
      virtual OGRCurveCasterToLinearRing GetCasterToLinearRing()
          const override;
  
      virtual double get_AreaOfCurveSegments() const override;
  //! @endcond
  
      static OGRLinearRing* CastToLinearRing( OGRLineString* poLS );
  
    public:
      OGRLineString();
      OGRLineString( const OGRLineString& other );
      ~OGRLineString() override;
  
      OGRLineString& operator=(const OGRLineString& other);
  
      virtual OGRLineString* CurveToLine( double dfMaxAngleStepSizeDegrees = 0,
                                          const char* const* papszOptions = nullptr )
          const override;
      virtual OGRGeometry* getCurveGeometry(
          const char* const* papszOptions = nullptr ) const override;
      virtual double get_Area() const override;
  
      // Non-standard from OGRGeometry.
      virtual OGRwkbGeometryType getGeometryType() const override;
      virtual const char *getGeometryName() const override;
  
      /** Return pointer of this in upper class */
      inline OGRSimpleCurve* toUpperClass() { return this; }
      /** Return pointer of this in upper class */
      inline const OGRSimpleCurve* toUpperClass() const { return this; }
  
      virtual void accept(IOGRGeometryVisitor* visitor) override { visitor->visit(this); }
      virtual void accept(IOGRConstGeometryVisitor* visitor) const override { visitor->visit(this); }
  };
  
  /************************************************************************/
  /*                            OGRLinearRing                             */
  /************************************************************************/
  
  /**
   * Concrete representation of a closed ring.
   *
   * This class is functionally equivalent to an OGRLineString, but has a
   * separate identity to maintain alignment with the OpenGIS simple feature
   * data model.  It exists to serve as a component of an OGRPolygon.
   *
   * The OGRLinearRing has no corresponding free standing well known binary
   * representation, so importFromWkb() and exportToWkb() will not actually
   * work.  There is a non-standard GDAL WKT representation though.
   *
   * Because OGRLinearRing is not a "proper" free standing simple features
   * object, it cannot be directly used on a feature via SetGeometry(), and
   * cannot generally be used with GEOS for operations like Intersects().
   * Instead the polygon should be used, or the OGRLinearRing should be
   * converted to an OGRLineString for such operations.
   *
   * Note: this class exists in SFSQL 1.2, but not in ISO SQL/MM Part 3.
   */
  
  class CPL_DLL OGRLinearRing : public OGRLineString
  {
      static OGRLineString*       CasterToLineString( OGRCurve* poCurve );
  
    protected:
  //! @cond Doxygen_Suppress
      friend class OGRPolygon;
      friend class OGRTriangle;
  
      // These are not IWks compatible ... just a convenience for OGRPolygon.
      virtual int _WkbSize( int _flags ) const;
      virtual OGRErr _importFromWkb( OGRwkbByteOrder, int _flags,
                                     const unsigned char *, int,
                                     int& nBytesConsumedOut );
      virtual OGRErr _exportToWkb( OGRwkbByteOrder, int _flags,
                                   unsigned char * ) const;
  
      virtual OGRCurveCasterToLineString GetCasterToLineString()
          const override;
      virtual OGRCurveCasterToLinearRing GetCasterToLinearRing()
          const override;
  //! @endcond
  
      static OGRLineString* CastToLineString( OGRLinearRing* poLR );
  
    public:
      OGRLinearRing();
      OGRLinearRing( const OGRLinearRing& other );
      explicit OGRLinearRing( OGRLinearRing * );
      ~OGRLinearRing() override;
  
      OGRLinearRing& operator=( const OGRLinearRing& other );
  
      // Non standard.
      virtual const char *getGeometryName() const override;
      virtual OGRGeometry *clone() const override;
      virtual int isClockwise() const;
      virtual void reverseWindingOrder();
      virtual void closeRings() override;
      OGRBoolean isPointInRing( const OGRPoint* pt,
                                int bTestEnvelope = TRUE ) const;
      OGRBoolean isPointOnRingBoundary( const OGRPoint* pt,
                                        int bTestEnvelope = TRUE ) const;
      virtual OGRErr  transform( OGRCoordinateTransformation *poCT ) override;
  
      /** Return pointer of this in upper class */
      inline OGRLineString* toUpperClass() { return this; }
      /** Return pointer of this in upper class */
      inline const OGRLineString* toUpperClass() const { return this; }
  
      virtual void accept(IOGRGeometryVisitor* visitor) override { visitor->visit(this); }
      virtual void accept(IOGRConstGeometryVisitor* visitor) const override { visitor->visit(this); }
  
      // IWks Interface - Note this isn't really a first class object
      // for the purposes of WKB form.  These methods always fail since this
      // object can't be serialized on its own.
      virtual int WkbSize() const override;
      virtual OGRErr importFromWkb( const unsigned char *,
                                    int,
                                    OGRwkbVariant,
                                    int& nBytesConsumedOut ) override;
      virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *,
                                  OGRwkbVariant=wkbVariantOldOgc )
          const override;
  };
  
  /************************************************************************/
  /*                         OGRCircularString                            */
  /************************************************************************/
  
  /**
   * Concrete representation of a circular string, that is to say a curve made
   * of one or several arc circles.
   *
   * Note: for implementation convenience, we make it inherit from OGRSimpleCurve
   * whereas SQL/MM only makes it inherits from OGRCurve.
   *
   * Compatibility: ISO SQL/MM Part 3.
   *
   * @since GDAL 2.0
   */
  
  class CPL_DLL OGRCircularString : public OGRSimpleCurve
  {
    private:
      void        ExtendEnvelopeWithCircular( OGREnvelope * psEnvelope ) const;
      OGRBoolean  IsValidFast() const;
      int         IsFullCircle( double& cx, double& cy, double& square_R ) const;
  
    protected:
  //! @cond Doxygen_Suppress
      virtual OGRCurveCasterToLineString GetCasterToLineString()
          const override;
      virtual OGRCurveCasterToLinearRing GetCasterToLinearRing()
          const override;
      virtual int    IntersectsPoint( const OGRPoint* p ) const override;
      virtual int    ContainsPoint( const OGRPoint* p ) const override;
      virtual double get_AreaOfCurveSegments() const override;
  //! @endcond
  
    public:
      OGRCircularString();
      OGRCircularString( const OGRCircularString& other );
      ~OGRCircularString() override;
  
      OGRCircularString& operator=(const OGRCircularString& other);
  
      // IWks Interface.
      virtual OGRErr importFromWkb( const unsigned char *,
                                    int,
                                    OGRwkbVariant,
                                    int& nBytesConsumedOut ) override;
      virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *,
                                  OGRwkbVariant=wkbVariantOldOgc )
          const override;
      using OGRGeometry::importFromWkt; /** deprecated */
      OGRErr importFromWkt( const char ** ) override;
      virtual OGRErr exportToWkt( char ** ppszDstText,
                                  OGRwkbVariant=wkbVariantOldOgc )
          const override;
  
      // IGeometry interface.
      virtual OGRBoolean  IsValid() const override;
      virtual void getEnvelope( OGREnvelope * psEnvelope ) const override;
      virtual void getEnvelope( OGREnvelope3D * psEnvelope ) const override;
  
      // ICurve methods.
      virtual double get_Length() const override;
      virtual OGRLineString* CurveToLine( double dfMaxAngleStepSizeDegrees = 0,
                                          const char* const* papszOptions = nullptr )
          const override;
      virtual void Value( double, OGRPoint * ) const override;
      virtual double get_Area() const override;
  
      // Non-standard from OGRGeometry.
      virtual OGRwkbGeometryType getGeometryType() const override;
      virtual const char *getGeometryName() const override;
      virtual void segmentize( double dfMaxLength ) override;
      virtual OGRBoolean hasCurveGeometry( int bLookForNonLinear = FALSE )
          const override;
      virtual OGRGeometry* getLinearGeometry(
          double dfMaxAngleStepSizeDegrees = 0,
          const char* const* papszOptions = nullptr) const override;
  
      /** Return pointer of this in upper class */
      inline OGRSimpleCurve* toUpperClass() { return this; }
      /** Return pointer of this in upper class */
      inline const OGRSimpleCurve* toUpperClass() const { return this; }
  
      virtual void accept(IOGRGeometryVisitor* visitor) override { visitor->visit(this); }
      virtual void accept(IOGRConstGeometryVisitor* visitor) const override { visitor->visit(this); }
  };
  
  /************************************************************************/
  /*                           OGRCurveCollection                         */
  /************************************************************************/
  
  /**
   * Utility class to store a collection of curves. Used as a member of
   * OGRCompoundCurve and OGRCurvePolygon.
   *
   * This class is only exported because of linking issues. It should never
   * be directly used.
   *
   * @since GDAL 2.0
   */
  
  //! @cond Doxygen_Suppress
  class CPL_DLL OGRCurveCollection
  {
    protected:
      friend class OGRCompoundCurve;
      friend class OGRCurvePolygon;
      friend class OGRPolygon;
      friend class OGRTriangle;
  
      int         nCurveCount;
      OGRCurve  **papoCurves;
  
    public:
                  OGRCurveCollection();
                  OGRCurveCollection(const OGRCurveCollection& other);
                 ~OGRCurveCollection();
  
      OGRCurveCollection& operator=(const OGRCurveCollection& other);
  
      /** Type of child elements. */
      typedef OGRCurve ChildType;
  
      /** Return begin of curve iterator.
       * @since GDAL 2.3
       */
      OGRCurve** begin() { return papoCurves; }
      /** Return end of curve iterator. */
      OGRCurve** end() { return papoCurves + nCurveCount; }
      /** Return begin of curve iterator.
       * @since GDAL 2.3
       */
      const OGRCurve* const* begin() const { return papoCurves; }
      /** Return end of curve iterator. */
      const OGRCurve* const* end() const { return papoCurves + nCurveCount; }
  
      void            empty(OGRGeometry* poGeom);
      OGRBoolean      IsEmpty() const;
      void            getEnvelope( OGREnvelope * psEnvelope ) const;
      void            getEnvelope( OGREnvelope3D * psEnvelope ) const;
  
      OGRErr          addCurveDirectly( OGRGeometry* poGeom, OGRCurve* poCurve,
                                        int bNeedRealloc );
      int             WkbSize() const;
      OGRErr          importPreambleFromWkb( OGRGeometry* poGeom,
                                              const unsigned char * pabyData,
                                              int& nSize,
                                              int& nDataOffset,
                                              OGRwkbByteOrder& eByteOrder,
                                              int nMinSubGeomSize,
                                              OGRwkbVariant eWkbVariant );
      OGRErr      importBodyFromWkb(
                      OGRGeometry* poGeom,
                      const unsigned char * pabyData,
                      int nSize,
                      int bAcceptCompoundCurve,
                      OGRErr (*pfnAddCurveDirectlyFromWkb)( OGRGeometry* poGeom,
                                                            OGRCurve* poCurve ),
                      OGRwkbVariant eWkbVariant,
                      int& nBytesConsumedOut );
      OGRErr          exportToWkt( const OGRGeometry* poGeom,
                                   char ** ppszDstText ) const;
      OGRErr          exportToWkb( const OGRGeometry* poGeom, OGRwkbByteOrder,
                                   unsigned char *,
                                   OGRwkbVariant eWkbVariant ) const;
      OGRBoolean      Equals(const OGRCurveCollection *poOCC) const;
      void            setCoordinateDimension( OGRGeometry* poGeom,
                                              int nNewDimension );
      void            set3D( OGRGeometry* poGeom, OGRBoolean bIs3D );
      void            setMeasured( OGRGeometry* poGeom, OGRBoolean bIsMeasured );
      void            assignSpatialReference( OGRGeometry* poGeom, OGRSpatialReference * poSR );
      int             getNumCurves() const;
      OGRCurve       *getCurve( int );
      const OGRCurve *getCurve( int ) const;
      OGRCurve       *stealCurve( int );
  
      OGRErr          removeCurve( int iIndex, bool bDelete = true );
  
      OGRErr          transform( OGRGeometry* poGeom,
                                 OGRCoordinateTransformation *poCT );
      void            flattenTo2D( OGRGeometry* poGeom );
      void            segmentize( double dfMaxLength );
      void            swapXY();
      OGRBoolean      hasCurveGeometry(int bLookForNonLinear) const;
  };
  //! @endcond
  
  /************************************************************************/
  /*                            OGRCompoundCurve                          */
  /************************************************************************/
  
  /**
   * Concrete representation of a compound curve, made of curves: OGRLineString
   * and OGRCircularString. Each curve is connected by its first point to
   * the last point of the previous curve.
   *
   * Compatibility: ISO SQL/MM Part 3.
   *
   * @since GDAL 2.0
   */
  
  class CPL_DLL OGRCompoundCurve : public OGRCurve
  {
    private:
      OGRCurveCollection oCC;
  
      OGRErr      addCurveDirectlyInternal( OGRCurve* poCurve,
                                            double dfToleranceEps,
                                            int bNeedRealloc );
      static OGRErr addCurveDirectlyFromWkt( OGRGeometry* poSelf,
                                             OGRCurve* poCurve );
      static OGRErr addCurveDirectlyFromWkb( OGRGeometry* poSelf,
                                             OGRCurve* poCurve );
      OGRLineString* CurveToLineInternal( double dfMaxAngleStepSizeDegrees,
                                          const char* const* papszOptions,
                                          int bIsLinearRing ) const;
      static OGRLineString* CasterToLineString( OGRCurve* poCurve );
      static OGRLinearRing* CasterToLinearRing( OGRCurve* poCurve );
  
    protected:
  //! @cond Doxygen_Suppress
      static OGRLineString* CastToLineString( OGRCompoundCurve* poCC );
      static OGRLinearRing* CastToLinearRing( OGRCompoundCurve* poCC );
  
      virtual OGRCurveCasterToLineString GetCasterToLineString()
          const override;
      virtual OGRCurveCasterToLinearRing GetCasterToLinearRing()
          const override;
  //! @endcond
  
    public:
      OGRCompoundCurve();
      OGRCompoundCurve( const OGRCompoundCurve& other );
      ~OGRCompoundCurve() override;
  
      OGRCompoundCurve& operator=( const OGRCompoundCurve& other );
  
      /** Type of child elements. */
      typedef OGRCurve ChildType;
  
      /** Return begin of curve iterator.
       * @since GDAL 2.3
       */
      ChildType** begin() { return oCC.begin(); }
      /** Return end of curve iterator. */
      ChildType** end() { return oCC.end(); }
      /** Return begin of curve iterator.
       * @since GDAL 2.3
       */
      const ChildType* const * begin() const { return oCC.begin(); }
      /** Return end of curve iterator. */
      const ChildType* const * end() const { return oCC.end(); }
  
      // IWks Interface
      virtual int WkbSize() const override;
      virtual OGRErr importFromWkb( const unsigned char *,
                                    int,
                                    OGRwkbVariant,
                                    int& nBytesConsumedOut ) override;
      virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *,
                                  OGRwkbVariant=wkbVariantOldOgc )
          const override;
      using OGRGeometry::importFromWkt; /** deprecated */
      OGRErr importFromWkt( const char ** ) override;
      virtual OGRErr exportToWkt( char ** ppszDstText,
                                  OGRwkbVariant=wkbVariantOldOgc )
          const override;
  
      // IGeometry interface.
      virtual OGRGeometry *clone() const override;
      virtual void empty() override;
      virtual void getEnvelope( OGREnvelope * psEnvelope ) const override;
      virtual void getEnvelope( OGREnvelope3D * psEnvelope ) const override;
      virtual OGRBoolean  IsEmpty() const override;
  
      // ICurve methods.
      virtual double get_Length() const override;
      virtual void StartPoint( OGRPoint * ) const override;
      virtual void EndPoint( OGRPoint * ) const override;
      virtual void Value( double, OGRPoint * ) const override;
      virtual OGRLineString* CurveToLine( double dfMaxAngleStepSizeDegrees = 0,
                                          const char* const* papszOptions = nullptr )
          const override;
  
      virtual int getNumPoints() const override;
      virtual double get_AreaOfCurveSegments() const override;
      virtual double get_Area() const override;
  
      // ISpatialRelation.
      virtual OGRBoolean  Equals( const OGRGeometry * ) const override;
  
      // ICompoundCurve method.
      int             getNumCurves() const;
      OGRCurve       *getCurve( int );
      const OGRCurve *getCurve( int ) const;
  
      // Non-standard.
      virtual void setCoordinateDimension( int nDimension ) override;
      virtual void set3D( OGRBoolean bIs3D ) override;
      virtual void setMeasured( OGRBoolean bIsMeasured ) override;
  
      virtual void    assignSpatialReference( OGRSpatialReference * poSR ) override;
  
      OGRErr         addCurve( OGRCurve*, double dfToleranceEps = 1e-14  );
      OGRErr         addCurveDirectly( OGRCurve*, double dfToleranceEps = 1e-14 );
      OGRCurve      *stealCurve( int );
      virtual OGRPointIterator* getPointIterator() const override;
  
      // Non-standard from OGRGeometry.
      virtual OGRwkbGeometryType getGeometryType() const override;
      virtual const char *getGeometryName() const override;
      virtual OGRErr  transform( OGRCoordinateTransformation *poCT ) override;
      virtual void flattenTo2D() override;
      virtual void segmentize(double dfMaxLength) override;
      virtual OGRBoolean hasCurveGeometry(int bLookForNonLinear = FALSE)
          const override;
      virtual OGRGeometry* getLinearGeometry(
          double dfMaxAngleStepSizeDegrees = 0,
          const char* const* papszOptions = nullptr) const override;
      virtual void accept(IOGRGeometryVisitor* visitor) override { visitor->visit(this); }
      virtual void accept(IOGRConstGeometryVisitor* visitor) const override { visitor->visit(this); }
  
      virtual void        swapXY() override;
  };
  
  //! @cond Doxygen_Suppress
  /** @see OGRCompoundCurve::begin() const */
  inline const OGRCompoundCurve::ChildType* const * begin(const OGRCompoundCurve* poCurve) { return poCurve->begin(); }
  /** @see OGRCompoundCurve::end() const */
  inline const OGRCompoundCurve::ChildType* const * end(const OGRCompoundCurve* poCurve) { return poCurve->end(); }
  
  /** @see OGRCompoundCurve::begin() */
  inline OGRCompoundCurve::ChildType** begin(OGRCompoundCurve* poCurve) { return poCurve->begin(); }
  /** @see OGRCompoundCurve::end() */
  inline OGRCompoundCurve::ChildType** end(OGRCompoundCurve* poCurve) { return poCurve->end(); }
  //! @endcond
  
  /************************************************************************/
  /*                              OGRSurface                              */
  /************************************************************************/
  
  /**
   * Abstract base class for 2 dimensional objects like polygons or curve
   * polygons.
   */
  
  class CPL_DLL OGRSurface : public OGRGeometry
  {
    protected:
  //! @cond Doxygen_Suppress
      virtual OGRSurfaceCasterToPolygon      GetCasterToPolygon() const = 0;
      virtual OGRSurfaceCasterToCurvePolygon GetCasterToCurvePolygon() const = 0;
  //! @endcond
  
    public:
      virtual double      get_Area() const = 0;
      virtual OGRErr      PointOnSurface( OGRPoint * poPoint ) const
                                  { return PointOnSurfaceInternal(poPoint); }
  //! @cond Doxygen_Suppress
      static OGRPolygon*      CastToPolygon(OGRSurface* poSurface);
      static OGRCurvePolygon* CastToCurvePolygon(OGRSurface* poSurface);
  //! @endcond
  };
  
  /************************************************************************/
  /*                          OGRCurvePolygon                             */
  /************************************************************************/
  
  /**
   * Concrete class representing curve polygons.
   *
   * Note that curve polygons consist of one outer (curve) ring, and zero or
   * more inner rings.  A curve polygon cannot represent disconnected
   * regions (such as multiple islands in a political body).  The
   * OGRMultiSurface must be used for this.
   *
   * Compatibility: ISO SQL/MM Part 3.
   *
   * @since GDAL 2.0
   */
  
  class CPL_DLL OGRCurvePolygon : public OGRSurface
  {
      static OGRPolygon*      CasterToPolygon(OGRSurface* poSurface);
  
    private:
      OGRBoolean      IntersectsPoint( const OGRPoint* p ) const;
      OGRBoolean      ContainsPoint( const OGRPoint* p ) const;
      virtual int   checkRing( OGRCurve * poNewRing ) const;
      OGRErr        addRingDirectlyInternal( OGRCurve* poCurve,
                                             int bNeedRealloc );
      static OGRErr addCurveDirectlyFromWkt( OGRGeometry* poSelf,
                                             OGRCurve* poCurve );
      static OGRErr addCurveDirectlyFromWkb( OGRGeometry* poSelf,
                                             OGRCurve* poCurve );
  
    protected:
  //! @cond Doxygen_Suppress
      friend class OGRPolygon;
      friend class OGRTriangle;
      OGRCurveCollection oCC;
  
      virtual OGRSurfaceCasterToPolygon      GetCasterToPolygon()
          const override;
      virtual OGRSurfaceCasterToCurvePolygon GetCasterToCurvePolygon()
          const override;
  //! @endcond
  
      static OGRPolygon* CastToPolygon( OGRCurvePolygon* poCP );
  
    public:
      OGRCurvePolygon();
      OGRCurvePolygon( const OGRCurvePolygon& );
      ~OGRCurvePolygon() override;
  
      OGRCurvePolygon& operator=( const OGRCurvePolygon& other );
  
      /** Type of child elements. */
      typedef OGRCurve ChildType;
  
      /** Return begin of curve iterator.
       * @since GDAL 2.3
       */
      ChildType** begin() { return oCC.begin(); }
      /** Return end of curve iterator. */
      ChildType** end() { return oCC.end(); }
      /** Return begin of curve iterator.
       * @since GDAL 2.3
       */
      const ChildType* const * begin() const { return oCC.begin(); }
      /** Return end of curve iterator. */
      const ChildType* const * end() const { return oCC.end(); }
  
      // Non standard (OGRGeometry).
      virtual const char *getGeometryName() const override;
      virtual OGRwkbGeometryType getGeometryType() const override;
      virtual OGRGeometry *clone() const override;
      virtual void empty() override;
      virtual OGRErr  transform( OGRCoordinateTransformation *poCT ) override;
      virtual void flattenTo2D() override;
      virtual OGRBoolean  IsEmpty() const override;
      virtual void segmentize( double dfMaxLength ) override;
      virtual OGRBoolean hasCurveGeometry( int bLookForNonLinear = FALSE )
          const override;
      virtual OGRGeometry* getLinearGeometry(
          double dfMaxAngleStepSizeDegrees = 0,
          const char* const* papszOptions = nullptr ) const override;
  
      // ISurface Interface
      virtual double      get_Area() const override;
  
      // IWks Interface
      virtual int WkbSize() const override;
      virtual OGRErr importFromWkb( const unsigned char *,
                                    int,
                                    OGRwkbVariant,
                                    int& nBytesConsumedOut ) override;
      virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *,
                                  OGRwkbVariant=wkbVariantOldOgc )
          const override;
      using OGRGeometry::importFromWkt; /** deprecated */
      OGRErr importFromWkt( const char ** ) override;
      virtual OGRErr exportToWkt( char ** ppszDstText,
                                  OGRwkbVariant eWkbVariant = wkbVariantOldOgc )
          const override;
  
      // IGeometry
      virtual int getDimension() const override;
      virtual void getEnvelope( OGREnvelope * psEnvelope ) const override;
      virtual void getEnvelope( OGREnvelope3D * psEnvelope ) const override;
  
      // ICurvePolygon
      virtual OGRPolygon* CurvePolyToPoly(
          double dfMaxAngleStepSizeDegrees = 0,
          const char* const* papszOptions = nullptr ) const;
  
      // ISpatialRelation
      virtual OGRBoolean  Equals( const OGRGeometry * ) const override;
      virtual OGRBoolean  Intersects( const OGRGeometry * ) const override;
      virtual OGRBoolean  Contains( const OGRGeometry * ) const override;
  
      // Non standard
      virtual void setCoordinateDimension( int nDimension ) override;
      virtual void set3D( OGRBoolean bIs3D ) override;
      virtual void setMeasured( OGRBoolean bIsMeasured ) override;
  
      virtual void    assignSpatialReference( OGRSpatialReference * poSR ) override;
  
      virtual OGRErr addRing( OGRCurve * );
      virtual OGRErr addRingDirectly( OGRCurve * );
  
      OGRCurve *getExteriorRingCurve();
      const OGRCurve *getExteriorRingCurve() const;
      int         getNumInteriorRings() const;
      OGRCurve *getInteriorRingCurve( int );
      const OGRCurve *getInteriorRingCurve( int ) const;
  
      OGRCurve *stealExteriorRingCurve();
  
      OGRErr removeRing( int iIndex, bool bDelete = true );
      virtual void accept(IOGRGeometryVisitor* visitor) override { visitor->visit(this); }
      virtual void accept(IOGRConstGeometryVisitor* visitor) const override { visitor->visit(this); }
  
      virtual void        swapXY() override;
  };
  
  //! @cond Doxygen_Suppress
  /** @see OGRCurvePolygon::begin() const */
  inline const OGRCurvePolygon::ChildType* const * begin(const OGRCurvePolygon* poGeom) { return poGeom->begin(); }
  /** @see OGRCurvePolygon::end() const */
  inline const OGRCurvePolygon::ChildType* const * end(const OGRCurvePolygon* poGeom) { return poGeom->end(); }
  
  /** @see OGRCurvePolygon::begin() */
  inline OGRCurvePolygon::ChildType** begin(OGRCurvePolygon* poGeom) { return poGeom->begin(); }
  /** @see OGRCurvePolygon::end() */
  inline OGRCurvePolygon::ChildType** end(OGRCurvePolygon* poGeom) { return poGeom->end(); }
  //! @endcond
  
  /************************************************************************/
  /*                              OGRPolygon                              */
  /************************************************************************/
  
  /**
   * Concrete class representing polygons.
   *
   * Note that the OpenGIS simple features polygons consist of one outer ring
   * (linearring), and zero or more inner rings.  A polygon cannot represent
   * disconnected regions (such as multiple islands in a political body).  The
   * OGRMultiPolygon must be used for this.
   */
  
  class CPL_DLL OGRPolygon : public OGRCurvePolygon
  {
      static OGRCurvePolygon*     CasterToCurvePolygon(OGRSurface* poSurface);
  
    protected:
  //! @cond Doxygen_Suppress
      friend class OGRMultiSurface;
      friend class OGRPolyhedralSurface;
      friend class OGRTriangulatedSurface;
  
      virtual int checkRing( OGRCurve * poNewRing ) const override;
      virtual OGRErr importFromWKTListOnly( const char ** ppszInput,
                                            int bHasZ, int bHasM,
                                            OGRRawPoint*& paoPoints,
                                            int& nMaxPoints,
                                            double*& padfZ );
  
      static OGRCurvePolygon* CastToCurvePolygon(OGRPolygon* poPoly);
  
      virtual OGRSurfaceCasterToPolygon      GetCasterToPolygon()
          const override;
      virtual OGRSurfaceCasterToCurvePolygon GetCasterToCurvePolygon()
          const override;
  //! @endcond
  
    public:
      OGRPolygon();
      OGRPolygon(const OGRPolygon& other);
      ~OGRPolygon() override;
  
      OGRPolygon& operator=(const OGRPolygon& other);
  
      /** Type of child elements. */
      typedef OGRLinearRing ChildType;
  
      /** Return begin of iterator.
       * @since GDAL 2.3
       */
      ChildType** begin() { return reinterpret_cast<ChildType**>(oCC.begin()); }
      /** Return end of iterator */
      ChildType** end() { return reinterpret_cast<ChildType**>(oCC.end()); }
      /** Return begin of iterator.
       * @since GDAL 2.3
       */
      const ChildType* const* begin() const { return reinterpret_cast<const ChildType* const*>(oCC.begin()); }
      /** Return end of iterator */
      const ChildType* const* end() const { return reinterpret_cast<const ChildType* const*>(oCC.end()); }
  
      // Non-standard (OGRGeometry).
      virtual const char *getGeometryName() const override;
      virtual OGRwkbGeometryType getGeometryType() const override;
      virtual OGRBoolean hasCurveGeometry( int bLookForNonLinear = FALSE )
          const override;
      virtual OGRGeometry* getCurveGeometry(
      const char* const* papszOptions = nullptr ) const override;
      virtual OGRGeometry* getLinearGeometry(
          double dfMaxAngleStepSizeDegrees = 0,
          const char* const* papszOptions = nullptr) const override;
  
      // IWks Interface.
      virtual int WkbSize() const override;
      virtual OGRErr importFromWkb( const unsigned char *,
                                    int,
                                    OGRwkbVariant,
                                    int& nBytesConsumedOut ) override;
      virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *,
                                  OGRwkbVariant=wkbVariantOldOgc )
          const override;
      using OGRGeometry::importFromWkt; /** deprecated */
      OGRErr importFromWkt( const char ** ) override;
  
      virtual OGRErr exportToWkt( char ** ppszDstText,
                                  OGRwkbVariant=wkbVariantOldOgc )
          const override;
  
      // ICurvePolygon.
      virtual OGRPolygon* CurvePolyToPoly(
          double dfMaxAngleStepSizeDegrees = 0,
          const char* const* papszOptions = nullptr ) const override;
  
      OGRLinearRing *getExteriorRing();
      const OGRLinearRing *getExteriorRing() const;
      virtual OGRLinearRing *getInteriorRing( int );
      virtual const OGRLinearRing *getInteriorRing( int ) const;
  
      OGRLinearRing *stealExteriorRing();
      virtual OGRLinearRing *stealInteriorRing(int);
  
      OGRBoolean IsPointOnSurface( const OGRPoint * ) const;
  
      /** Return pointer of this in upper class */
      inline OGRCurvePolygon* toUpperClass() { return this; }
      /** Return pointer of this in upper class */
      inline const OGRCurvePolygon* toUpperClass() const { return this; }
  
      virtual void accept(IOGRGeometryVisitor* visitor) override { visitor->visit(this); }
      virtual void accept(IOGRConstGeometryVisitor* visitor) const override { visitor->visit(this); }
  
      virtual void closeRings() override;
  };
  
  //! @cond Doxygen_Suppress
  /** @see OGRPolygon::begin() const */
  inline const OGRPolygon::ChildType* const * begin(const OGRPolygon* poGeom) { return poGeom->begin(); }
  /** @see OGRPolygon::end() const */
  inline const OGRPolygon::ChildType* const * end(const OGRPolygon* poGeom) { return poGeom->end(); }
  
  /** @see OGRPolygon::begin() */
  inline OGRPolygon::ChildType** begin(OGRPolygon* poGeom) { return poGeom->begin(); }
  /** @see OGRPolygon::end() */
  inline OGRPolygon::ChildType** end(OGRPolygon* poGeom) { return poGeom->end(); }
  //! @endcond
  
  /************************************************************************/
  /*                              OGRTriangle                             */
  /************************************************************************/
  
  /**
   * Triangle class.
   *
   * @since GDAL 2.2
   */
  
  class CPL_DLL OGRTriangle : public OGRPolygon
  {
    private:
      static OGRPolygon*          CasterToPolygon(OGRSurface* poSurface);
      bool quickValidityCheck() const;
  
    protected:
  //! @cond Doxygen_Suppress
      virtual OGRSurfaceCasterToPolygon   GetCasterToPolygon() const override;
      virtual OGRErr importFromWKTListOnly( const char ** ppszInput,
                                            int bHasZ, int bHasM,
                                            OGRRawPoint*& paoPoints,
                                            int& nMaxPoints,
                                            double*& padfZ ) override;
  //! @endcond
  
    public:
      OGRTriangle();
      OGRTriangle( const OGRPoint &p, const OGRPoint &q, const OGRPoint &r );
      OGRTriangle( const OGRTriangle &other );
      OGRTriangle( const OGRPolygon &other, OGRErr &eErr );
      OGRTriangle& operator=( const OGRTriangle& other );
      ~OGRTriangle() override;
      virtual const char *getGeometryName() const override;
      virtual OGRwkbGeometryType getGeometryType() const override;
  
      // IWks Interface.
      virtual OGRErr importFromWkb( const unsigned char *,
                                    int,
                                    OGRwkbVariant,
                                    int& nBytesConsumedOut ) override;
  
      // New methods rewritten from OGRPolygon/OGRCurvePolygon/OGRGeometry.
      virtual OGRErr addRingDirectly( OGRCurve * poNewRing ) override;
  
      /** Return pointer of this in upper class */
      inline OGRPolygon* toUpperClass() { return this; }
      /** Return pointer of this in upper class */
      inline const OGRPolygon* toUpperClass() const { return this; }
  
      virtual void accept(IOGRGeometryVisitor* visitor) override { visitor->visit(this); }
      virtual void accept(IOGRConstGeometryVisitor* visitor) const override { visitor->visit(this); }
  
  //! @cond Doxygen_Suppress
      static OGRGeometry* CastToPolygon( OGRGeometry* poGeom );
  //! @endcond
  };
  
  /************************************************************************/
  /*                        OGRGeometryCollection                         */
  /************************************************************************/
  
  /**
   * A collection of 1 or more geometry objects.
   *
   * All geometries must share a common spatial reference system, and
   * Subclasses may impose additional restrictions on the contents.
   */
  
  class CPL_DLL OGRGeometryCollection : public OGRGeometry
  {
      OGRErr      importFromWkbInternal( const unsigned char * pabyData,
                                         int nSize,
                                         int nRecLevel,
                                         OGRwkbVariant, int& nBytesConsumedOut );
      OGRErr      importFromWktInternal( const char **ppszInput, int nRecLevel );
  
    protected:
  //! @cond Doxygen_Suppress
      int         nGeomCount;
      OGRGeometry **papoGeoms;
  
      OGRErr              exportToWktInternal( char ** ppszDstText,
                                               OGRwkbVariant eWkbVariant,
                                               const char* pszSkipPrefix ) const;
      static OGRGeometryCollection* TransferMembersAndDestroy(
          OGRGeometryCollection* poSrc,
          OGRGeometryCollection* poDst );
  //! @endcond
      virtual OGRBoolean         isCompatibleSubType( OGRwkbGeometryType ) const;
  
    public:
      OGRGeometryCollection();
      OGRGeometryCollection( const OGRGeometryCollection& other );
      ~OGRGeometryCollection() override;
  
      OGRGeometryCollection& operator=( const OGRGeometryCollection& other );
  
      /** Type of child elements. */
      typedef OGRGeometry ChildType;
  
      /** Return begin of sub-geometry iterator.
       * @since GDAL 2.3
       */
      ChildType** begin() { return papoGeoms; }
      /** Return end of sub-geometry iterator. */
      ChildType** end() { return papoGeoms + nGeomCount; }
      /** Return begin of sub-geometry iterator.
       * @since GDAL 2.3
       */
      const ChildType* const* begin() const { return papoGeoms; }
      /** Return end of sub-geometry iterator. */
      const ChildType* const* end() const { return papoGeoms + nGeomCount; }
  
      // Non standard (OGRGeometry).
      virtual const char *getGeometryName() const override;
      virtual OGRwkbGeometryType getGeometryType() const override;
      virtual OGRGeometry *clone() const override;
      virtual void empty() override;
      virtual OGRErr  transform( OGRCoordinateTransformation *poCT ) override;
      virtual void flattenTo2D() override;
      virtual OGRBoolean  IsEmpty() const override;
      virtual void segmentize(double dfMaxLength) override;
      virtual OGRBoolean hasCurveGeometry( int bLookForNonLinear = FALSE )
          const override;
      virtual OGRGeometry* getCurveGeometry(
          const char* const* papszOptions = nullptr ) const override;
      virtual OGRGeometry* getLinearGeometry(
          double dfMaxAngleStepSizeDegrees = 0,
          const char* const* papszOptions = nullptr ) const override;
  
      // IWks Interface
      virtual int WkbSize() const override;
      virtual OGRErr importFromWkb( const unsigned char *,
                                    int,
                                    OGRwkbVariant,
                                    int& nBytesConsumedOut ) override;
      virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *,
                                  OGRwkbVariant=wkbVariantOldOgc )
          const override;
      using OGRGeometry::importFromWkt; /** deprecated */
      OGRErr importFromWkt( const char ** ) override;
  
      virtual OGRErr exportToWkt( char ** ppszDstText,
                                  OGRwkbVariant=wkbVariantOldOgc )
          const override;
  
      virtual double get_Length() const;
      virtual double get_Area() const;
  
      // IGeometry methods
      virtual int getDimension() const override;
      virtual void getEnvelope( OGREnvelope * psEnvelope ) const override;
      virtual void getEnvelope( OGREnvelope3D * psEnvelope ) const override;
  
      // IGeometryCollection
      int         getNumGeometries() const;
      OGRGeometry *getGeometryRef( int );
      const OGRGeometry *getGeometryRef( int ) const;
  
      // ISpatialRelation
      virtual OGRBoolean  Equals( const OGRGeometry * ) const override;
  
      // Non standard
      virtual void setCoordinateDimension( int nDimension ) override;
      virtual void set3D( OGRBoolean bIs3D ) override;
      virtual void setMeasured( OGRBoolean bIsMeasured ) override;
      virtual OGRErr addGeometry( const OGRGeometry * );
      virtual OGRErr addGeometryDirectly( OGRGeometry * );
      virtual OGRErr removeGeometry( int iIndex, int bDelete = TRUE );
  
      virtual void    assignSpatialReference( OGRSpatialReference * poSR ) override;
  
      void closeRings() override;
  
      virtual void swapXY() override;
  
      virtual void accept(IOGRGeometryVisitor* visitor) override { visitor->visit(this); }
      virtual void accept(IOGRConstGeometryVisitor* visitor) const override { visitor->visit(this); }
  
      static OGRGeometryCollection* CastToGeometryCollection(
          OGRGeometryCollection* poSrc );
  };
  
  //! @cond Doxygen_Suppress
  /** @see OGRGeometryCollection::begin() const */
  inline const OGRGeometryCollection::ChildType* const * begin(const OGRGeometryCollection* poGeom) { return poGeom->begin(); }
  /** @see OGRGeometryCollection::end() const */
  inline const OGRGeometryCollection::ChildType* const * end(const OGRGeometryCollection* poGeom) { return poGeom->end(); }
  
  /** @see OGRGeometryCollection::begin() */
  inline OGRGeometryCollection::ChildType** begin(OGRGeometryCollection* poGeom) { return poGeom->begin(); }
  /** @see OGRGeometryCollection::end() */
  inline OGRGeometryCollection::ChildType** end(OGRGeometryCollection* poGeom) { return poGeom->end(); }
  //! @endcond
  
  /************************************************************************/
  /*                          OGRMultiSurface                             */
  /************************************************************************/
  
  /**
   * A collection of non-overlapping OGRSurface.
   *
   * @since GDAL 2.0
   */
  
  class CPL_DLL OGRMultiSurface : public OGRGeometryCollection
  {
    protected:
      virtual OGRBoolean isCompatibleSubType( OGRwkbGeometryType )
          const override;
  
    public:
      OGRMultiSurface();
      OGRMultiSurface( const OGRMultiSurface& other );
      ~OGRMultiSurface() override;
  
      OGRMultiSurface& operator=( const OGRMultiSurface& other );
  
      /** Type of child elements. */
      typedef OGRSurface ChildType;
  
      /** Return begin of iterator.
       * @since GDAL 2.3
       */
      ChildType** begin() { return reinterpret_cast<ChildType**>(papoGeoms); }
      /** Return end of iterator */
      ChildType** end() { return reinterpret_cast<ChildType**>(papoGeoms + nGeomCount); }
      /** Return begin of iterator.
       * @since GDAL 2.3
       */
      const ChildType* const* begin() const { return reinterpret_cast<const ChildType* const*>(papoGeoms); }
      /** Return end of iterator */
      const ChildType* const* end() const { return reinterpret_cast<const ChildType* const*>(papoGeoms + nGeomCount); }
  
      // Non standard (OGRGeometry).
      virtual const char *getGeometryName() const override;
      virtual OGRwkbGeometryType getGeometryType() const override;
      using OGRGeometry::importFromWkt; /** deprecated */
      OGRErr importFromWkt( const char ** ) override;
  
      virtual OGRErr exportToWkt( char **, OGRwkbVariant=wkbVariantOldOgc )
          const override;
  
      // IMultiSurface methods
      virtual OGRErr PointOnSurface( OGRPoint * poPoint ) const;
  
      // IGeometry methods
      virtual int getDimension() const override;
  
      // Non standard
      virtual OGRBoolean hasCurveGeometry( int bLookForNonLinear = FALSE )
          const override;
  
      /** Return pointer of this in upper class */
      inline OGRGeometryCollection* toUpperClass() { return this; }
      /** Return pointer of this in upper class */
      inline const OGRGeometryCollection* toUpperClass() const { return this; }
  
      virtual void accept(IOGRGeometryVisitor* visitor) override { visitor->visit(this); }
      virtual void accept(IOGRConstGeometryVisitor* visitor) const override { visitor->visit(this); }
  
      static OGRMultiPolygon* CastToMultiPolygon( OGRMultiSurface* poMS );
  };
  
  //! @cond Doxygen_Suppress
  /** @see OGRMultiSurface::begin() const */
  inline const OGRMultiSurface::ChildType* const * begin(const OGRMultiSurface* poGeom) { return poGeom->begin(); }
  /** @see OGRMultiSurface::end() const */
  inline const OGRMultiSurface::ChildType* const * end(const OGRMultiSurface* poGeom) { return poGeom->end(); }
  
  /** @see OGRMultiSurface::begin() */
  inline OGRMultiSurface::ChildType** begin(OGRMultiSurface* poGeom) { return poGeom->begin(); }
  /** @see OGRMultiSurface::end() */
  inline OGRMultiSurface::ChildType** end(OGRMultiSurface* poGeom) { return poGeom->end(); }
  //! @endcond
  
  /************************************************************************/
  /*                           OGRMultiPolygon                            */
  /************************************************************************/
  
  /**
   * A collection of non-overlapping OGRPolygon.
   */
  
  class CPL_DLL OGRMultiPolygon : public OGRMultiSurface
  {
    protected:
      virtual OGRBoolean isCompatibleSubType( OGRwkbGeometryType )
          const override;
      friend class OGRPolyhedralSurface;
      friend class OGRTriangulatedSurface;
  
    private:
  //! @cond Doxygen_Suppress
              OGRErr _addGeometryWithExpectedSubGeometryType(
                  const OGRGeometry * poNewGeom,
                  OGRwkbGeometryType eSubGeometryType );
              OGRErr _addGeometryDirectlyWithExpectedSubGeometryType(
                  OGRGeometry * poNewGeom,
                  OGRwkbGeometryType eSubGeometryType );
  //! @endcond
  
  
    public:
      OGRMultiPolygon();
      OGRMultiPolygon( const OGRMultiPolygon& other );
      ~OGRMultiPolygon() override;
  
      OGRMultiPolygon& operator=(const OGRMultiPolygon& other);
  
      /** Type of child elements. */
      typedef OGRPolygon ChildType;
  
      /** Return begin of iterator.
       * @since GDAL 2.3
       */
      ChildType** begin() { return reinterpret_cast<ChildType**>(papoGeoms); }
      /** Return end of iterator */
      ChildType** end() { return reinterpret_cast<ChildType**>(papoGeoms + nGeomCount); }
      /** Return begin of iterator.
       * @since GDAL 2.3
       */
      const ChildType* const* begin() const { return reinterpret_cast<const ChildType* const*>(papoGeoms); }
      /** Return end of iterator */
      const ChildType* const* end() const { return reinterpret_cast<const ChildType* const*>(papoGeoms + nGeomCount); }
  
      // Non-standard (OGRGeometry).
      virtual const char *getGeometryName() const override;
      virtual OGRwkbGeometryType getGeometryType() const override;
      virtual OGRErr exportToWkt( char **, OGRwkbVariant=wkbVariantOldOgc )
          const override;
  
      // Non standard
      virtual OGRBoolean hasCurveGeometry( int bLookForNonLinear = FALSE )
          const override;
  
          /** Return pointer of this in upper class */
      inline OGRGeometryCollection* toUpperClass() { return this; }
      /** Return pointer of this in upper class */
      inline const OGRGeometryCollection* toUpperClass() const { return this; }
  
      virtual void accept(IOGRGeometryVisitor* visitor) override { visitor->visit(this); }
      virtual void accept(IOGRConstGeometryVisitor* visitor) const override { visitor->visit(this); }
  
      static OGRMultiSurface* CastToMultiSurface( OGRMultiPolygon* poMP );
  };
  
  //! @cond Doxygen_Suppress
  /** @see OGRMultiPolygon::begin() const */
  inline const OGRMultiPolygon::ChildType* const * begin(const OGRMultiPolygon* poGeom) { return poGeom->begin(); }
  /** @see OGRMultiPolygon::end() const */
  inline const OGRMultiPolygon::ChildType* const * end(const OGRMultiPolygon* poGeom) { return poGeom->end(); }
  
  /** @see OGRMultiPolygon::begin() */
  inline OGRMultiPolygon::ChildType** begin(OGRMultiPolygon* poGeom) { return poGeom->begin(); }
  /** @see OGRMultiPolygon::end() */
  inline OGRMultiPolygon::ChildType** end(OGRMultiPolygon* poGeom) { return poGeom->end(); }
  //! @endcond
  
  /************************************************************************/
  /*                         OGRPolyhedralSurface                         */
  /************************************************************************/
  
  /**
   * PolyhedralSurface class.
   *
   * @since GDAL 2.2
   */
  
  class CPL_DLL OGRPolyhedralSurface : public OGRSurface
  {
    protected:
  //! @cond Doxygen_Suppress
      friend class OGRTriangulatedSurface;
      OGRMultiPolygon oMP;
      virtual OGRSurfaceCasterToPolygon      GetCasterToPolygon()
          const override;
      virtual OGRSurfaceCasterToCurvePolygon GetCasterToCurvePolygon()
        const override;
      virtual OGRBoolean         isCompatibleSubType( OGRwkbGeometryType ) const;
      virtual const char*        getSubGeometryName() const;
      virtual OGRwkbGeometryType getSubGeometryType() const;
      OGRErr exportToWktInternal (char ** ppszDstText, OGRwkbVariant eWkbVariant,
                                  const char* pszSkipPrefix ) const;
  
      virtual OGRPolyhedralSurfaceCastToMultiPolygon GetCasterToMultiPolygon()
          const;
      static OGRMultiPolygon* CastToMultiPolygonImpl(OGRPolyhedralSurface* poPS);
  //! @endcond
  
    public:
      OGRPolyhedralSurface();
      OGRPolyhedralSurface( const OGRPolyhedralSurface &poGeom );
      ~OGRPolyhedralSurface() override;
      OGRPolyhedralSurface& operator=(const OGRPolyhedralSurface& other);
  
      /** Type of child elements. */
      typedef OGRPolygon ChildType;
  
      /** Return begin of iterator.
       * @since GDAL 2.3
       */
      ChildType** begin() { return oMP.begin(); }
      /** Return end of iterator */
      ChildType** end() { return oMP.end(); }
      /** Return begin of iterator.
       * @since GDAL 2.3
       */
      const ChildType* const* begin() const { return oMP.begin(); }
      /** Return end of iterator */
      const ChildType* const* end() const { return oMP.end(); }
  
      // IWks Interface.
      virtual int WkbSize() const override;
      virtual const char *getGeometryName() const override;
      virtual OGRwkbGeometryType getGeometryType() const  override;
      virtual OGRErr importFromWkb( const unsigned char *,
                                    int,
                                    OGRwkbVariant,
                                    int& nBytesConsumedOut ) override;
      virtual OGRErr exportToWkb( OGRwkbByteOrder, unsigned char *,
                                  OGRwkbVariant=wkbVariantOldOgc )
          const override;
      using OGRGeometry::importFromWkt; /** deprecated */
      OGRErr importFromWkt( const char ** ) override;
      virtual OGRErr exportToWkt( char ** ppszDstText,
                                  OGRwkbVariant=wkbVariantOldOgc )
          const override;
  
      // IGeometry methods.
      virtual int getDimension() const override;
  
      virtual void empty() override;
  
      virtual OGRGeometry *clone() const override;
      virtual void getEnvelope( OGREnvelope * psEnvelope ) const override;
      virtual void getEnvelope( OGREnvelope3D * psEnvelope ) const override;
  
      virtual void flattenTo2D() override;
      virtual OGRErr transform( OGRCoordinateTransformation* ) override;
      virtual OGRBoolean Equals( const OGRGeometry* ) const override;
      virtual double get_Area() const override;
      virtual OGRErr PointOnSurface( OGRPoint* ) const override;
  
      static OGRMultiPolygon* CastToMultiPolygon( OGRPolyhedralSurface* poPS );
      virtual OGRBoolean hasCurveGeometry( int bLookForNonLinear = FALSE )
          const override;
      virtual OGRErr addGeometry( const OGRGeometry * );
      OGRErr addGeometryDirectly( OGRGeometry *poNewGeom );
      int getNumGeometries() const;
      OGRGeometry* getGeometryRef(int i);
      const OGRGeometry* getGeometryRef(int i) const;
  
      virtual OGRBoolean  IsEmpty() const override;
      virtual void setCoordinateDimension( int nDimension ) override;
      virtual void set3D( OGRBoolean bIs3D ) override;
      virtual void setMeasured( OGRBoolean bIsMeasured ) override;
      virtual void swapXY() override;
      OGRErr removeGeometry( int iIndex, int bDelete = TRUE );
  
      virtual void accept(IOGRGeometryVisitor* visitor) override { visitor->visit(this); }
      virtual void accept(IOGRConstGeometryVisitor* visitor) const override { visitor->visit(this); }
  
      virtual void    assignSpatialReference( OGRSpatialReference * poSR ) override;
  };
  
  //! @cond Doxygen_Suppress
  /** @see OGRPolyhedralSurface::begin() const */
  inline const OGRPolyhedralSurface::ChildType* const * begin(const OGRPolyhedralSurface* poGeom) { return poGeom->begin(); }
  /** @see OGRPolyhedralSurface::end() const */
  inline const OGRPolyhedralSurface::ChildType* const * end(const OGRPolyhedralSurface* poGeom) { return poGeom->end(); }
  
  /** @see OGRPolyhedralSurface::begin() */
  inline OGRPolyhedralSurface::ChildType** begin(OGRPolyhedralSurface* poGeom) { return poGeom->begin(); }
  /** @see OGRPolyhedralSurface::end() */
  inline OGRPolyhedralSurface::ChildType** end(OGRPolyhedralSurface* poGeom) { return poGeom->end(); }
  //! @endcond
  
  /************************************************************************/
  /*                        OGRTriangulatedSurface                        */
  /************************************************************************/
  
  /**
   * TriangulatedSurface class.
   *
   * @since GDAL 2.2
   */
  
  class CPL_DLL OGRTriangulatedSurface : public OGRPolyhedralSurface
  {
    protected:
  //! @cond Doxygen_Suppress
      virtual OGRBoolean         isCompatibleSubType( OGRwkbGeometryType )
          const override;
      virtual const char*        getSubGeometryName() const override;
      virtual OGRwkbGeometryType getSubGeometryType() const override;
  
      virtual OGRPolyhedralSurfaceCastToMultiPolygon GetCasterToMultiPolygon()
          const override;
      static OGRMultiPolygon *
          CastToMultiPolygonImpl( OGRPolyhedralSurface* poPS );
  //! @endcond
  
    public:
      OGRTriangulatedSurface();
      OGRTriangulatedSurface( const OGRTriangulatedSurface &other );
      ~OGRTriangulatedSurface();
  
      /** Type of child elements. */
      typedef OGRTriangle ChildType;
  
      /** Return begin of iterator.
       * @since GDAL 2.3
       */
      ChildType** begin() { return reinterpret_cast<ChildType**>(oMP.begin()); }
      /** Return end of iterator */
      ChildType** end() { return reinterpret_cast<ChildType**>(oMP.end()); }
      /** Return begin of iterator.
       * @since GDAL 2.3
       */
      const ChildType* const* begin() const { return reinterpret_cast<const ChildType* const*>(oMP.begin()); }
      /** Return end of iterator */
      const ChildType* const* end() const { return reinterpret_cast<const ChildType* const*>(oMP.end()); }
  
      OGRTriangulatedSurface& operator=( const OGRTriangulatedSurface& other );
      virtual const char *getGeometryName() const override;
      virtual OGRwkbGeometryType getGeometryType() const override;
  
      // IWks Interface.
      virtual OGRErr addGeometry( const OGRGeometry * ) override;
  
      /** Return pointer of this in upper class */
      inline OGRPolyhedralSurface* toUpperClass() { return this; }
      /** Return pointer of this in upper class */
      inline const OGRPolyhedralSurface* toUpperClass() const { return this; }
  
      virtual void accept(IOGRGeometryVisitor* visitor) override { visitor->visit(this); }
      virtual void accept(IOGRConstGeometryVisitor* visitor) const override { visitor->visit(this); }
  
      static OGRPolyhedralSurface *
          CastToPolyhedralSurface( OGRTriangulatedSurface* poTS );
  };
  
  //! @cond Doxygen_Suppress
  /** @see OGRTriangulatedSurface::begin() const */
  inline const OGRTriangulatedSurface::ChildType* const * begin(const OGRTriangulatedSurface* poGeom) { return poGeom->begin(); }
  /** @see OGRTriangulatedSurface::end() const */
  inline const OGRTriangulatedSurface::ChildType* const * end(const OGRTriangulatedSurface* poGeom) { return poGeom->end(); }
  
  /** @see OGRTriangulatedSurface::begin() */
  inline OGRTriangulatedSurface::ChildType** begin(OGRTriangulatedSurface* poGeom) { return poGeom->begin(); }
  /** @see OGRTriangulatedSurface::end() */
  inline OGRTriangulatedSurface::ChildType** end(OGRTriangulatedSurface* poGeom) { return poGeom->end(); }
  //! @endcond
  
  /************************************************************************/
  /*                            OGRMultiPoint                             */
  /************************************************************************/
  
  /**
   * A collection of OGRPoint.
   */
  
  class CPL_DLL OGRMultiPoint : public OGRGeometryCollection
  {
    private:
      OGRErr  importFromWkt_Bracketed( const char **, int bHasM, int bHasZ );
  
    protected:
      virtual OGRBoolean  isCompatibleSubType( OGRwkbGeometryType )
          const override;
  
    public:
      OGRMultiPoint();
      OGRMultiPoint(const OGRMultiPoint& other);
      ~OGRMultiPoint() override;
  
      OGRMultiPoint& operator=(const OGRMultiPoint& other);
  
      /** Type of child elements. */
      typedef OGRPoint ChildType;
  
      /** Return begin of iterator.
       * @since GDAL 2.3
       */
      ChildType** begin() { return reinterpret_cast<ChildType**>(papoGeoms); }
      /** Return end of iterator */
      ChildType** end() { return reinterpret_cast<ChildType**>(papoGeoms + nGeomCount); }
      /** Return begin of iterator.
       * @since GDAL 2.3
       */
      const ChildType* const* begin() const { return reinterpret_cast<const ChildType* const*>(papoGeoms); }
      /** Return end of iterator */
      const ChildType* const* end() const { return reinterpret_cast<const ChildType* const*>(papoGeoms + nGeomCount); }
  
      // Non-standard (OGRGeometry).
      virtual const char *getGeometryName() const override;
      virtual OGRwkbGeometryType getGeometryType() const override;
      using OGRGeometry::importFromWkt; /** deprecated */
      OGRErr importFromWkt( const char ** ) override;
      virtual OGRErr exportToWkt( char **, OGRwkbVariant=wkbVariantOldOgc )
          const override;
  
      // IGeometry methods.
      virtual int getDimension() const override;
  
      /** Return pointer of this in upper class */
      inline OGRGeometryCollection* toUpperClass() { return this; }
      /** Return pointer of this in upper class */
      inline const OGRGeometryCollection* toUpperClass() const { return this; }
  
      virtual void accept(IOGRGeometryVisitor* visitor) override { visitor->visit(this); }
      virtual void accept(IOGRConstGeometryVisitor* visitor) const override { visitor->visit(this); }
  
      // Non-standard.
      virtual OGRBoolean hasCurveGeometry( int bLookForNonLinear = FALSE )
          const override;
  };
  
  //! @cond Doxygen_Suppress
  /** @see OGRMultiPoint::begin() const */
  inline const OGRMultiPoint::ChildType* const * begin(const OGRMultiPoint* poGeom) { return poGeom->begin(); }
  /** @see OGRMultiPoint::end() const */
  inline const OGRMultiPoint::ChildType* const * end(const OGRMultiPoint* poGeom) { return poGeom->end(); }
  
  /** @see OGRMultiPoint::begin() */
  inline OGRMultiPoint::ChildType** begin(OGRMultiPoint* poGeom) { return poGeom->begin(); }
  /** @see OGRMultiPoint::end() */
  inline OGRMultiPoint::ChildType** end(OGRMultiPoint* poGeom) { return poGeom->end(); }
  //! @endcond
  
  /************************************************************************/
  /*                          OGRMultiCurve                               */
  /************************************************************************/
  
  /**
   * A collection of OGRCurve.
   *
   * @since GDAL 2.0
   */
  
  class CPL_DLL OGRMultiCurve : public OGRGeometryCollection
  {
    protected:
  //! @cond Doxygen_Suppress
      static OGRErr addCurveDirectlyFromWkt( OGRGeometry* poSelf,
                                             OGRCurve* poCurve );
  //! @endcond
      virtual OGRBoolean isCompatibleSubType( OGRwkbGeometryType )
          const override;
  
    public:
      OGRMultiCurve();
      OGRMultiCurve( const OGRMultiCurve& other );
      ~OGRMultiCurve() override;
  
      OGRMultiCurve& operator=( const OGRMultiCurve& other );
  
      /** Type of child elements. */
      typedef OGRCurve ChildType;
  
      /** Return begin of iterator.
       * @since GDAL 2.3
       */
      ChildType** begin() { return reinterpret_cast<ChildType**>(papoGeoms); }
      /** Return end of iterator */
      ChildType** end() { return reinterpret_cast<ChildType**>(papoGeoms + nGeomCount); }
      /** Return begin of iterator.
       * @since GDAL 2.3
       */
      const ChildType* const* begin() const { return reinterpret_cast<const ChildType* const*>(papoGeoms); }
      /** Return end of iterator */
      const ChildType* const* end() const { return reinterpret_cast<const ChildType* const*>(papoGeoms + nGeomCount); }
  
      // Non standard (OGRGeometry).
      virtual const char *getGeometryName() const override;
      virtual OGRwkbGeometryType getGeometryType() const override;
      using OGRGeometry::importFromWkt; /** deprecated */
      OGRErr importFromWkt( const char ** ) override;
      virtual OGRErr exportToWkt( char **, OGRwkbVariant=wkbVariantOldOgc )
          const override;
  
      // IGeometry methods.
      virtual int getDimension() const override;
  
      // Non-standard.
      virtual OGRBoolean hasCurveGeometry( int bLookForNonLinear = FALSE )
          const override;
  
      /** Return pointer of this in upper class */
      inline OGRGeometryCollection* toUpperClass() { return this; }
      /** Return pointer of this in upper class */
      inline const OGRGeometryCollection* toUpperClass() const { return this; }
  
      virtual void accept(IOGRGeometryVisitor* visitor) override { visitor->visit(this); }
      virtual void accept(IOGRConstGeometryVisitor* visitor) const override { visitor->visit(this); }
  
      static OGRMultiLineString* CastToMultiLineString(OGRMultiCurve* poMC);
  };
  
  //! @cond Doxygen_Suppress
  /** @see OGRMultiCurve::begin() const */
  inline const OGRMultiCurve::ChildType* const * begin(const OGRMultiCurve* poGeom) { return poGeom->begin(); }
  /** @see OGRMultiCurve::end() const */
  inline const OGRMultiCurve::ChildType* const * end(const OGRMultiCurve* poGeom) { return poGeom->end(); }
  
  /** @see OGRMultiCurve::begin() */
  inline OGRMultiCurve::ChildType** begin(OGRMultiCurve* poGeom) { return poGeom->begin(); }
  /** @see OGRMultiCurve::end() */
  inline OGRMultiCurve::ChildType** end(OGRMultiCurve* poGeom) { return poGeom->end(); }
  //! @endcond
  
  /************************************************************************/
  /*                          OGRMultiLineString                          */
  /************************************************************************/
  
  /**
   * A collection of OGRLineString.
   */
  
  class CPL_DLL OGRMultiLineString : public OGRMultiCurve
  {
    protected:
      virtual OGRBoolean  isCompatibleSubType( OGRwkbGeometryType )
          const override;
  
    public:
      OGRMultiLineString();
      OGRMultiLineString( const OGRMultiLineString& other );
      ~OGRMultiLineString() override;
  
      OGRMultiLineString& operator=( const OGRMultiLineString& other );
  
      /** Type of child elements. */
      typedef OGRLineString ChildType;
  
      /** Return begin of iterator.
       * @since GDAL 2.3
       */
      ChildType** begin() { return reinterpret_cast<ChildType**>(papoGeoms); }
      /** Return end of iterator */
      ChildType** end() { return reinterpret_cast<ChildType**>(papoGeoms + nGeomCount); }
      /** Return begin of iterator.
       * @since GDAL 2.3
       */
      const ChildType* const* begin() const { return reinterpret_cast<const ChildType* const*>(papoGeoms); }
      /** Return end of iterator */
      const ChildType* const* end() const { return reinterpret_cast<const ChildType* const*>(papoGeoms + nGeomCount); }
  
      // Non standard (OGRGeometry).
      virtual const char *getGeometryName() const override;
      virtual OGRwkbGeometryType getGeometryType() const override;
      virtual OGRErr exportToWkt( char **, OGRwkbVariant=wkbVariantOldOgc )
          const override;
  
      // Non standard
      virtual OGRBoolean hasCurveGeometry( int bLookForNonLinear = FALSE )
          const override;
  
      /** Return pointer of this in upper class */
      inline OGRGeometryCollection* toUpperClass() { return this; }
      /** Return pointer of this in upper class */
      inline const OGRGeometryCollection* toUpperClass() const { return this; }
  
      virtual void accept(IOGRGeometryVisitor* visitor) override { visitor->visit(this); }
      virtual void accept(IOGRConstGeometryVisitor* visitor) const override { visitor->visit(this); }
  
      static OGRMultiCurve* CastToMultiCurve( OGRMultiLineString* poMLS );
  };
  
  //! @cond Doxygen_Suppress
  /** @see OGRMultiLineString::begin() const */
  inline const OGRMultiLineString::ChildType* const * begin(const OGRMultiLineString* poGeom) { return poGeom->begin(); }
  /** @see OGRMultiLineString::end() const */
  inline const OGRMultiLineString::ChildType* const * end(const OGRMultiLineString* poGeom) { return poGeom->end(); }
  
  /** @see OGRMultiLineString::begin() */
  inline OGRMultiLineString::ChildType** begin(OGRMultiLineString* poGeom) { return poGeom->begin(); }
  /** @see OGRMultiLineString::end() */
  inline OGRMultiLineString::ChildType** end(OGRMultiLineString* poGeom) { return poGeom->end(); }
  //! @endcond
  
  /************************************************************************/
  /*                          OGRGeometryFactory                          */
  /************************************************************************/
  
  /**
   * Create geometry objects from well known text/binary.
   */
  
  class CPL_DLL OGRGeometryFactory
  {
      static OGRErr createFromFgfInternal( const unsigned char *pabyData,
                                           OGRSpatialReference * poSR,
                                           OGRGeometry **ppoReturn,
                                           int nBytes,
                                           int *pnBytesConsumed,
                                           int nRecLevel );
    public:
      static OGRErr createFromWkb( const void *, OGRSpatialReference *,
                                   OGRGeometry **, int = -1,
                                   OGRwkbVariant=wkbVariantOldOgc );
      static OGRErr createFromWkb( const void * pabyData,
                                   OGRSpatialReference *,
                                   OGRGeometry **,
                                   int nSize,
                                   OGRwkbVariant eVariant,
                                   int& nBytesConsumedOut );
      static OGRErr createFromWkt( const char* , OGRSpatialReference *,
                                   OGRGeometry ** );
      static OGRErr createFromWkt( const char **, OGRSpatialReference *,
                                   OGRGeometry ** );
      /** Deprecated.
       * @deprecated in GDAL 2.3
       */
      static OGRErr createFromWkt( char ** ppszInput, OGRSpatialReference * poSRS,
                                   OGRGeometry ** ppoGeom )
                                  CPL_WARN_DEPRECATED("Use createFromWkt(const char**, ...) instead")
      {
          return createFromWkt( const_cast<const char**>(ppszInput), poSRS, ppoGeom);
      }
  
      static OGRErr createFromFgf( const void*, OGRSpatialReference *,
                                   OGRGeometry **, int = -1, int * = nullptr );
      static OGRGeometry *createFromGML( const char * );
      static OGRGeometry *createFromGEOS( GEOSContextHandle_t hGEOSCtxt,
                                          GEOSGeom );
      static OGRGeometry *createFromGeoJson( const char *);
      static OGRGeometry *createFromGeoJson( const CPLJSONObject &oJSONObject );
  
      static void   destroyGeometry( OGRGeometry * );
      static OGRGeometry *createGeometry( OGRwkbGeometryType );
  
      static OGRGeometry * forceToPolygon( OGRGeometry * );
      static OGRGeometry * forceToLineString( OGRGeometry *,
                                              bool bOnlyInOrder = true );
      static OGRGeometry * forceToMultiPolygon( OGRGeometry * );
      static OGRGeometry * forceToMultiPoint( OGRGeometry * );
      static OGRGeometry * forceToMultiLineString( OGRGeometry * );
  
      static OGRGeometry * forceTo( OGRGeometry* poGeom,
                                    OGRwkbGeometryType eTargetType,
                                    const char*const* papszOptions = nullptr );
  
      static OGRGeometry * organizePolygons( OGRGeometry **papoPolygons,
                                             int nPolygonCount,
                                             int *pbResultValidGeometry,
                                             const char **papszOptions = nullptr);
      static bool haveGEOS();
  
      static OGRGeometry* transformWithOptions( const OGRGeometry* poSrcGeom,
                                                OGRCoordinateTransformation *poCT,
                                                char** papszOptions );
  
      static OGRGeometry*
          approximateArcAngles( double dfX, double dfY, double dfZ,
                                double dfPrimaryRadius, double dfSecondaryAxis,
                                double dfRotation,
                                double dfStartAngle, double dfEndAngle,
                                double dfMaxAngleStepSizeDegrees );
  
      static int GetCurveParmeters( double x0, double y0,
                                    double x1, double y1,
                                    double x2, double y2,
                                    double& R, double& cx, double& cy,
                                    double& alpha0, double& alpha1,
                                    double& alpha2 );
      static OGRLineString* curveToLineString(
          double x0, double y0, double z0,
          double x1, double y1, double z1,
          double x2, double y2, double z2,
          int bHasZ,
          double dfMaxAngleStepSizeDegrees,
          const char* const * papszOptions = nullptr );
      static OGRCurve* curveFromLineString(
          const OGRLineString* poLS,
          const char* const * papszOptions = nullptr);
  };
  
  OGRwkbGeometryType CPL_DLL OGRFromOGCGeomType( const char *pszGeomType );
  const char CPL_DLL * OGRToOGCGeomType( OGRwkbGeometryType eGeomType );
  
  /** Prepared geometry API (needs GEOS >= 3.1.0) */
  typedef struct _OGRPreparedGeometry OGRPreparedGeometry;
  int OGRHasPreparedGeometrySupport();
  OGRPreparedGeometry* OGRCreatePreparedGeometry( const OGRGeometry* poGeom );
  void OGRDestroyPreparedGeometry( OGRPreparedGeometry* poPreparedGeom );
  int OGRPreparedGeometryIntersects( const OGRPreparedGeometry* poPreparedGeom,
                                     const OGRGeometry* poOtherGeom );
  int OGRPreparedGeometryContains( const OGRPreparedGeometry* poPreparedGeom,
                                   const OGRGeometry* poOtherGeom );
  
  //! @cond Doxygen_Suppress
  struct CPL_DLL OGRPreparedGeometryUniquePtrDeleter
  {
      void operator()(OGRPreparedGeometry*) const;
  };
  //! @endcond
  
  /** Unique pointer type for OGRPreparedGeometry.
   * @since GDAL 2.3
   */
  typedef std::unique_ptr<OGRPreparedGeometry, OGRPreparedGeometryUniquePtrDeleter> OGRPreparedGeometryUniquePtr;
  
  #endif /* ndef OGR_GEOMETRY_H_INCLUDED */
  