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