]> granicus.if.org Git - postgis/commitdiff
Add ST_GeomFromGeoJSON (#376)
authorPaul Ramsey <pramsey@cleverelephant.ca>
Fri, 18 Nov 2011 00:17:56 +0000 (00:17 +0000)
committerPaul Ramsey <pramsey@cleverelephant.ca>
Fri, 18 Nov 2011 00:17:56 +0000 (00:17 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@8167 b70326c6-7e19-0410-871a-916f4a2858ee

12 files changed:
configure.ac
doc/installation.xml
postgis/Makefile.in
postgis/geometry_estimate.c
postgis/lwgeom_export.c
postgis/lwgeom_export.h
postgis/lwgeom_in_geojson.c [new file with mode: 0644]
postgis/postgis.sql.in.c
postgis_config.h.in
regress/Makefile.in
regress/in_geojson.sql [new file with mode: 0644]
regress/in_geojson_expected [new file with mode: 0644]

index c1734663dd4ed6c6dd242c30dca0a73fa8d455d8..702ac78456e46871d8ae745dd2a79ed7239c3e24 100644 (file)
@@ -575,7 +575,7 @@ AC_ARG_WITH([projdir],
 if test ! "x$PROJDIR" = "x"; then
        dnl Make sure that the directory exists 
        if test "x$PROJDIR" = "xyes"; then
-               AC_MSG_ERROR([you must specifiy a parameter to --with-projdir, e.g. --with-projdir=/path/to])
+               AC_MSG_ERROR([you must specify a parameter to --with-projdir, e.g. --with-projdir=/path/to])
        else
                if test -d "$PROJDIR"; then
                        AC_MSG_RESULT([Using user-specified proj directory: $PROJDIR])
@@ -618,6 +618,53 @@ AC_CHECK_LIB([proj], [pj_get_release],
        [])
 LIBS="$LIBS_SAVE"
 
+dnl ===========================================================================
+dnl Detect if json-c installed
+dnl ===========================================================================
+
+HAVE_JSON=No
+
+AC_ARG_WITH([jsondir],
+       [AS_HELP_STRING([--with-jsondir=PATH], [specify the json-c installation directory])],
+       [JSONDIR="$withval"], [JSONDIR=])
+
+if test ! "x$JSONDIR" = "x"; then
+       dnl Make sure that the directory exists
+       if test "x$JSONDIR" = "xyes"; then
+               AC_MSG_ERROR([you must specify a parameter to --with-jsondir, e.g. --with-jsondir=/path/to])
+       else
+               if test -d "$JSONDIR"; then
+                       AC_MSG_RESULT([Using user-specified json-c directory: $JSONDIR])
+
+                       dnl Add the include directory to JSON_CPPFLAGS
+                       JSON_CPPFLAGS="-I$JSONDIR/include"
+                       JSON_LDFLAGS="-L$JSONDIR/lib"
+
+                       dnl Check that we can find the json/json.h header file
+                       CPPFLAGS_SAVE="$CPPFLAGS"
+                       CPPFLAGS="$JSON_CPPFLAGS"
+                       AC_CHECK_HEADER([json/json.h], [], [AC_MSG_ERROR([could not find json/json.h - you may need to specify the directory of a json-c installation using --with-jsondir])])  
+                       CPPFLAGS="$CPPFLAGS_SAVE"
+
+                       dnl Ensure we can link against libjson
+                       LIBS_SAVE="$LIBS"
+                       LIBS="$JSON_LDFLAGS"
+                       AC_CHECK_LIB([json], [json_object_get],
+                               [],
+                               [AC_MSG_ERROR([could not find libjson - you may need to specify the directory of a json-c installation using --with-jsondir])],
+                               [])
+                       LIBS="$LIBS_SAVE"
+                       HAVE_JSON=Yes
+               else
+                       AC_MSG_ERROR([the --with-jsondir directory "$JSONDIR" cannot be found])
+               fi
+       fi
+fi
+
+AC_SUBST([JSON_CPPFLAGS])
+AC_SUBST([JSON_LDFLAGS])
+AC_SUBST([HAVE_JSON])
+
 dnl ===========================================================================
 dnl Detect GTK+2.0 for GUI
 dnl ===========================================================================
@@ -709,10 +756,10 @@ dnl Always enable use of ANALYZE statistics by default
 AC_DEFINE_UNQUOTED([POSTGIS_USE_STATS], [1], [Enable use of ANALYZE statistics])
 
 
-CPPFLAGS="$PGSQL_CPPFLAGS $GEOS_CPPFLAGS $PROJ_CPPFLAGS $XML2_CPPFLAGS"
+CPPFLAGS="$PGSQL_CPPFLAGS $GEOS_CPPFLAGS $PROJ_CPPFLAGS $JSON_CPPFLAGS $XML2_CPPFLAGS"
 dnl AC_MSG_RESULT([CPPFLAGS: $CPPFLAGS])
 
-SHLIB_LINK="$PGSQL_LDFLAGS $GEOS_LDFLAGS $PROJ_LDFLAGS -lgeos_c -lproj $XML2_LDFLAGS"
+SHLIB_LINK="$PGSQL_LDFLAGS $GEOS_LDFLAGS $PROJ_LDFLAGS -lgeos_c -lproj $JSON_LDFLAGS -ljson $XML2_LDFLAGS"
 AC_SUBST([SHLIB_LINK])
 dnl AC_MSG_RESULT([SHLIB_LINK: $SHLIB_LINK])
 
@@ -959,6 +1006,7 @@ AC_MSG_RESULT([  PostgreSQL version:   ${PGSQL_FULL_VERSION}])
 AC_MSG_RESULT([  PROJ4 version:        ${POSTGIS_PROJ_VERSION}])
 AC_MSG_RESULT([  Libxml2 config:       ${XML2CONFIG}])
 AC_MSG_RESULT([  Libxml2 version:      ${POSTGIS_LIBXML2_VERSION}])
+AC_MSG_RESULT([  JSON-C support:       ${HAVE_JSON}])
 AC_MSG_RESULT([  PostGIS debug level:  ${POSTGIS_DEBUG_LEVEL}])
 if test "x$RASTER" = "xraster" -o "x$TOPOLOGY" = "xtopology"; then
     AC_MSG_RESULT([ -------------- Extensions -------------- ])
index 65b1401201bbfa737c2f816d7a1172dae1275faa..a2c88d4c558e172d78158fa94de69a8f64fce33a 100644 (file)
@@ -114,6 +114,13 @@ you do a <varname>make comments</varname> or <varname>make topology_comments.sql
                  <ulink url="http://xmlsoft.org/downloads.html">http://xmlsoft.org/downloads.html</ulink>.
                </para>
          </listitem>
+         <listitem>
+               <para>
+                 JSON-C, version 0.9 or higher. JSON-C is currently used to import GeoJSON via the
+                 function ST_GeomFromGeoJson. JSON-C is available for download from
+                 <ulink url="http://oss.metaparadigm.com/json-c/">http://oss.metaparadigm.com/json-c/</ulink>.
+               </para>
+         </listitem>
          
          <listitem>
                <para>
index a433b4b3f73e4b7404650893a88b7193bce0cd1b..b628023e25966c6f1417f6dc6852016452279c81 100644 (file)
@@ -39,6 +39,7 @@ PG_OBJS=lwgeom_debug.o \
        lwgeom_export.o \
        lwgeom_in_gml.o \
        lwgeom_in_kml.o \
+       lwgeom_in_geojson.o \
        lwgeom_triggers.o \
        lwgeom_dump.o \
        lwgeom_functions_lrs.o \
index b6fd89b1300be83227817c11bfe809406047683a..a323f4b4fb37798cf9972f4b878261689efa8586 100644 (file)
@@ -1500,7 +1500,7 @@ Datum geometry_estimated_extent(PG_FUNCTION_ARGS)
        SPIcode = SPI_finish();
        if (SPIcode != SPI_OK_FINISH )
        {
-               elog(ERROR, "geometry_estimated_extent: couldnt disconnect from SPI");
+               elog(ERROR, "geometry_estimated_extent: couldn't disconnect from SPI");
        }
 
        /* TODO: enlarge the box by some factor */
index 226fa732ad036f4cad0bc9b0c7e8b5182fc1379d..2829b64dec447a4ce2145a781aef16dfaa123ccf 100644 (file)
@@ -60,7 +60,7 @@ char * getSRSbySRID(int srid, bool short_crs)
                elog(NOTICE, "getSRSbySRID: error executing query %d", err);\r
                SPI_finish();\r
                return NULL;\r
-       }\r
+       } \r
 \r
        /* no entry in spatial_ref_sys */\r
        if (SPI_processed <= 0)\r
@@ -91,6 +91,70 @@ char * getSRSbySRID(int srid, bool short_crs)
 }\r
 \r
 \r
