1 : /******************************************************************************
2 : * $Id: ogrgeojsonwriter.cpp 19491 2010-04-21 22:55:17Z rouault $
3 : *
4 : * Project: OpenGIS Simple Features Reference Implementation
5 : * Purpose: Implementation of GeoJSON writer utilities (OGR GeoJSON Driver).
6 : * Author: Mateusz Loskot, mateusz@loskot.net
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2007, Mateusz Loskot
10 : *
11 : * Permission is hereby granted, free of charge, to any person obtaining a
12 : * copy of this software and associated documentation files (the "Software"),
13 : * to deal in the Software without restriction, including without limitation
14 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 : * and/or sell copies of the Software, and to permit persons to whom the
16 : * Software is furnished to do so, subject to the following conditions:
17 : *
18 : * The above copyright notice and this permission notice shall be included
19 : * in all copies or substantial portions of the Software.
20 : *
21 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 : * DEALINGS IN THE SOFTWARE.
28 : ****************************************************************************/
29 : #include "ogrgeojsonwriter.h"
30 : #include "ogrgeojsonutils.h"
31 : #include "ogr_geojson.h"
32 : #include <jsonc/json.h> // JSON-C
33 : #include <ogr_api.h>
34 :
35 : /************************************************************************/
36 : /* OGRGeoJSONWriteFeature */
37 : /************************************************************************/
38 :
39 25 : json_object* OGRGeoJSONWriteFeature( OGRFeature* poFeature )
40 : {
41 25 : CPLAssert( NULL != poFeature );
42 :
43 25 : json_object* poObj = json_object_new_object();
44 25 : CPLAssert( NULL != poObj );
45 :
46 : json_object_object_add( poObj, "type",
47 25 : json_object_new_string("Feature") );
48 :
49 : /* -------------------------------------------------------------------- */
50 : /* Write feature attributes to GeoJSON "properties" object. */
51 : /* -------------------------------------------------------------------- */
52 25 : json_object* poObjProps = NULL;
53 :
54 25 : poObjProps = OGRGeoJSONWriteAttributes( poFeature );
55 25 : json_object_object_add( poObj, "properties", poObjProps );
56 :
57 : /* -------------------------------------------------------------------- */
58 : /* Write feature geometry to GeoJSON "geometry" object. */
59 : /* Null geometries are allowed, according to the GeoJSON Spec. */
60 : /* -------------------------------------------------------------------- */
61 25 : json_object* poObjGeom = NULL;
62 :
63 25 : OGRGeometry* poGeometry = poFeature->GetGeometryRef();
64 25 : if ( NULL != poGeometry )
65 : {
66 25 : poObjGeom = OGRGeoJSONWriteGeometry( poGeometry );
67 25 : CPLAssert( NULL != poObjGeom );
68 : }
69 :
70 25 : json_object_object_add( poObj, "geometry", poObjGeom );
71 :
72 25 : return poObj;
73 : }
74 :
75 : /************************************************************************/
76 : /* OGRGeoJSONWriteGeometry */
77 : /************************************************************************/
78 :
79 25 : json_object* OGRGeoJSONWriteAttributes( OGRFeature* poFeature )
80 : {
81 25 : CPLAssert( NULL != poFeature );
82 :
83 25 : json_object* poObjProps = json_object_new_object();
84 25 : CPLAssert( NULL != poObjProps );
85 :
86 25 : OGRFeatureDefn* poDefn = poFeature->GetDefnRef();
87 51 : for( int nField = 0; nField < poDefn->GetFieldCount(); ++nField )
88 : {
89 26 : json_object* poObjProp = NULL;
90 26 : OGRFieldDefn* poFieldDefn = poDefn->GetFieldDefn( nField );
91 26 : CPLAssert( NULL != poFieldDefn );
92 :
93 26 : if( OFTInteger == poFieldDefn->GetType() )
94 : {
95 : poObjProp = json_object_new_int(
96 0 : poFeature->GetFieldAsInteger( nField ) );
97 : }
98 26 : else if( OFTReal == poFieldDefn->GetType() )
99 : {
100 : poObjProp = json_object_new_double(
101 13 : poFeature->GetFieldAsDouble(nField) );
102 : }
103 13 : else if( OFTString == poFieldDefn->GetType() )
104 : {
105 : poObjProp = json_object_new_string(
106 13 : poFeature->GetFieldAsString(nField) );
107 : }
108 : else
109 : {
110 : poObjProp = json_object_new_string(
111 0 : poFeature->GetFieldAsString(nField) );
112 : }
113 :
114 : json_object_object_add( poObjProps,
115 : poFieldDefn->GetNameRef(),
116 26 : poObjProp );
117 : }
118 :
119 25 : return poObjProps;
120 : }
121 :
122 : /************************************************************************/
123 : /* OGRGeoJSONWriteGeometry */
124 : /************************************************************************/
125 :
126 26 : json_object* OGRGeoJSONWriteGeometry( OGRGeometry* poGeometry )
127 : {
128 26 : CPLAssert( NULL != poGeometry );
129 :
130 26 : json_object* poObj = json_object_new_object();
131 26 : CPLAssert( NULL != poObj );
132 :
133 : /* -------------------------------------------------------------------- */
134 : /* Build "type" member of GeoJSOn "geometry" object. */
135 : /* -------------------------------------------------------------------- */
136 :
137 : // XXX - mloskot: workaround hack for pure JSON-C API design.
138 26 : char* pszName = const_cast<char*>(OGRGeoJSONGetGeometryName( poGeometry ));
139 26 : json_object_object_add( poObj, "type", json_object_new_string(pszName) );
140 :
141 : /* -------------------------------------------------------------------- */
142 : /* Build "coordinates" member of GeoJSOn "geometry" object. */
143 : /* -------------------------------------------------------------------- */
144 26 : json_object* poObjGeom = NULL;
145 :
146 26 : OGRwkbGeometryType eType = poGeometry->getGeometryType();
147 28 : if( wkbGeometryCollection == eType || wkbGeometryCollection25D == eType )
148 : {
149 2 : poObjGeom = OGRGeoJSONWriteGeometryCollection( static_cast<OGRGeometryCollection*>(poGeometry) );
150 2 : json_object_object_add( poObj, "geometries", poObjGeom);
151 : }
152 : else
153 : {
154 27 : if( wkbPoint == eType || wkbPoint25D == eType )
155 3 : poObjGeom = OGRGeoJSONWritePoint( static_cast<OGRPoint*>(poGeometry) );
156 24 : else if( wkbLineString == eType || wkbLineString25D == eType )
157 3 : poObjGeom = OGRGeoJSONWriteLineString( static_cast<OGRLineString*>(poGeometry) );
158 23 : else if( wkbPolygon == eType || wkbPolygon25D == eType )
159 5 : poObjGeom = OGRGeoJSONWritePolygon( static_cast<OGRPolygon*>(poGeometry) );
160 17 : else if( wkbMultiPoint == eType || wkbMultiPoint25D == eType )
161 4 : poObjGeom = OGRGeoJSONWriteMultiPoint( static_cast<OGRMultiPoint*>(poGeometry) );
162 13 : else if( wkbMultiLineString == eType || wkbMultiLineString25D == eType )
163 4 : poObjGeom = OGRGeoJSONWriteMultiLineString( static_cast<OGRMultiLineString*>(poGeometry) );
164 10 : else if( wkbMultiPolygon == eType || wkbMultiPolygon25D == eType )
165 5 : poObjGeom = OGRGeoJSONWriteMultiPolygon( static_cast<OGRMultiPolygon*>(poGeometry) );
166 : else
167 : {
168 : CPLDebug( "GeoJSON",
169 : "Unsupported geometry type detected. "
170 0 : "Feature gets NULL geometry assigned." );
171 : }
172 :
173 24 : json_object_object_add( poObj, "coordinates", poObjGeom);
174 : }
175 :
176 26 : return poObj;
177 : }
178 :
179 : /************************************************************************/
180 : /* OGRGeoJSONWritePoint */
181 : /************************************************************************/
182 :
183 12 : json_object* OGRGeoJSONWritePoint( OGRPoint* poPoint )
184 : {
185 12 : CPLAssert( NULL != poPoint );
186 :
187 12 : json_object* poObj = NULL;
188 :
189 : /* Generate "coordinates" object for 2D or 3D dimension. */
190 12 : if( 3 == poPoint->getCoordinateDimension() )
191 : {
192 : poObj = OGRGeoJSONWriteCoords( poPoint->getX(),
193 : poPoint->getY(),
194 0 : poPoint->getZ() );
195 : }
196 12 : else if( 2 == poPoint->getCoordinateDimension() )
197 : {
198 : poObj = OGRGeoJSONWriteCoords( poPoint->getX(),
199 9 : poPoint->getY() );
200 : }
201 : else
202 : {
203 : /* We can get here with POINT EMPTY geometries */
204 : }
205 :
206 12 : return poObj;
207 : }
208 :
209 : /************************************************************************/
210 : /* OGRGeoJSONWriteLineString */
211 : /************************************************************************/
212 :
213 10 : json_object* OGRGeoJSONWriteLineString( OGRLineString* poLine )
214 : {
215 10 : CPLAssert( NULL != poLine );
216 :
217 : /* Generate "coordinates" object for 2D or 3D dimension. */
218 10 : json_object* poObj = NULL;
219 10 : poObj = OGRGeoJSONWriteLineCoords( poLine );
220 :
221 10 : return poObj;
222 : }
223 :
224 : /************************************************************************/
225 : /* OGRGeoJSONWritePolygon */
226 : /************************************************************************/
227 :
228 15 : json_object* OGRGeoJSONWritePolygon( OGRPolygon* poPolygon )
229 : {
230 15 : CPLAssert( NULL != poPolygon );
231 :
232 : /* Generate "coordinates" array object. */
233 15 : json_object* poObj = NULL;
234 15 : poObj = json_object_new_array();
235 :
236 : /* Exterior ring. */
237 15 : OGRLinearRing* poRing = poPolygon->getExteriorRing();
238 15 : if (poRing == NULL)
239 3 : return poObj;
240 :
241 12 : json_object* poObjRing = NULL;
242 12 : poObjRing = OGRGeoJSONWriteLineCoords( poRing );
243 12 : json_object_array_add( poObj, poObjRing );
244 :
245 : /* Interior rings. */
246 12 : const int nCount = poPolygon->getNumInteriorRings();
247 14 : for( int i = 0; i < nCount; ++i )
248 : {
249 2 : poRing = poPolygon->getInteriorRing( i );
250 2 : if (poRing == NULL)
251 0 : continue;
252 :
253 2 : poObjRing = OGRGeoJSONWriteLineCoords( poRing );
254 :
255 2 : json_object_array_add( poObj, poObjRing );
256 : }
257 :
258 12 : return poObj;
259 : }
260 :
261 : /************************************************************************/
262 : /* OGRGeoJSONWriteMultiPoint */
263 : /************************************************************************/
264 :
265 4 : json_object* OGRGeoJSONWriteMultiPoint( OGRMultiPoint* poGeometry )
266 : {
267 4 : CPLAssert( NULL != poGeometry );
268 :
269 : /* Generate "coordinates" object for 2D or 3D dimension. */
270 4 : json_object* poObj = NULL;
271 4 : poObj = json_object_new_array();
272 :
273 13 : for( int i = 0; i < poGeometry->getNumGeometries(); ++i )
274 : {
275 9 : OGRGeometry* poGeom = poGeometry->getGeometryRef( i );
276 9 : CPLAssert( NULL != poGeom );
277 9 : OGRPoint* poPoint = static_cast<OGRPoint*>(poGeom);
278 :
279 9 : json_object* poObjPoint = NULL;
280 9 : poObjPoint = OGRGeoJSONWritePoint( poPoint );
281 :
282 9 : json_object_array_add( poObj, poObjPoint );
283 : }
284 :
285 4 : return poObj;
286 : }
287 :
288 : /************************************************************************/
289 : /* OGRGeoJSONWriteMultiLineString */
290 : /************************************************************************/
291 :
292 4 : json_object* OGRGeoJSONWriteMultiLineString( OGRMultiLineString* poGeometry )
293 : {
294 4 : CPLAssert( NULL != poGeometry );
295 :
296 : /* Generate "coordinates" object for 2D or 3D dimension. */
297 4 : json_object* poObj = NULL;
298 4 : poObj = json_object_new_array();
299 :
300 11 : for( int i = 0; i < poGeometry->getNumGeometries(); ++i )
301 : {
302 7 : OGRGeometry* poGeom = poGeometry->getGeometryRef( i );
303 7 : CPLAssert( NULL != poGeom );
304 7 : OGRLineString* poLine = static_cast<OGRLineString*>(poGeom);
305 :
306 7 : json_object* poObjLine = NULL;
307 7 : poObjLine = OGRGeoJSONWriteLineString( poLine );
308 :
309 7 : json_object_array_add( poObj, poObjLine );
310 : }
311 :
312 4 : return poObj;
313 : }
314 :
315 : /************************************************************************/
316 : /* OGRGeoJSONWriteMultiPolygon */
317 : /************************************************************************/
318 :
319 5 : json_object* OGRGeoJSONWriteMultiPolygon( OGRMultiPolygon* poGeometry )
320 : {
321 5 : CPLAssert( NULL != poGeometry );
322 :
323 : /* Generate "coordinates" object for 2D or 3D dimension. */
324 5 : json_object* poObj = NULL;
325 5 : poObj = json_object_new_array();
326 :
327 15 : for( int i = 0; i < poGeometry->getNumGeometries(); ++i )
328 : {
329 10 : OGRGeometry* poGeom = poGeometry->getGeometryRef( i );
330 10 : CPLAssert( NULL != poGeom );
331 10 : OGRPolygon* poPoly = static_cast<OGRPolygon*>(poGeom);
332 :
333 10 : json_object* poObjPoly = NULL;
334 10 : poObjPoly = OGRGeoJSONWritePolygon( poPoly );
335 :
336 10 : json_object_array_add( poObj, poObjPoly );
337 : }
338 :
339 5 : return poObj;
340 : }
341 :
342 : /************************************************************************/
343 : /* OGRGeoJSONWriteGeometryCollection */
344 : /************************************************************************/
345 :
346 2 : json_object* OGRGeoJSONWriteGeometryCollection( OGRGeometryCollection* poGeometry )
347 : {
348 2 : CPLAssert( NULL != poGeometry );
349 :
350 : /* Generate "geometries" object. */
351 2 : json_object* poObj = NULL;
352 2 : poObj = json_object_new_array();
353 :
354 3 : for( int i = 0; i < poGeometry->getNumGeometries(); ++i )
355 : {
356 1 : OGRGeometry* poGeom = poGeometry->getGeometryRef( i );
357 1 : CPLAssert( NULL != poGeom );
358 :
359 1 : json_object* poObjGeom = NULL;
360 1 : poObjGeom = OGRGeoJSONWriteGeometry( poGeom );
361 :
362 1 : json_object_array_add( poObj, poObjGeom );
363 : }
364 :
365 2 : return poObj;
366 : }
367 : /************************************************************************/
368 : /* OGRGeoJSONWriteCoords */
369 : /************************************************************************/
370 :
371 76 : json_object* OGRGeoJSONWriteCoords( double const& fX, double const& fY )
372 : {
373 76 : json_object* poObjCoords = NULL;
374 76 : poObjCoords = json_object_new_array();
375 76 : json_object_array_add( poObjCoords, json_object_new_double( fX ) );
376 76 : json_object_array_add( poObjCoords, json_object_new_double( fY ) );
377 :
378 76 : return poObjCoords;
379 : }
380 :
381 0 : json_object* OGRGeoJSONWriteCoords( double const& fX, double const& fY, double const& fZ )
382 : {
383 0 : json_object* poObjCoords = NULL;
384 0 : poObjCoords = json_object_new_array();
385 0 : json_object_array_add( poObjCoords, json_object_new_double( fX ) );
386 0 : json_object_array_add( poObjCoords, json_object_new_double( fY ) );
387 0 : json_object_array_add( poObjCoords, json_object_new_double( fZ ) );
388 :
389 0 : return poObjCoords;
390 : }
391 :
392 : /************************************************************************/
393 : /* OGRGeoJSONWriteLineCoords */
394 : /************************************************************************/
395 :
396 24 : json_object* OGRGeoJSONWriteLineCoords( OGRLineString* poLine )
397 : {
398 24 : json_object* poObjPoint = NULL;
399 24 : json_object* poObjCoords = json_object_new_array();
400 :
401 24 : const int nCount = poLine->getNumPoints();
402 91 : for( int i = 0; i < nCount; ++i )
403 : {
404 67 : poObjPoint = OGRGeoJSONWriteCoords( poLine->getX(i), poLine->getY(i) );
405 67 : json_object_array_add( poObjCoords, poObjPoint );
406 : }
407 :
408 24 : return poObjCoords;
409 : }
410 :
411 : /************************************************************************/
412 : /* OGR_G_ExportToJson */
413 : /************************************************************************/
414 :
415 0 : char* OGR_G_ExportToJson( OGRGeometryH hGeometry )
416 : {
417 0 : VALIDATE_POINTER1( hGeometry, "OGR_G_ExportToJson", NULL );
418 :
419 0 : OGRGeometry* poGeometry = (OGRGeometry*) (hGeometry);
420 :
421 0 : json_object* poObj = NULL;
422 0 : poObj = OGRGeoJSONWriteGeometry( poGeometry );
423 :
424 0 : if( NULL != poObj )
425 : {
426 0 : char* pszJson = CPLStrdup( json_object_to_json_string( poObj ) );
427 :
428 : /* Release JSON tree. */
429 0 : json_object_put( poObj );
430 :
431 0 : return pszJson;
432 : }
433 :
434 : /* Translation failed */
435 0 : return NULL;
436 : }
437 :
|