Coverage Report

Created: 2025-07-23 09:13

/src/gdal/ogr/ogrsf_frmts/mvt/mvtutils.cpp
Line
Count
Source (jump to first uncovered line)
1
/******************************************************************************
2
 *
3
 * Project:  MVT Translator
4
 * Purpose:  Mapbox Vector Tile decoder
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
#include "mvtutils.h"
14
#include "ogr_api.h"
15
16
/************************************************************************/
17
/*                        OGRMVTInitFields()                            */
18
/************************************************************************/
19
20
void OGRMVTInitFields(OGRFeatureDefn *poFeatureDefn,
21
                      const CPLJSONObject &oFields,
22
                      const CPLJSONArray &oAttributesFromTileStats)
23
228k
{
24
228k
    {
25
228k
        OGRFieldDefn oFieldDefnId("mvt_id", OFTInteger64);
26
228k
        poFeatureDefn->AddFieldDefn(&oFieldDefnId);
27
228k
    }
28
29
228k
    if (oFields.IsValid())
30
82.5k
    {
31
82.5k
        for (const auto &oField : oFields.GetChildren())
32
38.5k
        {
33
38.5k
            if (oField.GetType() == CPLJSONObject::Type::String)
34
16.9k
            {
35
16.9k
                if (oField.ToString() == "Number")
36
0
                {
37
0
                    OGRFieldDefn oFieldDefn(oField.GetName().c_str(), OFTReal);
38
39
0
                    for (int i = 0; i < oAttributesFromTileStats.Size(); ++i)
40
0
                    {
41
0
                        if (oAttributesFromTileStats[i].GetString(
42
0
                                "attribute") == oField.GetName() &&
43
0
                            oAttributesFromTileStats[i].GetString("type") ==
44
0
                                "number")
45
0
                        {
46
0
                            const auto eMinType = oAttributesFromTileStats[i]
47
0
                                                      .GetObj("min")
48
0
                                                      .GetType();
49
0
                            const auto eMaxType = oAttributesFromTileStats[i]
50
0
                                                      .GetObj("max")
51
0
                                                      .GetType();
52
0
                            if (eMinType == CPLJSONObject::Type::Integer &&
53
0
                                eMaxType == CPLJSONObject::Type::Integer)
54
0
                            {
55
0
                                oFieldDefn.SetType(OFTInteger);
56
0
                            }
57
0
                            else if ((eMinType ==
58
0
                                          CPLJSONObject::Type::Integer ||
59
0
                                      eMinType == CPLJSONObject::Type::Long) &&
60
0
                                     eMaxType == CPLJSONObject::Type::Long)
61
0
                            {
62
0
                                oFieldDefn.SetType(OFTInteger64);
63
0
                            }
64
0
                            break;
65
0
                        }
66
0
                    }
67
68
0
                    poFeatureDefn->AddFieldDefn(&oFieldDefn);
69
0
                }
70
16.9k
                else if (oField.ToString() == "Integer")  // GDAL extension
71
0
                {
72
0
                    OGRFieldDefn oFieldDefn(oField.GetName().c_str(),
73
0
                                            OFTInteger);
74
0
                    poFeatureDefn->AddFieldDefn(&oFieldDefn);
75
0
                }
76
16.9k
                else if (oField.ToString() == "Boolean")
77
0
                {
78
0
                    OGRFieldDefn oFieldDefn(oField.GetName().c_str(),
79
0
                                            OFTInteger);
80
0
                    oFieldDefn.SetSubType(OFSTBoolean);
81
0
                    poFeatureDefn->AddFieldDefn(&oFieldDefn);
82
0
                }
83
16.9k
                else
84
16.9k
                {
85
16.9k
                    OGRFieldDefn oFieldDefn(oField.GetName().c_str(),
86
16.9k
                                            OFTString);
87
16.9k
                    poFeatureDefn->AddFieldDefn(&oFieldDefn);
88
16.9k
                }
89
16.9k
            }
90
38.5k
        }
91
82.5k
    }
92
228k
}
93
94
/************************************************************************/
95
/*                     OGRMVTFindGeomTypeFromTileStat()                 */
96
/************************************************************************/
97
98
OGRwkbGeometryType
99
OGRMVTFindGeomTypeFromTileStat(const CPLJSONArray &oTileStatLayers,
100
                               const char *pszLayerName)