+/*\r
+* Retrieve an SRID from a given SRS\r
+* Require valid spatial_ref_sys table entry\r
+*\r
+*/\r
+int getSRIDbySRS(const char* srs)\r
+{\r
+       char query[256];\r
+       int srid, err;\r
+\r
+       if (srs == NULL)\r
+               return 0;\r
+\r
+       if (SPI_OK_CONNECT != SPI_connect ())\r
+       {\r
+               elog(NOTICE, "getSRIDbySRS: could not connect to SPI manager");\r
+               SPI_finish();\r
+               return 0;\r
+       }\r
+       sprintf(query, "SELECT srid \\r
+               FROM spatial_ref_sys WHERE auth_name||':'||auth_srid = '%s'", srs);\r
+\r
+       err = SPI_exec(query, 1);\r
+       if ( err < 0 )\r
+       {\r
+               elog(NOTICE, "getSRIDbySRS: error executing query %d", err);\r
+               SPI_finish();\r
+               return 0;\r
+       }\r
+\r
+       /* no entry in spatial_ref_sys */\r
+       if (SPI_processed <= 0)\r
+       {\r
+               sprintf(query, "SELECT srid \\r
+                       FROM spatial_ref_sys WHERE \\r
+                       'urn:ogc:def:crs:'||auth_name||'::'||auth_srid = '%s'", srs);\r
+\r
+               err = SPI_exec(query, 1);\r
+               if ( err < 0 )\r
+               {\r
+                       elog(NOTICE, "getSRIDbySRS: error executing query %d", err);\r
+                       SPI_finish();\r
+                       return 0;\r
+               }\r
+\r
+               if (SPI_processed <= 0) {\r
+                       SPI_finish();\r
+                       return 0;\r
+               }\r
+       }\r
+\r
+       srid = atoi(SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1));\r
+       if ( ! srs )\r
+       {\r
+               SPI_finish();\r
+               return 0;\r
+       }\r
+\r
+       SPI_finish();\r
+\r
+       return srid;\r
+}\r
+\r
+\r
 /**\r
  * Encode feature in GML\r
  */\r
index 2250b8a12e037738b8dd44cb81f983ea5640d54d..842ca7f03fc0f4f20d4563ceb23286894fad5c55 100644 (file)
@@ -10,3 +10,4 @@
  **********************************************************************/
 
 char * getSRSbySRID(int SRID, bool short_crs);
+int getSRIDbySRS(const char* SRS);
diff --git a/postgis/lwgeom_in_geojson.c b/postgis/lwgeom_in_geojson.c
new file mode 100644 (file)
index 0000000..42ee636
--- /dev/null
@@ -0,0 +1,520 @@
+/**********************************************************************
+ *
+ * PostGIS - Spatial Types for PostgreSQL
+ * Copyright 2011 Kashif Rasul <kashif.rasul@gmail.com>
+ *
+ * This is free software; you can redistribute and/or modify it under
+ * the terms of the GNU General Public Licence. See the COPYING file.
+ *
+ **********************************************************************/
+
+#include "postgres.h"
+#include "lwgeom_pg.h"
+#include "liblwgeom.h"
+#include <assert.h>
+
+Datum geom_from_geojson(PG_FUNCTION_ARGS);
+
+
+static void geojson_lwerror(char *msg, int error_code)
+{
+       POSTGIS_DEBUGF(3, "ST_GeomFromGeoJSON ERROR %i", error_code);
+       lwerror("%s", msg);
+}
+
+#ifdef HAVE_LIBJSON
+
+#include "lwgeom_export.h"
+#include <json/json.h>
+#include <json/json_object_private.h>
+
+/* Prototype */
+LWGEOM* parse_geojson(json_object *geojson, bool *hasz,  int *root_srid);
+
+static json_object*
+findMemberByName(json_object* poObj, const char* pszName )
+{
+       json_object* poTmp;
+       json_object_iter it;
+
+       poTmp = poObj;
+
+       if( NULL == pszName || NULL == poObj)
+               return NULL;
+
+       it.key = NULL;
+       it.val = NULL;
+       it.entry = NULL;
+
+       if( NULL != json_object_get_object(poTmp) )
+       {
+               assert( NULL != json_object_get_object(poTmp)->head );
+
+               for( it.entry = json_object_get_object(poTmp)->head;
+                       ( it.entry ?
+                         ( it.key = (char*)it.entry->k,
+                           it.val = (json_object*)it.entry->v, it.entry) : 0);
+                       it.entry = it.entry->next)
+               {
+                       if( strcasecmp((char *)it.key, pszName )==0 )
+                               return it.val;
+               }
+       }
+
+       return NULL;
+}
+
+
+static int
+parse_geojson_coord(json_object *poObj, bool *hasz, POINTARRAY *pa)
+{
+       POINT4D pt;
+       int iType = 0;
+
+       POSTGIS_DEBUGF(3, "parse_geojson_coord called for object %s.", json_object_to_json_string( poObj ) );
+
+       if( json_type_array == json_object_get_type( poObj ) )
+       {
+
+               json_object* poObjCoord = NULL;
+               const int nSize = json_object_array_length( poObj );
+               POSTGIS_DEBUGF(3, "parse_geojson_coord called for array size %d.", nSize );
+
+
+               // Read X coordinate
+               poObjCoord = json_object_array_get_idx( poObj, 0 );
+               iType = json_object_get_type(poObjCoord);
+               if (iType == json_type_double)
+                       pt.x = json_object_get_double( poObjCoord );
+               else
+                       pt.x = json_object_get_int( poObjCoord );
+               POSTGIS_DEBUGF(3, "parse_geojson_coord pt.x = %f.", pt.x );
+
+               // Read Y coordiante
+               poObjCoord = json_object_array_get_idx( poObj, 1 );
+               if (iType == json_type_double)
+                       pt.y = json_object_get_double( poObjCoord );
+               else
+                       pt.y = json_object_get_int( poObjCoord );
+               POSTGIS_DEBUGF(3, "parse_geojson_coord pt.y = %f.", pt.y );
+
+               *hasz = false;
+
+               if( nSize == 3 )
+               {
+                       // Read Z coordiante
+                       poObjCoord = json_object_array_get_idx( poObj, 2 );
+                       if (iType == 3)
+                               pt.z = json_object_get_double( poObjCoord );
+                       else
+                               pt.z = json_object_get_int( poObjCoord );
+                       POSTGIS_DEBUGF(3, "parse_geojson_coord pt.z = %f.", pt.z );
+                       *hasz = true;
+               }
+       }
+
+       return ptarray_append_point(pa, &pt, LW_FALSE);
+}
+
+static LWGEOM*
+parse_geojson_point(json_object *geojson, bool *hasz,  int *root_srid)
+{
+       LWGEOM *geom;
+       POINTARRAY *pa;
+       json_object* coords = NULL;
+
+       POSTGIS_DEBUGF(3, "parse_geojson_point called with root_srid = %d.", *root_srid );
+
+       coords = findMemberByName( geojson, "coordinates" );
+
+       pa = ptarray_construct_empty(1, 0, 1);
+       parse_geojson_coord(coords, hasz, pa);
+
+       geom = (LWGEOM *) lwpoint_construct(*root_srid, NULL, pa);
+       POSTGIS_DEBUG(2, "parse_geojson_point finished.");
+       return geom;
+}
+
+static LWGEOM*
+parse_geojson_linestring(json_object *geojson, bool *hasz,  int *root_srid)
+{
+       LWGEOM *geom;
+       POINTARRAY *pa;
+       json_object* points = NULL;
+       int i = 0;
+
+       POSTGIS_DEBUG(2, "parse_geojson_linestring called.");
+
+       points = findMemberByName( geojson, "coordinates" );
+
+       pa = ptarray_construct_empty(1, 0, 1);
+
+       if( json_type_array == json_object_get_type( points ) )
+       {
+               const int nPoints = json_object_array_length( points );
+               for(i = 0; i < nPoints; ++i)
+               {
+                       json_object* coords = NULL;
+                       coords = json_object_array_get_idx( points, i );
+                       parse_geojson_coord(coords, hasz, pa);
+               }
+       }
+
+       geom = (LWGEOM *) lwline_construct(*root_srid, NULL, pa);
+
+       POSTGIS_DEBUG(2, "parse_geojson_linestring finished.");
+       return geom;
+}
+
+static LWGEOM*
+parse_geojson_polygon(json_object *geojson, bool *hasz,  int *root_srid)
+{
+       LWGEOM *geom;
+       POINTARRAY **ppa;
+       json_object* rings = NULL;
+       int i = 0, j = 0;
+       int ring = 0;
+
+       rings = findMemberByName( geojson, "coordinates" );
+
+       ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
+
+       if( json_type_array == json_object_get_type( rings ) )
+       {
+               int nPoints;
+               json_object* points = NULL;
+               ppa[0] = ptarray_construct_empty(1, 0, 1);
+               ring = json_object_array_length( rings );
+               points = json_object_array_get_idx( rings, 0 );
+               nPoints = json_object_array_length( points );
+
+               for (i=0; i < nPoints; i++ )
+               {
+                       json_object* coords = NULL;
+                       coords = json_object_array_get_idx( points, i );
+                       parse_geojson_coord(coords, hasz, ppa[0]);
+               }
+
+               for(i = 1; i < ring; ++i)
+               {
+                       int nPoints;
+                       ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa, sizeof(POINTARRAY*) * (i + 1));
+                       ppa[i] = ptarray_construct_empty(1, 0, 1);
+                       points = json_object_array_get_idx( rings, i );
+                       nPoints = json_object_array_length( points );
+                       for (j=0; j < nPoints; j++ )
+                       {
+                               json_object* coords = NULL;
+                               coords = json_object_array_get_idx( points, j );
+                               parse_geojson_coord(coords, hasz, ppa[i]);
+                       }
+               }
+       }
+
+       geom = (LWGEOM *) lwpoly_construct(*root_srid, NULL, ring, ppa);
+       return geom;
+}
+
+static LWGEOM*
+parse_geojson_multipoint(json_object *geojson, bool *hasz,  int *root_srid)
+{
+       LWGEOM *geom;
+       int i = 0;
+       json_object* poObjPoints = NULL;
+
+       if (!*root_srid)
+       {
+               geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOINTTYPE, *root_srid, 1, 0);
+       }
+       else
+       {
+               geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOINTTYPE, -1, 1, 0);
+       }
+
+       poObjPoints = findMemberByName( geojson, "coordinates" );
+
+       if( json_type_array == json_object_get_type( poObjPoints ) )
+       {
+               const int nPoints = json_object_array_length( poObjPoints );
+               for( i = 0; i < nPoints; ++i)
+               {
+                       POINTARRAY *pa;
+                       json_object* poObjCoords = NULL;
+                       poObjCoords = json_object_array_get_idx( poObjPoints, i );
+
+                       pa = ptarray_construct_empty(1, 0, 1);
+                       parse_geojson_coord(poObjCoords, hasz, pa);
+
+                       geom = (LWGEOM*)lwmpoint_add_lwpoint((LWMPOINT*)geom,
+                                                            (LWPOINT*)lwpoint_construct(*root_srid, NULL, pa));
+               }
+       }
+
+       return geom;
+}
+
+static LWGEOM*
+parse_geojson_multilinestring(json_object *geojson, bool *hasz,  int *root_srid)
+{
+       LWGEOM *geom = NULL;
+       int i, j;
+       json_object* poObjLines = NULL;
+
+       if (!*root_srid)
+       {
+               geom = (LWGEOM *)lwcollection_construct_empty(MULTILINETYPE, *root_srid, 1, 0);
+       }
+       else
+       {
+               geom = (LWGEOM *)lwcollection_construct_empty(MULTILINETYPE, -1, 1, 0);
+       }
+
+       poObjLines = findMemberByName( geojson, "coordinates" );
+
+       if( json_type_array == json_object_get_type( poObjLines ) )
+       {
+               const int nLines = json_object_array_length( poObjLines );
+               for( i = 0; i < nLines; ++i)
+               {
+                       POINTARRAY *pa = NULL;
+                       json_object* poObjLine = NULL;
+                       poObjLine = json_object_array_get_idx( poObjLines, i );
+                       pa = ptarray_construct_empty(1, 0, 1);
+
+                       if( json_type_array == json_object_get_type( poObjLine ) )
+                       {
+                               const int nPoints = json_object_array_length( poObjLine );
+                               for(j = 0; j < nPoints; ++j)
+                               {
+                                       json_object* coords = NULL;
+                                       coords = json_object_array_get_idx( poObjLine, j );
+                                       parse_geojson_coord(coords, hasz, pa);
+                               }
+
+                               geom = (LWGEOM*)lwmline_add_lwline((LWMLINE*)geom,
+                                                                  (LWLINE*)lwline_construct(*root_srid, NULL, pa));
+                       }
+               }
+       }
+
+       return geom;
+}
+
+static LWGEOM*
+parse_geojson_multipolygon(json_object *geojson, bool *hasz,  int *root_srid)
+{
+       LWGEOM *geom = NULL;
+       int i, j, k;
+       json_object* poObjPolys = NULL;
+
+       if (!*root_srid)
+       {
+               geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, *root_srid, 1, 0);
+       }
+       else
+       {
+               geom = (LWGEOM *)lwcollection_construct_empty(MULTIPOLYGONTYPE, -1, 1, 0);
+       }
+
+       poObjPolys = findMemberByName( geojson, "coordinates" );
+
+       if( json_type_array == json_object_get_type( poObjPolys ) )
+       {
+               const int nPolys = json_object_array_length( poObjPolys );
+
+               for(i = 0; i < nPolys; ++i)
+               {
+                       POINTARRAY **ppa;
+                       json_object* poObjPoly = NULL;
+                       poObjPoly = json_object_array_get_idx( poObjPolys, i );
+
+                       ppa = (POINTARRAY**) lwalloc(sizeof(POINTARRAY*));
+
+                       if( json_type_array == json_object_get_type( poObjPoly ) )
+                       {
+                               int nPoints;
+                               json_object* points = NULL;
+                               int ring = json_object_array_length( poObjPoly );
+                               ppa[0] = ptarray_construct_empty(1, 0, 1);
+
+                               points = json_object_array_get_idx( poObjPoly, 0 );
+                               nPoints = json_object_array_length( points );
+
+                               for (j=0; j < nPoints; j++ )
+                               {
+                                       json_object* coords = NULL;
+                                       coords = json_object_array_get_idx( points, j );
+                                       parse_geojson_coord(coords, hasz, ppa[0]);
+                               }
+
+                               for(j = 1; j < ring; ++j)
+                               {
+                                       int nPoints;
+                                       ppa = (POINTARRAY**) lwrealloc((POINTARRAY *) ppa, sizeof(POINTARRAY*) * (j + 1));
+                                       ppa[i] = ptarray_construct_empty(1, 0, 1);
+                                       points = json_object_array_get_idx( poObjPoly, j );
+
+                                       nPoints = json_object_array_length( points );
+                                       for (k=0; k < nPoints; k++ )
+                                       {
+                                               json_object* coords = NULL;
+                                               coords = json_object_array_get_idx( points, k );
+                                               parse_geojson_coord(coords, hasz, ppa[i]);
+                                       }
+                               }
+
+                               geom = (LWGEOM*)lwmpoly_add_lwpoly((LWMPOLY*)geom,
+                                                                  (LWPOLY*)lwpoly_construct(*root_srid, NULL, ring, ppa));
+                       }
+               }
+       }
+
+       return geom;
+}
+
+static LWGEOM*
+parse_geojson_geometrycollection(json_object *geojson, bool *hasz,  int *root_srid)
+{
+       LWGEOM *geom = NULL;
+       int i;
+       json_object* poObjGeoms = NULL;
+
+       if (!*root_srid)
+       {
+               geom = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, *root_srid, 1, 0);
+       }
+       else
+       {
+               geom = (LWGEOM *)lwcollection_construct_empty(COLLECTIONTYPE, -1, 1, 0);
+       }
+
+       poObjGeoms = findMemberByName( geojson, "geometries" );
+
+       if( json_type_array == json_object_get_type( poObjGeoms ) )
+       {
+               const int nGeoms = json_object_array_length( poObjGeoms );
+               json_object* poObjGeom = NULL;
+               for(i = 0; i < nGeoms; ++i )
+               {
+                       poObjGeom = json_object_array_get_idx( poObjGeoms, i );
+                       geom = (LWGEOM*)lwcollection_add_lwgeom((LWCOLLECTION *)geom,
+                                                               parse_geojson(poObjGeom, hasz, root_srid));
+               }
+       }
+
+       return geom;
+}
+
+LWGEOM*
+parse_geojson(json_object *geojson, bool *hasz,  int *root_srid)
+{
+       json_object* type = NULL;
+       const char* name;
+
+       if( NULL == geojson )
+               geojson_lwerror("invalid GeoJSON representation", 2);
+
+       type = findMemberByName( geojson, "type" );
+       if( NULL == type )
+               geojson_lwerror("unknown GeoJSON type", 3);
+
+       name = json_object_get_string( type );
+
+       if( strcasecmp( name, "Point" )==0 )
+               return parse_geojson_point(geojson, hasz, root_srid);
+
+       if( strcasecmp( name, "LineString" )==0 )
+               return parse_geojson_linestring(geojson, hasz, root_srid);
+
+       if( strcasecmp( name, "Polygon" )==0 )
+               return parse_geojson_polygon(geojson, hasz, root_srid);
+
+       if( strcasecmp( name, "MultiPoint" )==0 )
+               return parse_geojson_multipoint(geojson, hasz, root_srid);
+
+       if( strcasecmp( name, "MultiLineString" )==0 )
+               return parse_geojson_multilinestring(geojson, hasz, root_srid);
+
+       if( strcasecmp( name, "MultiPolygon" )==0 )
+               return parse_geojson_multipolygon(geojson, hasz, root_srid);
+
+       if( strcasecmp( name, "GeometryCollection" )==0 )
+               return parse_geojson_geometrycollection(geojson, hasz, root_srid);
+
+       lwerror("invalid GeoJson representation");
+       return NULL; /* Never reach */
+}
+#endif /* HAVE_LIBJSON  */
+
+PG_FUNCTION_INFO_V1(geom_from_geojson);
+Datum geom_from_geojson(PG_FUNCTION_ARGS)
+{
+#ifndef HAVE_LIBJSON
+       elog(ERROR, "You need JSON-C for ST_GeomFromGeoJSON");
+       PG_RETURN_NULL();
+#else /* HAVE_LIBJSON  */
+
+       GSERIALIZED *geom;
+       LWGEOM *lwgeom;
+       text *geojson_input;
+       int geojson_size;
+       char *geojson;
+       int root_srid=0;
+       bool hasz=true;
+       json_tokener* jstok = NULL;
+       json_object* poObj = NULL;
+       json_object* poObjSrs = NULL;
+
+       /* Get the geojson stream */
+       if (PG_ARGISNULL(0)) PG_RETURN_NULL();
+       geojson_input = PG_GETARG_TEXT_P(0);
+       geojson = text2cstring(geojson_input);
+       geojson_size = VARSIZE(geojson_input) - VARHDRSZ;
+
+       /* Begin to Parse json */
+       jstok = json_tokener_new();
+       poObj = json_tokener_parse_ex(jstok, geojson, -1);
+       if( jstok->err != json_tokener_success)
+       {
+               char *err;
+               err += sprintf(err, "%s (at offset %d)", json_tokener_errors[jstok->err], jstok->char_offset);
+               json_tokener_free(jstok);
+               geojson_lwerror(err, 1);
+       }
+       json_tokener_free(jstok);
+
+       poObjSrs = findMemberByName( poObj, "crs" );
+       if (poObjSrs != NULL)
+       {
+               json_object* poObjSrsType = findMemberByName( poObjSrs, "type" );
+               if (poObjSrsType != NULL)
+               {
+                       json_object* poObjSrsProps = findMemberByName( poObjSrs, "properties" );
+                       json_object* poNameURL = findMemberByName( poObjSrsProps, "name" );
+                       const char* pszName = json_object_get_string( poNameURL );
+                       root_srid = getSRIDbySRS(pszName);
+                       POSTGIS_DEBUGF(3, "getSRIDbySRS returned root_srid = %d.", root_srid );
+               }
+       }
+
+       lwgeom = parse_geojson(poObj, &hasz, &root_srid);
+
+       lwgeom_add_bbox(lwgeom);
+       if (root_srid && lwgeom->srid == -1) lwgeom->srid = root_srid;
+
+       if (!hasz)
+       {
+               LWGEOM *tmp = lwgeom_force_2d(lwgeom);
+               lwgeom_free(lwgeom);
+               lwgeom = tmp;
+
+               POSTGIS_DEBUG(2, "geom_from_geojson called.");
+       }
+
+       geom = geometry_serialize(lwgeom);
+       lwgeom_free(lwgeom);
+
+       PG_RETURN_POINTER(geom);
+#endif
+}
+
index 6b4a6f5cb7855704451bd2b4b0886c86f63a5023..6a4ad680c85523c0a56aeb48e2f76e5db379aae0 100644 (file)
@@ -3199,6 +3199,15 @@ CREATE OR REPLACE FUNCTION ST_GeomFromKML(text)
        AS 'MODULE_PATHNAME','geom_from_kml'\r
        LANGUAGE 'C' IMMUTABLE STRICT;\r
 \r
