25 #include "../postgis_config.h"
30 #if POSTGIS_PGSQL_VERSION >= 190
31 #include "access/htup_details.h"
33 #include "utils/builtins.h"
38 #include "lwgeom_transform.h"
61 int32 srid_to, srid_from;
63 srid_to = PG_GETARG_INT32(1);
66 elog(ERROR,
"ST_Transform: %d is an invalid target SRID",
SRID_UNKNOWN);
70 geom = PG_GETARG_GSERIALIZED_P_COPY(0);
75 PG_FREE_IF_COPY(geom, 0);
76 elog(ERROR,
"ST_Transform: Input geometry has unknown (%d) SRID",
SRID_UNKNOWN);
81 if ( srid_from == srid_to )
82 PG_RETURN_POINTER(geom);
84 postgis_initialize_cache();
85 if ( lwproj_lookup(srid_from, srid_to, &pj) ==
LW_FAILURE )
87 PG_FREE_IF_COPY(geom, 0);
88 elog(ERROR,
"ST_Transform: Failure reading projections from spatial_ref_sys.");
95 lwgeom->
srid = srid_to;
103 result = geometry_serialize(lwgeom);
105 PG_FREE_IF_COPY(geom, 0);
107 PG_RETURN_POINTER(
result);
123 char *input_srs, *output_srs;
128 gser = PG_GETARG_GSERIALIZED_P_COPY(0);
131 input_srs = text_to_cstring(PG_GETARG_TEXT_P(1));
132 output_srs = text_to_cstring(PG_GETARG_TEXT_P(2));
133 result_srid = PG_GETARG_INT32(3);
143 elog(ERROR,
"coordinate transformation failed");
148 geom->
srid = result_srid;
152 gser_result = geometry_serialize(geom);
154 PG_FREE_IF_COPY(gser, 0);
156 PG_RETURN_POINTER(gser_result);
169 char *input_pipeline;
175 gser = PG_GETARG_GSERIALIZED_P_COPY(0);
178 input_pipeline = text_to_cstring(PG_GETARG_TEXT_P(1));
179 is_forward = PG_GETARG_BOOL(2);
180 result_srid = PG_GETARG_INT32(3);
184 pfree(input_pipeline);
188 elog(ERROR,
"coordinate transformation failed");
193 geom->
srid = result_srid;
197 gser_result = geometry_serialize(geom);
199 PG_FREE_IF_COPY(gser, 0);
201 PG_RETURN_POINTER(gser_result);
210 PJ_INFO pji = proj_info();
214 #if POSTGIS_PROJ_VERSION >= 70100
217 " NETWORK_ENABLED=%s",
218 proj_context_is_network_enabled(NULL) ?
"ON" :
"OFF");
220 if (proj_context_get_url_endpoint(NULL))
223 if (proj_context_get_user_writable_directory(NULL, 0))
224 stringbuffer_aprintf(&sb,
" USER_WRITABLE_DIRECTORY=%s", proj_context_get_user_writable_directory(NULL, 0));
226 if (proj_context_get_database_path(NULL))
247 result = cstring_to_text(ver);
248 PG_RETURN_POINTER(
result);
259 const char *default_prefix =
"";
261 const char *prefix = default_prefix;
263 const int32_t srid_to = 4326;
266 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P_COPY(0);
268 text *prefix_text = PG_GETARG_TEXT_P(2);
273 PG_FREE_IF_COPY(geom, 0);
274 elog(ERROR,
"ST_AsKML: Input geometry has unknown (%d) SRID",
SRID_UNKNOWN);
282 if (VARSIZE_ANY_EXHDR(prefix_text) > 0)
285 prefixbuf = palloc(VARSIZE_ANY_EXHDR(prefix_text)+2);
286 memcpy(prefixbuf, VARDATA(prefix_text),
287 VARSIZE_ANY_EXHDR(prefix_text));
289 prefixbuf[VARSIZE_ANY_EXHDR(prefix_text)] =
':';
290 prefixbuf[VARSIZE_ANY_EXHDR(prefix_text)+1] =
'\0';
296 if (srid_from != srid_to)
299 if (lwproj_lookup(srid_from, srid_to, &pj) ==
LW_FAILURE)
301 PG_FREE_IF_COPY(geom, 0);
302 elog(ERROR,
"ST_AsKML: Failure reading projections from spatial_ref_sys.");
310 PG_RETURN_TEXT_P(kml);
336 if (entry_a->
sort < entry_b->
sort)
return -1;
337 else if (entry_a->
sort > entry_b->
sort)
return 1;
345 Datum tuple_data[7] = {0, 0, 0, 0, 0, 0, 0};
346 bool tuple_null[7] = {
true,
true,
true,
true,
true,
true,
true};
347 PJ_CONTEXT * ctx = NULL;
348 const char *
const empty_options[2] = {NULL};
349 const char *
const wkt_options[2] = {
"MULTILINE=NO", NULL};
351 const char * proj4text;
353 double w_lon, s_lat, e_lon, n_lat;
356 PJ *obj = proj_create_from_database(ctx,
359 PJ_CATEGORY_CRS, 0, empty_options);
364 srtext = proj_as_wkt(ctx, obj, PJ_WKT1_GDAL, wkt_options);
365 proj4text = proj_as_proj_string(ctx, obj, PJ_PROJ_4, empty_options);
366 srname = proj_get_name(obj);
367 ok = proj_get_area_of_use(ctx, obj, &w_lon, &s_lat, &e_lon, &n_lat, NULL);
370 tuple_data[0] = PointerGetDatum(entry->
auth_name);
371 tuple_null[0] =
false;
375 tuple_data[1] = PointerGetDatum(entry->
auth_code);
376 tuple_null[1] =
false;
380 tuple_data[2] = PointerGetDatum(cstring_to_text(srname));
381 tuple_null[2] =
false;
385 tuple_data[3] = PointerGetDatum(cstring_to_text(srtext));
386 tuple_null[3] =
false;
390 tuple_data[4] = PointerGetDatum(cstring_to_text(proj4text));
391 tuple_null[4] =
false;
399 tuple_data[5] = PointerGetDatum(g_sw);
400 tuple_null[5] =
false;
401 tuple_data[6] = PointerGetDatum(g_ne);
402 tuple_null[6] =
false;
405 tuple = heap_form_tuple(tuple_desc, tuple_data, tuple_null);
408 return HeapTupleGetDatum(tuple);
414 struct srs_data *state = palloc0(
sizeof(*state));
440 PJ_TYPE types[
ntypes] = {PJ_TYPE_PROJECTED_CRS, PJ_TYPE_GEOGRAPHIC_CRS, PJ_TYPE_COMPOUND_CRS};
443 for (j = 0; j <
ntypes; j++)
445 PJ_CONTEXT *ctx = NULL;
446 int allow_deprecated = 0;
447 PJ_TYPE
type = types[j];
448 PROJ_STRING_LIST codes_ptr = proj_get_codes_from_database(ctx, auth_name,
type, allow_deprecated);
449 PROJ_STRING_LIST codes = codes_ptr;
451 while(codes && *codes)
464 proj_string_list_destroy(codes_ptr);
472 const int32_t srid_to = 4326;
474 PJ_TYPE types[1] = {PJ_TYPE_PROJECTED_CRS};
475 PROJ_CRS_INFO **crs_list_ptr, **crs_list;
477 PJ_CONTEXT *ctx = NULL;
479 PROJ_CRS_LIST_PARAMETERS *params = proj_get_crs_list_parameters_create();
480 params->types = types;
481 params->typesCount = 1;
482 params->crs_area_of_use_contains_bbox =
true;
483 params->bbox_valid =
true;
484 params->allow_deprecated =
false;
486 #if POSTGIS_PROJ_VERSION >= 80100
487 params->celestial_body_name =
"Earth";
490 if (srid_from != srid_to)
493 if (lwproj_lookup(srid_from, srid_to, &pj) ==
LW_FAILURE)
494 elog(ERROR,
"%s: Lookup of SRID %u => %u transform failed",
495 __func__, srid_from, srid_to);
500 params->west_lon_degree = gbox.
xmin;
501 params->south_lat_degree = gbox.
ymin;
502 params->east_lon_degree = gbox.
xmax;
503 params->north_lat_degree = gbox.
ymax;
505 crs_list = crs_list_ptr = proj_get_crs_info_list_from_database(
506 ctx, auth_name, params, &crs_count);
510 while (crs_list && *crs_list)
513 PROJ_CRS_INFO *crs = *crs_list++;
517 double height = crs->north_lat_degree - crs->south_lat_degree;
518 double width = crs->east_lon_degree - crs->west_lon_degree;
520 width = 360 - (crs->west_lon_degree - crs->east_lon_degree);
521 area = width * height;
536 proj_crs_info_list_destroy(crs_list_ptr);
537 proj_get_crs_list_parameters_destroy(params);
552 TupleDesc tuple_desc;
554 if (get_call_result_type(fcinfo, 0, &tuple_desc) != TYPEFUNC_COMPOSITE)
556 ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
557 errmsg(
"%s called with incompatible return type", __func__)));
559 BlessTupleDesc(tuple_desc);
576 FuncCallContext *funcctx;
577 MemoryContext oldcontext;
587 if (SRF_IS_FIRSTCALL())
589 funcctx = SRF_FIRSTCALL_INIT();
590 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
607 if (get_call_result_type(fcinfo, 0, &funcctx->tuple_desc) != TYPEFUNC_COMPOSITE)
609 ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
610 errmsg(
"%s called with incompatible return type", __func__)));
613 BlessTupleDesc(funcctx->tuple_desc);
614 funcctx->user_fctx = state;
615 MemoryContextSwitchTo(oldcontext);
619 funcctx = SRF_PERCALL_SETUP();
620 state = funcctx->user_fctx;
625 SRF_RETURN_DONE(funcctx);
631 funcctx->tuple_desc);
634 SRF_RETURN_NEXT(funcctx,
result);
637 SRF_RETURN_DONE(funcctx);
645 FuncCallContext *funcctx;
646 MemoryContext oldcontext;
649 text* auth_name = PG_GETARG_TEXT_P(0);
658 if (SRF_IS_FIRSTCALL())
664 funcctx = SRF_FIRSTCALL_INIT();
665 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
668 funcctx->user_fctx = state;
669 MemoryContextSwitchTo(oldcontext);
673 funcctx = SRF_PERCALL_SETUP();
674 state = funcctx->user_fctx;
679 SRF_RETURN_DONE(funcctx);
684 result = PointerGetDatum(auth_code);
688 SRF_RETURN_NEXT(funcctx,
result);
691 SRF_RETURN_DONE(funcctx);
692 SRF_RETURN_DONE(funcctx);
704 FuncCallContext *funcctx;
705 MemoryContext oldcontext;
715 if (SRF_IS_FIRSTCALL())
719 text *auth_name = PG_GETARG_TEXT_P(1);
721 funcctx = SRF_FIRSTCALL_INIT();
722 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
739 if (get_call_result_type(fcinfo, 0, &funcctx->tuple_desc) != TYPEFUNC_COMPOSITE)
741 ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
742 errmsg(
"%s called with incompatible return type", __func__)));
745 BlessTupleDesc(funcctx->tuple_desc);
746 funcctx->user_fctx = state;
747 MemoryContextSwitchTo(oldcontext);
751 funcctx = SRF_PERCALL_SETUP();
752 state = funcctx->user_fctx;
758 SRF_RETURN_DONE(funcctx);
764 funcctx->tuple_desc);
767 SRF_RETURN_NEXT(funcctx,
result);
770 SRF_RETURN_DONE(funcctx);
char result[OUT_DOUBLE_BUFFER_SIZE]
int32_t gserialized_get_srid(const GSERIALIZED *g)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
void lwgeom_refresh_bbox(LWGEOM *lwgeom)
Drop current bbox and calculate a fresh one.
lwvarlena_t * lwgeom_to_kml2(const LWGEOM *geom, int precision, const char *prefix)
int32_t lwgeom_get_srid(const LWGEOM *geom)
Return SRID number.
LWPOINT * lwpoint_make2d(int32_t srid, double x, double y)
int lwgeom_transform(LWGEOM *geom, LWPROJ *pj)
Transform (reproject) a geometry in-place.
void lwgeom_free(LWGEOM *geom)
int box3d_transform(GBOX *box, LWPROJ *pj)
int lwgeom_transform_from_str(LWGEOM *geom, const char *instr, const char *outstr)
const GBOX * lwgeom_get_bbox(const LWGEOM *lwgeom)
Get a non-empty geometry bounding box, computing and caching it if not already there.
int lwgeom_transform_pipeline(LWGEOM *geom, const char *pipeline, bool is_forward)
Transform (reproject) a geometry in-place using a PROJ pipeline.
#define SRID_UNKNOWN
Unknown SRID value.
This library is the generic geometry handling section of PostGIS.
static struct srs_data * srs_state_init()
static void srs_state_memcheck(struct srs_data *state)
Datum postgis_proj_compiled_version(PG_FUNCTION_ARGS)
Datum postgis_srs_entry(PG_FUNCTION_ARGS)
Search for srtext and proj4text given auth_name and auth_srid, returns TABLE(auth_name text,...
static void srs_state_codes(const char *auth_name, struct srs_data *state)
Datum transform_geom(PG_FUNCTION_ARGS)
Datum postgis_srs_search(PG_FUNCTION_ARGS)
Search for projections given extent and (optional) auth_name returns TABLE(auth_name,...
Datum transform(PG_FUNCTION_ARGS)
Datum postgis_proj_version(PG_FUNCTION_ARGS)
Datum postgis_srs_entry_all(PG_FUNCTION_ARGS)
static Datum srs_tuple_from_entry(const struct srs_entry *entry, TupleDesc tuple_desc)
static int srs_entry_cmp(const void *a, const void *b)
Datum transform_pipeline_geom(PG_FUNCTION_ARGS)
Datum LWGEOM_asKML(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(transform)
transform( GEOMETRY, INT (output srid) ) tmpPts - if there is a nadgrid error (-38),...
static void srs_find_planar(const char *auth_name, const LWGEOM *bounds, struct srs_data *state)
Datum postgis_srs_codes(PG_FUNCTION_ARGS)
#define POSTGIS_PROJ_VERSION
int stringbuffer_aprintf(stringbuffer_t *s, const char *fmt,...)
Appends a formatted string to the current string buffer, using the format and argument list provided.
void stringbuffer_init(stringbuffer_t *s)
const char * stringbuffer_getstring(stringbuffer_t *s)
Returns a reference to the internal string being managed by the stringbuffer.
static void stringbuffer_append(stringbuffer_t *s, const char *a)
Append the specified string to the stringbuffer_t.
struct srs_entry * entries