]> granicus.if.org Git - postgis/commitdiff
PROJ6: Speed improvements
authorRaúl Marín Rodríguez <rmrodriguez@carto.com>
Wed, 19 Jun 2019 15:12:21 +0000 (15:12 +0000)
committerRaúl Marín Rodríguez <rmrodriguez@carto.com>
Wed, 19 Jun 2019 15:12:21 +0000 (15:12 +0000)
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
liblwgeom/liblwgeom.h.in
liblwgeom/lwgeom_transform.c
libpgcommon/lwgeom_cache.h
libpgcommon/lwgeom_transform.c
libpgcommon/lwgeom_transform.h
postgis/lwgeom_in_gml.c
postgis/lwgeom_transform.c

diff --git a/NEWS b/NEWS
index f16b1f5a09791872500a3490e288a4ecf7804922..7bccbe67dd57bd07f54d7a4084c186d8ecde8b8b 100644 (file)
--- 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
index 86f2c623c2e5af5400b8ce42577f6468d3b29b2b..2350e4fdadd40ceceee2f71256e91cf1bce7a753 100644 (file)
@@ -30,8 +30,8 @@
 #define _LIBLWGEOM_H 1
 
 #include <stdarg.h>
-#include <stdio.h>
 #include <stdint.h>
+#include <stdio.h>
 
 #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
 
 
 /*******************************************************************************
index af4b09453c716bbbe611bc91b871cca5e3544d14..5fe145f8686f4916377329a3236ea193625b553c 100644 (file)
@@ -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++)
                {
index 68fc7a2c728f3e184fdbc2160066989084b28a03..b6ccc25a7ede56a84095224e3bf69048fbdb0999 100644 (file)
@@ -67,7 +67,7 @@ typedef struct struct_PROJSRSCacheItem
 {
        int32_t srid_from;
        int32_t srid_to;
-       PJ* projection;
+       LWPROJ *projection;
        MemoryContext projection_mcxt;
 }
 PROJSRSCacheItem;
index 5a8338fc42dc1cbde4ccb849584a4e6f40fdb6fa..f5a612a1ea9cc72136f0a5e2cbb30145c53af2e1 100644 (file)
@@ -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))
index 32d4009279b5bcc776fc402aae240c827c41e732..bd9b414c8be11f6b45e0f93b8667feca076c0b15 100644 (file)
@@ -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);
index 57b2846caf09e86cc9ab96a92a2b9f2879f8ddfb..a1d162cafa1f04165f9b6652d6c04f7f5138d166 100644 (file)
@@ -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;
 }
index 986cd6cabefc6d5fff4ad572438453bcf0ae4de8..4e75ece7e03447c090d20654492e415b595ee061 100644 (file)
@@ -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);