Replace home-grown axis swapping code with the proj_normalize_for_visualization()

function from proj. This moves responsibility for maintaining "gis friendly"
coordinates, with eastings in X and northings in Y (longitude first, latitude second)
to proj, for proj versions 6.1 and greater. This means that proj 6.0 is
demoted to using the old proj4 proj_api.h header, but otherwise we
lose a bunch of code to maintain, and there should be no major changes in
behaviour.
stable-3.2
pramsey 2021-07-28 13:20:38 -07:00
parent ff9de2c109
commit 0981555c35
7 changed files with 150 additions and 339 deletions

2
.gitignore vendored
View File

@ -1,3 +1,4 @@
*~
*.a
*.la
.libs
@ -29,7 +30,6 @@ doc/html/docbook.css
doc/Makefile
doc/Makefile.comments
doc/po/*/*.xml
doc/po/*/*.po~
doc/po/*/html
doc/po/*/xsl
doc/po/*/*_comments.sql

View File

@ -35,7 +35,11 @@
#include "../postgis_config.h"
#if POSTGIS_PROJ_VERSION < 60
#if POSTGIS_PROJ_VERSION < 61
/* For Proj 6.0 use of old API */
#define ACCEPT_USE_OF_DEPRECATED_PROJ_API_H
#include "proj_api.h"
typedef struct PJ
{
@ -53,16 +57,12 @@ typedef PJ LWPROJ;
*/
typedef struct LWPROJ
{
PJ* pj;
/* CRSs are swapped: Used in transformation calls */
uint8_t source_swapped;
uint8_t target_swapped;
/* Source crs is geographic: Used in geography calls (source srid == dst srid) */
uint8_t source_is_latlong;
/* Source ellipsoid parameters */
double source_semi_major_metre;
double source_semi_minor_metre;
PJ* pj;
/* Source crs is geographic: Used in geography calls (source srid == dst srid) */
uint8_t source_is_latlong;
/* Source ellipsoid parameters */
double source_semi_major_metre;
double source_semi_minor_metre;
} LWPROJ;
#endif
@ -2450,8 +2450,15 @@ int lwgeom_is_simple(const LWGEOM *lwgeom);
******************************************************************************/
int lwgeom_transform_from_str(LWGEOM *geom, const char* instr, const char* outstr);
/**
* Transform (reproject) a geometry in-place.
* @param geom the geometry to transform
* @param pj the transformation
*/
int lwgeom_transform(LWGEOM *geom, LWPROJ* pj);
int ptarray_transform(POINTARRAY *pa, LWPROJ* pj);
#if POSTGIS_PROJ_VERSION < 60
#if POSTGIS_PROJ_VERSION < 61
/**
* Get a projection from a string representation
*
@ -2459,23 +2466,14 @@ int lwgeom_transform_from_str(LWGEOM *geom, const char* instr, const char* outst
*/
projPJ projpj_from_string(const char* txt);
#endif
/**
* Transform (reproject) a geometry in-place.
* @param geom the geometry to transform
* @param pj the input and output
*/
int lwgeom_transform(LWGEOM *geom, LWPROJ* pj);
int ptarray_transform(POINTARRAY *pa, LWPROJ* pj);
#if POSTGIS_PROJ_VERSION >= 60
#else // POSTGIS_PROJ_VERSION >= 61
/**
* Allocate a new LWPROJ containing the reference to the PROJ's PJ
* If extra_geography_data is true, it will generate the following values for
* the source srs: is_latlong (geometric or not) and spheroid values
*/
LWPROJ *lwproj_from_PJ(PJ *pj, int8_t extra_geography_data);
LWPROJ *lwproj_from_str(const char* str_in, const char* str_out);
#endif

View File

@ -46,7 +46,7 @@ to_dec(POINT4D *pt)
/***************************************************************************/
#if POSTGIS_PROJ_VERSION < 60
#if POSTGIS_PROJ_VERSION < 61
static int
point4d_transform(POINT4D *pt, LWPROJ *pj)
@ -136,66 +136,7 @@ lwgeom_transform_from_str(LWGEOM *geom, const char* instr, const char* outstr)
return rv;
}
/**
* Transform given LWGEOM geometry
* from inpj projection to outpj projection
*/
int
lwgeom_transform(LWGEOM *geom, LWPROJ *pj)
{
uint32_t i;
/* No points to transform in an empty! */
if ( lwgeom_is_empty(geom) )
return LW_SUCCESS;
switch(geom->type)
{
case POINTTYPE:
case LINETYPE:
case CIRCSTRINGTYPE:
case TRIANGLETYPE:
{
LWLINE *g = (LWLINE*)geom;
if ( ! ptarray_transform(g->points, pj) ) return LW_FAILURE;
break;
}
case POLYGONTYPE:
{
LWPOLY *g = (LWPOLY*)geom;
for ( i = 0; i < g->nrings; i++ )
{
if ( ! ptarray_transform(g->rings[i], pj) ) return LW_FAILURE;
}
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++ )
{
if ( ! lwgeom_transform(g->geoms[i], pj) ) return LW_FAILURE;
}
break;
}
default:
{
lwerror("lwgeom_transform: Cannot handle type '%s'",
lwtype_name(geom->type));
return LW_FAILURE;
}
}
return LW_SUCCESS;
}
projPJ
projpj_from_string(const char *str1)
@ -209,202 +150,94 @@ projpj_from_string(const char *str1)
/***************************************************************************/
#else /* POSTGIS_PROJ_VERION >= 60 */
static PJ *
proj_cs_get_simplecs(const PJ *pj_crs)
{
PJ *pj_sub = NULL;
if (proj_get_type(pj_crs) == PJ_TYPE_COMPOUND_CRS)
{
/* Sub-CRS[0] is the horizontal component */
pj_sub = proj_crs_get_sub_crs(NULL, pj_crs, 0);
if (!pj_sub)
lwerror("%s: proj_crs_get_sub_crs(0) returned NULL", __func__);
}
else if (proj_get_type(pj_crs) == PJ_TYPE_BOUND_CRS)
{
pj_sub = proj_get_source_crs(NULL, pj_crs);
if (!pj_sub)
lwerror("%s: proj_get_source_crs returned NULL", __func__);
}
else
{
/* If this works, we have a CS so we can return */
pj_sub = proj_crs_get_coordinate_system(NULL, pj_crs);
if (pj_sub)
return pj_sub;
}
/* Only sub-components of the Compound or Bound CRS's get here */
/* If we failed to get sub-components, or we failed to extract */
/* a CS from a generic CRS, then this is another case we don't */
/* handle */
if (!pj_sub)
lwerror("%s: %s", __func__, proj_errno_string(proj_context_errno(NULL)));
/* If the components are usable, we can extract the CS and return */
int pj_type = proj_get_type(pj_sub);
if (pj_type == PJ_TYPE_GEOGRAPHIC_2D_CRS || pj_type == PJ_TYPE_PROJECTED_CRS)
{
PJ *pj_2d = proj_crs_get_coordinate_system(NULL, pj_sub);
proj_destroy(pj_sub);
return pj_2d;
}
/* If the components are *themselves* Bound/Compound, we can recurse */
if (pj_type == PJ_TYPE_COMPOUND_CRS || pj_type == PJ_TYPE_BOUND_CRS)
return proj_cs_get_simplecs(pj_sub);
/* This is a case we don't know how to handle */
lwerror("%s: un-handled CRS sub-type: %s", __func__, pj_type);
return NULL;
}
static uint8_t
proj_crs_is_swapped(const PJ *pj_crs)
{
int axis_count;
PJ *pj_cs = proj_cs_get_simplecs(pj_crs);
if (!pj_cs)
lwerror("%s: proj_cs_get_simplecs returned NULL", __func__);
axis_count = proj_cs_get_axis_count(NULL, pj_cs);
if (axis_count >= 2)
{
const char *out_name1, *out_abbrev1, *out_direction1;
const char *out_name2, *out_abbrev2, *out_direction2;
/* Read first axis */
proj_cs_get_axis_info(NULL,
pj_cs, 0,
&out_name1, &out_abbrev1, &out_direction1,
NULL, NULL, NULL, NULL);
/* Read second axis */
proj_cs_get_axis_info(NULL,
pj_cs, 1,
&out_name2, &out_abbrev2, &out_direction2,
NULL, NULL, NULL, NULL);
proj_destroy(pj_cs);
/* Directions agree, this is a northing/easting CRS, so reverse it */
if(out_direction1 && STR_IEQUALS(out_direction1, "north") &&
out_direction2 && STR_IEQUALS(out_direction2, "east") )
{
return LW_TRUE;
}
/* Oddball case? Both axes north / both axes south, swap */
if(out_direction1 && out_direction2 &&
((STR_IEQUALS(out_direction1, "north") && STR_IEQUALS(out_direction2, "north")) ||
(STR_IEQUALS(out_direction1, "south") && STR_IEQUALS(out_direction2, "south"))) &&
out_name1 && STR_ISTARTS(out_name1, "northing") &&
out_name2 && STR_ISTARTS(out_name2, "easting"))
{
return LW_TRUE;
}
/* Any lat/lon system with Lat in first axis gets swapped */
if (STR_ISTARTS(out_abbrev1, "Lat"))
return LW_TRUE;
return LW_FALSE;
}
/* Failed the axis count test, leave quietly */
proj_destroy(pj_cs);
return LW_FALSE;
}
#else /* POSTGIS_PROJ_VERION >= 61 */
LWPROJ *
lwproj_from_PJ(PJ *pj, int8_t extra_geography_data)
lwproj_from_str(const char* str_in, const char* str_out)
{
PJ *pj_source_crs = proj_get_source_crs(NULL, pj);
uint8_t source_is_latlong = LW_FALSE;
double out_semi_major_metre = DBL_MAX, out_semi_minor_metre = DBL_MAX;
double semi_major_metre = DBL_MAX, semi_minor_metre = DBL_MAX;
if (!pj_source_crs)
{
lwerror("%s: unable to access source crs", __func__);
/* Usable inputs? */
if (! (str_in && str_out))
return NULL;
}
uint8_t source_swapped = proj_crs_is_swapped(pj_source_crs);
/* We only care about the extra values if there is no transformation */
if (!extra_geography_data)
{
proj_destroy(pj_source_crs);
}
else
PJ* pj = proj_create_crs_to_crs(PJ_DEFAULT_CTX, str_in, str_out, NULL);
if (!pj)
return NULL;
/* Fill in geodetic parameter information when a null-transform */
/* is passed, because that's how we signal we want to store */
/* that info in the cache */
if (strcmp(str_in, str_out) == 0)
{
PJ *pj_source_crs = proj_get_source_crs(PJ_DEFAULT_CTX, pj);
PJ *pj_ellps;
double out_inv_flattening;
int out_is_semi_minor_computed;
PJ_TYPE pj_type = proj_get_type(pj_source_crs);
if (pj_type == PJ_TYPE_UNKNOWN)
{
proj_destroy(pj_source_crs);
proj_destroy(pj);
lwerror("%s: unable to access source crs type", __func__);
return NULL;
}
source_is_latlong = (pj_type == PJ_TYPE_GEOGRAPHIC_2D_CRS) || (pj_type == PJ_TYPE_GEOGRAPHIC_3D_CRS);
pj_ellps = proj_get_ellipsoid(NULL, pj_source_crs);
pj_ellps = proj_get_ellipsoid(PJ_DEFAULT_CTX, pj_source_crs);
proj_destroy(pj_source_crs);
if (!pj_ellps)
{
proj_destroy(pj);
lwerror("%s: unable to access source crs ellipsoid", __func__);
return NULL;
}
if (!proj_ellipsoid_get_parameters(NULL,
if (!proj_ellipsoid_get_parameters(PJ_DEFAULT_CTX,
pj_ellps,
&out_semi_major_metre,
&out_semi_minor_metre,
&out_is_semi_minor_computed,
&out_inv_flattening))
&semi_major_metre,
&semi_minor_metre,
NULL,
NULL))
{
proj_destroy(pj_ellps);
proj_destroy(pj);
lwerror("%s: unable to access source crs ellipsoid parameters", __func__);
return NULL;
}
proj_destroy(pj_ellps);
}
PJ *pj_target_crs = proj_get_target_crs(NULL, pj);
if (!pj_target_crs)
{
lwerror("%s: unable to access target crs", __func__);
return NULL;
}
uint8_t target_swapped = proj_crs_is_swapped(pj_target_crs);
proj_destroy(pj_target_crs);
/* Add in an axis swap if necessary */
PJ* pj_norm = proj_normalize_for_visualization(PJ_DEFAULT_CTX, pj);
/* Swap failed for some reason? Fall back to coordinate operation */
if (!pj_norm)
pj_norm = pj;
/* Swap is not a copy of input? Clean up input */
else if (pj != pj_norm)
proj_destroy(pj);
/* Allocate and populate return value */
LWPROJ *lp = lwalloc(sizeof(LWPROJ));
lp->pj = pj;
lp->source_swapped = source_swapped;
lp->target_swapped = target_swapped;
lp->pj = pj_norm; /* Caller is going to have to explicitly proj_destroy this */
lp->source_is_latlong = LW_FALSE;
lp->source_is_latlong = source_is_latlong;
lp->source_semi_major_metre = out_semi_major_metre;
lp->source_semi_minor_metre = out_semi_minor_metre;
lp->source_semi_major_metre = semi_major_metre;
lp->source_semi_minor_metre = semi_minor_metre;
return lp;
}
int
lwgeom_transform_from_str(LWGEOM *geom, const char* instr, const char* outstr)
{
PJ *pj = proj_create_crs_to_crs(NULL, instr, outstr, NULL);
if (!pj)
LWPROJ *lp = lwproj_from_str(instr, outstr);
if (!lp)
{
PJ *pj_in = proj_create(NULL, instr);
PJ *pj_in = proj_create(PJ_DEFAULT_CTX, instr);
if (!pj_in)
{
lwerror("could not parse proj string '%s'", instr);
}
proj_destroy(pj_in);
PJ *pj_out = proj_create(NULL, outstr);
PJ *pj_out = proj_create(PJ_DEFAULT_CTX, outstr);
if (!pj_out)
{
lwerror("could not parse proj string '%s'", outstr);
@ -413,77 +246,11 @@ lwgeom_transform_from_str(LWGEOM *geom, const char* instr, const char* outstr)
lwerror("%s: Failed to transform", __func__);
return LW_FAILURE;
}
LWPROJ *lp = lwproj_from_PJ(pj, LW_FALSE);
int ret = lwgeom_transform(geom, lp);
proj_destroy(pj);
lwfree(lp);
proj_destroy(lp->pj);
return ret;
}
int
lwgeom_transform(LWGEOM *geom, LWPROJ *pj)
{
uint32_t i;
/* No points to transform in an empty! */
if (lwgeom_is_empty(geom))
return LW_SUCCESS;
switch(geom->type)
{
case POINTTYPE:
case LINETYPE:
case CIRCSTRINGTYPE:
case TRIANGLETYPE:
{
LWLINE *g = (LWLINE*)geom;
if (!ptarray_transform(g->points, pj))
return LW_FAILURE;
break;
}
case POLYGONTYPE:
{
LWPOLY *g = (LWPOLY*)geom;
for (i = 0; i < g->nrings; i++)
{
if (!ptarray_transform(g->rings[i], pj))
return LW_FAILURE;
}
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++)
{
if (!lwgeom_transform(g->geoms[i], pj))
return LW_FAILURE;
}
break;
}
default:
{
lwerror("lwgeom_transform: Cannot handle type '%s'",
lwtype_name(geom->type));
return LW_FAILURE;
}
}
return LW_SUCCESS;
}
int
ptarray_transform(POINTARRAY *pa, LWPROJ *pj)
{
@ -505,9 +272,6 @@ ptarray_transform(POINTARRAY *pa, LWPROJ *pj)
}
}
if (pj->source_swapped)
ptarray_swap_ordinates(pa, LWORD_X, LWORD_Y);
if (n_points == 1)
{
/* For single points it's faster to call proj_trans */
@ -567,9 +331,6 @@ ptarray_transform(POINTARRAY *pa, LWPROJ *pj)
}
}
if (pj->target_swapped)
ptarray_swap_ordinates(pa, LWORD_X, LWORD_Y);
/* Convert radians to degrees if necessary */
if (proj_angular_output(pj->pj, PJ_FWD))
{
@ -584,3 +345,64 @@ ptarray_transform(POINTARRAY *pa, LWPROJ *pj)
}
#endif
/**
* Transform given LWGEOM geometry
* from inpj projection to outpj projection
*/
int
lwgeom_transform(LWGEOM *geom, LWPROJ *pj)
{
uint32_t i;
/* No points to transform in an empty! */
if ( lwgeom_is_empty(geom) )
return LW_SUCCESS;
switch(geom->type)
{
case POINTTYPE:
case LINETYPE:
case CIRCSTRINGTYPE:
case TRIANGLETYPE:
{
LWLINE *g = (LWLINE*)geom;
if ( ! ptarray_transform(g->points, pj) ) return LW_FAILURE;
break;
}
case POLYGONTYPE:
{
LWPOLY *g = (LWPOLY*)geom;
for ( i = 0; i < g->nrings; i++ )
{
if ( ! ptarray_transform(g->rings[i], pj) ) return LW_FAILURE;
}
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++ )
{
if ( ! lwgeom_transform(g->geoms[i], pj) ) return LW_FAILURE;
}
break;
}
default:
{
lwerror("lwgeom_transform: Cannot handle type '%s'",
lwtype_name(geom->type));
return LW_FAILURE;
}
}
return LW_SUCCESS;
}

