Coverage Report

Created: 2025-06-09 08:44

/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
305k
{
24
305k
    {
25
305k
        OGRFieldDefn oFieldDefnId("mvt_id", OFTInteger64);
26
305k
        poFeatureDefn->AddFieldDefn(&oFieldDefnId);
27
305k
    }
28
29
305k
    if (oFields.IsValid())
30
110k
    {
31
110k
        for (const auto &oField : oFields.GetChildren())
32
50.3k
        {
33
50.3k
            if (oField.GetType() == CPLJSONObject::Type::String)
34
22.4k
            {
35
22.4k
                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
22.4k
                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
22.4k
                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
22.4k
                else
84
22.4k
                {
85
22.4k
                    OGRFieldDefn oFieldDefn(oField.GetName().c_str(),
86
22.4k
                                            OFTString);
87
22.4k
                    poFeatureDefn->AddFieldDefn(&oFieldDefn);
88
22.4k
                }
89
22.4k
            }
90
50.3k
        }
91
110k
    }
92
305k
}
93
94
/************************************************************************/
95
/*                     OGRMVTFindGeomTypeFromTileStat()                 */
96
/************************************************************************/
97
98
OGRwkbGeometryType
99
OGRMVTFindGeomTypeFromTileStat(const CPLJSONArray &oTileStatLayers,
100
                               const char *pszLayerName)
101
20.8k
{
102
20.8k
    OGRwkbGeometryType eGeomType = wkbUnknown;
103
43.7k
    for (int i = 0; i < oTileStatLayers.Size(); i++)
104
32.3k
    {
105
32.3k
        CPLJSONObject oId = oTileStatLayers[i].GetObj("layer");
106
32.3k
        if (oId.IsValid() && oId.GetType() == CPLJSONObject::Type::String)
107
24.0k
        {
108
24.0k
            if (oId.ToString() == pszLayerName)
109
9.49k
            {
110
9.49k
                CPLJSONObject oGeom = oTileStatLayers[i].GetObj("geometry");
111
9.49k
                if (oGeom.IsValid() &&
112
9.49k
                    oGeom.GetType() == CPLJSONObject::Type::String)
113
6.98k
                {
114
6.98k
                    const std::string oGeomType(oGeom.ToString());
115
                    // Note: this information is not
116
                    // reliable in case
117
                    // of mix of geometry types
118
6.98k
                    if (oGeomType == "Point")
119
5.87k
                    {
120
5.87k
                        eGeomType = wkbMultiPoint;
121
5.87k
                    }
122
1.10k
                    else if (oGeomType == "LineString")
123
0
                    {
124
0
                        eGeomType = wkbMultiLineString;
125
0
                    }
126
1.10k
                    else if (oGeomType == "Polygon")
127
8
                    {
128
8
                        eGeomType = wkbMultiPolygon;
129
8
                    }
130
6.98k
                }
131
9.49k
                break;
132
9.49k
            }
133
24.0k
        }
134
32.3k
    }
135
20.8k
    return eGeomType;
136
20.8k
}
137
138
/************************************************************************/
139
/*                     OGRMVTFindAttributesFromTileStat()               */
140
/************************************************************************/
141
142
CPLJSONArray
143
OGRMVTFindAttributesFromTileStat(const CPLJSONArray &oTileStatLayers,
144
                                 const char *pszLayerName)
145
458k
{
146
481k
    for (int i = 0; i < oTileStatLayers.Size(); i++)
147
32.3k
    {
148
32.3k
        CPLJSONObject oId = oTileStatLayers[i].GetObj("layer");
149
32.3k
        if (oId.IsValid() && oId.GetType() == CPLJSONObject::Type::String)
150
24.0k
        {
151
24.0k
            if (oId.ToString() == pszLayerName)
152
9.49k
            {
153
9.49k
                CPLJSONObject oAttributes =
154
9.49k
                    oTileStatLayers[i].GetObj("attributes");
155
9.49k
                if (oAttributes.IsValid() &&
156
9.49k
                    oAttributes.GetType() == CPLJSONObject::Type::Array)
157
3.20k
                {
158
3.20k
                    return oAttributes.ToArray();
159
3.20k
                }
160
6.28k
                break;
161
9.49k
            }
162
24.0k
        }
163
32.3k
    }
164
455k
    CPLJSONArray oAttributes;
165
455k
    oAttributes.Deinit();
166
455k
    return oAttributes;
167
458k
}
168
169
/************************************************************************/
170
/*                     OGRMVTCreateFeatureFrom()                        */
171
/************************************************************************/
172
173
OGRFeature *OGRMVTCreateFeatureFrom(OGRFeature *poSrcFeature,
174
                                    OGRFeatureDefn *poTargetFeatureDefn,
175
                                    bool bJsonField, OGRSpatialReference *poSRS)
176
50.7k
{
177
50.7k
    OGRFeature *poFeature = new OGRFeature(poTargetFeatureDefn);
178
50.7k
    if (bJsonField)
179
7.57k
    {
180
7.57k
        CPLJSONObject oProperties;
181
7.57k
        bool bEmpty = true;
182
14.2k
        for (int i = 1; i < poSrcFeature->GetFieldCount(); i++)
183
6.64k
        {
184
6.64k
            if (poSrcFeature->IsFieldSet(i))
185
6.64k
            {
186
6.64k
                bEmpty = false;
187
6.64k
                OGRFieldDefn *poFDefn = poSrcFeature->GetFieldDefnRef(i);
188
6.64k
                if (poSrcFeature->IsFieldNull(i))
189
0
                {
190
0
                    oProperties.AddNull(poFDefn->GetNameRef());
191
0
                }
192
6.64k
                else if (poFDefn->GetType() == OFTInteger ||
193
6.64k
                         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
6.64k
                else if (poFDefn->GetType() == OFTReal)
208
0
                {
209
0
                    oProperties.Add(poFDefn->GetNameRef(),
210
0
                                    poSrcFeature->GetFieldAsDouble(i));
211
0
                }
212
6.64k
                else
213
6.64k
                {
214
6.64k
                    oProperties.Add(poFDefn->GetNameRef(),
215
6.64k
                                    poSrcFeature->GetFieldAsString(i));
216
6.64k
                }
217
6.64k
            }
218
6.64k
        }
219
7.57k
        if (!bEmpty)
220
6.64k
        {
221
6.64k
            poFeature->SetField(
222
6.64k
                "json", oProperties.Format(CPLJSONObject::PrettyFormat::Pretty)
223
6.64k
                            .c_str());
224
6.64k
        }
225
226
7.57k
        OGRGeometry *poSrcGeom = poSrcFeature->GetGeometryRef();
227
7.57k
        if (poSrcGeom)
228
3.54k
        {
229
3.54k
            poFeature->SetGeometry(poSrcGeom);
230
3.54k
        }
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
7.57k
    }
251
43.1k
    else
252
43.1k
    {
253
43.1k
        poFeature->SetFrom(poSrcFeature);
254
43.1k
    }
255
50.7k
    OGRGeometry *poGeom = poFeature->GetGeometryRef();
256
50.7k
    if (poGeom)
257
18.2k
        poGeom->assignSpatialReference(poSRS);
258
50.7k
    return poFeature;
259
50.7k
}