1 : /******************************************************************************
2 : * $Id$
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 6 : json_object* OGRGeoJSONWriteFeature( OGRFeature* poFeature )
40 : {
41 : CPLAssert( NULL != poFeature );
42 :
43 6 : json_object* poObj = json_object_new_object();
44 : CPLAssert( NULL != poObj );
45 :
46 : json_object_object_add( poObj, "type",
47 6 : json_object_new_string("Feature") );
48 :
49 : /* -------------------------------------------------------------------- */
50 : /* Write feature attributes to GeoJSON "properties" object. */
51 : /* -------------------------------------------------------------------- */
52 6 : json_object* poObjProps = NULL;
53 :
54 6 : poObjProps = OGRGeoJSONWriteAttributes( poFeature );
55 6 : 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 6 : json_object* poObjGeom = NULL;
62 :
63 6 : OGRGeometry* poGeometry = poFeature->GetGeometryRef();
64 6 : if ( NULL != poGeometry )
65 : {
66 6 : poObjGeom = OGRGeoJSONWriteGeometry( poGeometry );
67 : CPLAssert( NULL != poObjGeom );
68 : }
69 :
70 6 : json_object_object_add( poObj, "geometry", poObjGeom );
71 :
72 6 : return poObj;
73 : }
74 :
75 : /************************************************************************/
76 : /* OGRGeoJSONWriteGeometry */
77 : /************************************************************************/
78 :
79 6 : json_object* OGRGeoJSONWriteAttributes( OGRFeature* poFeature )
80 : {
81 : CPLAssert( NULL != poFeature );
82 :
83 6 : json_object* poObjProps = json_object_new_object();
84 : CPLAssert( NULL != poObjProps );
85 :
86 6 : OGRFeatureDefn* poDefn = poFeature->GetDefnRef();
87 18 : for( int nField = 0; nField < poDefn->GetFieldCount(); ++nField )
88 : {
89 12 : json_object* poObjProp = NULL;
90 12 : OGRFieldDefn* poFieldDefn = poDefn->GetFieldDefn( nField );
91 : CPLAssert( NULL != poFieldDefn );
92 :
93 12 : if( OFTInteger == poFieldDefn->GetType() )
94 : {
95 : poObjProp = json_object_new_int(
96 0 : poFeature->GetFieldAsInteger( nField ) );
97 : }
98 12 : else if( OFTReal == poFieldDefn->GetType() )
99 : {
100 : poObjProp = json_object_new_double(
101 6 : poFeature->GetFieldAsDouble(nField) );
102 : }
103 6 : else if( OFTString == poFieldDefn->GetType() )
104 : {
105 : poObjProp = json_object_new_string(
106 6 : 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 12 : poObjProp );
117 : }
118 :
119 6 : return poObjProps;
120 : }
121 :
122 : /************************************************************************/
123 : /* OGRGeoJSONWriteGeometry */
124 : /************************************************************************/
125 :
126 6 : json_object* OGRGeoJSONWriteGeometry( OGRGeometry* poGeometry )
127 : {
128 : CPLAssert( NULL != poGeometry );
129 :
130 6 : json_object* poObj = json_object_new_object();
131 : 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 6 : char* pszName = const_cast<char*>(OGRGeoJSONGetGeometryName( poGeometry ));
139 6 : json_object_object_add( poObj, "type", json_object_new_string(pszName) );
140 :
141 : /* -------------------------------------------------------------------- */
142 : /* Build "coordinates" member of GeoJSOn "geometry" object. */
143 : /* -------------------------------------------------------------------- */
144 6 : json_object* poObjGeom = NULL;
145 :
146 6 : OGRwkbGeometryType eType = poGeometry->getGeometryType();
147 6 : if( wkbGeometryCollection == eType || wkbGeometryCollection25D == eType )
148 : {
149 0 : poObjGeom = OGRGeoJSONWriteGeometryCollection( static_cast<OGRGeometryCollection*>(poGeometry) );
150 0 : json_object_object_add( poObj, "geometries", poObjGeom);
151 : }
152 : else
153 : {
154 7 : if( wkbPoint == eType || wkbPoint25D == eType )
155 1 : poObjGeom = OGRGeoJSONWritePoint( static_cast<OGRPoint*>(poGeometry) );
156 6 : else if( wkbLineString == eType || wkbLineString25D == eType )
157 1 : poObjGeom = OGRGeoJSONWriteLineString( static_cast<OGRLineString*>(poGeometry) );
158 5 : else if( wkbPolygon == eType || wkbPolygon25D == eType )
159 1 : poObjGeom = OGRGeoJSONWritePolygon( static_cast<OGRPolygon*>(poGeometry) );
160 4 : else if( wkbMultiPoint == eType || wkbMultiPoint25D == eType )
161 1 : poObjGeom = OGRGeoJSONWriteMultiPoint( static_cast<OGRMultiPoint*>(poGeometry) );
162 3 : else if( wkbMultiLineString == eType || wkbMultiLineString25D == eType )
163 1 : poObjGeom = OGRGeoJSONWriteMultiLineString( static_cast<OGRMultiLineString*>(poGeometry) );
164 2 : else if( wkbMultiPolygon == eType || wkbMultiPolygon25D == eType )
165 1 : 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 6 : json_object_object_add( poObj, "coordinates", poObjGeom);
174 : }
175 :
176 6 : return poObj;
177 : }
178 :
179 : /************************************************************************/
180 : /* OGRGeoJSONWritePoint */
181 : /************************************************************************/
182 :
183 3 : json_object* OGRGeoJSONWritePoint( OGRPoint* poPoint )
184 : {
185 : CPLAssert( NULL != poPoint );
186 :
187 3 : json_object* poObj = NULL;
188 :
189 : /* Generate "coordinates" object for 2D or 3D dimension. */
190 3 : if( 3 == poPoint->getCoordinateDimension() )
191 : {
192 : poObj = OGRGeoJSONWriteCoords( poPoint->getX(),
193 : poPoint->getY(),
194 0 : poPoint->getZ() );
195 : }
196 3 : else if( 2 == poPoint->getCoordinateDimension() )
197 : {
198 : poObj = OGRGeoJSONWriteCoords( poPoint->getX(),
199 3 : poPoint->getY() );
200 : }
201 : else
202 : {
203 : CPLAssert( !"SHOULD NEVER GET HERE" );
204 : }
205 :
206 3 : return poObj;
207 : }
208 :
209 : /************************************************************************/
210 : /* OGRGeoJSONWriteLineString */
211 : /************************************************************************/
212 :
213 3 : json_object* OGRGeoJSONWriteLineString( OGRLineString* poLine )
214 : {
215 : CPLAssert( NULL != poLine );
216 :
217 : /* Generate "coordinates" object for 2D or 3D dimension. */
218 3 : json_object* poObj = NULL;
219 3 : poObj = OGRGeoJSONWriteLineCoords( poLine );
220 :
221 3 : return poObj;
222 : }
223 :
224 : /************************************************************************/
225 : /* OGRGeoJSONWritePolygon */
226 : /************************************************************************/
227 :
228 4 : json_object* OGRGeoJSONWritePolygon( OGRPolygon* poPolygon )
229 : {
230 : CPLAssert( NULL != poPolygon );
231 :
232 : /* Generate "coordinates" array object. */
233 4 : json_object* poObj = NULL;
234 4 : poObj = json_object_new_array();
235 :
236 : /* Exterior ring. */
237 4 : OGRLinearRing* poRing = poPolygon->getExteriorRing();
238 :
239 4 : json_object* poObjRing = NULL;
240 4 : poObjRing = OGRGeoJSONWriteLineCoords( poRing );
241 4 : json_object_array_add( poObj, poObjRing );
242 :
243 : /* Interior rings. */
244 4 : const int nCount = poPolygon->getNumInteriorRings();
245 4 : for( int i = 0; i < nCount; ++i )
246 : {
247 0 : poRing = poPolygon->getInteriorRing( i );
248 0 : poObjRing = OGRGeoJSONWriteLineCoords( poRing );
249 :
250 0 : json_object_array_add( poObj, poObjRing );
251 : }
252 :
253 4 : return poObj;
254 : }
255 :
256 : /************************************************************************/
257 : /* OGRGeoJSONWriteMultiPoint */
258 : /************************************************************************/
259 :
260 1 : json_object* OGRGeoJSONWriteMultiPoint( OGRMultiPoint* poGeometry )
261 : {
262 : CPLAssert( NULL != poGeometry );
263 :
264 : /* Generate "coordinates" object for 2D or 3D dimension. */
265 1 : json_object* poObj = NULL;
266 1 : poObj = json_object_new_array();
267 :
268 3 : for( int i = 0; i < poGeometry->getNumGeometries(); ++i )
269 : {
270 2 : OGRGeometry* poGeom = poGeometry->getGeometryRef( i );
271 : CPLAssert( NULL != poGeom );
272 2 : OGRPoint* poPoint = static_cast<OGRPoint*>(poGeom);
273 :
274 2 : json_object* poObjPoint = NULL;
275 2 : poObjPoint = OGRGeoJSONWritePoint( poPoint );
276 :
277 2 : json_object_array_add( poObj, poObjPoint );
278 : }
279 :
280 1 : return poObj;
281 : }
282 :
283 : /************************************************************************/
284 : /* OGRGeoJSONWriteMultiLineString */
285 : /************************************************************************/
286 :
287 1 : json_object* OGRGeoJSONWriteMultiLineString( OGRMultiLineString* poGeometry )
288 : {
289 : CPLAssert( NULL != poGeometry );
290 :
291 : /* Generate "coordinates" object for 2D or 3D dimension. */
292 1 : json_object* poObj = NULL;
293 1 : poObj = json_object_new_array();
294 :
295 3 : for( int i = 0; i < poGeometry->getNumGeometries(); ++i )
296 : {
297 2 : OGRGeometry* poGeom = poGeometry->getGeometryRef( i );
298 : CPLAssert( NULL != poGeom );
299 2 : OGRLineString* poLine = static_cast<OGRLineString*>(poGeom);
300 :
301 2 : json_object* poObjLine = NULL;
302 2 : poObjLine = OGRGeoJSONWriteLineString( poLine );
303 :
304 2 : json_object_array_add( poObj, poObjLine );
305 : }
306 :
307 1 : return poObj;
308 : }
309 :
310 : /************************************************************************/
311 : /* OGRGeoJSONWriteMultiPolygon */
312 : /************************************************************************/
313 :
314 1 : json_object* OGRGeoJSONWriteMultiPolygon( OGRMultiPolygon* poGeometry )
315 : {
316 : CPLAssert( NULL != poGeometry );
317 :
318 : /* Generate "coordinates" object for 2D or 3D dimension. */
319 1 : json_object* poObj = NULL;
320 1 : poObj = json_object_new_array();
321 :
322 4 : for( int i = 0; i < poGeometry->getNumGeometries(); ++i )
323 : {
324 3 : OGRGeometry* poGeom = poGeometry->getGeometryRef( i );
325 : CPLAssert( NULL != poGeom );
326 3 : OGRPolygon* poPoly = static_cast<OGRPolygon*>(poGeom);
327 :
328 3 : json_object* poObjPoly = NULL;
329 3 : poObjPoly = OGRGeoJSONWritePolygon( poPoly );
330 :
331 3 : json_object_array_add( poObj, poObjPoly );
332 : }
333 :
334 1 : return poObj;
335 : }
336 :
337 : /************************************************************************/
338 : /* OGRGeoJSONWriteGeometryCollection */
339 : /************************************************************************/
340 :
341 0 : json_object* OGRGeoJSONWriteGeometryCollection( OGRGeometryCollection* poGeometry )
342 : {
343 : CPLAssert( NULL != poGeometry );
344 :
345 : /* Generate "geometries" object. */
346 0 : json_object* poObj = NULL;
347 0 : poObj = json_object_new_array();
348 :
349 0 : for( int i = 0; i < poGeometry->getNumGeometries(); ++i )
350 : {
351 0 : OGRGeometry* poGeom = poGeometry->getGeometryRef( i );
352 : CPLAssert( NULL != poGeom );
353 :
354 0 : json_object* poObjGeom = NULL;
355 0 : poObjGeom = OGRGeoJSONWriteGeometry( poGeom );
356 :
357 0 : json_object_array_add( poObj, poObjGeom );
358 : }
359 :
360 0 : return poObj;
361 : }
362 : /************************************************************************/
363 : /* OGRGeoJSONWriteCoords */
364 : /************************************************************************/
365 :
366 29 : json_object* OGRGeoJSONWriteCoords( double const& fX, double const& fY )
367 : {
368 29 : json_object* poObjCoords = NULL;
369 29 : poObjCoords = json_object_new_array();
370 29 : json_object_array_add( poObjCoords, json_object_new_double( fX ) );
371 29 : json_object_array_add( poObjCoords, json_object_new_double( fY ) );
372 :
373 29 : return poObjCoords;
374 : }
375 :
376 0 : json_object* OGRGeoJSONWriteCoords( double const& fX, double const& fY, double const& fZ )
377 : {
378 0 : json_object* poObjCoords = NULL;
379 0 : poObjCoords = json_object_new_array();
380 0 : json_object_array_add( poObjCoords, json_object_new_double( fX ) );
381 0 : json_object_array_add( poObjCoords, json_object_new_double( fY ) );
382 0 : json_object_array_add( poObjCoords, json_object_new_double( fZ ) );
383 :
384 0 : return poObjCoords;
385 : }
386 :
387 : /************************************************************************/
388 : /* OGRGeoJSONWriteLineCoords */
389 : /************************************************************************/
390 :
391 7 : json_object* OGRGeoJSONWriteLineCoords( OGRLineString* poLine )
392 : {
393 7 : json_object* poObjPoint = NULL;
394 7 : json_object* poObjCoords = json_object_new_array();
395 :
396 7 : const int nCount = poLine->getNumPoints();
397 33 : for( int i = 0; i < nCount; ++i )
398 : {
399 26 : poObjPoint = OGRGeoJSONWriteCoords( poLine->getX(i), poLine->getY(i) );
400 26 : json_object_array_add( poObjCoords, poObjPoint );
401 : }
402 :
403 7 : return poObjCoords;
404 : }
405 :
406 : /************************************************************************/
407 : /* OGR_G_ExportToJson */
408 : /************************************************************************/
409 :
410 0 : char* OGR_G_ExportToJson( OGRGeometryH hGeometry )
411 : {
412 0 : VALIDATE_POINTER1( hGeometry, "OGR_G_ExportToJson", NULL );
413 :
414 0 : OGRGeometry* poGeometry = (OGRGeometry*) (hGeometry);
415 :
416 0 : json_object* poObj = NULL;
417 0 : poObj = OGRGeoJSONWriteGeometry( poGeometry );
418 :
419 0 : if( NULL != poObj )
420 : {
421 0 : char* pszJson = CPLStrdup( json_object_to_json_string( poObj ) );
422 :
423 : /* Release JSON tree. */
424 0 : json_object_put( poObj );
425 :
426 0 : return pszJson;
427 : }
428 :
429 : /* Translation failed */
430 0 : return NULL;
431 : }
432 :
|