From 7c054713e9c50ab531dc8d3d98e08029ebb00612 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Ra=C3=BAl=20Mar=C3=ADn=20Rodr=C3=ADguez?= Date: Wed, 19 Jun 2019 15:12:21 +0000 Subject: [PATCH] PROJ6: Speed improvements Caches more elements to avoid recalculation per row References #4372 git-svn-id: http://svn.osgeo.org/postgis/trunk@17541 b70326c6-7e19-0410-871a-916f4a2858ee --- NEWS | 3 +- liblwgeom/liblwgeom.h.in | 39 +++++- liblwgeom/lwgeom_transform.c | 248 +++++++++++++++++++++------------ libpgcommon/lwgeom_cache.h | 2 +- libpgcommon/lwgeom_transform.c | 85 +++++------ libpgcommon/lwgeom_transform.h | 2 +- postgis/lwgeom_in_gml.c | 28 +++- postgis/lwgeom_transform.c | 4 +- 8 files changed, 257 insertions(+), 154 deletions(-) diff --git a/NEWS b/NEWS index f16b1f5a0..7bccbe67d 100644 --- a/NEWS +++ b/NEWS @@ -13,7 +13,8 @@ Additional features enabled if you are running Proj6+ and PostgreSQL 12 - #4388, AddRasterConstraints: Ignore NULLs when generating constraints (Raúl Marín) - #4327, Avoid pfree'ing the result of getenv (Raúl Marín) - #4406, Throw on invalid characters when decoding geohash (Raúl Marín) - - #4372, Avoid resource leaks with PROJ6 (Raúl Marín) + - #4429, Avoid resource leaks with PROJ6 (Raúl Marín) + - #4372, PROJ6: Speed improvements (Raúl Marín) PostGIS 3.0.0alpha2 2019/06/02 diff --git a/liblwgeom/liblwgeom.h.in b/liblwgeom/liblwgeom.h.in index 86f2c623c..2350e4fda 100644 --- a/liblwgeom/liblwgeom.h.in +++ b/liblwgeom/liblwgeom.h.in @@ -30,8 +30,8 @@ #define _LIBLWGEOM_H 1 #include -#include #include +#include #include "../postgis_config.h" @@ -42,8 +42,28 @@ typedef struct PJ projPJ pj_from; projPJ pj_to; } PJ; + +typedef PJ LWPROJ; + #else #include "proj.h" + +/* For PROJ6 we cache several extra values to avoid calls to proj_get_source_crs + * or proj_get_target_crs since those are very costly + */ +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; +} LWPROJ; #endif #if POSTGIS_PROJ_VERSION < 49 @@ -2358,7 +2378,7 @@ int lwgeom_transform_from_str(LWGEOM *geom, const char* instr, const char* outst * * Eg: "+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs" */ -projPJ lwproj_from_string(const char* txt); +projPJ projpj_from_string(const char* txt); #endif /** @@ -2366,8 +2386,19 @@ projPJ lwproj_from_string(const char* txt); * @param geom the geometry to transform * @param PJ the input and output */ -int lwgeom_transform(LWGEOM *geom, PJ* pj); -int ptarray_transform(POINTARRAY *pa, PJ* pj); +int lwgeom_transform(LWGEOM *geom, LWPROJ* pj); +int ptarray_transform(POINTARRAY *pa, LWPROJ* pj); + +#if POSTGIS_PROJ_VERSION >= 60 + +/** + * 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); + +#endif /******************************************************************************* diff --git a/liblwgeom/lwgeom_transform.c b/liblwgeom/lwgeom_transform.c index af4b09453..5fe145f86 100644 --- a/liblwgeom/lwgeom_transform.c +++ b/liblwgeom/lwgeom_transform.c @@ -48,9 +48,8 @@ to_dec(POINT4D *pt) #if POSTGIS_PROJ_VERSION < 60 - static int -point4d_transform(POINT4D *pt, PJ* pj) +point4d_transform(POINT4D *pt, LWPROJ *pj) { POINT3D orig_pt = {pt->x, pt->y, pt->z}; /* Copy for error report*/ @@ -90,7 +89,7 @@ point4d_transform(POINT4D *pt, PJ* pj) * from inpj projection to outpj projection */ int -ptarray_transform(POINTARRAY *pa, PJ* pj) +ptarray_transform(POINTARRAY *pa, LWPROJ *pj) { uint32_t i; POINT4D p; @@ -110,9 +109,9 @@ lwgeom_transform_from_str(LWGEOM *geom, const char* instr, const char* outstr) { char *pj_errstr; int rv; - PJ pj; + LWPROJ pj; - pj.pj_from = lwproj_from_string(instr); + pj.pj_from = projpj_from_string(instr); if (!pj.pj_from) { pj_errstr = pj_strerrno(*pj_get_errno_ref()); @@ -121,7 +120,7 @@ lwgeom_transform_from_str(LWGEOM *geom, const char* instr, const char* outstr) return LW_FAILURE; } - pj.pj_to = lwproj_from_string(outstr); + pj.pj_to = projpj_from_string(outstr); if (!pj.pj_to) { pj_free(pj.pj_from); @@ -142,7 +141,7 @@ lwgeom_transform_from_str(LWGEOM *geom, const char* instr, const char* outstr) * from inpj projection to outpj projection */ int -lwgeom_transform(LWGEOM *geom, PJ* pj) +lwgeom_transform(LWGEOM *geom, LWPROJ *pj) { uint32_t i; @@ -199,7 +198,7 @@ lwgeom_transform(LWGEOM *geom, PJ* pj) } projPJ -lwproj_from_string(const char *str1) +projpj_from_string(const char *str1) { if (!str1 || str1[0] == '\0') { @@ -212,6 +211,132 @@ lwproj_from_string(const char *str1) #else /* POSTGIS_PROJ_VERION >= 60 */ +static uint8_t +proj_crs_is_swapped(const PJ *pj_crs) +{ + PJ *pj_cs; + uint8_t rv = LW_FALSE; + + if (proj_get_type(pj_crs) == PJ_TYPE_COMPOUND_CRS) + { + PJ *pj_horiz_crs = proj_crs_get_sub_crs(NULL, pj_crs, 0); + if (!pj_horiz_crs) + lwerror("%s: proj_crs_get_sub_crs returned NULL", __func__); + pj_cs = proj_crs_get_coordinate_system(NULL, pj_horiz_crs); + proj_destroy(pj_horiz_crs); + } + else if (proj_get_type(pj_crs) == PJ_TYPE_BOUND_CRS) + { + PJ *pj_src_crs = proj_get_source_crs(NULL, pj_crs); + if (!pj_src_crs) + lwerror("%s: proj_get_source_crs returned NULL", __func__); + pj_cs = proj_crs_get_coordinate_system(NULL, pj_src_crs); + proj_destroy(pj_src_crs); + } + else + { + pj_cs = proj_crs_get_coordinate_system(NULL, pj_crs); + } + if (!pj_cs) + lwerror("%s: proj_crs_get_coordinate_system returned NULL", __func__); + int axis_count = proj_cs_get_axis_count(NULL, pj_cs); + if (axis_count > 0) + { + const char *out_name, *out_abbrev, *out_direction; + double out_unit_conv_factor; + const char *out_unit_name, *out_unit_auth_name, *out_unit_code; + /* Read only first axis, see if it is degrees / north */ + proj_cs_get_axis_info(NULL, + pj_cs, + 0, + &out_name, + &out_abbrev, + &out_direction, + &out_unit_conv_factor, + &out_unit_name, + &out_unit_auth_name, + &out_unit_code); + rv = (strcasecmp(out_direction, "north") == 0); + } + proj_destroy(pj_cs); + return rv; +} + +LWPROJ * +lwproj_from_PJ(PJ *pj, int8_t extra_geography_data) +{ + 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; + + if (!pj_source_crs) + { + lwerror("%s: unable to access source crs", __func__); + 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_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); + 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); + proj_destroy(pj_source_crs); + if (!pj_ellps) + { + lwerror("%s: unable to access source crs ellipsoid", __func__); + return NULL; + } + if (!proj_ellipsoid_get_parameters(NULL, + pj_ellps, + &out_semi_major_metre, + &out_semi_minor_metre, + &out_is_semi_minor_computed, + &out_inv_flattening)) + { + proj_destroy(pj_ellps); + 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); + + LWPROJ *lp = malloc(sizeof(LWPROJ)); + lp->pj = pj; + lp->source_swapped = source_swapped; + lp->target_swapped = target_swapped; + 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; + + return lp; +} + int lwgeom_transform_from_str(LWGEOM *geom, const char* instr, const char* outstr) { @@ -235,14 +360,18 @@ lwgeom_transform_from_str(LWGEOM *geom, const char* instr, const char* outstr) return LW_FAILURE; } - int ret = lwgeom_transform(geom, pj); + LWPROJ *lp = lwproj_from_PJ(pj, LW_FALSE); + + int ret = lwgeom_transform(geom, lp); + proj_destroy(pj); + free(lp); return ret; } int -lwgeom_transform(LWGEOM* geom, PJ* pj) +lwgeom_transform(LWGEOM *geom, LWPROJ *pj) { uint32_t i; @@ -301,56 +430,8 @@ lwgeom_transform(LWGEOM* geom, PJ* pj) return LW_SUCCESS; } -static int -proj_crs_is_swapped(const PJ* pj_crs) -{ - PJ *pj_cs; - int rv = LW_FALSE; - - if (proj_get_type(pj_crs) == PJ_TYPE_COMPOUND_CRS) - { - PJ *pj_horiz_crs = proj_crs_get_sub_crs(NULL, pj_crs, 0); - if (!pj_horiz_crs) lwerror("%s: proj_crs_get_sub_crs returned NULL", __func__); - pj_cs = proj_crs_get_coordinate_system(NULL, pj_horiz_crs); - proj_destroy(pj_horiz_crs); - } - else if (proj_get_type(pj_crs) == PJ_TYPE_BOUND_CRS) - { - PJ *pj_src_crs = proj_get_source_crs(NULL, pj_crs); - if (!pj_src_crs) lwerror("%s: proj_get_source_crs returned NULL", __func__); - pj_cs = proj_crs_get_coordinate_system(NULL, pj_src_crs); - proj_destroy(pj_src_crs); - } - else - { - pj_cs = proj_crs_get_coordinate_system(NULL, pj_crs); - } - if (!pj_cs) lwerror("%s: proj_crs_get_coordinate_system returned NULL", __func__); - int axis_count = proj_cs_get_axis_count(NULL, pj_cs); - if (axis_count > 0) - { - const char *out_name, *out_abbrev, *out_direction; - double out_unit_conv_factor; - const char *out_unit_name, *out_unit_auth_name, *out_unit_code; - /* Read only first axis, see if it is degrees / north */ - proj_cs_get_axis_info(NULL, pj_cs, 0, - &out_name, - &out_abbrev, - &out_direction, - &out_unit_conv_factor, - &out_unit_name, - &out_unit_auth_name, - &out_unit_code - ); - rv = (strcasecmp(out_direction, "north") == 0); - } - proj_destroy(pj_cs); - return rv; -} - - int -ptarray_transform(POINTARRAY* pa, PJ* pj) +ptarray_transform(POINTARRAY *pa, LWPROJ *pj) { uint32_t i; POINT4D p; @@ -359,24 +440,9 @@ ptarray_transform(POINTARRAY* pa, PJ* pj) size_t point_size = ptarray_point_size(pa); int has_z = ptarray_has_z(pa); double *pa_double = (double*)(pa->serialized_pointlist); - int input_swapped, output_swapped; - - PJ* pj_source_crs = proj_get_source_crs(NULL, pj); - PJ* pj_target_crs = proj_get_target_crs(NULL, pj); - - if (!(pj_source_crs && pj_target_crs)) - { - lwerror("ptarray_transform: unable to access source and target crs"); - return LW_FAILURE; - } - - input_swapped = proj_crs_is_swapped(pj_source_crs); - output_swapped = proj_crs_is_swapped(pj_target_crs); - proj_destroy(pj_source_crs); - proj_destroy(pj_target_crs); /* Convert to radians if necessary */ - if (proj_angular_input(pj, PJ_FWD)) + if (proj_angular_input(pj->pj, PJ_FWD)) /* CACHE THIS TOO */ { for (i = 0; i < pa->npoints; i++) { @@ -385,7 +451,7 @@ ptarray_transform(POINTARRAY* pa, PJ* pj) } } - if (input_swapped) + if (pj->source_swapped) ptarray_swap_ordinates(pa, LWORD_X, LWORD_Y); /* @@ -396,15 +462,21 @@ ptarray_transform(POINTARRAY* pa, PJ* pj) * double *t, size_t st, size_t nt) */ - n_converted = proj_trans_generic( - pj, PJ_FWD, - pa_double, point_size, n_points, /* X */ - pa_double + 1, point_size, n_points, /* Y */ - has_z ? pa_double + 2 : NULL, - has_z ? point_size : 0, - has_z ? n_points : 0, /* Z */ - NULL, 0, 0 /* M */ - ); + n_converted = proj_trans_generic(pj->pj, + PJ_FWD, + pa_double, + point_size, + n_points, /* X */ + pa_double + 1, + point_size, + n_points, /* Y */ + has_z ? pa_double + 2 : NULL, + has_z ? point_size : 0, + has_z ? n_points : 0, /* Z */ + NULL, + 0, + 0 /* M */ + ); if (n_converted != n_points) { @@ -413,7 +485,7 @@ ptarray_transform(POINTARRAY* pa, PJ* pj) return LW_FAILURE; } - int pj_errno_val = proj_errno(pj); + int pj_errno_val = proj_errno(pj->pj); if (pj_errno_val) { lwerror("transform: %s (%d)", @@ -421,11 +493,11 @@ ptarray_transform(POINTARRAY* pa, PJ* pj) return LW_FAILURE; } - if (output_swapped) + if (pj->target_swapped) ptarray_swap_ordinates(pa, LWORD_X, LWORD_Y); /* Convert radians to degrees if necessary */ - if (proj_angular_output(pj, PJ_FWD)) + if (proj_angular_output(pj->pj, PJ_FWD)) { for (i = 0; i < pa->npoints; i++) { diff --git a/libpgcommon/lwgeom_cache.h b/libpgcommon/lwgeom_cache.h index 68fc7a2c7..b6ccc25a7 100644 --- a/libpgcommon/lwgeom_cache.h +++ b/libpgcommon/lwgeom_cache.h @@ -67,7 +67,7 @@ typedef struct struct_PROJSRSCacheItem { int32_t srid_from; int32_t srid_to; - PJ* projection; + LWPROJ *projection; MemoryContext projection_mcxt; } PROJSRSCacheItem; diff --git a/libpgcommon/lwgeom_transform.c b/libpgcommon/lwgeom_transform.c index 5a8338fc4..f5a612a1e 100644 --- a/libpgcommon/lwgeom_transform.c +++ b/libpgcommon/lwgeom_transform.c @@ -77,7 +77,7 @@ typedef struct { typedef struct struct_PJHashEntry { MemoryContext ProjectionContext; - PJ* projection; + LWPROJ *projection; } PJHashEntry; @@ -87,8 +87,8 @@ uint32 mcxt_ptr_hash(const void *key, Size keysize); static HTAB *CreatePJHash(void); static void DeletePJHashEntry(MemoryContext mcxt); -static PJ* GetPJHashEntry(MemoryContext mcxt); -static void AddPJHashEntry(MemoryContext mcxt, PJ* projection); +static LWPROJ *GetPJHashEntry(MemoryContext mcxt); +static void AddPJHashEntry(MemoryContext mcxt, LWPROJ *projection); /* Internal Cache API */ /* static PROJPortalCache *GetPROJSRSCache(FunctionCallInfo fcinfo) ; */ @@ -127,7 +127,7 @@ SetSpatialRefSysSchema(FunctionCallInfo fcinfo) } static void -PROJSRSDestroyPJ(PJ* pj) +PROJSRSDestroyPJ(LWPROJ *pj) { #if POSTGIS_PROJ_VERSION < 60 /* Ape the Proj 6+ API for versions < 6 */ @@ -137,7 +137,8 @@ PROJSRSDestroyPJ(PJ* pj) pj_free(pj->pj_to); free(pj); #else - proj_destroy(pj); + proj_destroy(pj->pj); + free(pj); #endif } @@ -163,7 +164,7 @@ PROJSRSCacheDelete(void *ptr) #endif /* Lookup the PJ pointer in the global hash table so we can free it */ - PJ* projection = GetPJHashEntry(context); + LWPROJ *projection = GetPJHashEntry(context); if (!projection) elog(ERROR, "PROJSRSCacheDelete: Trying to delete non-existant projection object with MemoryContext key (%p)", (void *)context); @@ -278,7 +279,8 @@ static HTAB *CreatePJHash(void) return hash_create("PostGIS PROJ Backend MemoryContext Hash", PROJ_BACKEND_HASH_SIZE, &ctl, (HASH_ELEM | HASH_FUNCTION)); } -static void AddPJHashEntry(MemoryContext mcxt, PJ* projection) +static void +AddPJHashEntry(MemoryContext mcxt, LWPROJ *projection) { bool found; void **key; @@ -301,7 +303,8 @@ static void AddPJHashEntry(MemoryContext mcxt, PJ* projection) } } -static PJ* GetPJHashEntry(MemoryContext mcxt) +static LWPROJ * +GetPJHashEntry(MemoryContext mcxt) { void **key; PJHashEntry *he; @@ -356,7 +359,7 @@ IsInPROJSRSCache(PROJPortalCache *cache, int32_t srid_from, int32_t srid_to) return false; } -static PJ * +static LWPROJ * GetProjectionFromPROJCache(PROJPortalCache *cache, int32_t srid_from, int32_t srid_to) { uint32_t i; @@ -644,8 +647,8 @@ AddToPROJSRSCache(PROJPortalCache *PROJCache, int32_t srid_from, int32_t srid_to PJ* projection = malloc(sizeof(PJ)); pj_from_str = from_strs.proj4text; pj_to_str = to_strs.proj4text; - projection->pj_from = lwproj_from_string(pj_from_str); - projection->pj_to = lwproj_from_string(pj_to_str); + projection->pj_from = projpj_from_string(pj_from_str); + projection->pj_to = projpj_from_string(pj_to_str); if (!projection->pj_from) elog(ERROR, @@ -657,7 +660,7 @@ AddToPROJSRSCache(PROJPortalCache *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* projection = NULL; + PJ *projpj = 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 */ @@ -669,15 +672,20 @@ AddToPROJSRSCache(PROJPortalCache *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; - projection = proj_create_crs_to_crs(NULL, pj_from_str, pj_to_str, NULL); - if (projection && !proj_errno(projection)) + projpj = proj_create_crs_to_crs(NULL, pj_from_str, pj_to_str, NULL); + if (projpj && !proj_errno(projpj)) break; } + if (!projpj) + { + elog(ERROR, "could not form projection (PJ) from 'srid=%d' to 'srid=%d'", srid_from, srid_to); + return; + } + LWPROJ *projection = lwproj_from_PJ(projpj, srid_from == srid_to); if (!projection) { - elog(ERROR, - "could not form projection from 'srid=%d' to 'srid=%d'", - srid_from, srid_to); + elog(ERROR, "could not form projection (LWPROJ) from 'srid=%d' to 'srid=%d'", srid_from, srid_to); + return; } #endif @@ -836,7 +844,7 @@ void SetPROJLibPath(void) } int -GetPJUsingFCInfo(FunctionCallInfo fcinfo, int32_t srid_from, int32_t srid_to, PJ **pj) +GetPJUsingFCInfo(FunctionCallInfo fcinfo, int32_t srid_from, int32_t srid_to, LWPROJ **pj) { PROJPortalCache *proj_cache = NULL; @@ -862,26 +870,19 @@ GetPJUsingFCInfo(FunctionCallInfo fcinfo, int32_t srid_from, int32_t srid_to, PJ } static int -proj_pj_is_latlong(const PJ* pj) +proj_pj_is_latlong(const LWPROJ *pj) { #if POSTGIS_PROJ_VERSION < 60 return pj_is_latlong(pj->pj_from); #else - PJ_TYPE pj_type; - PJ *pj_src_crs = proj_get_source_crs(NULL, pj); - if (!pj_src_crs) - elog(ERROR, "%s: proj_get_source_crs returned NULL", __func__); - pj_type = proj_get_type(pj_src_crs); - proj_destroy(pj_src_crs); - return (pj_type == PJ_TYPE_GEOGRAPHIC_2D_CRS) || - (pj_type == PJ_TYPE_GEOGRAPHIC_3D_CRS); + return pj->source_is_latlong; #endif } static int srid_is_latlong(FunctionCallInfo fcinfo, int32_t srid) { - PJ* pj; + LWPROJ *pj; if ( GetPJUsingFCInfo(fcinfo, srid, srid, &pj) == LW_FAILURE) return LW_FALSE; return proj_pj_is_latlong(pj); @@ -924,12 +925,8 @@ srid_axis_precision(FunctionCallInfo fcinfo, int32_t srid, int precision) int spheroid_init_from_srid(FunctionCallInfo fcinfo, int32_t srid, SPHEROID *s) { - PJ* pj; -#if POSTGIS_PROJ_VERSION >= 60 - double out_semi_major_metre, out_semi_minor_metre, out_inv_flattening; - int out_is_semi_minor_computed; - PJ *pj_ellps, *pj_crs; -#elif POSTGIS_PROJ_VERSION >= 48 + LWPROJ *pj; +#if POSTGIS_PROJ_VERSION >= 48 && POSTGIS_PROJ_VERSION < 60 double major_axis, minor_axis, eccentricity_squared; #endif @@ -937,25 +934,9 @@ spheroid_init_from_srid(FunctionCallInfo fcinfo, int32_t srid, SPHEROID *s) return LW_FAILURE; #if POSTGIS_PROJ_VERSION >= 60 - if (!proj_pj_is_latlong(pj)) + if (!pj->source_is_latlong) return LW_FAILURE; - pj_crs = proj_get_source_crs(NULL, pj); - if (!pj_crs) - { - lwerror("%s: proj_get_source_crs returned NULL", __func__); - } - pj_ellps = proj_get_ellipsoid(NULL, pj_crs); - if (!pj_ellps) - { - proj_destroy(pj_crs); - lwerror("%s: proj_get_ellipsoid returned NULL", __func__); - } - proj_ellipsoid_get_parameters(NULL, pj_ellps, - &out_semi_major_metre, &out_semi_minor_metre, - &out_is_semi_minor_computed, &out_inv_flattening); - proj_destroy(pj_ellps); - proj_destroy(pj_crs); - spheroid_init(s, out_semi_major_metre, out_semi_minor_metre); + spheroid_init(s, pj->source_semi_major_metre, pj->source_semi_minor_metre); #elif POSTGIS_PROJ_VERSION >= 48 if (!pj_is_latlong(pj->pj_from)) diff --git a/libpgcommon/lwgeom_transform.h b/libpgcommon/lwgeom_transform.h index 32d400927..bd9b414c8 100644 --- a/libpgcommon/lwgeom_transform.h +++ b/libpgcommon/lwgeom_transform.h @@ -32,7 +32,7 @@ typedef void *ProjCache ; void SetPROJLibPath(void); bool IsInPROJCache(ProjCache cache, int32_t srid_from, int32_t srid_to); PJ *GetPJFromPROJCache(ProjCache cache, int32_t srid_from, int32_t srid_to); -int GetPJUsingFCInfo(FunctionCallInfo fcinfo, int32_t srid_from, int32_t srid_to, PJ **pj); +int GetPJUsingFCInfo(FunctionCallInfo fcinfo, int32_t srid_from, int32_t srid_to, LWPROJ **pj); int spheroid_init_from_srid(FunctionCallInfo fcinfo, int32_t srid, SPHEROID *s); void srid_check_latlong(FunctionCallInfo fcinfo, int32_t srid); srs_precision srid_axis_precision(FunctionCallInfo fcinfo, int32_t srid, int precision); diff --git a/postgis/lwgeom_in_gml.c b/postgis/lwgeom_in_gml.c index 57b2846ca..a1d162caf 100644 --- a/postgis/lwgeom_in_gml.c +++ b/postgis/lwgeom_in_gml.c @@ -311,8 +311,8 @@ gml_reproject_pa(POINTARRAY *pa, int32_t srid_in, int32_t srid_out) text_in = GetProj4String(srid_in); text_out = GetProj4String(srid_out); - pj.pj_from = lwproj_from_string(text_in); - pj.pj_to = lwproj_from_string(text_out); + pj.pj_from = projpj_from_string(text_in); + pj.pj_to = projpj_from_string(text_out); lwfree(text_in); lwfree(text_out); @@ -337,21 +337,39 @@ static POINTARRAY * gml_reproject_pa(POINTARRAY *pa, int32_t srid_in, int32_t srid_out) { PJ *pj; + LWPROJ *lwp; char text_in[32]; char text_out[32]; - if (srid_in == SRID_UNKNOWN) return pa; /* nothing to do */ - if (srid_out == SRID_UNKNOWN) gml_lwpgerror("invalid GML representation", 3); + if (srid_in == SRID_UNKNOWN) + return pa; /* nothing to do */ + + if (srid_out == SRID_UNKNOWN) + { + gml_lwpgerror("invalid GML representation", 3); + return NULL; + } snprintf(text_in, 32, "EPSG:%d", srid_in); snprintf(text_out, 32, "EPSG:%d", srid_out); pj = proj_create_crs_to_crs(NULL, text_in, text_out, NULL); - if (ptarray_transform(pa, pj) == LW_FAILURE) + lwp = lwproj_from_PJ(pj, LW_FALSE); + 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); + free(lwp); return pa; } diff --git a/postgis/lwgeom_transform.c b/postgis/lwgeom_transform.c index 986cd6cab..4e75ece7e 100644 --- a/postgis/lwgeom_transform.c +++ b/postgis/lwgeom_transform.c @@ -50,7 +50,7 @@ Datum transform(PG_FUNCTION_ARGS) GSERIALIZED* geom; GSERIALIZED* result=NULL; LWGEOM* lwgeom; - PJ* pj; + LWPROJ *pj; int32 srid_to, srid_from; srid_to = PG_GETARG_INT32(1); @@ -216,7 +216,7 @@ Datum LWGEOM_asKML(PG_FUNCTION_ARGS) if (srid_from != srid_to) { - PJ* pj; + LWPROJ *pj; if (GetPJUsingFCInfo(fcinfo, srid_from, srid_to, &pj) == LW_FAILURE) { PG_FREE_IF_COPY(geom, 0); -- 2.40.0