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: 31 31 100.0 %
Date: 2024-11-21 22:18:42 Functions: 15 15 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        6586 :     OGRFeatureDefn *GetLayerDefn() override
     254             :     {
     255        6586 :         return m_poFeatureDefn;
     256             :     }
     257             : 
     258             :     int TestCapability(const char *) override;
     259             : 
     260             :     OGRErr GetExtent(OGREnvelope *psExtent, int bForce) override;
     261             : 
     262          23 :     OGRErr GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce) override
     263             :     {
     264          23 :         return OGRLayer::GetExtent(iGeomField, psExtent, bForce);
     265             :     }
     266             : 
     267             :     void SetSpatialFilter(OGRGeometry *) override;
     268             : 
     269          52 :     void SetSpatialFilter(int iGeomField, OGRGeometry *poGeom) override
     270             :     {
     271          52 :         OGRLayer::SetSpatialFilter(iGeomField, poGeom);
     272          52 :     }
     273             : 
     274             :     GIntBig GetFeatureCount(int bForce) override;
     275             : 
     276             :     OGRFeature *GetFeature(GIntBig nFID) override;
     277             : 
     278             :     static OGRwkbGeometryType GuessGeometryType(OGRPMTilesDataset *poDS,
     279             :                                                 const char *pszLayerName,
     280             :                                                 int nZoomLevel);
     281             : 
     282             :   private:
     283             :     OGRPMTilesDataset *m_poDS = nullptr;
     284             :     OGRFeatureDefn *m_poFeatureDefn = nullptr;
     285             : 
     286             :     //! Iterator over tiles
     287             :     std::unique_ptr<OGRPMTilesTileIterator> m_poTileIterator{};
     288             : 
     289             :     //! Total feature count (may over-estimate due to not applying clipping)
     290             :     GIntBig m_nFeatureCount = -1;
     291             : 
     292             :     //! X tile value of currently opened tile
     293             :     uint32_t m_nX = 0;
     294             : 
     295             :     //! Y tile value of currently opened tile
     296             :     uint32_t m_nY = 0;
     297             : 
     298             :     //! Offset of the currently opened tile
     299             :     uint64_t m_nLastTileOffset = 0;
     300             : 
     301             :     //! Uncompressed MVT tile
     302             :     std::string m_osTileData{};
     303             : 
     304             :     //! In-memory MVT dataset of the currently opened tile
     305             :     std::unique_ptr<GDALDataset> m_poTileDS{};
     306             : 
     307             :     //! Layer of m_poTileDS
     308             :     OGRLayer *m_poTileLayer = nullptr;
     309             : 
     310             :     //! Layer extent
     311             :     OGREnvelope m_sExtent{};
     312             : 
     313             :     //! Minimum X tile value corresponding to m_sFilterEnvelope
     314             :     int m_nFilterMinX = 0;
     315             : 
     316             :     //! Minimum Y tile value corresponding to m_sFilterEnvelope
     317             :     int m_nFilterMinY = 0;
     318             : 
     319             :     //! Maximum X tile value corresponding to m_sFilterEnvelope
     320             :     int m_nFilterMaxX = 0;
     321             : 
     322             :     //! Maximum Y tile value corresponding to m_sFilterEnvelope
     323             :     int m_nFilterMaxY = 0;
     324             : 
     325             :     //! Currently used zoom level
     326             :     int m_nZoomLevel = 0;
     327             : 
     328             :     //! Whether we should auto-adapt m_nZoomLevel from the spatial filter extent
     329             :     bool m_bZoomLevelAuto = false;
     330             : 
     331             :     //! Whether we should expose the tile fields in a "json" field
     332             :     bool m_bJsonField = false;
     333             : 
     334             :     std::unique_ptr<OGRFeature> GetNextSrcFeature();
     335             :     std::unique_ptr<OGRFeature> CreateFeatureFrom(OGRFeature *poSrcFeature);
     336             :     GIntBig GetTotalFeatureCount() const;
     337             :     void ExtentToTileExtent(const OGREnvelope &sEnvelope, int &nTileMinX,
     338             :                             int &nTileMinY, int &nTileMaxX,
     339             :                             int &nTileMaxY) const;
     340             : 
     341             :     CPL_DISALLOW_COPY_ASSIGN(OGRPMTilesVectorLayer)
     342             : };
     343             : 
     344             : #ifdef HAVE_MVT_WRITE_SUPPORT
     345             : 
     346             : /************************************************************************/
     347             : /*                     OGRPMTilesWriterDataset                          */
     348             : /************************************************************************/
     349             : 
     350             : class OGRPMTilesWriterDataset final : public GDALDataset
     351             : {
     352             :     std::unique_ptr<GDALDataset> m_poMBTilesWriterDataset{};
     353             : 
     354             :   public:
     355          34 :     OGRPMTilesWriterDataset() = default;
     356             : 
     357             :     ~OGRPMTilesWriterDataset() override;
     358             : 
     359             :     bool Create(const char *pszFilename, CSLConstList papszOptions);
     360             : 
     361             :     CPLErr Close() override;
     362             : 
     363             :     OGRLayer *ICreateLayer(const char *pszName,
     364             :                            const OGRGeomFieldDefn *poGeomFieldDefn,
     365             :                            CSLConstList papszOptions) override;
     366             : 
     367             :     int TestCapability(const char *) override;
     368             : };
     369             : 
     370             : #endif  // HAVE_MVT_WRITE_SUPPORT
     371             : 
     372             : #endif  // OGR_PMTILES_H_INCLUDED

Generated by: LCOV version 1.14