+-----------------------------------------------------------------------\r
+-- GEOJSON INPUT\r
+-----------------------------------------------------------------------\r
+-- Availability: 2.0.0\r
+CREATE OR REPLACE FUNCTION ST_GeomFromGeoJson(text)\r
+       RETURNS geometry\r
+       AS 'MODULE_PATHNAME','geom_from_geojson'\r
+       LANGUAGE 'C' IMMUTABLE STRICT;\r
+\r
 -----------------------------------------------------------------------\r
 -- SVG OUTPUT\r
 -----------------------------------------------------------------------\r
index 65ec2cbcf219902f89ab26e97e3387ff005eb06d..dadf66cd6a4094f9b763b8da5ff3739514bee903 100644 (file)
@@ -27,6 +27,9 @@
 /* Define to 1 if you have the `proj' library (-lproj). */
 #undef HAVE_LIBPROJ
 
+/* Define to 1 if you have the `json-c' */
+#undef HAVE_LIBJSON
+
 /* Define to 1 if you have the <memory.h> header file. */
 #undef HAVE_MEMORY_H
 
index 9a1213bc7931aecd7a8c53616e415866825f3e2a..67e82b9930668d1a3808b955884751ab9a4a8272 100644 (file)
@@ -3,7 +3,7 @@ TMPDIR?=/tmp
 POSTGIS_PGSQL_VERSION=@POSTGIS_PGSQL_VERSION@
 POSTGIS_GEOS_VERSION=@POSTGIS_GEOS_VERSION@
 POSTGIS_PROJ_VERSION=@POSTGIS_PROJ_VERSION@
