Coverage Report

Created: 2025-11-15 08:43

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/ogr/ogrsf_frmts/mvt/mvt_tile.h
Line
Count
Source
1
/******************************************************************************
2
 *
3
 * Project:  MVT Translator
4
 * Purpose:  Mapbox Vector Tile decoder and encoder
5
 * Author:   Even Rouault, Even Rouault <even dot rouault at spatialys dot com>
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 2018, Even Rouault <even dot rouault at spatialys dot com>
9
 *
10
 * SPDX-License-Identifier: MIT
11
 ****************************************************************************/
12
13
#ifndef MVT_TILE_H
14
#define MVT_TILE_H
15
16
#include "cpl_port.h"
17
18
#include <memory>
19
#include <string>
20
#include <vector>
21
22
/* See
23
 * https://github.com/mapbox/vector-tile-spec/blob/master/2.1/vector_tile.proto
24
 */
25
constexpr int knLAYER = 3;
26
27
constexpr int knLAYER_NAME = 1;
28
constexpr int knLAYER_FEATURES = 2;
29
constexpr int knLAYER_KEYS = 3;
30
constexpr int knLAYER_VALUES = 4;
31
constexpr int knLAYER_EXTENT = 5;
32
constexpr int knLAYER_VERSION = 15;
33
34
constexpr int knVALUE_STRING = 1;
35
constexpr int knVALUE_FLOAT = 2;
36
constexpr int knVALUE_DOUBLE = 3;
37
constexpr int knVALUE_INT = 4;
38
constexpr int knVALUE_UINT = 5;
39
constexpr int knVALUE_SINT = 6;
40
constexpr int knVALUE_BOOL = 7;
41
42
constexpr int knFEATURE_ID = 1;
43
constexpr int knFEATURE_TAGS = 2;
44
constexpr int knFEATURE_TYPE = 3;
45
constexpr int knFEATURE_GEOMETRY = 4;
46
47
constexpr int knGEOM_TYPE_UNKNOWN = 0;
48
constexpr int knGEOM_TYPE_POINT = 1;
49
constexpr int knGEOM_TYPE_LINESTRING = 2;
50
constexpr int knGEOM_TYPE_POLYGON = 3;
51
52
constexpr int knCMD_MOVETO = 1;
53
constexpr int knCMD_LINETO = 2;
54
constexpr int knCMD_CLOSEPATH = 7;
55
56
constexpr unsigned knDEFAULT_EXTENT = 4096;
57
58
/************************************************************************/
59
/*                         MVTTileLayerValue                            */
60
/************************************************************************/
61
62
class MVTTileLayerValue
63
{
64
  public:
65
    enum class ValueType
66
    {
67
        NONE,
68
        STRING,
69
        FLOAT,
70
        DOUBLE,
71
        INT,
72
        UINT,
73
        SINT,
74
        BOOL,
75
        STRING_MAX_8,  // optimization for short strings.
76
    };
77
78
  private:
79
    // Layout optimized for small memory footprint
80
    union
81
    {
82
        float m_fValue;
83
        double m_dfValue;
84
        GInt64 m_nIntValue;
85
        GUInt64 m_nUIntValue;
86
        bool m_bBoolValue;
87
        char *m_pszValue;
88
        char m_achValue[8];  // optimization for short strings
89
    };
90
91
    ValueType m_eType = ValueType::NONE;
92
93
    void unset();
94
95
  public:
96
    MVTTileLayerValue();
97
    ~MVTTileLayerValue();
98
    MVTTileLayerValue(const MVTTileLayerValue &oOther);
99
    MVTTileLayerValue &operator=(const MVTTileLayerValue &oOther);
100
101
    bool operator<(const MVTTileLayerValue &rhs) const;
102
103
    ValueType getType() const
104
0
    {
105
0
        return m_eType;
106
0
    }
107
108
    bool isNumeric() const
109
0
    {
110
0
        return m_eType == ValueType::FLOAT || m_eType == ValueType::DOUBLE ||
111
0
               m_eType == ValueType::INT || m_eType == ValueType::UINT ||
112
0
               m_eType == ValueType::SINT;
113
0
    }
114
115
    bool isString() const
116
0
    {
117
0
        return m_eType == ValueType::STRING ||
118
0
               m_eType == ValueType::STRING_MAX_8;
119
0
    }
120
121
    float getFloatValue() const
122
0
    {
123
0
        return m_fValue;
124
0
    }
125
126
    double getDoubleValue() const
127
0
    {
128
0
        return m_dfValue;
129
0
    }
130
131
    GInt64 getIntValue() const
132
0
    {
133
0
        return m_nIntValue;
134
0
    }
135
136
    GUInt64 getUIntValue() const
137
0
    {
138
0
        return m_nUIntValue;
139
0
    }
140
141
    bool getBoolValue() const
142
0
    {
143
0
        return m_bBoolValue;
144
0
    }
145
146
    double getNumericValue() const
147
0
    {
148
0
        if (m_eType == ValueType::FLOAT)
149
0
            return m_fValue;
150
0
        if (m_eType == ValueType::DOUBLE)
151
0
            return m_dfValue;
152
0
        if (m_eType == ValueType::INT || m_eType == ValueType::SINT)
153
0
            return static_cast<double>(m_nIntValue);
154
0
        if (m_eType == ValueType::UINT)
155
0
            return static_cast<double>(m_nUIntValue);
156
0
        return 0.0;
157
0
    }
158
159
    std::string getStringValue() const
160
0
    {
161
0
        if (m_eType == ValueType::STRING)
162
0
            return m_pszValue;
163
0
        else if (m_eType == ValueType::STRING_MAX_8)
164
0
        {
165
0
            char szBuf[8 + 1];
166
0
            memcpy(szBuf, m_achValue, 8);
167
0
            szBuf[8] = 0;
168
0
            return szBuf;
169
0
        }
170
0
        return std::string();
171
0
    }
172
173
    void setStringValue(const std::string &osValue);
174
175
    void setFloatValue(float fValue)
176
0
    {
177
0
        unset();
178
0
        m_eType = ValueType::FLOAT;
179
0
        m_fValue = fValue;
180
0
    }
181
182
    void setDoubleValue(double dfValue)
183
0
    {
184
0
        unset();
185
0
        m_eType = ValueType::DOUBLE;
186
0
        m_dfValue = dfValue;
187
0
    }
188
189
    void setIntValue(GInt64 nVal)
190
0
    {
191
0
        unset();
192
0
        m_eType = ValueType::INT;
193
0
        m_nIntValue = nVal;
194
0
    }
195
196
    void setUIntValue(GUInt64 nVal)
197
0
    {
198
0
        unset();
199
0
        m_eType = ValueType::UINT;
200
0
        m_nUIntValue = nVal;
201
0
    }
202
203
    void setSIntValue(GInt64 nVal)
204
0
    {
205
0
        unset();
206
0
        m_eType = ValueType::SINT;
207
0
        m_nIntValue = nVal;
208
0
    }
209
210
    void setBoolValue(bool bVal)
211
0
    {
212
0
        unset();
213
0
        m_eType = ValueType::BOOL;
214
0
        m_bBoolValue = bVal;
215
0
    }
216
217
    void setValue(double dfVal);
218
219
    void setValue(int nVal)
220
0
    {
221
0
        setValue(static_cast<GInt64>(nVal));
222
0
    }
223
224
    void setValue(GInt64 nVal)
225
0
    {
226
0
        if (nVal < 0)
227
0
            setSIntValue(nVal);
228
0
        else
229
0
            setUIntValue(nVal);
230
0
    }
231
232
    size_t getSize() const;
233
    void write(GByte **ppabyData) const;
234
    bool read(const GByte **ppabyData, const GByte *pabyEnd);
235
};
236
237
/************************************************************************/
238
/*                       MVTTileLayerFeature                            */
239
/************************************************************************/
240
241
class MVTTileLayer;
242
243
class MVTTileLayerFeature
244
{
245
  public:
246
    enum class GeomType : char
247
    {
248
        UNKNOWN = 0,
249
        POINT = 1,
250
        LINESTRING = 2,
251
        POLYGON = 3
252
    };
253
254
  private:
255
    mutable size_t m_nCachedSize = 0;
256
    GUInt64 m_nId = 0;
257
    std::vector<GUInt32> m_anTags;
258
    std::vector<GUInt32> m_anGeometry;
259
    GeomType m_eType = GeomType::UNKNOWN;
260
    mutable bool m_bCachedSize = false;
261
    bool m_bHasId = false;
262
    bool m_bHasType = false;
263
    MVTTileLayer *m_poOwner = nullptr;
264
265
  public:
266
    MVTTileLayerFeature();
267
    void setOwner(MVTTileLayer *poOwner);
268
269
    bool hasId() const
270
0
    {
271
0
        return m_bHasId;
272
0
    }
273
274
    GUInt64 getId() const
275
0
    {
276
0
        return m_nId;
277
0
    }
278
279
    const std::vector<GUInt32> &getTags() const
280
0
    {
281
0
        return m_anTags;
282
0
    }
283
284
    bool hasType() const
285
0
    {
286
0
        return m_bHasType;
287
0
    }
288
289
    GeomType getType() const
290
0
    {
291
0
        return m_eType;
292
0
    }
293
294
    GUInt32 getGeometryCount() const
295
0
    {
296
0
        return static_cast<GUInt32>(m_anGeometry.size());
297
0
    }
298
299
    const std::vector<GUInt32> &getGeometry() const
300
0
    {
301
0
        return m_anGeometry;
302
0
    }
303
304
    void setId(GUInt64 nId)
305
0
    {
306
0
        m_bHasId = true;
307
0
        m_nId = nId;
308
0
        invalidateCachedSize();
309
0
    }
310
311
    void addTag(GUInt32 nTag)
312
0
    {
313
0
        m_anTags.push_back(nTag);
314
0
        invalidateCachedSize();
315
0
    }
316
317
    void setType(GeomType eType)
318
0
    {
319
0
        m_bHasType = true;
320
0
        m_eType = eType;
321
0
        invalidateCachedSize();
322
0
    }
323
324
    void resizeGeometryArray(GUInt32 nNewSize)
325
0
    {
326
0
        m_anGeometry.resize(nNewSize);
327
0
        invalidateCachedSize();
328
0
    }
329
330
    void addGeometry(GUInt32 nGeometry)
331
0
    {
332
0
        m_anGeometry.push_back(nGeometry);
333
0
        invalidateCachedSize();
334
0
    }
335
336
    void setGeometry(GUInt32 nIdx, GUInt32 nVal)
337
0
    {
338
0
        m_anGeometry[nIdx] = nVal;
339
0
        invalidateCachedSize();
340
0
    }
341
342
    void setGeometry(const std::vector<GUInt32> &anGeometry)
343
0
    {
344
0
        m_anGeometry = anGeometry;
345
0
        invalidateCachedSize();
346
0
    }
347
348
    size_t getSize() const;
349
    void write(GByte **ppabyData) const;
350
    bool read(const GByte **ppabyData, const GByte *pabyEnd);
351
352
    void invalidateCachedSize();
353
};
354
355
/************************************************************************/
356
/*                           MVTTileLayer                               */
357
/************************************************************************/
358
359
class MVTTile;
360
361
class MVTTileLayer
362
{
363
    mutable bool m_bCachedSize = false;
364
    mutable size_t m_nCachedSize = 0;
365
    GUInt32 m_nVersion = 1;
366
    std::string m_osName;
367
    std::vector<std::shared_ptr<MVTTileLayerFeature>> m_apoFeatures;
368
    std::vector<std::string> m_aosKeys;
369
    std::vector<MVTTileLayerValue> m_aoValues;
370
    bool m_bHasExtent = false;
371
    GUInt32 m_nExtent = 4096;
372
    MVTTile *m_poOwner = nullptr;
373
374
  public:
375
    MVTTileLayer();
376
    void setOwner(MVTTile *poOwner);
377
378
    GUInt32 getVersion() const
379
0
    {
380
0
        return m_nVersion;
381
0
    }
382
383
    const std::string &getName() const
384
0
    {
385
0
        return m_osName;
386
0
    }
387
388
    const std::vector<std::shared_ptr<MVTTileLayerFeature>> &getFeatures() const
389
0
    {
390
0
        return m_apoFeatures;
391
0
    }
392
393
    const std::vector<std::string> &getKeys() const
394
0
    {
395
0
        return m_aosKeys;
396
0
    }
397
398
    const std::vector<MVTTileLayerValue> &getValues() const
399
0
    {
400
0
        return m_aoValues;
401
0
    }
402
403
    GUInt32 getExtent() const
404
0
    {
405
0
        return m_nExtent;
406
0
    }
407
408
    void setVersion(GUInt32 nVersion)
409
0
    {
410
0
        m_nVersion = nVersion;
411
0
        invalidateCachedSize();
412
0
    }
413
414
    void setName(const std::string &osName)
415
0
    {
416
0
        m_osName = osName;
417
0
        invalidateCachedSize();
418
0
    }
419
420
    size_t addFeature(std::shared_ptr<MVTTileLayerFeature> poFeature);
421
422
    GUInt32 addKey(const std::string &osKey)
423
0
    {
424
0
        m_aosKeys.push_back(osKey);
425
0
        invalidateCachedSize();
426
0
        return static_cast<GUInt32>(m_aosKeys.size()) - 1;
427
0
    }
428
429
    GUInt32 addValue(const MVTTileLayerValue &oValue)
430
0
    {
431
0
        m_aoValues.push_back(oValue);
432
0
        invalidateCachedSize();
433
0
        return static_cast<GUInt32>(m_aoValues.size()) - 1;
434
0
    }
435
436
    void setExtent(GUInt32 nExtent)
437
0
    {
438
0
        m_nExtent = nExtent;
439
0
        m_bHasExtent = true;
440
0
        invalidateCachedSize();
441
0
    }
442
443
    size_t getSize() const;
444
    void write(GByte **ppabyData) const;
445
    void write(GByte *pabyData) const;
446
    std::string write() const;
447
    bool read(const GByte **ppabyData, const GByte *pabyEnd);
448
    bool read(const GByte *pabyData, const GByte *pabyEnd);
449
450
    void invalidateCachedSize();
451
};
452
453
/************************************************************************/
454
/*                              MVTTile                                 */
455
/************************************************************************/
456
457
class MVTTile
458
{
459
    std::vector<std::shared_ptr<MVTTileLayer>> m_apoLayers;
460
    mutable size_t m_nCachedSize = 0;
461
    mutable bool m_bCachedSize = false;
462
463
  public:
464
    MVTTile();
465
466
    const std::vector<std::shared_ptr<MVTTileLayer>> &getLayers() const
467
0
    {
468
0
        return m_apoLayers;
469
0
    }
470
471
    void clear()
472
0
    {
473
0
        m_apoLayers.clear();
474
0
        invalidateCachedSize();
475
0
    }
476
477
    void addLayer(std::shared_ptr<MVTTileLayer> poLayer);
478
    size_t getSize() const;
479
    void write(GByte **ppabyData) const;
480
    void write(GByte *pabyData) const;
481
    std::string write() const;
482
#ifdef ADD_MVT_TILE_READ
483
    bool read(const GByte **ppabyData, const GByte *pabyEnd);
484
    bool read(const GByte *pabyData, const GByte *pabyEnd);
485
#endif
486
    void invalidateCachedSize()
487
0
    {
488
0
        m_bCachedSize = false;
489
0
        m_nCachedSize = 0;
490
0
    }
491
};
492
493
#endif  // MVT_TILE_H