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

Generated by: LCOV version 1.14