From: Paul Ramsey Date: Fri, 18 Nov 2011 00:17:56 +0000 (+0000) Subject: Add ST_GeomFromGeoJSON (#376) X-Git-Tag: 2.0.0alpha1~693 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=07b03da7830c573da903181a96c3bb92c190a3e3;p=postgis Add ST_GeomFromGeoJSON (#376) git-svn-id: http://svn.osgeo.org/postgis/trunk@8167 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/configure.ac b/configure.ac index c1734663d..702ac7845 100644 --- a/configure.ac +++ b/configure.ac @@ -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 -------------- ]) diff --git a/doc/installation.xml b/doc/installation.xml index 65b140120..a2c88d4c5 100644 --- a/doc/installation.xml +++ b/doc/installation.xml @@ -114,6 +114,13 @@ you do a make comments or make topology_comments.sql http://xmlsoft.org/downloads.html. + + + 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 + http://oss.metaparadigm.com/json-c/. + + diff --git a/postgis/Makefile.in b/postgis/Makefile.in index a433b4b3f..b628023e2 100644 --- a/postgis/Makefile.in +++ b/postgis/Makefile.in @@ -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 \ diff --git a/postgis/geometry_estimate.c b/postgis/geometry_estimate.c index b6fd89b13..a323f4b4f 100644 --- a/postgis/geometry_estimate.c +++ b/postgis/geometry_estimate.c @@ -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 */ diff --git a/postgis/lwgeom_export.c b/postgis/lwgeom_export.c index 226fa732a..2829b64de 100644 --- a/postgis/lwgeom_export.c +++ b/postgis/lwgeom_export.c @@ -60,7 +60,7 @@ char * getSRSbySRID(int srid, bool short_crs) elog(NOTICE, "getSRSbySRID: error executing query %d", err); SPI_finish(); return NULL; - } + } /* no entry in spatial_ref_sys */ if (SPI_processed <= 0) @@ -91,6 +91,70 @@ char * getSRSbySRID(int srid, bool short_crs) } +/* +* Retrieve an SRID from a given SRS +* Require valid spatial_ref_sys table entry +* +*/ +int getSRIDbySRS(const char* srs) +{ + char query[256]; + int srid, err; + + if (srs == NULL) + return 0; + + if (SPI_OK_CONNECT != SPI_connect ()) + { + elog(NOTICE, "getSRIDbySRS: could not connect to SPI manager"); + SPI_finish(); + return 0; + } + sprintf(query, "SELECT srid \ + FROM spatial_ref_sys WHERE auth_name||':'||auth_srid = '%s'", srs); + + err = SPI_exec(query, 1); + if ( err < 0 ) + { + elog(NOTICE, "getSRIDbySRS: error executing query %d", err); + SPI_finish(); + return 0; + } + + /* no entry in spatial_ref_sys */ + if (SPI_processed <= 0) + { + sprintf(query, "SELECT srid \ + FROM spatial_ref_sys WHERE \ + 'urn:ogc:def:crs:'||auth_name||'::'||auth_srid = '%s'", srs); + + err = SPI_exec(query, 1); + if ( err < 0 ) + { + elog(NOTICE, "getSRIDbySRS: error executing query %d", err); + SPI_finish(); + return 0; + } + + if (SPI_processed <= 0) { + SPI_finish(); + return 0; + } + } + + srid = atoi(SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1)); + if ( ! srs ) + { + SPI_finish(); + return 0; + } + + SPI_finish(); + + return srid; +} + + /** * Encode feature in GML */ diff --git a/postgis/lwgeom_export.h b/postgis/lwgeom_export.h index 2250b8a12..842ca7f03 100644 --- a/postgis/lwgeom_export.h +++ b/postgis/lwgeom_export.h @@ -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 index 000000000..42ee636d5 --- /dev/null +++ b/postgis/lwgeom_in_geojson.c @@ -0,0 +1,520 @@ +/********************************************************************** + * + * PostGIS - Spatial Types for PostgreSQL + * Copyright 2011 Kashif Rasul + * + * 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 + +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 +#include + +/* 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 +} + diff --git a/postgis/postgis.sql.in.c b/postgis/postgis.sql.in.c index 6b4a6f5cb..6a4ad680c 100644 --- a/postgis/postgis.sql.in.c +++ b/postgis/postgis.sql.in.c @@ -3199,6 +3199,15 @@ CREATE OR REPLACE FUNCTION ST_GeomFromKML(text) AS 'MODULE_PATHNAME','geom_from_kml' LANGUAGE 'C' IMMUTABLE STRICT; +----------------------------------------------------------------------- +-- GEOJSON INPUT +----------------------------------------------------------------------- +-- Availability: 2.0.0 +CREATE OR REPLACE FUNCTION ST_GeomFromGeoJson(text) + RETURNS geometry + AS 'MODULE_PATHNAME','geom_from_geojson' + LANGUAGE 'C' IMMUTABLE STRICT; + ----------------------------------------------------------------------- -- SVG OUTPUT ----------------------------------------------------------------------- diff --git a/postgis_config.h.in b/postgis_config.h.in index 65ec2cbcf..dadf66cd6 100644 --- a/postgis_config.h.in +++ b/postgis_config.h.in @@ -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 header file. */ #undef HAVE_MEMORY_H diff --git a/regress/Makefile.in b/regress/Makefile.in index 9a1213bc7..67e82b993 100644 --- a/regress/Makefile.in +++ b/regress/Makefile.in @@ -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 index 000000000..f38efda7b --- /dev/null +++ b/regress/in_geojson.sql @@ -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 index 000000000..d310e655d --- /dev/null +++ b/regress/in_geojson_expected @@ -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)))