-HAVE_LIBXML2=@HAVE_LIBXML2@
+HAVE_JSON=@HAVE_JSON@
 
 # MingW hack: rather than use PGSQL_BINDIR directly, we change
 # to the directory and then use "pwd" to return the path. This
@@ -117,6 +117,13 @@ ifeq ($(shell expr $(POSTGIS_GEOS_VERSION) ">=" 33),1)
                relate_bnr
 endif
 
+ifeq ($(HAVE_JSON),Yes)
+       # JSON-C adds:
+       # ST_GeomFromGeoJSON()
+       TESTS += \
+               in_geojson 
+endif
+
 all install uninstall distclean:
 
 postgis.sql: ../postgis/postgis.sql
diff --git a/regress/in_geojson.sql b/regress/in_geojson.sql
new file mode 100644 (file)
index 0000000..f38efda
--- /dev/null
@@ -0,0 +1,8 @@
+-- FromGeoJSON
+select 'geomfromgeojson_01',st_asewkt(st_geomfromgeojson(st_asgeojson('SRID=3005;MULTIPOINT(1 1, 1 1)')));
+select 'geomfromgeojson_02',st_astext(st_geomfromgeojson(st_asgeojson('SRID=3005;MULTIPOINT(1 1, 1 1)')));
+select 'geomfromgeojson_03',st_astext(st_geomfromgeojson(st_asgeojson('POINT(1 1)')));
+select 'geomfromgeojson_04',st_astext(st_geomfromgeojson(st_asgeojson('LINESTRING(0 0,1 1)')));
+select 'geomfromgeojson_05',st_astext(st_geomfromgeojson(st_asgeojson('POLYGON((0 0,1 1,1 0,0 0))')));
+select 'geomfromgeojson_06',st_astext(st_geomfromgeojson(st_asgeojson('MULTIPOLYGON(((0 0,1 1,1 0,0 0)))')));
+
diff --git a/regress/in_geojson_expected b/regress/in_geojson_expected
new file mode 100644 (file)
index 0000000..d310e65
--- /dev/null
@@ -0,0 +1,6 @@
+geomfromgeojson_01|MULTIPOINT(1 1,1 1)
+geomfromgeojson_02|MULTIPOINT(1 1,1 1)
+geomfromgeojson_03|POINT(1 1)
+geomfromgeojson_04|LINESTRING(0 0,1 1)
+geomfromgeojson_05|POLYGON((0 0,1 1,1 0,0 0))
+geomfromgeojson_06|MULTIPOLYGON(((0 0,1 1,1 0,0 0)))