Line data Source code
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 1146 : void OGRMVTInitFields(OGRFeatureDefn *poFeatureDefn, 21 : const CPLJSONObject &oFields, 22 : const CPLJSONArray &oAttributesFromTileStats) 23 : { 24 : { 25 2292 : OGRFieldDefn oFieldDefnId("mvt_id", OFTInteger64); 26 1146 : poFeatureDefn->AddFieldDefn(&oFieldDefnId); 27 : } 28 : 29 1146 : if (oFields.IsValid()) 30 : { 31 20004 : for (const auto &oField : oFields.GetChildren()) 32 : { 33 18942 : if (oField.GetType() == CPLJSONObject::Type::String) 34 : { 35 18942 : if (oField.ToString() == "Number") 36 : { 37 16310 : OGRFieldDefn oFieldDefn(oField.GetName().c_str(), OFTReal); 38 : 39 205416 : for (int i = 0; i < oAttributesFromTileStats.Size(); ++i) 40 : { 41 408118 : if (oAttributesFromTileStats[i].GetString( 42 618975 : "attribute") == oField.GetName() && 43 210857 : oAttributesFromTileStats[i].GetString("type") == 44 : "number") 45 : { 46 : const auto eMinType = oAttributesFromTileStats[i] 47 13596 : .GetObj("min") 48 6798 : .GetType(); 49 : const auto eMaxType = oAttributesFromTileStats[i] 50 13596 : .GetObj("max") 51 6798 : .GetType(); 52 6798 : if (eMinType == CPLJSONObject::Type::Integer && 53 : eMaxType == CPLJSONObject::Type::Integer) 54 : { 55 6398 : oFieldDefn.SetType(OFTInteger); 56 : } 57 400 : else if ((eMinType == 58 400 : CPLJSONObject::Type::Integer || 59 5 : eMinType == CPLJSONObject::Type::Long) && 60 : eMaxType == CPLJSONObject::Type::Long) 61 : { 62 5 : oFieldDefn.SetType(OFTInteger64); 63 : } 64 6798 : if (oFieldDefn.GetType() != OFTReal) 65 : { 66 : const auto oValues = 67 : oAttributesFromTileStats[i].GetObj( 68 19209 : "values"); 69 6403 : if (oValues.GetType() == 70 : CPLJSONObject::Type::Array) 71 : { 72 12806 : const auto oValuesArray = oValues.ToArray(); 73 31044 : for (int iVal = 0; 74 31044 : iVal < oValuesArray.Size(); ++iVal) 75 : { 76 24642 : if (oValuesArray[iVal].GetType() == 77 : CPLJSONObject::Type::Double) 78 : { 79 1 : oFieldDefn.SetType(OFTReal); 80 1 : break; 81 : } 82 : } 83 : } 84 : } 85 6798 : break; 86 : } 87 : } 88 : 89 8155 : poFeatureDefn->AddFieldDefn(&oFieldDefn); 90 : } 91 10787 : else if (oField.ToString() == "Integer") // GDAL extension 92 : { 93 0 : OGRFieldDefn oFieldDefn(oField.GetName().c_str(), 94 0 : OFTInteger); 95 0 : poFeatureDefn->AddFieldDefn(&oFieldDefn); 96 : } 97 10787 : else if (oField.ToString() == "Boolean") 98 : { 99 115 : OGRFieldDefn oFieldDefn(oField.GetName().c_str(), 100 230 : OFTInteger); 101 115 : oFieldDefn.SetSubType(OFSTBoolean); 102 115 : poFeatureDefn->AddFieldDefn(&oFieldDefn); 103 : } 104 : else 105 : { 106 10672 : OGRFieldDefn oFieldDefn(oField.GetName().c_str(), 107 21344 : OFTString); 108 10672 : poFeatureDefn->AddFieldDefn(&oFieldDefn); 109 : } 110 : } 111 : } 112 : } 113 1146 : } 114 : 115 : /************************************************************************/ 116 : /* OGRMVTFindGeomTypeFromTileStat() */ 117 : /************************************************************************/ 118 : 119 : OGRwkbGeometryType 120 657 : OGRMVTFindGeomTypeFromTileStat(const CPLJSONArray &oTileStatLayers, 121 : const char *pszLayerName) 122 : { 123 657 : OGRwkbGeometryType eGeomType = wkbUnknown; 124 805 : for (int i = 0; i < oTileStatLayers.Size(); i++) 125 : { 126 1610 : CPLJSONObject oId = oTileStatLayers[i].GetObj("layer"); 127 805 : if (oId.IsValid() && oId.GetType() == CPLJSONObject::Type::String) 128 : { 129 805 : if (oId.ToString() == pszLayerName) 130 : { 131 1971 : CPLJSONObject oGeom = oTileStatLayers[i].GetObj("geometry"); 132 1314 : if (oGeom.IsValid() && 133 657 : oGeom.GetType() == CPLJSONObject::Type::String) 134 : { 135 1971 : const std::string oGeomType(oGeom.ToString()); 136 : // Note: this information is not 137 : // reliable in case 138 : // of mix of geometry types 139 657 : if (oGeomType == "Point") 140 : { 141 118 : eGeomType = wkbMultiPoint; 142 : } 143 539 : else if (oGeomType == "LineString") 144 : { 145 28 : eGeomType = wkbMultiLineString; 146 : } 147 511 : else if (oGeomType == "Polygon") 148 : { 149 511 : eGeomType = wkbMultiPolygon; 150 : } 151 : } 152 657 : break; 153 : } 154 : } 155 : } 156 657 : return eGeomType; 157 : } 158 : 159 : /************************************************************************/ 160 : /* OGRMVTFindAttributesFromTileStat() */ 161 : /************************************************************************/ 162 : 163 : CPLJSONArray 164 1145 : OGRMVTFindAttributesFromTileStat(const CPLJSONArray &oTileStatLayers, 165 : const char *pszLayerName) 166 : { 167 1293 : for (int i = 0; i < oTileStatLayers.Size(); i++) 168 : { 169 1610 : CPLJSONObject oId = oTileStatLayers[i].GetObj("layer"); 170 805 : if (oId.IsValid() && oId.GetType() == CPLJSONObject::Type::String) 171 : { 172 805 : if (oId.ToString() == pszLayerName) 173 : { 174 : CPLJSONObject oAttributes = 175 1314 : oTileStatLayers[i].GetObj("attributes"); 176 1314 : if (oAttributes.IsValid() && 177 657 : oAttributes.GetType() == CPLJSONObject::Type::Array) 178 : { 179 657 : return oAttributes.ToArray(); 180 : } 181 0 : break; 182 : } 183 : } 184 : } 185 976 : CPLJSONArray oAttributes; 186 488 : oAttributes.Deinit(); 187 488 : return oAttributes; 188 : } 189 : 190 : /************************************************************************/ 191 : /* OGRMVTCreateFeatureFrom() */ 192 : /************************************************************************/ 193 : 194 1998 : OGRFeature *OGRMVTCreateFeatureFrom(OGRFeature *poSrcFeature, 195 : OGRFeatureDefn *poTargetFeatureDefn, 196 : bool bJsonField, 197 : const OGRSpatialReference *poSRS) 198 : { 199 1998 : OGRFeature *poFeature = new OGRFeature(poTargetFeatureDefn); 200 1998 : if (bJsonField) 201 : { 202 8 : CPLJSONObject oProperties; 203 4 : bool bEmpty = true; 204 38 : for (int i = 1; i < poSrcFeature->GetFieldCount(); i++) 205 : { 206 34 : if (poSrcFeature->IsFieldSet(i)) 207 : { 208 34 : bEmpty = false; 209 34 : const OGRFieldDefn *poFDefn = poSrcFeature->GetFieldDefnRef(i); 210 34 : if (poSrcFeature->IsFieldNull(i)) 211 : { 212 0 : oProperties.AddNull(poFDefn->GetNameRef()); 213 : } 214 52 : else if (poFDefn->GetType() == OFTInteger || 215 18 : poFDefn->GetType() == OFTInteger64) 216 : { 217 23 : if (poFDefn->GetSubType() == OFSTBoolean) 218 : { 219 6 : oProperties.Add(poFDefn->GetNameRef(), 220 6 : poSrcFeature->GetFieldAsInteger(i) == 221 : 1); 222 : } 223 : else 224 : { 225 17 : oProperties.Add(poFDefn->GetNameRef(), 226 : poSrcFeature->GetFieldAsInteger64(i)); 227 : } 228 : } 229 11 : else if (poFDefn->GetType() == OFTReal) 230 : { 231 7 : oProperties.Add(poFDefn->GetNameRef(), 232 : poSrcFeature->GetFieldAsDouble(i)); 233 : } 234 : else 235 : { 236 4 : oProperties.Add(poFDefn->GetNameRef(), 237 : poSrcFeature->GetFieldAsString(i)); 238 : } 239 : } 240 : } 241 4 : if (!bEmpty) 242 : { 243 4 : poFeature->SetField( 244 8 : "json", oProperties.Format(CPLJSONObject::PrettyFormat::Pretty) 245 : .c_str()); 246 : } 247 : 248 4 : OGRGeometry *poSrcGeom = poSrcFeature->GetGeometryRef(); 249 4 : if (poSrcGeom) 250 : { 251 4 : poFeature->SetGeometry(poSrcGeom); 252 : } 253 : #ifdef nodef 254 : CPLJSONObject oObj; 255 : oObj.Add("type", "Feature"); 256 : if (poSrcFeature->IsFieldSet(0)) 257 : oObj.Add("id", poSrcFeature->GetFieldAsInteger64("mvt_id")); 258 : oObj.Add("properties", oProperties); 259 : if (poSrcGeom) 260 : { 261 : char *pszGeomJson = 262 : OGR_G_ExportToJson(OGRGeometry::ToHandle(poSrcGeom)); 263 : CPLJSONDocument oJSonDoc; 264 : oJSonDoc.LoadMemory(reinterpret_cast<const GByte *>(pszGeomJson)); 265 : CPLFree(pszGeomJson); 266 : oObj.Add("geometry", oJSonDoc.GetRoot()); 267 : } 268 : poFeature->SetNativeData( 269 : oObj.Format(CPLJSONObject::PrettyFormat::Pretty).c_str()); 270 : poFeature->SetNativeMediaType("application/vnd.geo+json"); 271 : #endif 272 : } 273 : else 274 : { 275 1994 : poFeature->SetFrom(poSrcFeature); 276 : } 277 1998 : OGRGeometry *poGeom = poFeature->GetGeometryRef(); 278 1998 : if (poGeom) 279 1998 : poGeom->assignSpatialReference(poSRS); 280 1998 : return poFeature; 281 : }