From: Sandro Santilli Date: Fri, 12 Aug 2011 17:25:01 +0000 (+0000) Subject: Make transformation and projection cache API available (ticket #1053) X-Git-Tag: 2.0.0alpha1~1113 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=4239e692bbf3619bbf23eac8fe0f1c5faf3a3edb;p=postgis Make transformation and projection cache API available (ticket #1053) git-svn-id: http://svn.osgeo.org/postgis/trunk@7734 b70326c6-7e19-0410-871a-916f4a2858ee --- diff --git a/.gitignore b/.gitignore index a4c85cfcf..20431e593 100644 --- a/.gitignore +++ b/.gitignore @@ -40,6 +40,8 @@ macros/ltversion.m4 *.o postgis_config.h postgis/Makefile +postgis/legacy_compatibility_layer.sql +postgis/legacy_compatibility_layer.sql.in postgis/legacy.sql postgis/legacy.sql.in postgis/postgis.sql @@ -49,6 +51,8 @@ postgis/postgis_upgrade_14_to_15.sql postgis/postgis_upgrade_15_minor.sql postgis/postgis_upgrade_20_minor.sql postgis/sqldefines.h +postgis/uninstall_legacy.sql +postgis/uninstall_legacy.sql.in postgis/uninstall_postgis.sql postgis/uninstall_postgis.sql.in raster/Makefile @@ -77,3 +81,5 @@ topology/test/topo_predicates.sql topology/topology.sql topology/topology.sql.in authors.git +libpgcommon/Makefile +libpgcommon/cunit/Makefile diff --git a/GNUmakefile.in b/GNUmakefile.in index daf8d77dd..ae890d16e 100644 --- a/GNUmakefile.in +++ b/GNUmakefile.in @@ -5,7 +5,7 @@ #----------------------------------------------------- # todo: add all subdirs -SUBDIRS = liblwgeom regress postgis loader utils @RASTER@ @TOPOLOGY@ +SUBDIRS = liblwgeom libpgcommon regress postgis loader utils @RASTER@ @TOPOLOGY@ # todo: add more rules here, like uninstall, clean... all install uninstall noop clean distclean check: diff --git a/configure.ac b/configure.ac index 9a679c6b3..624e633ee 100644 --- a/configure.ac +++ b/configure.ac @@ -357,6 +357,11 @@ PGSQL_FE_CPPFLAGS=-I`$PGCONFIG --includedir` AC_SUBST([PGSQL_FE_LDFLAGS]) AC_SUBST([PGSQL_FE_CPPFLAGS]) +dnl Extract the include flags for the backend (libpgcommon) +PGSQL_BE_CPPFLAGS=-I`$PGCONFIG --includedir-server` + +AC_SUBST([PGSQL_BE_CPPFLAGS]) + dnl Extract the documentation and man page directories PGSQL_DOCDIR=`$PGCONFIG --docdir` PGSQL_MANDIR=`$PGCONFIG --mandir` @@ -589,6 +594,9 @@ AC_DEFINE_UNQUOTED([POSTGIS_PROJ_VERSION], [$POSTGIS_PROJ_VERSION], [PROJ librar AC_SUBST([POSTGIS_PROJ_VERSION]) CPPFLAGS="$CPPFLAGS_SAVE" +AC_SUBST([PROJ_CPPFLAGS]) +AC_SUBST([PROJ_LDFLAGS]) + dnl Ensure that we are using PROJ >= 4.5.0 (requires pj_set_searchpath) if test ! "$POSTGIS_PROJ_VERSION" -ge 45; then AC_MSG_ERROR([PostGIS requires PROJ >= 4.5.0]) @@ -778,10 +786,14 @@ if test "x$RASTER" = "xraster"; then dnl # { POSTGIS_SRCDIR=`$PWDREGRESS` LIBLWGEOM_CFLAGS="-I${POSTGIS_SRCDIR}/liblwgeom" LIBLWGEOM_LDFLAGS="${POSTGIS_SRCDIR}/liblwgeom/liblwgeom.a" + LIBPGCOMMON_CFLAGS="-I${POSTGIS_SRCDIR}/libpgcommon" + LIBPGCOMMON_LDFLAGS="${POSTGIS_SRCDIR}/libpgcommon/libpgcommon.a" AC_SUBST([POSTGIS_SRCDIR]) AC_SUBST([LIBLWGEOM_CFLAGS]) AC_SUBST([LIBLWGEOM_LDFLAGS]) + AC_SUBST([LIBPGCOMMON_CFLAGS]) + AC_SUBST([LIBPGCOMMON_LDFLAGS]) dnl ======================================================================== dnl Determine GDAL Support @@ -910,6 +922,7 @@ fi dnl # } dnl Output the relevant files AC_OUTPUT([GNUmakefile liblwgeom/Makefile liblwgeom/cunit/Makefile postgis/Makefile + libpgcommon/Makefile libpgcommon/cunit/Makefile postgis/sqldefines.h loader/Makefile loader/cunit/Makefile topology/Makefile regress/Makefile doc/Makefile doc/Makefile.comments doc/html/image_src/Makefile $RT_MAKEFILE_LIST]) diff --git a/liblwgeom/Makefile.in b/liblwgeom/Makefile.in index ce451838a..5d1956dac 100644 --- a/liblwgeom/Makefile.in +++ b/liblwgeom/Makefile.in @@ -11,8 +11,10 @@ # ********************************************************************** CC = @CC@ -CFLAGS = @CFLAGS@ @PICFLAGS@ @WARNFLAGS@ @GEOS_CPPFLAGS@ -DPOSTGIS_GEOS_VERSION=@POSTGIS_GEOS_VERSION@ -LDFLAGS = @GEOS_LDFLAGS@ -lgeos_c +CFLAGS = @CFLAGS@ @PICFLAGS@ @WARNFLAGS@ \ + @GEOS_CPPFLAGS@ -DPOSTGIS_GEOS_VERSION=@POSTGIS_GEOS_VERSION@ \ + @PROJ_CPPFLAGS@ -DPOSTGIS_PROJ_VERSION=@POSTGIS_PROJ_VERSION@ +LDFLAGS = @GEOS_LDFLAGS@ @PROJ_LDFLAGS@ -lgeos_c NUMERICFLAGS = @NUMERICFLAGS@ top_builddir = @top_builddir@ prefix = @prefix@ @@ -76,7 +78,8 @@ SA_OBJS = \ lwout_x3d.o \ lwgeom_geos.o \ lwgeom_geos_clean.o \ - lwgeom_geos_split.o + lwgeom_geos_split.o \ + lwgeom_transform.o NM_OBJS = \ lwspheroid.o diff --git a/liblwgeom/liblwgeom.h b/liblwgeom/liblwgeom.h index 9d42b4922..4fa724aa5 100644 --- a/liblwgeom/liblwgeom.h +++ b/liblwgeom/liblwgeom.h @@ -19,6 +19,7 @@ #include #include +#include "proj_api.h" /** * @file liblwgeom.h @@ -2187,6 +2188,19 @@ LWGEOM* lwgeom_snap(const LWGEOM* geom1, const LWGEOM* geom2, double tolerance); LWGEOM* lwgeom_sharedpaths(const LWGEOM* geom1, const LWGEOM* geom2); +/******************************************************************************* + * PROJ4-dependent extra functions on LWGEOM + ******************************************************************************/ +/** + * Transform (reproject) a geometry in-place. + * @param geom the geometry to transform + * @param inpj the input (or current, or source) projection + * @param outpj the output (or destination) projection + */ +int lwgeom_transform(LWGEOM *geom, projPJ inpj, projPJ outpj) ; +int point4d_transform(POINT4D *pt, projPJ srcpj, projPJ dstpj) ; + + /******************************************************************************* * GEOS-dependent extra functions on LWGEOM ******************************************************************************/ diff --git a/liblwgeom/lwgeom_transform.c b/liblwgeom/lwgeom_transform.c new file mode 100644 index 000000000..661d6076b --- /dev/null +++ b/liblwgeom/lwgeom_transform.c @@ -0,0 +1,151 @@ +/********************************************************************** + * $Id:$ + * + * PostGIS - Spatial Types for PostgreSQL + * http://postgis.refractions.net + * Copyright 2001-2003 Refractions Research Inc. + * + * 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 "proj_api.h" +#include "liblwgeom.h" +#include + + +/** convert decimal degress to radians */ +static void +to_rad(POINT4D *pt) +{ + pt->x *= M_PI/180.0; + pt->y *= M_PI/180.0; +} + +/** convert radians to decimal degress */ +static void +to_dec(POINT4D *pt) +{ + pt->x *= 180.0/M_PI; + pt->y *= 180.0/M_PI; +} + + +/** + * Transform given SERIALIZED geometry + * from inpj projection to outpj projection + */ +int +lwgeom_transform(LWGEOM *geom, projPJ inpj, projPJ outpj) +{ + int j, i; + int type = geom->type; + POINT4D p; + POINTARRAY *pa; + + /* No points to transform in an empty! */ + if ( lwgeom_is_empty(geom) ) + return LW_SUCCESS; + + switch(type) + { + case POINTTYPE: + case LINETYPE: + case CIRCSTRINGTYPE: + case TRIANGLETYPE: + { + LWLINE *g = (LWLINE*)geom; + pa = g->points; + for ( i = 0; i < pa->npoints; i++ ) + { + getPoint4d_p(pa, i, &p); + point4d_transform(&p, inpj, outpj); + ptarray_set_point4d(pa, i, &p); + } + break; + } + case POLYGONTYPE: + { + LWPOLY *g = (LWPOLY*)geom; + for ( j = 0; j < g->nrings; j++ ) + { + pa = g->rings[j]; + for ( i = 0; i < pa->npoints; i++ ) + { + getPoint4d_p(pa, i, &p); + point4d_transform(&p, inpj, outpj); + ptarray_set_point4d(pa, i, &p); + } + } + break; + } + case MULTIPOINTTYPE: + case MULTILINETYPE: + case MULTIPOLYGONTYPE: + case COLLECTIONTYPE: + case COMPOUNDTYPE: + case CURVEPOLYTYPE: + case MULTICURVETYPE: + case MULTISURFACETYPE: + case POLYHEDRALSURFACETYPE: + case TINTYPE: + { + LWCOLLECTION *g = (LWCOLLECTION*)geom; + for ( i = 0; i < g->ngeoms; i++ ) + { + lwgeom_transform(g->geoms[i], inpj, outpj); + } + break; + } + default: + { + lwerror("lwgeom_transform: Cannot handle type '%s'", lwtype_name(type)); + return LW_FAILURE; + } + } + return LW_SUCCESS; + +} + +int +point4d_transform(POINT4D *pt, projPJ srcpj, projPJ dstpj) +{ + int* pj_errno_ref; + POINT4D orig_pt; + + /* Make a copy of the input point so we can report the original should an error occur */ + orig_pt.x = pt->x; + orig_pt.y = pt->y; + orig_pt.z = pt->z; + + if (pj_is_latlong(srcpj)) to_rad(pt) ; + + LWDEBUGF(4, "transforming POINT(%f %f) from '%s' to '%s'", orig_pt.x, orig_pt.y, pj_get_def(srcpj,0), pj_get_def(dstpj,0)); + + /* Perform the transform */ + pj_transform(srcpj, dstpj, 1, 0, &(pt->x), &(pt->y), &(pt->z)); + + /* For NAD grid-shift errors, display an error message with an additional hint */ + pj_errno_ref = pj_get_errno_ref(); + + if (*pj_errno_ref != 0) + { + if (*pj_errno_ref == -38) + { + LWDEBUGF(0, "transform: couldn't project point (%g %g %g): %s (%d)", + orig_pt.x, orig_pt.y, orig_pt.z, pj_strerrno(*pj_errno_ref), *pj_errno_ref) ; + LWDEBUG(0, "HINT: PostGIS was unable to transform the point because either no grid shift files were found, or the point does not lie within the range for which the grid shift is defined. Refer to the ST_Transform() section of the PostGIS manual for details on how to configure PostGIS to alter this behaviour.") ; + return 0; + } + else + { + LWDEBUGF(0, "transform: couldn't project point (%g %g %g): %s (%d)", + orig_pt.x, orig_pt.y, orig_pt.z, pj_strerrno(*pj_errno_ref), *pj_errno_ref); + return 0; + } + } + + if (pj_is_latlong(dstpj)) to_dec(pt); + return 1; +} diff --git a/libpgcommon/Makefile.in b/libpgcommon/Makefile.in new file mode 100644 index 000000000..eadae7c9d --- /dev/null +++ b/libpgcommon/Makefile.in @@ -0,0 +1,60 @@ +# ********************************************************************** +# * $Id: Makefile.in +# * +# * PostGIS - Spatial Types for PostgreSQL +# * http://postgis.refractions.net +# * Copyright 2008 Mark Cave-Ayland +# * +# * This is free software; you can redistribute and/or modify it under +# * the terms of the GNU General Public Licence. See the COPYING file. +# * +# ********************************************************************** + +CC=@CC@ +CFLAGS=@CFLAGS@ @PGSQL_BE_CPPFLAGS@ -I../liblwgeom @PICFLAGS@ @WARNFLAGS@ +NUMERICFLAGS=@NUMERICFLAGS@ + +YACC=@YACC@ +LEX=@LEX@ + +# Standalone COMMON objects +SA_OBJS = \ + lwgeom_transform.o \ + lwgeom_pg.o + + +SA_HEADERS = \ + lwgeom_pg.h \ + lwgeom_transform.h \ + pgsql_compat.h + +all: libpgcommon.a + +# nothing to install or uninstall +install uninstall: + +libpgcommon.a: $(SA_OBJS) $(SA_HEADERS) + ar rs libpgcommon.a $(SA_OBJS) + +maintainer-clean: clean + +clean: + $(MAKE) -C cunit clean + rm -f $(SA_OBJS) + rm -f $(NM_OBJS) + rm -f libpgcommon.a + +# Nothing specific in distclean (will be done by clean) +distclean: + +check: libpgcommon.a + make -C cunit check + +# Command to build each of the .o files +$(SA_OBJS): %.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + + + + + diff --git a/postgis/lwgeom_transform.h b/libpgcommon/common.h similarity index 60% rename from postgis/lwgeom_transform.h rename to libpgcommon/common.h index 6cfd2242d..452c69603 100644 --- a/postgis/lwgeom_transform.h +++ b/libpgcommon/common.h @@ -1,20 +1,20 @@ /********************************************************************** - * $Id$ + * $Id: $ * * PostGIS - Spatial Types for PostgreSQL * http://postgis.refractions.net - * Copyright 2001-2003 Refractions Research Inc. + * Copyright 2011 OSGeo * * 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 "liblwgeom.h" +#ifndef PG_LIBCOMMON_H +#define PG_LIBCOMMON_H + +#include "pgsql_compat.h" #include "lwgeom_pg.h" -#include "proj_api.h" +#include "lwgeom_transform.h" -projPJ make_project(char *str1); -int transform_point(POINT4D *pt, projPJ srcdefn, projPJ dstdefn); -char* GetProj4StringSPI(int srid); +#endif /* PG_LIBCOMMON_H */ diff --git a/libpgcommon/cunit/Makefile.in b/libpgcommon/cunit/Makefile.in new file mode 100644 index 000000000..76e688a66 --- /dev/null +++ b/libpgcommon/cunit/Makefile.in @@ -0,0 +1,13 @@ +# ********************************************************************** +# * $Id: Makefile.in +# * +# * PostGIS - Spatial Types for PostgreSQL +# * http://postgis.refractions.net +# * Copyright 2008 Mark Cave-Ayland +# * +# * This is free software; you can redistribute and/or modify it under +# * the terms of the GNU General Public Licence. See the COPYING file. +# * +# ********************************************************************** + +all check clean : \ No newline at end of file diff --git a/postgis/gserialized.h b/libpgcommon/gserialized.h similarity index 100% rename from postgis/gserialized.h rename to libpgcommon/gserialized.h diff --git a/postgis/lwgeom_pg.c b/libpgcommon/lwgeom_pg.c similarity index 100% rename from postgis/lwgeom_pg.c rename to libpgcommon/lwgeom_pg.c diff --git a/postgis/lwgeom_pg.h b/libpgcommon/lwgeom_pg.h similarity index 100% rename from postgis/lwgeom_pg.h rename to libpgcommon/lwgeom_pg.h diff --git a/postgis/lwgeom_transform.c b/libpgcommon/lwgeom_transform.c similarity index 83% rename from postgis/lwgeom_transform.c rename to libpgcommon/lwgeom_transform.c index d01627433..9a9f05fda 100644 --- a/postgis/lwgeom_transform.c +++ b/libpgcommon/lwgeom_transform.c @@ -1,5 +1,5 @@ /********************************************************************** - * $Id$ + * $Id: lwgeom_transform.c -1M 2011-08-11 09:54:25Z (local) $ * * PostGIS - Spatial Types for PostgreSQL * http://postgis.refractions.net @@ -37,10 +37,7 @@ Datum postgis_proj_version(PG_FUNCTION_ARGS); #include "lwgeom_transform.h" projPJ make_project(char *str1); -void to_rad(POINT4D *pt); -void to_dec(POINT4D *pt); int pj_transform_nodatum(projPJ srcdefn, projPJ dstdefn, long point_count, int point_offset, double *x, double *y, double *z ); -int transform_point(POINT4D *pt, projPJ srcdefn, projPJ dstdefn); @@ -104,11 +101,12 @@ static void AddPJHashEntry(MemoryContext mcxt, projPJ projection); static projPJ GetPJHashEntry(MemoryContext mcxt); static void DeletePJHashEntry(MemoryContext mcxt); -/* Cache API */ -bool IsInPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid); -projPJ GetProjectionFromPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid); -void AddToPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid, int other_srid); -void DeleteFromPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid); +/* Internal Cache API */ +static PROJ4PortalCache *GetPROJ4SRSCache(FunctionCallInfoData *fcinfo) ; +static bool IsInPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid); +static projPJ GetProjectionFromPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid); +static void AddToPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid, int other_srid); +static void DeleteFromPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid); /* Search path for PROJ.4 library */ static bool IsPROJ4LibPathSet = false; @@ -300,12 +298,16 @@ static void DeletePJHashEntry(MemoryContext mcxt) elog(ERROR, "DeletePJHashEntry: There was an error removing the PROJ4 projection object from this MemoryContext (%p)", (void *)mcxt); } +bool +IsInPROJ4Cache(Proj4Cache PROJ4Cache, int srid) { + return IsInPROJ4SRSCache((PROJ4PortalCache *)PROJ4Cache, srid) ; +} /* * Per-cache management functions */ -bool +static bool IsInPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid) { /* @@ -318,19 +320,23 @@ IsInPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid) for (i = 0; i < PROJ4_CACHE_ITEMS; i++) { if (PROJ4Cache->PROJ4SRSCache[i].srid == srid) - return true; + return 1; } /* Otherwise not found */ - return false; + return 0; } +projPJ GetProjectionFromPROJ4Cache(Proj4Cache cache, int srid) +{ + return GetProjectionFromPROJ4SRSCache((PROJ4PortalCache *)cache, srid) ; +} /** * Return the projection object from the cache (we should * already have checked it exists using IsInPROJ4SRSCache first) */ -projPJ +static projPJ GetProjectionFromPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid) { int i; @@ -454,13 +460,17 @@ static char* GetProj4String(int srid) } } +void AddToPROJ4Cache(Proj4Cache cache, int srid, int other_srid) { + AddToPROJ4SRSCache((PROJ4PortalCache *)cache, srid, other_srid) ; +} + /** * Add an entry to the local PROJ4 SRS cache. If we need to wrap around then * we must make sure the entry we choose to delete does not contain other_srid * which is the definition for the other half of the transformation. */ -void +static void AddToPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid, int other_srid) { MemoryContext PJMemoryContext; @@ -545,8 +555,12 @@ AddToPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid, int other_srid) } +void DeleteFromPROJ4Cache(Proj4Cache cache, int srid) { + DeleteFromPROJ4SRSCache((PROJ4PortalCache *)cache, srid) ; +} + -void DeleteFromPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid) +static void DeleteFromPROJ4SRSCache(PROJ4PortalCache *PROJ4Cache, int srid) { /* * Delete the SRID entry from the cache @@ -590,40 +604,28 @@ void SetPROJ4LibPath(void) char *path; const char **proj_lib_path; - /* - * Get the sharepath and append /contrib/postgis/proj to form a suitable - * directory in which to store the grid shift files - */ - proj_lib_path = palloc(sizeof(char *)); - path = palloc(MAXPGPATH); - *proj_lib_path = path; + if (!IsPROJ4LibPathSet) { - get_share_path(my_exec_path, path); - strncat(path, "/contrib/postgis/proj", MAXPGPATH - strlen(path) - 1); + /* + * Get the sharepath and append /contrib/postgis/proj to form a suitable + * directory in which to store the grid shift files + */ + proj_lib_path = palloc(sizeof(char *)); + path = palloc(MAXPGPATH); + *proj_lib_path = path; - /* Set the search path for PROJ.4 */ - pj_set_searchpath(1, proj_lib_path); - - /* Ensure we only do this once... */ - IsPROJ4LibPathSet = true; -} + get_share_path(my_exec_path, path); + strncat(path, "/contrib/postgis/proj", MAXPGPATH - strlen(path) - 1); + /* Set the search path for PROJ.4 */ + pj_set_searchpath(1, proj_lib_path); -/** convert decimal degress to radians */ -void -to_rad(POINT4D *pt) -{ - pt->x *= M_PI/180.0; - pt->y *= M_PI/180.0; + /* Ensure we only do this once... */ + IsPROJ4LibPathSet = true; + } } -/** convert radians to decimal degress */ -void -to_dec(POINT4D *pt) -{ - pt->x *= 180.0/M_PI; - pt->y *= 180.0/M_PI; -} + /** given a string, make a PJ object */ projPJ @@ -673,84 +675,55 @@ make_project(char *str1) } -/** - * Transform given SERIALIZED geometry - * from inpj projection to outpj projection - */ -static int -lwgeom_transform(LWGEOM *geom, projPJ inpj, projPJ outpj) + +Proj4Cache GetPROJ4Cache(FunctionCallInfoData *fcinfo) { + return (Proj4Cache)GetPROJ4SRSCache(fcinfo) ; +} + +static PROJ4PortalCache *GetPROJ4SRSCache(FunctionCallInfoData *fcinfo) { - int j, i; - int type = geom->type; - POINT4D p; - POINTARRAY *pa; - - /* No points to transform in an empty! */ - if ( lwgeom_is_empty(geom) ) - return LW_SUCCESS; - - switch(type) + PROJ4PortalCache *PROJ4Cache ; + + /* + * If we have not already created PROJ4 cache for this portal + * then create it + */ + if (fcinfo->flinfo->fn_extra == NULL) { - case POINTTYPE: - case LINETYPE: - case CIRCSTRINGTYPE: - case TRIANGLETYPE: - { - LWLINE *g = (LWLINE*)geom; - pa = g->points; - for ( i = 0; i < pa->npoints; i++ ) - { - getPoint4d_p(pa, i, &p); - transform_point(&p, inpj, outpj); - ptarray_set_point4d(pa, i, &p); - } - break; - } - case POLYGONTYPE: - { - LWPOLY *g = (LWPOLY*)geom; - for ( j = 0; j < g->nrings; j++ ) - { - pa = g->rings[j]; - for ( i = 0; i < pa->npoints; i++ ) - { - getPoint4d_p(pa, i, &p); - transform_point(&p, inpj, outpj); - ptarray_set_point4d(pa, i, &p); - } - } - break; - } - case MULTIPOINTTYPE: - case MULTILINETYPE: - case MULTIPOLYGONTYPE: - case COLLECTIONTYPE: - case COMPOUNDTYPE: - case CURVEPOLYTYPE: - case MULTICURVETYPE: - case MULTISURFACETYPE: - case POLYHEDRALSURFACETYPE: - case TINTYPE: + MemoryContext old_context; + + old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); + PROJ4Cache = palloc(sizeof(PROJ4PortalCache)); + MemoryContextSwitchTo(old_context); + + if (PROJ4Cache) { - LWCOLLECTION *g = (LWCOLLECTION*)geom; - for ( i = 0; i < g->ngeoms; i++ ) + int i; + + POSTGIS_DEBUGF(3, "Allocating PROJ4Cache for portal with transform() MemoryContext %p", fcinfo->flinfo->fn_mcxt); + /* Put in any required defaults */ + for (i = 0; i < PROJ4_CACHE_ITEMS; i++) { - lwgeom_transform(g->geoms[i], inpj, outpj); + PROJ4Cache->PROJ4SRSCache[i].srid = SRID_UNKNOWN; + PROJ4Cache->PROJ4SRSCache[i].projection = NULL; + PROJ4Cache->PROJ4SRSCache[i].projection_mcxt = NULL; } - break; - } - default: - { - lwerror("lwgeom_transform: Cannot handle type '%s'", lwtype_name(type)); - return LW_FAILURE; + PROJ4Cache->PROJ4SRSCacheCount = 0; + PROJ4Cache->PROJ4SRSCacheContext = fcinfo->flinfo->fn_mcxt; + + /* Store the pointer in fcinfo->flinfo->fn_extra */ + fcinfo->flinfo->fn_extra = PROJ4Cache; } } - return LW_SUCCESS; + else + { + /* Use the existing cache */ + PROJ4Cache = fcinfo->flinfo->fn_extra; + } + return PROJ4Cache ; } - - /** * transform( GEOMETRY, INT (output srid) ) * tmpPts - if there is a nadgrid error (-38), we re-try the transform @@ -798,42 +771,8 @@ Datum transform(PG_FUNCTION_ARGS) PG_RETURN_POINTER(PG_GETARG_DATUM(0)); } - /* - * If we have not already created PROJ4 cache for this portal - * then create it - */ - if (fcinfo->flinfo->fn_extra == NULL) - { - MemoryContext old_context; - - old_context = MemoryContextSwitchTo(fcinfo->flinfo->fn_mcxt); - PROJ4Cache = palloc(sizeof(PROJ4PortalCache)); - MemoryContextSwitchTo(old_context); - - if (PROJ4Cache) - { - int i; - - POSTGIS_DEBUGF(3, "Allocating PROJ4Cache for portal with transform() MemoryContext %p", fcinfo->flinfo->fn_mcxt); - /* Put in any required defaults */ - for (i = 0; i < PROJ4_CACHE_ITEMS; i++) - { - PROJ4Cache->PROJ4SRSCache[i].srid = SRID_UNKNOWN; - PROJ4Cache->PROJ4SRSCache[i].projection = NULL; - PROJ4Cache->PROJ4SRSCache[i].projection_mcxt = NULL; - } - PROJ4Cache->PROJ4SRSCacheCount = 0; - PROJ4Cache->PROJ4SRSCacheContext = fcinfo->flinfo->fn_mcxt; - - /* Store the pointer in fcinfo->flinfo->fn_extra */ - fcinfo->flinfo->fn_extra = PROJ4Cache; - } - } - else - { - /* Use the existing cache */ - PROJ4Cache = fcinfo->flinfo->fn_extra; - } + /* get or initialize the cache for this round */ + PROJ4Cache = GetPROJ4SRSCache(fcinfo) ; /* Add the output srid to the cache if it's not already there */ if (!IsInPROJ4SRSCache(PROJ4Cache, result_srid)) @@ -983,49 +922,6 @@ Datum postgis_proj_version(PG_FUNCTION_ARGS) } -int -transform_point(POINT4D *pt, projPJ srcpj, projPJ dstpj) -{ - int* pj_errno_ref; - POINT4D orig_pt; - - /* Make a copy of the input point so we can report the original should an error occur */ - orig_pt.x = pt->x; - orig_pt.y = pt->y; - orig_pt.z = pt->z; - - if (pj_is_latlong(srcpj)) to_rad(pt); - - LWDEBUGF(4, "transforming POINT(%f %f) from '%s' to '%s'", orig_pt.x, orig_pt.y, pj_get_def(srcpj,0), pj_get_def(dstpj,0)); - - /* Perform the transform */ - pj_transform(srcpj, dstpj, 1, 0, &(pt->x), &(pt->y), &(pt->z)); - - /* For NAD grid-shift errors, display an error message with an additional hint */ - pj_errno_ref = pj_get_errno_ref(); - - if (*pj_errno_ref != 0) - { - if (*pj_errno_ref == -38) - { - ereport(ERROR, ( - errmsg_internal("transform: couldn't project point (%g %g %g): %s (%d)", - orig_pt.x, orig_pt.y, orig_pt.z, pj_strerrno(*pj_errno_ref), *pj_errno_ref), - errhint("PostGIS was unable to transform the point because either no grid shift files were found, or the point does not lie within the range for which the grid shift is defined. Refer to the ST_Transform() section of the PostGIS manual for details on how to configure PostGIS to alter this behaviour.") - )); - return 0; - } - else - { - elog(ERROR, "transform: couldn't project point (%g %g %g): %s (%d)", - orig_pt.x, orig_pt.y, orig_pt.z, pj_strerrno(*pj_errno_ref), *pj_errno_ref); - return 0; - } - } - - if (pj_is_latlong(dstpj)) to_dec(pt); - return 1; -} diff --git a/libpgcommon/lwgeom_transform.h b/libpgcommon/lwgeom_transform.h new file mode 100644 index 000000000..c988dfdaf --- /dev/null +++ b/libpgcommon/lwgeom_transform.h @@ -0,0 +1,33 @@ +/********************************************************************** + * $Id: lwgeom_transform.h -1M 2011-08-11 11:15:57Z (local) $ + * + * PostGIS - Spatial Types for PostgreSQL + * http://postgis.refractions.net + * Copyright 2001-2003 Refractions Research Inc. + * + * 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 "liblwgeom.h" +#include "lwgeom_pg.h" +#include "proj_api.h" + +projPJ make_project(char *str1); +char* GetProj4StringSPI(int srid); + +/** + * Opaque type to use in the projection cache API. + */ +typedef void *Proj4Cache ; + +void SetPROJ4LibPath(void); +Proj4Cache GetPROJ4Cache(FunctionCallInfoData *fcinfo) ; +bool IsInPROJ4Cache(Proj4Cache cache, int srid) ; +void AddToPROJ4Cache(Proj4Cache cache, int srid, int other_srid); +void DeleteFromPROJ4Cache(Proj4Cache cache, int srid) ; +projPJ GetProjectionFromPROJ4Cache(Proj4Cache cache, int srid); + + diff --git a/postgis/pgsql_compat.h b/libpgcommon/pgsql_compat.h similarity index 100% rename from postgis/pgsql_compat.h rename to libpgcommon/pgsql_compat.h diff --git a/postgis/Makefile.in b/postgis/Makefile.in index 1f0953cb3..6e3934e07 100644 --- a/postgis/Makefile.in +++ b/postgis/Makefile.in @@ -21,8 +21,7 @@ DATA=../spatial_ref_sys.sql SQL_OBJS=postgis.sql.in uninstall_postgis.sql.in legacy.sql.in uninstall_legacy.sql.in legacy_compatibility_layer.sql.in # PostgreSQL objects -PG_OBJS=lwgeom_pg.o \ - lwgeom_debug.o \ +PG_OBJS=lwgeom_debug.o \ lwgeom_accum.o \ lwgeom_spheroid.o \ lwgeom_ogc.o \ @@ -32,7 +31,6 @@ PG_OBJS=lwgeom_pg.o \ lwgeom_functions_basic.o \ lwgeom_gist.o \ lwgeom_btree.o \ - lwgeom_transform.o \ lwgeom_box.o \ lwgeom_box3d.o \ lwgeom_box2dfloat4.o \ @@ -69,8 +67,8 @@ OBJS=$(PG_OBJS) # to an existing liblwgeom.so in the PostgreSQL $libdir supplied by an # older version of PostGIS, rather than with the static liblwgeom.a # supplied with newer versions of PostGIS -PG_CPPFLAGS += @CPPFLAGS@ -I../liblwgeom -SHLIB_LINK = ../liblwgeom/liblwgeom.a @SHLIB_LINK@ +PG_CPPFLAGS += @CPPFLAGS@ -I../liblwgeom -I../libpgcommon +SHLIB_LINK = ../libpgcommon/libpgcommon.a ../liblwgeom/liblwgeom.a @SHLIB_LINK@ # Extra files to remove during 'make clean' EXTRA_CLEAN=$(SQL_OBJS) @@ -103,7 +101,7 @@ endif # Make all PostGIS objects depend upon liblwgeom, so that if an underlying # change is made, a PostGIS rebuild is triggered. -$(PG_OBJS): ../liblwgeom/liblwgeom.a +$(PG_OBJS): ../liblwgeom/liblwgeom.a ../libpgcommon/libpgcommon.a # Borrow the $libdir substitution from PGXS but customise by adding the version number %.sql: %.sql.in @@ -114,6 +112,6 @@ postgis_upgrade_20_minor.sql: postgis.sql # Generate any .sql.in files from .sql.in.c files by running them through the C pre-processor $(SQL_OBJS): %.in: %.in.c - $(CPP) -traditional-cpp $< | grep -v '^#' > $@ + $(CPP) -traditional-cpp -I../libpgcommon $< | grep -v '^#' > $@ postgis.sql.in: geography.sql.in.c diff --git a/postgis/lwgeom_in_gml.c b/postgis/lwgeom_in_gml.c index 66414334b..201c9fdea 100644 --- a/postgis/lwgeom_in_gml.c +++ b/postgis/lwgeom_in_gml.c @@ -333,7 +333,7 @@ static POINTARRAY* gml_reproject_pa(POINTARRAY *pa, int srid_in, int srid_out) for (i=0 ; i < pa->npoints ; i++) { getPoint4d_p(pa, i, &p); - transform_point(&p, in_pj, out_pj); + point4d_transform(&p, in_pj, out_pj); ptarray_set_point4d(pa, i, &p); } diff --git a/raster/rt_pg/Makefile.in b/raster/rt_pg/Makefile.in index a95c4bc2e..f3abfa8bd 100644 --- a/raster/rt_pg/Makefile.in +++ b/raster/rt_pg/Makefile.in @@ -32,11 +32,13 @@ OBJS=rt_pg.o LIBLWGEOM_LDFLAGS=@LIBLWGEOM_LDFLAGS@ LIBLWGEOM_CFLAGS=@LIBLWGEOM_CFLAGS@ +LIBPGCOMMON_CFLAGS=@LIBPGCOMMON_CFLAGS@ +LIBPGCOMMON_LDFLAGS=@LIBPGCOMMON_LDFLAGS@ LIBGDAL_CFLAGS=@LIBGDAL_CFLAGS@ LIBGDAL_LDFLAGS=@LIBGDAL_LDFLAGS@ -PG_CPPFLAGS+=@CPPFLAGS@ $(LIBLWGEOM_CFLAGS) $(LIBGDAL_CFLAGS) -I../rt_core -SHLIB_LINK+=@SHLIB_LINK@ ../rt_core/librtcore.a $(LIBLWGEOM_LDFLAGS) $(LIBGDAL_LDFLAGS) +PG_CPPFLAGS+=@CPPFLAGS@ $(LIBLWGEOM_CFLAGS) $(LIBGDAL_CFLAGS) $(LIBPGCOMMON_CFLAGS) -I../rt_core +SHLIB_LINK+=@SHLIB_LINK@ ../rt_core/librtcore.a $(LIBPGCOMMON_LDFLAGS) $(LIBLWGEOM_LDFLAGS) $(LIBGDAL_LDFLAGS) # Extra files to remove during 'make clean' EXTRA_CLEAN=$(SQL_OBJS) rtpostgis.sql diff --git a/raster/rt_pg/rt_pg.h b/raster/rt_pg/rt_pg.h index 9bffaedf2..715a9533e 100644 --- a/raster/rt_pg/rt_pg.h +++ b/raster/rt_pg/rt_pg.h @@ -33,7 +33,7 @@ #include "rt_api.h" #include "../../postgis_config.h" -#include "../../postgis/gserialized.h" +#include "gserialized.h" /* Debugging macros */ #if POSTGIS_DEBUG_LEVEL > 0 diff --git a/raster/rt_pg/rtpostgis.sql.in.c b/raster/rt_pg/rtpostgis.sql.in.c index 7c83d26ea..ebdc5acb9 100644 --- a/raster/rt_pg/rtpostgis.sql.in.c +++ b/raster/rt_pg/rtpostgis.sql.in.c @@ -22,7 +22,7 @@ -- -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -#include "../../postgis/gserialized.h" +#include "../../libpgcommon/gserialized.h" -- BEGIN;