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 1110 : void OGRMVTInitFields(OGRFeatureDefn *poFeatureDefn, 21 : const CPLJSONObject &oFields, 22 : const CPLJSONArray &oAttributesFromTileStats) 23 : { 24 : { 25 2220 : OGRFieldDefn oFieldDefnId("mvt_id", OFTInteger64); 26 1110 : poFeatureDefn->AddFieldDefn(&oFieldDefnId); 27 : } 28 : 29 1110 : if (oFields.IsValid()) 30 : { 31 19293 : for (const auto &oField : oFields.GetChildren()) 32 : { 33 18262 : if (oField.GetType() == CPLJSONObject::Type::String) 34 : { 35 18262 : if (oField.ToString() == "Number") 36 : { 37 15744 : OGRFieldDefn oFieldDefn(oField.GetName().c_str(), OFTReal); 38 : 39 197576 : for (int i = 0; i < oAttributesFromTileStats.Size(); ++i) 40 : { 41 392488 : if (oAttributesFromTileStats[i].GetString( 42 595272 : "attribute") == oField.GetName() && 43 202784 : oAttributesFromTileStats[i].GetString("type") == 44 : "number") 45 : { 46 : const auto eMinType = oAttributesFromTileStats[i] 47 13080 : .GetObj("min") 48 6540 : .GetType(); 49 : const auto eMaxType = oAttributesFromTileStats[i] 50 13080 : .GetObj("max") 51 6540 : .GetType(); 52 6540 : if (eMinType == CPLJSONObject::Type::Integer && 53 : eMaxType == CPLJSONObject::Type::Integer) 54 : { 55 6154 : oFieldDefn.SetType(OFTInteger); 56 : } 57 386 : else if ((eMinType == 58 386 : CPLJSONObject::Type::Integer || 59 5 : eMinType == CPLJSONObject::Type::Long) && 60 : eMaxType == CPLJSONObject::Type::Long) 61 : { 62 5 : oFieldDefn.SetType(OFTInteger64); 63 : } 64 6540 : break; 65 : } 66 : } 67 : 68 7872 : poFeatureDefn->AddFieldDefn(&oFieldDefn); 69 : } 70 10390 : 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 10390 : else if (oField.ToString() == "Boolean") 77 : { 78 111 : OGRFieldDefn oFieldDefn(oField.GetName().c_str(), 79 222 : OFTInteger); 80 111 : oFieldDefn.SetSubType(OFSTBoolean); 81 111 : poFeatureDefn->AddFieldDefn(&oFieldDefn); 82 : } 83 : else 84 : { 85 10279 : OGRFieldDefn oFieldDefn(oField.GetName().c_str(), 86 20558 : OFTString); 87 10279 : poFeatureDefn->AddFieldDefn(&oFieldDefn); 88 : } 89 : } 90 : } 91 : } 92 1110 : } 93 : 94 : /************************************************************************/ 95 : /* OGRMVTFindGeomTypeFromTileStat() */ 96 : /************************************************************************/ 97 : 98 : OGRwkbGeometryType 99 628 : OGRMVTFindGeomTypeFromTileStat(const CPLJSONArray &oTileStatLayers, 100 : const char *pszLayerName) 101 : { 102 628 : OGRwkbGeometryType eGeomType = wkbUnknown; 103 771 : for (int i = 0; i < oTileStatLayers.Size(); i++) 104 : { 105 1542 : CPLJSONObject oId = oTileStatLayers[i].GetObj("layer"); 106 771 : if (oId.IsValid() && oId.GetType() == CPLJSONObject::Type::String) 107 : { 108 771 : if (oId.ToString() == pszLayerName) 109 : { 110 1884 : CPLJSONObject oGeom = oTileStatLayers[i].GetObj("geometry"); 111 1256 : if (oGeom.IsValid() && 112 628 : oGeom.GetType() == CPLJSONObject::Type::String) 113 : { 114 1884 : const std::string oGeomType(oGeom.ToString()); 115 : // Note: this information is not 116 : // reliable in case 117 : // of mix of geometry types 118 628 : if (oGeomType == "Point") 119 : { 120 109 : eGeomType = wkbMultiPoint; 121 : } 122 519 : else if (oGeomType == "LineString") 123 : { 124 26 : eGeomType = wkbMultiLineString; 125 : } 126 493 : else if (oGeomType == "Polygon") 127 : { 128 493 : eGeomType = wkbMultiPolygon; 129 : } 130 : } 131 628 : break; 132 : } 133 : } 134 : } 135 628 : return eGeomType; 136 : } 137 : 138 : /************************************************************************/ 139 : /* OGRMVTFindAttributesFromTileStat() */ 140 : /************************************************************************/ 141 : 142 : CPLJSONArray 143 1109 : OGRMVTFindAttributesFromTileStat(const CPLJSONArray &oTileStatLayers, 144 : const char *pszLayerName) 145 : { 146 1252 : for (int i = 0; i < oTileStatLayers.Size(); i++) 147 : { 148 1542 : CPLJSONObject oId = oTileStatLayers[i].GetObj("layer"); 149 771 : if (oId.IsValid() && oId.GetType() == CPLJSONObject::Type::String) 150 : { 151 771 : if (oId.ToString() == pszLayerName) 152 : { 153 : CPLJSONObject oAttributes = 154 1256 : oTileStatLayers[i].GetObj("attributes"); 155 1256 : if (oAttributes.IsValid() && 156 628 : oAttributes.GetType() == CPLJSONObject::Type::Array) 157 : { 158 628 : return oAttributes.ToArray(); 159 : } 160 0 : break; 161 : } 162 : } 163 : } 164 962 : CPLJSONArray oAttributes; 165 481 : oAttributes.Deinit(); 166 481 : return oAttributes; 167 : } 168 : 169 : /************************************************************************/ 170 : /* OGRMVTCreateFeatureFrom() */ 171 : /************************************************************************/ 172 : 173 1928 : OGRFeature *OGRMVTCreateFeatureFrom(OGRFeature *poSrcFeature, 174 : OGRFeatureDefn *poTargetFeatureDefn, 175 : bool bJsonField, OGRSpatialReference *poSRS) 176 : { 177 1928 : OGRFeature *poFeature = new OGRFeature(poTargetFeatureDefn); 178 1928 : if (bJsonField) 179 : { 180 8 : CPLJSONObject oProperties; 181 4 : bool bEmpty = true; 182 38 : for (int i = 1; i < poSrcFeature->GetFieldCount(); i++) 183 : { 184 34 : if (poSrcFeature->IsFieldSet(i)) 185 : { 186 34 : bEmpty = false; 187 34 : OGRFieldDefn *poFDefn = poSrcFeature->GetFieldDefnRef(i); 188 34 : if (poSrcFeature->IsFieldNull(i)) 189 : { 190 0 : oProperties.AddNull(poFDefn->GetNameRef()); 191 : } 192 52 : else if (poFDefn->GetType() == OFTInteger || 193 18 : poFDefn->GetType() == OFTInteger64) 194 : { 195 23 : if (poFDefn->GetSubType() == OFSTBoolean) 196 : { 197 6 : oProperties.Add(poFDefn->GetNameRef(), 198 6 : poSrcFeature->GetFieldAsInteger(i) == 199 : 1); 200 : } 201 : else 202 : { 203 17 : oProperties.Add(poFDefn->GetNameRef(), 204 : poSrcFeature->GetFieldAsInteger64(i)); 205 : } 206 : } 207 11 : else if (poFDefn->GetType() == OFTReal) 208 : { 209 7 : oProperties.Add(poFDefn->GetNameRef(), 210 : poSrcFeature->GetFieldAsDouble(i)); 211 : } 212 : else 213 : { 214 4 : oProperties.Add(poFDefn->GetNameRef(), 215 : poSrcFeature->GetFieldAsString(i)); 216 : } 217 : } 218 : } 219 4 : if (!bEmpty) 220 : { 221 4 : poFeature->SetField( 222 8 : "json", oProperties.Format(CPLJSONObject::PrettyFormat::Pretty) 223 : .c_str()); 224 : } 225 : 226 4 : OGRGeometry *poSrcGeom = poSrcFeature->GetGeometryRef(); 227 4 : if (poSrcGeom) 228 : { 229 4 : poFeature->SetGeometry(poSrcGeom); 230 : } 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 : } 251 : else 252 : { 253 1924 : poFeature->SetFrom(poSrcFeature); 254 : } 255 1928 : OGRGeometry *poGeom = poFeature->GetGeometryRef(); 256 1928 : if (poGeom) 257 1928 : poGeom->assignSpatialReference(poSRS); 258 1928 : return poFeature; 259 : }