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  * Permission is hereby granted, free of charge, to any person obtaining a
11  * copy of this software and associated documentation files (the "Software"),
12  * to deal in the Software without restriction, including without limitation
13  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
14  * and/or sell copies of the Software, and to permit persons to whom the
15  * Software is furnished to do so, subject to the following conditions:
16  *
17  * The above copyright notice and this permission notice shall be included
18  * in all copies or substantial portions of the Software.
19  *
20  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
21  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
23  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26  * DEALINGS IN THE SOFTWARE.
27  ****************************************************************************/
28 
29 #include "mvtutils.h"
30 #include "ogr_api.h"
31 
32 /************************************************************************/
33 /*                        OGRMVTInitFields()                            */
34 /************************************************************************/
35 
OGRMVTInitFields(OGRFeatureDefn * poFeatureDefn,const CPLJSONObject & oFields)36 void OGRMVTInitFields(OGRFeatureDefn* poFeatureDefn,
37                       const CPLJSONObject& oFields)
38 {
39     {
40         OGRFieldDefn oFieldDefnId("mvt_id", OFTInteger64);
41         poFeatureDefn->AddFieldDefn(&oFieldDefnId);
42     }
43 
44     if( oFields.IsValid() )
45     {
46         for( const auto& oField: oFields.GetChildren() )
47         {
48             if( oField.GetType() == CPLJSONObject::Type::String )
49             {
50                 if( oField.ToString() == "Number" )
51                 {
52                     OGRFieldDefn oFieldDefn(
53                         oField.GetName().c_str(), OFTReal );
54                     poFeatureDefn->AddFieldDefn(&oFieldDefn);
55                 }
56                 else if( oField.ToString() == "Integer" ) // GDAL extension
57                 {
58                     OGRFieldDefn oFieldDefn(
59                         oField.GetName().c_str(), OFTInteger );
60                     poFeatureDefn->AddFieldDefn(&oFieldDefn);
61                 }
62                 else if( oField.ToString() == "Boolean" )
63                 {
64                     OGRFieldDefn oFieldDefn(
65                         oField.GetName().c_str(), OFTInteger );
66                     oFieldDefn.SetSubType(OFSTBoolean);
67                     poFeatureDefn->AddFieldDefn(&oFieldDefn);
68                 }
69                 else
70                 {
71                     OGRFieldDefn oFieldDefn(
72                         oField.GetName().c_str(), OFTString );
73                     poFeatureDefn->AddFieldDefn(&oFieldDefn);
74                 }
75             }
76         }
77     }
78 }
79 
80 /************************************************************************/
81 /*                     OGRMVTFindGeomTypeFromTileStat()                 */
82 /************************************************************************/
83 
OGRMVTFindGeomTypeFromTileStat(const CPLJSONArray & oTileStatLayers,const char * pszLayerName)84 OGRwkbGeometryType OGRMVTFindGeomTypeFromTileStat(
85                                 const CPLJSONArray& oTileStatLayers,
86                                 const char* pszLayerName)
87 {
88     OGRwkbGeometryType eGeomType = wkbUnknown;
89     for( int i = 0; i < oTileStatLayers.Size(); i++ )
90     {
91         CPLJSONObject oId =
92             oTileStatLayers[i].GetObj("layer");
93         if( oId.IsValid() && oId.GetType() ==
94                 CPLJSONObject::Type::String )
95         {
96             if( oId.ToString() == pszLayerName )
97             {
98                 CPLJSONObject oGeom =
99                     oTileStatLayers[i].GetObj("geometry");
100                 if( oGeom.IsValid() && oGeom.GetType() ==
101                         CPLJSONObject::Type::String )
102                 {
103                     const std::string oGeomType(
104                         oGeom.ToString());
105                     // Note: this information is not
106                     // reliable in case
107                     // of mix of geometry types
108                     if( oGeomType == "Point" )
109                     {
110                         eGeomType = wkbMultiPoint;
111                     }
112                     else if( oGeomType == "LineString" )
113                     {
114                         eGeomType = wkbMultiLineString;
115                     }
116                     else if( oGeomType == "Polygon" )
117                     {
118                         eGeomType = wkbMultiPolygon;
119                     }
120                 }
121                 break;
122             }
123         }
124     }
125     return eGeomType;
126 }
127 
128 
129 /************************************************************************/
130 /*                     OGRMVTCreateFeatureFrom()                        */
131 /************************************************************************/
132 
OGRMVTCreateFeatureFrom(OGRFeature * poSrcFeature,OGRFeatureDefn * poTargetFeatureDefn,bool bJsonField,OGRSpatialReference * poSRS)133 OGRFeature* OGRMVTCreateFeatureFrom(OGRFeature* poSrcFeature,
134                                     OGRFeatureDefn* poTargetFeatureDefn,
135                                     bool bJsonField,
136                                     OGRSpatialReference* poSRS)
137 {
138     OGRFeature* poFeature = new OGRFeature(poTargetFeatureDefn);
139     if( bJsonField )
140     {
141         CPLJSONObject oProperties;
142         bool bEmpty = true;
143         for( int i = 1; i < poSrcFeature->GetFieldCount(); i++ )
144         {
145             if( poSrcFeature->IsFieldSet(i) )
146             {
147                 bEmpty = false;
148                 OGRFieldDefn* poFDefn = poSrcFeature->GetFieldDefnRef(i);
149                 if( poSrcFeature->IsFieldNull(i) )
150                 {
151                     oProperties.AddNull(poFDefn->GetNameRef());
152                 }
153                 else if( poFDefn->GetType() == OFTInteger ||
154                          poFDefn->GetType() == OFTInteger64 )
155                 {
156                     if( poFDefn->GetSubType() == OFSTBoolean )
157                     {
158                         oProperties.Add(poFDefn->GetNameRef(),
159                                   poSrcFeature->GetFieldAsInteger(i) == 1);
160                     }
161                     else
162                     {
163                         oProperties.Add(poFDefn->GetNameRef(),
164                                   poSrcFeature->GetFieldAsInteger64(i));
165                     }
166                 }
167                 else if( poFDefn->GetType() == OFTReal )
168                 {
169                     oProperties.Add(poFDefn->GetNameRef(),
170                               poSrcFeature->GetFieldAsDouble(i));
171                 }
172                 else
173                 {
174                     oProperties.Add(poFDefn->GetNameRef(),
175                               poSrcFeature->GetFieldAsString(i));
176                 }
177             }
178         }
179         if( !bEmpty )
180         {
181             poFeature->SetField("json",
182                             oProperties.Format(CPLJSONObject::PrettyFormat::Pretty).c_str());
183         }
184 
185         OGRGeometry* poSrcGeom = poSrcFeature->GetGeometryRef();
186         if( poSrcGeom )
187         {
188             poFeature->SetGeometry( poSrcGeom );
189         }
190 #ifdef nodef
191         CPLJSONObject oObj;
192         oObj.Add("type", "Feature");
193         if( poSrcFeature->IsFieldSet(0) )
194             oObj.Add("id", poSrcFeature->GetFieldAsInteger64("mvt_id"));
195         oObj.Add("properties", oProperties);
196         if( poSrcGeom )
197         {
198             char* pszGeomJson = OGR_G_ExportToJson(
199                 reinterpret_cast<OGRGeometryH>(poSrcGeom) );
200             CPLJSONDocument oJSonDoc;
201             oJSonDoc.LoadMemory(reinterpret_cast<const GByte*>(pszGeomJson));
202             CPLFree(pszGeomJson);
203             oObj.Add( "geometry", oJSonDoc.GetRoot() );
204         }
205         poFeature->SetNativeData(
206             oObj.Format(CPLJSONObject::PrettyFormat::Pretty).c_str());
207         poFeature->SetNativeMediaType("application/vnd.geo+json");
208 #endif
209     }
210     else
211     {
212         poFeature->SetFrom( poSrcFeature );
213     }
214     OGRGeometry* poGeom = poFeature->GetGeometryRef();
215     if( poGeom )
216         poGeom->assignSpatialReference(poSRS);
217     return poFeature;
218 }
219