View File

@ -67,8 +67,8 @@ static void
PROJSRSDestroyPJ(void *projection)
{
LWPROJ *pj = (LWPROJ *)projection;
#if POSTGIS_PROJ_VERSION < 60
/* Ape the Proj 6+ API for versions < 6 */
#if POSTGIS_PROJ_VERSION < 61
/* Ape the Proj 6+ API for versions < 6.1 */
if (pj->pj_from)
{
pj_free(pj->pj_from);
@ -359,7 +359,7 @@ pjstrs_pfree(PjStrs *strs)
pfree(strs->srtext);
}
#if POSTGIS_PROJ_VERSION >= 60
#if POSTGIS_PROJ_VERSION >= 61
static char*
pgstrs_get_entry(const PjStrs *strs, int n)
{
@ -377,7 +377,7 @@ pgstrs_get_entry(const PjStrs *strs, int n)
}
#endif
#if POSTGIS_PROJ_VERSION < 60
#if POSTGIS_PROJ_VERSION < 61
/*
* Utility function for GML reader that still
* needs proj4text access
@ -421,7 +421,7 @@ AddToPROJSRSCache(PROJSRSCache *PROJCache, int32_t srid_from, int32_t srid_to)
oldContext = MemoryContextSwitchTo(PROJCache->PROJSRSCacheContext);
#if POSTGIS_PROJ_VERSION < 60
#if POSTGIS_PROJ_VERSION < 61
PJ *projection = palloc(sizeof(PJ));
pj_from_str = from_strs.proj4text;
pj_to_str = to_strs.proj4text;
@ -438,7 +438,8 @@ AddToPROJSRSCache(PROJSRSCache *PROJCache, int32_t srid_from, int32_t srid_to)
"could not form projection from 'srid=%d' to 'srid=%d'",
srid_from, srid_to);
#else
PJ *projpj = NULL;
LWPROJ *projection = NULL;
/* Try combinations of ESPG/SRTEXT/PROJ4TEXT until we find */
/* one that gives us a usable transform. Note that we prefer */
/* EPSG numbers over SRTEXT and SRTEXT over PROJ4TEXT */
@ -450,16 +451,11 @@ AddToPROJSRSCache(PROJSRSCache *PROJCache, int32_t srid_from, int32_t srid_to)
pj_to_str = pgstrs_get_entry(&to_strs, i % 3);
if (!(pj_from_str && pj_to_str))
continue;
projpj = proj_create_crs_to_crs(NULL, pj_from_str, pj_to_str, NULL);
if (projpj && !proj_errno(projpj))
projection = lwproj_from_str(pj_from_str, pj_to_str);
if (projection)
break;
}
if (!projpj)
{
elog(ERROR, "could not form projection (PJ) from 'srid=%d' to 'srid=%d'", srid_from, srid_to);
return NULL;
}
LWPROJ *projection = lwproj_from_PJ(projpj, srid_from == srid_to);
if (!projection)
{
elog(ERROR, "could not form projection (LWPROJ) from 'srid=%d' to 'srid=%d'", srid_from, srid_to);
@ -557,7 +553,7 @@ GetLWPROJ(int32_t srid_from, int32_t srid_to, LWPROJ **pj)
static int
proj_pj_is_latlong(const LWPROJ *pj)
{
#if POSTGIS_PROJ_VERSION < 60
#if POSTGIS_PROJ_VERSION < 61
return pj_is_latlong(pj->pj_from);
#else
return pj->source_is_latlong;
@ -611,14 +607,14 @@ int
spheroid_init_from_srid(int32_t srid, SPHEROID *s)
{
LWPROJ *pj;
#if POSTGIS_PROJ_VERSION >= 48 && POSTGIS_PROJ_VERSION < 60
#if POSTGIS_PROJ_VERSION >= 48 && POSTGIS_PROJ_VERSION < 61
double major_axis, minor_axis, eccentricity_squared;
#endif
if ( GetLWPROJ(srid, srid, &pj) == LW_FAILURE)
return LW_FAILURE;
#if POSTGIS_PROJ_VERSION >= 60
#if POSTGIS_PROJ_VERSION >= 61
if (!pj->source_is_latlong)
return LW_FAILURE;
spheroid_init(s, pj->source_semi_major_metre, pj->source_semi_minor_metre);

View File

@ -56,7 +56,7 @@ typedef struct srs_precision
int precision_m;
} srs_precision;
#if POSTGIS_PROJ_VERSION < 60
#if POSTGIS_PROJ_VERSION < 61
/* Needs to call postgis_initialize_cache first */
char *GetProj4String(int32_t srid);
#endif

View File

@ -112,7 +112,7 @@ Datum geom_from_gml(PG_FUNCTION_ARGS)
/* Zero for undefined */
root_srid = PG_GETARG_INT32(1);
#if POSTGIS_PROJ_VERSION < 60
#if POSTGIS_PROJ_VERSION < 61
/* Internally lwgeom_from_gml calls gml_reproject_pa which, for PROJ before 6, called GetProj4String.
* That function requires access to spatial_ref_sys, so in order to have it ready we need to ensure
* the internal cache is initialized
@ -303,12 +303,12 @@ static xmlNodePtr get_xlink_node(xmlNodePtr xnode)
* Use Proj to reproject a given POINTARRAY
*/
#if POSTGIS_PROJ_VERSION < 60
#if POSTGIS_PROJ_VERSION < 61
static POINTARRAY *
gml_reproject_pa(POINTARRAY *pa, int32_t srid_in, int32_t srid_out)
{
PJ pj;
LWPROJ pj;
char *text_in, *text_out;
if (srid_in == SRID_UNKNOWN) return pa; /* nothing to do */
@ -333,16 +333,12 @@ gml_reproject_pa(POINTARRAY *pa, int32_t srid_in, int32_t srid_out)
return pa;
}
#else
/*
* TODO: rework GML projection handling to skip the spatial_ref_sys
* lookups, and use the Proj 6+ EPSG catalogue and built-in SRID
* lookups directly. Drop this ugly hack.
*/
#else /* POSTGIS_PROJ_VERSION >= 61 */
static POINTARRAY *
gml_reproject_pa(POINTARRAY *pa, int32_t epsg_in, int32_t epsg_out)
{
PJ *pj;
LWPROJ *lwp;
char text_in[16];
char text_out[16];
@ -358,27 +354,26 @@ gml_reproject_pa(POINTARRAY *pa, int32_t epsg_in, int32_t epsg_out)
snprintf(text_in, 16, "EPSG:%d", epsg_in);
snprintf(text_out, 16, "EPSG:%d", epsg_out);
pj = proj_create_crs_to_crs(NULL, text_in, text_out, NULL);
lwp = lwproj_from_PJ(pj, LW_FALSE);
lwp = lwproj_from_str(text_in, text_out);
if (!lwp)
{
proj_destroy(pj);
gml_lwpgerror("Could not create LWPROJ*", 57);
return NULL;
}
if (ptarray_transform(pa, lwp) == LW_FAILURE)
{
proj_destroy(pj);
elog(ERROR, "gml_reproject_pa: reprojection failed");
return NULL;
}
proj_destroy(pj);
proj_destroy(lwp->pj);
pfree(lwp);
return pa;
}
#endif /* POSTGIS_PROJ_VERSION */

View File

@ -152,7 +152,7 @@ Datum transform_geom(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(postgis_proj_version);
Datum postgis_proj_version(PG_FUNCTION_ARGS)
{
#if POSTGIS_PROJ_VERSION < 60
#if POSTGIS_PROJ_VERSION < 61
const char *ver = pj_get_release();
text *result = cstring_to_text(ver);
#else