LCOV - code coverage report
Current view: top level - ogr/ogrsf_frmts/pmtiles - ogr_pmtiles.h (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 26 26 100.0 %
Date: 2025-02-18 14:19:29 Functions: 13 13 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  OpenGIS Simple Features Reference Implementation
       4             :  * Purpose:  Implementation of PMTiles
       5             :  * Author:   Even Rouault <even.rouault at spatialys.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2023, Planet Labs
       9             :  *
      10             :  * SPDX-License-Identifier: MIT
      11             :  ****************************************************************************/
      12             : 
      13             : #ifndef OGR_PMTILES_H_INCLUDED
      14             : #define OGR_PMTILES_H_INCLUDED
      15             : 
      16             : #include "gdal_priv.h"
      17             : #include "ogrsf_frmts.h"
      18             : 
      19             : #include "cpl_compressor.h"
      20             : #include "cpl_vsi_virtual.h"
      21             : 
      22             : #include "include_pmtiles.h"
      23             : 
      24             : #include <limits>
      25             : #include <set>
      26             : #include <stack>
      27             : 
      28             : // #define DEBUG_PMTILES
      29             : 
      30             : #define SPHERICAL_RADIUS 6378137.0
      31             : #define MAX_GM (SPHERICAL_RADIUS * M_PI)  // 20037508.342789244
      32             : 
      33             : #if defined(HAVE_SQLITE) && defined(HAVE_GEOS)
      34             : // Needed by mvtutils.h
      35             : #define HAVE_MVT_WRITE_SUPPORT
      36             : #endif
      37             : 
      38             : /************************************************************************/
      39             : /*                          OGRPMTilesDataset                           */
      40             : /************************************************************************/
      41             : 
      42             : class OGRPMTilesDataset final : public GDALDataset
      43             : {
      44             :   public:
      45          96 :     OGRPMTilesDataset() = default;
      46             : 
      47             :     ~OGRPMTilesDataset() override;
      48             : 
      49             :     bool Open(GDALOpenInfo *poOpenInfo);
      50             : 
      51         230 :     int GetLayerCount() override
      52             :     {
      53         230 :         return static_cast<int>(m_apoLayers.size());
      54             :     }
      55             : 
      56             :     OGRLayer *GetLayer(int) override;
      57             : 
      58           3 :     inline int GetMinZoomLevel() const
      59             :     {
      60           3 :         return m_nMinZoomLevel;
      61             :     }
      62             : 
      63           8 :     inline int GetMaxZoomLevel() const
      64             :     {
      65           8 :         return m_nMaxZoomLevel;
      66             :     }
      67             : 
      68        1141 :     inline const pmtiles::headerv3 &GetHeader() const
      69             :     {
      70        1141 :         return m_sHeader;
      71             :     }
      72             : 
      73             :     static const char *GetCompression(uint8_t nVal);
      74             : 
      75             :     static const char *GetTileType(const pmtiles::headerv3 &sHeader);
      76             : 
      77           6 :     inline const std::string &GetMetadataContent() const
      78             :     {
      79           6 :         return m_osMetadata;
      80             :     }
      81             : 
      82         673 :     inline const std::string &GetMetadataFilename() const
      83             :     {
      84         673 :         return m_osMetadataFilename;
      85             :     }
      86             : 
      87         667 :     inline const std::string &GetClipOpenOption() const
      88             :     {
      89         667 :         return m_osClipOpenOption;
      90             :     }
      91             : 
      92             :     /** Return a short-lived decompressed buffer for metadata or directory
      93             :      * entries or nullptr in case of error.
      94             :      */
      95             :     const std::string *ReadInternal(uint64_t nOffset, uint64_t nSize,
      96             :                                     const char *pszDataType);
      97             : 
      98             :     /** Return a short-lived decompressed buffer for tile data.
      99             :      *  or nullptr in case of error.
     100             :      */
     101             :     const std::string *ReadTileData(uint64_t nOffset, uint64_t nSize);
     102             : 
     103             :   private:
     104             :     VSIVirtualHandleUniquePtr m_poFile{};
     105             : 
     106             :     //! PMTiles header
     107             :     pmtiles::headerv3 m_sHeader{};
     108             : 
     109             :     //! JSON serialized metadata
     110             :     std::string m_osMetadata{};
     111             : 
     112             :     //! /vsimem/ filename with the m_osMetadata content
     113             :     std::string m_osMetadataFilename{};
     114             : 
     115             :     //! Value of the CLIP open option
     116             :     std::string m_osClipOpenOption{};
     117             : 
     118             :     //! Decompressor for metadata and directories
     119             :     const CPLCompressor *m_psInternalDecompressor = nullptr;
     120             : 
     121             :     //! Decompressor for tile
     122             :     const CPLCompressor *m_psTileDataDecompressor = nullptr;
     123             : 
     124             :     //! Last raw data read by Read()
     125             :     std::string m_osBuffer{};
     126             : 
     127             :     //! Last uncompressed data read by Read(). Only used if compression
     128             :     std::string m_osDecompressedBuffer{};
     129             : 
     130             :     std::vector<std::unique_ptr<OGRLayer>> m_apoLayers{};
     131             : 
     132             :     //! Minimum zoom level got from header
     133             :     int m_nMinZoomLevel = 0;
     134             : 
     135             :     //! Maximum zoom level got from header
     136             :     int m_nMaxZoomLevel = 0;
     137             : 
     138             :     /** Return a short-lived decompressed buffer, or nullptr in case of error
     139             :      */
     140             :     const std::string *Read(const CPLCompressor *psDecompressor,
     141             :                             uint64_t nOffset, uint64_t nSize,
     142             :                             const char *pszDataType);
     143             : 
     144             :     CPL_DISALLOW_COPY_ASSIGN(OGRPMTilesDataset)
     145             : };
     146             : 
     147             : /************************************************************************/
     148             : /*                        OGRPMTilesTileIterator                        */
     149             : /************************************************************************/
     150             : 
     151             : //! Iterator to browse through tiles
     152             : class OGRPMTilesTileIterator
     153             : {
     154             :   public:
     155             :     //! Constructor to iterate over all tiles (possibly limited to a zoom level
     156          15 :     explicit OGRPMTilesTileIterator(OGRPMTilesDataset *poDS,
     157             :                                     int nZoomLevel = -1)
     158          15 :         : m_poDS(poDS), m_nZoomLevel(nZoomLevel)
     159             :     {
     160          15 :     }
     161             : 
     162             :     //! Constructor with a window of interest in tile coordinates
     163         237 :     OGRPMTilesTileIterator(OGRPMTilesDataset *poDS, int nZoomLevel, int nMinX,
     164             :                            int nMinY, int nMaxX, int nMaxY)
     165         237 :         : m_poDS(poDS), m_nZoomLevel(nZoomLevel), m_nMinX(nMinX),
     166         237 :           m_nMinY(nMinY), m_nMaxX(nMaxX), m_nMaxY(nMaxY)
     167             :     {
     168         237 :     }
     169             : 
     170             :     /** Return the (z, x, y, offset, length) of the next tile.
     171             :      *
     172             :      * If entry_zxy.offset == 0, the iteration has stopped.
     173             :      */
     174             :     pmtiles::entry_zxy GetNextTile(uint32_t *pnRunLength = nullptr);
     175             : 
     176             :     void SkipRunLength();
     177             : 
     178             : #ifdef DEBUG_PMTILES
     179             :     void DumpTiles();
     180             : #endif
     181             : 
     182             :   private:
     183             :     // Input parameters
     184             :     OGRPMTilesDataset *m_poDS = nullptr;
     185             :     int m_nZoomLevel = -1;
     186             :     int m_nMinX = -1;
     187             :     int m_nMinY = -1;
     188             :     int m_nMaxX = -1;
     189             :     int m_nMaxY = -1;
     190             : 
     191             :     // Used when iterating over tile id is inefficient
     192             :     int m_nCurX = -1;
     193             :     int m_nCurY = -1;
     194             : 
     195             :     // for sanity checks. Must be increasing when walking through entries
     196             :     static constexpr uint64_t INVALID_LAST_TILE_ID =
     197             :         std::numeric_limits<uint64_t>::max();
     198             :     uint64_t m_nLastTileId = INVALID_LAST_TILE_ID;
     199             : 
     200             :     // Computed values from zoom leven and min/max x/y
     201             :     uint64_t m_nMinTileId = std::numeric_limits<uint64_t>::max();
     202             :     uint64_t m_nMaxTileId = 0;
     203             : 
     204             :     bool m_bEOF = false;
     205             : 
     206             :     // State of exploration of a directory
     207             :     struct DirectoryContext
     208             :     {
     209             :         // Entries, either tiles (sEntry.run_length > 0) or subdiretories
     210             :         // (sEntry.run_length == 0)
     211             :         std::vector<pmtiles::entryv3> sEntries{};
     212             : 
     213             :         // Next index of sEntries[] to explore
     214             :         uint32_t nIdxInEntries = 0;
     215             : 
     216             :         // For tiles, value between 0 and
     217             :         // sEntries[nIdxInEntries].run_length - 1
     218             :         uint32_t nIdxInRunLength = 0;
     219             :     };
     220             : 
     221             :     // Stack of directories: bottom is root directory, and then we
     222             :     // push subdiretories we browse throw
     223             :     std::stack<DirectoryContext> m_aoStack{};
     224             : 
     225             :     bool LoadRootDirectory();
     226             : 
     227             :     CPL_DISALLOW_COPY_ASSIGN(OGRPMTilesTileIterator)
     228             : };
     229             : 
     230             : /************************************************************************/
     231             : /*                        OGRPMTilesVectorLayer                         */
     232             : /************************************************************************/
     233             : 
     234             : class OGRPMTilesVectorLayer final
     235             :     : public OGRLayer,
     236             :       public OGRGetNextFeatureThroughRaw<OGRPMTilesVectorLayer>
     237             : {
     238             :   public:
     239             :     OGRPMTilesVectorLayer(OGRPMTilesDataset *poDS, const char *pszLayerName,
     240             :                           const CPLJSONObject &oFields,
     241             :                           const CPLJSONArray &oAttributesFromTileStats,
     242             :                           bool bJsonField, double dfMinX, double dfMinY,
     243             :                           double dfMaxX, double dfMaxY,
     244             :                           OGRwkbGeometryType eGeomType, int nZoomLevel,
     245             :                           bool bZoomLevelFromSpatialFilter);
     246             :     ~OGRPMTilesVectorLayer();
     247             : 
     248             :     void ResetReading() override;
     249             : 
     250             :     OGRFeature *GetNextRawFeature();
     251        1330 :     DEFINE_GET_NEXT_FEATURE_THROUGH_RAW(OGRPMTilesVectorLayer)
     252             : 
     253        6608 :     OGRFeatureDefn *GetLayerDefn() override
     254             :     {
     255        6608 :         return m_poFeatureDefn;
     256             :     }
     257             : 
     258             :     int TestCapability(const char *) override;
     259             : 
     260             :     OGRErr IGetExtent(int iGeomField, OGREnvelope *psExtent,
     261             :                       bool bForce) override;
     262             : 
     263             :     OGRErr ISetSpatialFilter(int iGeomField,
     264             :                              const OGRGeometry *poGeom) override;
     265             : 
     266             :     GIntBig GetFeatureCount(int bForce) override;
     267             : 
     268             :     OGRFeature *GetFeature(GIntBig nFID) override;
     269             : 
     270             :     static OGRwkbGeometryType GuessGeometryType(OGRPMTilesDataset *poDS,
     271             :                                                 const char *pszLayerName,
     272             :                                                 int nZoomLevel);
     273             : 
     274             :   private:
     275             :     OGRPMTilesDataset *m_poDS = nullptr;
     276             :     OGRFeatureDefn *m_poFeatureDefn = nullptr;
     277             : 
     278             :     //! Iterator over tiles
     279             :     std::unique_ptr<OGRPMTilesTileIterator> m_poTileIterator{};
     280             : 
     281             :     //! Total feature count (may over-estimate due to not applying clipping)
     282             :     GIntBig m_nFeatureCount = -1;
     283             : 
     284             :     //! X tile value of currently opened tile
     285             :     uint32_t m_nX = 0;
     286             : 
     287             :     //! Y tile value of currently opened tile
     288             :     uint32_t m_nY = 0;
     289             : 
     290             :     //! Offset of the currently opened tile
     291             :     uint64_t m_nLastTileOffset = 0;
     292             : 
     293             :     //! Uncompressed MVT tile
     294             :     std::string m_osTileData{};
     295             : 
     296             :     //! In-memory MVT dataset of the currently opened tile
     297             :     std::unique_ptr<GDALDataset> m_poTileDS{};
     298             : 
     299             :     //! Layer of m_poTileDS
     300             :     OGRLayer *m_poTileLayer = nullptr;
     301             : 
     302             :     //! Layer extent
     303             :     OGREnvelope m_sExtent{};
     304             : 
     305             :     //! Minimum X tile value corresponding to m_sFilterEnvelope
     306             :     int m_nFilterMinX = 0;
     307             : 
     308             :     //! Minimum Y tile value corresponding to m_sFilterEnvelope
     309             :     int m_nFilterMinY = 0;
     310             : 
     311             :     //! Maximum X tile value corresponding to m_sFilterEnvelope
     312             :     int m_nFilterMaxX = 0;
     313             : 
     314             :     //! Maximum Y tile value corresponding to m_sFilterEnvelope
     315             :     int m_nFilterMaxY = 0;
     316             : 
     317             :     //! Currently used zoom level
     318             :     int m_nZoomLevel = 0;
     319             : 
     320             :     //! Whether we should auto-adapt m_nZoomLevel from the spatial filter extent
     321             :     bool m_bZoomLevelAuto = false;
     322             : 
     323             :     //! Whether we should expose the tile fields in a "json" field
     324             :     bool m_bJsonField = false;
     325             : 
     326             :     std::unique_ptr<OGRFeature> GetNextSrcFeature();
     327             :     std::unique_ptr<OGRFeature> CreateFeatureFrom(OGRFeature *poSrcFeature);
     328             :     GIntBig GetTotalFeatureCount() const;
     329             :     void ExtentToTileExtent(const OGREnvelope &sEnvelope, int &nTileMinX,
     330             :                             int &nTileMinY, int &nTileMaxX,
     331             :                             int &nTileMaxY) const;
     332             : 
     333             :     CPL_DISALLOW_COPY_ASSIGN(OGRPMTilesVectorLayer)
     334             : };
     335             : 
     336             : #ifdef HAVE_MVT_WRITE_SUPPORT
     337             : 
     338             : /************************************************************************/
     339             : /*                     OGRPMTilesWriterDataset                          */
     340             : /************************************************************************/
     341             : 
     342             : class OGRPMTilesWriterDataset final : public GDALDataset
     343             : {
     344             :     std::unique_ptr<GDALDataset> m_poMBTilesWriterDataset{};
     345             : 
     346             :   public:
     347          34 :     OGRPMTilesWriterDataset() = default;
     348             : 
     349             :     ~OGRPMTilesWriterDataset() override;
     350             : 
     351             :     bool Create(const char *pszFilename, CSLConstList papszOptions);
     352             : 
     353             :     CPLErr Close() override;
     354             : 
     355             :     OGRLayer *ICreateLayer(const char *pszName,
     356             :                            const OGRGeomFieldDefn *poGeomFieldDefn,
     357             :                            CSLConstList papszOptions) override;
     358             : 
     359             :     int TestCapability(const char *) override;
     360             : };
     361             : 
     362             : #endif  // HAVE_MVT_WRITE_SUPPORT
     363             : 
     364             : #endif  // OGR_PMTILES_H_INCLUDED

Generated by: LCOV version 1.14