29 #include "utils/builtins.h"
31 #include "../postgis_config.h"
35 #include "lwgeom_transform.h"
57 int32 srid_to, srid_from;
59 srid_to = PG_GETARG_INT32(1);
62 elog(ERROR,
"ST_Transform: %d is an invalid target SRID",
SRID_UNKNOWN);
66 geom = PG_GETARG_GSERIALIZED_P_COPY(0);
71 PG_FREE_IF_COPY(geom, 0);
72 elog(ERROR,
"ST_Transform: Input geometry has unknown (%d) SRID",
SRID_UNKNOWN);
77 if ( srid_from == srid_to )
78 PG_RETURN_POINTER(geom);
80 postgis_initialize_cache();
81 if ( lwproj_lookup(srid_from, srid_to, &pj) ==
LW_FAILURE )
83 PG_FREE_IF_COPY(geom, 0);
84 elog(ERROR,
"ST_Transform: Failure reading projections from spatial_ref_sys.");
91 lwgeom->
srid = srid_to;
99 result = geometry_serialize(lwgeom);
101 PG_FREE_IF_COPY(geom, 0);
103 PG_RETURN_POINTER(
result);
119 char *input_srs, *output_srs;
124 gser = PG_GETARG_GSERIALIZED_P_COPY(0);
127 input_srs = text_to_cstring(PG_GETARG_TEXT_P(1));
128 output_srs = text_to_cstring(PG_GETARG_TEXT_P(2));
129 result_srid = PG_GETARG_INT32(3);
139 elog(ERROR,
"coordinate transformation failed");
144 geom->
srid = result_srid;
148 gser_result = geometry_serialize(geom);
150 PG_FREE_IF_COPY(gser, 0);
152 PG_RETURN_POINTER(gser_result);
165 char *input_pipeline;
171 gser = PG_GETARG_GSERIALIZED_P_COPY(0);
174 input_pipeline = text_to_cstring(PG_GETARG_TEXT_P(1));
175 is_forward = PG_GETARG_BOOL(2);
176 result_srid = PG_GETARG_INT32(3);
180 pfree(input_pipeline);
184 elog(ERROR,
"coordinate transformation failed");
189 geom->
srid = result_srid;
193 gser_result = geometry_serialize(geom);
195 PG_FREE_IF_COPY(gser, 0);
197 PG_RETURN_POINTER(gser_result);
206 #if POSTGIS_PROJ_VERSION < 61
210 PJ_INFO pji = proj_info();
215 #if POSTGIS_PROJ_VERSION >= 70
218 " NETWORK_ENABLED=%s",
219 proj_context_is_network_enabled(NULL) ?
"ON" :
"OFF");
221 if (proj_context_get_url_endpoint(NULL))
224 if (proj_context_get_user_writable_directory(NULL, 0))
225 stringbuffer_aprintf(&sb,
" USER_WRITABLE_DIRECTORY=%s", proj_context_get_user_writable_directory(NULL, 0));
227 if (proj_context_get_database_path(NULL))
244 const char *default_prefix =
"";
246 const char *prefix = default_prefix;
248 const int32_t srid_to = 4326;
251 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P_COPY(0);
253 text *prefix_text = PG_GETARG_TEXT_P(2);
258 PG_FREE_IF_COPY(geom, 0);
259 elog(ERROR,
"ST_AsKML: Input geometry has unknown (%d) SRID",
SRID_UNKNOWN);
267 if (VARSIZE_ANY_EXHDR(prefix_text) > 0)
270 prefixbuf = palloc(VARSIZE_ANY_EXHDR(prefix_text)+2);
271 memcpy(prefixbuf, VARDATA(prefix_text),
272 VARSIZE_ANY_EXHDR(prefix_text));
274 prefixbuf[VARSIZE_ANY_EXHDR(prefix_text)] =
':';
275 prefixbuf[VARSIZE_ANY_EXHDR(prefix_text)+1] =
'\0';
281 if (srid_from != srid_to)
284 if (lwproj_lookup(srid_from, srid_to, &pj) ==
LW_FAILURE)
286 PG_FREE_IF_COPY(geom, 0);
287 elog(ERROR,
"ST_AsKML: Failure reading projections from spatial_ref_sys.");
295 PG_RETURN_TEXT_P(kml);
303 #if POSTGIS_PROJ_VERSION >= 61
323 if (entry_a->
sort < entry_b->
sort)
return -1;
324 else if (entry_a->
sort > entry_b->
sort)
return 1;
332 Datum tuple_data[7] = {0, 0, 0, 0, 0, 0, 0};
333 bool tuple_null[7] = {
true,
true,
true,
true,
true,
true,
true};
334 PJ_CONTEXT * ctx = NULL;
335 const char *
const empty_options[2] = {NULL};
336 const char *
const wkt_options[2] = {
"MULTILINE=NO", NULL};
338 const char * proj4text;
340 double w_lon, s_lat, e_lon, n_lat;
343 PJ *obj = proj_create_from_database(ctx,
346 PJ_CATEGORY_CRS, 0, empty_options);
351 srtext = proj_as_wkt(ctx, obj, PJ_WKT1_GDAL, wkt_options);
352 proj4text = proj_as_proj_string(ctx, obj, PJ_PROJ_4, empty_options);
353 srname = proj_get_name(obj);
354 ok = proj_get_area_of_use(ctx, obj, &w_lon, &s_lat, &e_lon, &n_lat, NULL);
357 tuple_data[0] = PointerGetDatum(entry->
auth_name);
358 tuple_null[0] =
false;
362 tuple_data[1] = PointerGetDatum(entry->
auth_code);
363 tuple_null[1] =
false;
367 tuple_data[2] = PointerGetDatum(cstring_to_text(srname));
368 tuple_null[2] =
false;
372 tuple_data[3] = PointerGetDatum(cstring_to_text(srtext));
373 tuple_null[3] =
false;
377 tuple_data[4] = PointerGetDatum(cstring_to_text(proj4text));
378 tuple_null[4] =
false;
386 tuple_data[5] = PointerGetDatum(g_sw);
387 tuple_null[5] =
false;
388 tuple_data[6] = PointerGetDatum(g_ne);
389 tuple_null[6] =
false;
392 tuple = heap_form_tuple(tuple_desc, tuple_data, tuple_null);
395 return HeapTupleGetDatum(tuple);
401 struct srs_data *state = palloc0(
sizeof(*state));
427 PJ_TYPE types[
ntypes] = {PJ_TYPE_PROJECTED_CRS, PJ_TYPE_GEOGRAPHIC_CRS, PJ_TYPE_COMPOUND_CRS};
430 for (j = 0; j <
ntypes; j++)
432 PJ_CONTEXT *ctx = NULL;
433 int allow_deprecated = 0;
434 PJ_TYPE
type = types[j];
435 PROJ_STRING_LIST codes_ptr = proj_get_codes_from_database(ctx, auth_name,
type, allow_deprecated);
436 PROJ_STRING_LIST codes = codes_ptr;
438 while(codes && *codes)
451 proj_string_list_destroy(codes_ptr);
459 const int32_t srid_to = 4326;
461 PJ_TYPE types[1] = {PJ_TYPE_PROJECTED_CRS};
462 PROJ_CRS_INFO **crs_list_ptr, **crs_list;
464 PJ_CONTEXT *ctx = NULL;
466 PROJ_CRS_LIST_PARAMETERS *params = proj_get_crs_list_parameters_create();
467 params->types = types;
468 params->typesCount = 1;
469 params->crs_area_of_use_contains_bbox =
true;
470 params->bbox_valid =
true;
471 params->allow_deprecated =
false;
473 #if POSTGIS_PROJ_VERSION >= 81
474 params->celestial_body_name =
"Earth";
477 if (srid_from != srid_to)
480 if (lwproj_lookup(srid_from, srid_to, &pj) ==
LW_FAILURE)
481 elog(ERROR,
"%s: Lookup of SRID %u => %u transform failed",
482 __func__, srid_from, srid_to);
487 params->west_lon_degree = gbox.
xmin;
488 params->south_lat_degree = gbox.
ymin;
489 params->east_lon_degree = gbox.
xmax;
490 params->north_lat_degree = gbox.
ymax;
492 crs_list = crs_list_ptr = proj_get_crs_info_list_from_database(
493 ctx, auth_name, params, &crs_count);
497 while (crs_list && *crs_list)
500 PROJ_CRS_INFO *crs = *crs_list++;
504 double height = crs->north_lat_degree - crs->south_lat_degree;
505 double width = crs->east_lon_degree - crs->west_lon_degree;
507 width = 360 - (crs->west_lon_degree - crs->east_lon_degree);
508 area = width * height;
523 proj_crs_info_list_destroy(crs_list_ptr);
524 proj_get_crs_list_parameters_destroy(params);
536 #if POSTGIS_PROJ_VERSION < 60
537 elog(ERROR,
"%s is not supported with Proj < 6.0", __func__);
543 TupleDesc tuple_desc;
545 if (get_call_result_type(fcinfo, 0, &tuple_desc) != TYPEFUNC_COMPOSITE)
547 ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
548 errmsg(
"%s called with incompatible return type", __func__)));
550 BlessTupleDesc(tuple_desc);
568 #if POSTGIS_PROJ_VERSION < 60
569 elog(ERROR,
"%s is not supported with Proj < 6.0", __func__);
571 FuncCallContext *funcctx;
572 MemoryContext oldcontext;
582 if (SRF_IS_FIRSTCALL())
584 funcctx = SRF_FIRSTCALL_INIT();
585 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
602 if (get_call_result_type(fcinfo, 0, &funcctx->tuple_desc) != TYPEFUNC_COMPOSITE)
604 ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
605 errmsg(
"%s called with incompatible return type", __func__)));
608 BlessTupleDesc(funcctx->tuple_desc);
609 funcctx->user_fctx = state;
610 MemoryContextSwitchTo(oldcontext);
614 funcctx = SRF_PERCALL_SETUP();
615 state = funcctx->user_fctx;
620 SRF_RETURN_DONE(funcctx);
626 funcctx->tuple_desc);
629 SRF_RETURN_NEXT(funcctx,
result);
632 SRF_RETURN_DONE(funcctx);
641 #if POSTGIS_PROJ_VERSION < 60
642 elog(ERROR,
"%s is not supported with Proj < 6.0", __func__);
644 FuncCallContext *funcctx;
645 MemoryContext oldcontext;
648 text* auth_name = PG_GETARG_TEXT_P(0);
657 if (SRF_IS_FIRSTCALL())
663 funcctx = SRF_FIRSTCALL_INIT();
664 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
667 funcctx->user_fctx = state;
668 MemoryContextSwitchTo(oldcontext);
672 funcctx = SRF_PERCALL_SETUP();
673 state = funcctx->user_fctx;
678 SRF_RETURN_DONE(funcctx);
683 result = PointerGetDatum(auth_code);
687 SRF_RETURN_NEXT(funcctx,
result);
690 SRF_RETURN_DONE(funcctx);
691 SRF_RETURN_DONE(funcctx);
704 #if POSTGIS_PROJ_VERSION < 60
705 elog(ERROR,
"%s is not supported with Proj < 6.0", __func__);
707 FuncCallContext *funcctx;
708 MemoryContext oldcontext;
718 if (SRF_IS_FIRSTCALL())
722 text *auth_name = PG_GETARG_TEXT_P(1);
724 funcctx = SRF_FIRSTCALL_INIT();
725 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
742 if (get_call_result_type(fcinfo, 0, &funcctx->tuple_desc) != TYPEFUNC_COMPOSITE)
744 ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
745 errmsg(
"%s called with incompatible return type", __func__)));
748 BlessTupleDesc(funcctx->tuple_desc);
749 funcctx->user_fctx = state;
750 MemoryContextSwitchTo(oldcontext);
754 funcctx = SRF_PERCALL_SETUP();
755 state = funcctx->user_fctx;
761 SRF_RETURN_DONE(funcctx);
767 funcctx->tuple_desc);
770 SRF_RETURN_NEXT(funcctx,
result);
773 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_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)
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