101
13.2k
{
102
13.2k
    OGRwkbGeometryType eGeomType = wkbUnknown;
103
27.7k
    for (int i = 0; i < oTileStatLayers.Size(); i++)
104
20.5k
    {
105
20.5k
        CPLJSONObject oId = oTileStatLayers[i].GetObj("layer");
106
20.5k
        if (oId.IsValid() && oId.GetType() == CPLJSONObject::Type::String)
107
15.5k
        {
108
15.5k
            if (oId.ToString() == pszLayerName)
109
6.09k
            {
110
6.09k
                CPLJSONObject oGeom = oTileStatLayers[i].GetObj("geometry");
111
6.09k
                if (oGeom.IsValid() &&
112
6.09k
                    oGeom.GetType() == CPLJSONObject::Type::String)
113
5.71k
                {
114
5.71k
                    const std::string oGeomType(oGeom.ToString());
115
                    // Note: this information is not
116
                    // reliable in case
117
                    // of mix of geometry types
118
5.71k
                    if (oGeomType == "Point")
119
4.55k
                    {
120
4.55k
                        eGeomType = wkbMultiPoint;
121
4.55k
                    }
122
1.16k
                    else if (oGeomType == "LineString")
123
0
                    {
124
0
                        eGeomType = wkbMultiLineString;
125
0
                    }
126
1.16k
                    else if (oGeomType == "Polygon")
127
3
                    {
128
3
                        eGeomType = wkbMultiPolygon;
129
3
                    }
130
5.71k
                }
131
6.09k
                break;
132
6.09k
            }
133
15.5k
        }
134
20.5k
    }
135
13.2k
    return eGeomType;
136
13.2k
}
137
138
/************************************************************************/
139
/*                     OGRMVTFindAttributesFromTileStat()               */
140
/************************************************************************/
141
142
CPLJSONArray
143
OGRMVTFindAttributesFromTileStat(const CPLJSONArray &oTileStatLayers,
144
                                 const char *pszLayerName)
145
363k
{
146
377k
    for (int i = 0; i < oTileStatLayers.Size(); i++)
147
20.5k
    {
148
20.5k
        CPLJSONObject oId = oTileStatLayers[i].GetObj("layer");
149
20.5k
        if (oId.IsValid() && oId.GetType() == CPLJSONObject::Type::String)
150
15.5k
        {
151
15.5k
            if (oId.ToString() == pszLayerName)
152
6.09k
            {
153
6.09k
                CPLJSONObject oAttributes =
154
6.09k
                    oTileStatLayers[i].GetObj("attributes");
155
6.09k
                if (oAttributes.IsValid() &&
156
6.09k
                    oAttributes.GetType() == CPLJSONObject::Type::Array)
157
1.07k
                {
158
1.07k
                    return oAttributes.ToArray();
159
1.07k
                }
160
5.02k
                break;
161
6.09k
            }
162
15.5k
        }
163
20.5k
    }
164
362k
    CPLJSONArray oAttributes;
165
362k
    oAttributes.Deinit();
166
362k
    return oAttributes;
167
363k
}
168
169
/************************************************************************/
170
/*                     OGRMVTCreateFeatureFrom()                        */
171
/************************************************************************/
172
173
OGRFeature *OGRMVTCreateFeatureFrom(OGRFeature *poSrcFeature,
174
                                    OGRFeatureDefn *poTargetFeatureDefn,
175
                                    bool bJsonField, OGRSpatialReference *poSRS)
176
39.7k
{
177
39.7k
    OGRFeature *poFeature = new OGRFeature(poTargetFeatureDefn);
178
39.7k
    if (bJsonField)
179
5.74k
    {
180
5.74k
        CPLJSONObject oProperties;
181
5.74k
        bool bEmpty = true;
182
10.7k
        for (int i = 1; i < poSrcFeature->GetFieldCount(); i++)
183
4.99k
        {
184
4.99k
            if (poSrcFeature->IsFieldSet(i))
185
4.99k
            {
186
4.99k
                bEmpty = false;
187
4.99k
                OGRFieldDefn *poFDefn = poSrcFeature->GetFieldDefnRef(i);
188
4.99k
                if (poSrcFeature->IsFieldNull(i))
189
0
                {
190
0
                    oProperties.AddNull(poFDefn->GetNameRef());
191
0
                }
192
4.99k
                else if (poFDefn->GetType() == OFTInteger ||
193
4.99k
                         poFDefn->GetType() == OFTInteger64)
194
0
                {
195
0
                    if (poFDefn->GetSubType() == OFSTBoolean)
196
0
                    {
197
0
                        oProperties.Add(poFDefn->GetNameRef(),
198
0
                                        poSrcFeature->GetFieldAsInteger(i) ==
199
0
                                            1);
200
0
                    }
201
0
                    else
202
0
                    {
203
0
                        oProperties.Add(poFDefn->GetNameRef(),
204
0
                                        poSrcFeature->GetFieldAsInteger64(i));
205
0
                    }
206
0
                }
207
4.99k
                else if (poFDefn->GetType() == OFTReal)
208
0
                {
209
0
                    oProperties.Add(poFDefn->GetNameRef(),
210
0
                                    poSrcFeature->GetFieldAsDouble(i));
211
0
                }
212
4.99k
                else
213
4.99k
                {
214
4.99k
                    oProperties.Add(poFDefn->GetNameRef(),
215
4.99k
                                    poSrcFeature->GetFieldAsString(i));
216
4.99k
                }
217
4.99k
            }
218
4.99k
        }
219
5.74k
        if (!bEmpty)
220
4.99k
        {
221
4.99k
            poFeature->SetField(
222
4.99k
                "json", oProperties.Format(CPLJSONObject::PrettyFormat::Pretty)
223
4.99k
                            .c_str());
224
4.99k
        }
225
226
5.74k
        OGRGeometry *poSrcGeom = poSrcFeature->GetGeometryRef();
227
5.74k
        if (poSrcGeom)
228
2.89k
        {
229
2.89k
            poFeature->SetGeometry(poSrcGeom);
230
2.89k
        }
231
#ifdef nodef
232
        CPLJSONObject oObj;
233
        oObj.Add("type", "Feature");
234
        if (poSrcFeature->IsFieldSet(0))
235
            oObj.Add("id", poSrcFeature->GetFieldAsInteger64("mvt_id"));
236
        oObj.Add("properties", oProperties);
237
        if (poSrcGeom)
238
        {
239
            char *pszGeomJson =
240
                OGR_G_ExportToJson(OGRGeometry::ToHandle(poSrcGeom));
241
            CPLJSONDocument oJSonDoc;
242
            oJSonDoc.LoadMemory(reinterpret_cast<const GByte *>(pszGeomJson));
243
            CPLFree(pszGeomJson);
244
            oObj.Add("geometry", oJSonDoc.GetRoot());
245
        }
246
        poFeature->SetNativeData(
247
            oObj.Format(CPLJSONObject::PrettyFormat::Pretty).c_str());
248
        poFeature->SetNativeMediaType("application/vnd.geo+json");
249
#endif
250
5.74k
    }
251
34.0k
    else
252
34.0k
    {
253
34.0k
        poFeature->SetFrom(poSrcFeature);
254
34.0k
    }
255
39.7k
    OGRGeometry *poGeom = poFeature->GetGeometryRef();
256
39.7k
    if (poGeom)
257
14.0k
        poGeom->assignSpatialReference(poSRS);
258
39.7k
    return poFeature;
259
39.7k
}