PostGIS 3.6.2dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
postgis/lwgeom_transform.c
Go to the documentation of this file.
1/**********************************************************************
2 *
3 * PostGIS - Spatial Types for PostgreSQL
4 * http://postgis.net
5 *
6 * PostGIS is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * PostGIS is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18 *
19 **********************************************************************
20 *
21 * Copyright (C) 2001-2003 Refractions Research Inc.
22 *
23 **********************************************************************/
24
25#include "../postgis_config.h"
26
27#include "postgres.h"
28#include "fmgr.h"
29#include "funcapi.h"
30#if POSTGIS_PGSQL_VERSION >= 190
31#include "access/htup_details.h"
32#endif
33#include "utils/builtins.h"
34
35#include "liblwgeom.h"
36#include "lwgeodetic.h"
37#include "stringbuffer.h"
38#include "lwgeom_transform.h"
39
40
41Datum transform(PG_FUNCTION_ARGS);
42Datum transform_geom(PG_FUNCTION_ARGS);
43Datum transform_pipeline_geom(PG_FUNCTION_ARGS);
44Datum postgis_proj_version(PG_FUNCTION_ARGS);
45Datum postgis_proj_compiled_version(PG_FUNCTION_ARGS);
46Datum LWGEOM_asKML(PG_FUNCTION_ARGS);
47
55Datum transform(PG_FUNCTION_ARGS)
56{
57 GSERIALIZED* geom;
58 GSERIALIZED* result=NULL;
59 LWGEOM* lwgeom;
60 LWPROJ *pj;
61 int32 srid_to, srid_from;
62
63 srid_to = PG_GETARG_INT32(1);
64 if (srid_to == SRID_UNKNOWN)
65 {
66 elog(ERROR, "ST_Transform: %d is an invalid target SRID", SRID_UNKNOWN);
67 PG_RETURN_NULL();
68 }
69
70 geom = PG_GETARG_GSERIALIZED_P_COPY(0);
71 srid_from = gserialized_get_srid(geom);
72
73 if ( srid_from == SRID_UNKNOWN )
74 {
75 PG_FREE_IF_COPY(geom, 0);
76 elog(ERROR, "ST_Transform: Input geometry has unknown (%d) SRID", SRID_UNKNOWN);
77 PG_RETURN_NULL();
78 }
79
80 /* Input SRID and output SRID are equal, noop */
81 if ( srid_from == srid_to )
82 PG_RETURN_POINTER(geom);
83
84 postgis_initialize_cache();
85 if ( lwproj_lookup(srid_from, srid_to, &pj) == LW_FAILURE )
86 {
87 PG_FREE_IF_COPY(geom, 0);
88 elog(ERROR, "ST_Transform: Failure reading projections from spatial_ref_sys.");
89 PG_RETURN_NULL();
90 }
91
92 /* now we have a geometry, and input/output PJ structs. */
93 lwgeom = lwgeom_from_gserialized(geom);
94 lwgeom_transform(lwgeom, pj);
95 lwgeom->srid = srid_to;
96
97 /* Re-compute bbox if input had one (COMPUTE_BBOX TAINTING) */
98 if ( lwgeom->bbox )
99 {
100 lwgeom_refresh_bbox(lwgeom);
101 }
102
103 result = geometry_serialize(lwgeom);
104 lwgeom_free(lwgeom);
105 PG_FREE_IF_COPY(geom, 0);
106
107 PG_RETURN_POINTER(result); /* new geometry */
108}
109
119Datum transform_geom(PG_FUNCTION_ARGS)
120{
121 GSERIALIZED *gser, *gser_result=NULL;
122 LWGEOM *geom;
123 char *input_srs, *output_srs;
124 int32 result_srid;
125 int rv;
126
127 /* Take a copy, since we will be altering the coordinates */
128 gser = PG_GETARG_GSERIALIZED_P_COPY(0);
129
130 /* Convert from text to cstring for libproj */
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);
134
135 /* now we have a geometry, and input/output PJ structs. */
136 geom = lwgeom_from_gserialized(gser);
137 rv = lwgeom_transform_from_str(geom, input_srs, output_srs);
138 pfree(input_srs);
139 pfree(output_srs);
140
141 if (rv == LW_FAILURE)
142 {
143 elog(ERROR, "coordinate transformation failed");
144 PG_RETURN_NULL();
145 }
146
147 /* Re-compute bbox if input had one (COMPUTE_BBOX TAINTING) */
148 geom->srid = result_srid;
149 if (geom->bbox)
151
152 gser_result = geometry_serialize(geom);
153 lwgeom_free(geom);
154 PG_FREE_IF_COPY(gser, 0);
155
156 PG_RETURN_POINTER(gser_result); /* new geometry */
157}
158
159
165Datum transform_pipeline_geom(PG_FUNCTION_ARGS)
166{
167 GSERIALIZED *gser, *gser_result=NULL;
168 LWGEOM *geom;
169 char *input_pipeline;
170 bool is_forward;
171 int32 result_srid;
172 int rv;
173
174 /* Take a copy, since we will be altering the coordinates */
175 gser = PG_GETARG_GSERIALIZED_P_COPY(0);
176
177 /* Convert from text to cstring for libproj */
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);
181
182 geom = lwgeom_from_gserialized(gser);
183 rv = lwgeom_transform_pipeline(geom, input_pipeline, is_forward);
184 pfree(input_pipeline);
185
186 if (rv == LW_FAILURE)
187 {
188 elog(ERROR, "coordinate transformation failed");
189 PG_RETURN_NULL();
190 }
191
192 /* Re-compute bbox if input had one (COMPUTE_BBOX TAINTING) */
193 geom->srid = result_srid;
194 if (geom->bbox)
196
197 gser_result = geometry_serialize(geom);
198 lwgeom_free(geom);
199 PG_FREE_IF_COPY(gser, 0);
200
201 PG_RETURN_POINTER(gser_result); /* new geometry */
202}
203
204
206Datum postgis_proj_version(PG_FUNCTION_ARGS)
207{
209
210 PJ_INFO pji = proj_info();
212 stringbuffer_append(&sb, pji.version);
213
214#if POSTGIS_PROJ_VERSION >= 70100
215
217 " NETWORK_ENABLED=%s",
218 proj_context_is_network_enabled(NULL) ? "ON" : "OFF");
219
220 if (proj_context_get_url_endpoint(NULL))
221 stringbuffer_aprintf(&sb, " URL_ENDPOINT=%s", proj_context_get_url_endpoint(NULL));
222
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));
225
226 if (proj_context_get_database_path(NULL))
227 stringbuffer_aprintf(&sb, " DATABASE_PATH=%s", proj_context_get_database_path(NULL));
228
229#endif
230
231 PG_RETURN_POINTER(cstring_to_text(stringbuffer_getstring(&sb)));
232}
233
235Datum postgis_proj_compiled_version(PG_FUNCTION_ARGS)
236{
237 static char ver[64];
238 text *result;
239 sprintf(
240 ver,
241 "%d.%d.%d",
242 (POSTGIS_PROJ_VERSION/10000),
243 ((POSTGIS_PROJ_VERSION%10000)/100),
245 );
246
247 result = cstring_to_text(ver);
248 PG_RETURN_POINTER(result);
249}
250
255Datum LWGEOM_asKML(PG_FUNCTION_ARGS)
256{
257 LWGEOM *lwgeom;
258 lwvarlena_t *kml;
259 const char *default_prefix = ""; /* default prefix */
260 char *prefixbuf;
261 const char *prefix = default_prefix;
262 int32_t srid_from;
263 const int32_t srid_to = 4326;
264
265 /* Get the geometry */
266 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P_COPY(0);
267 int precision = PG_GETARG_INT32(1);
268 text *prefix_text = PG_GETARG_TEXT_P(2);
269 srid_from = gserialized_get_srid(geom);
270
271 if ( srid_from == SRID_UNKNOWN )
272 {
273 PG_FREE_IF_COPY(geom, 0);
274 elog(ERROR, "ST_AsKML: Input geometry has unknown (%d) SRID", SRID_UNKNOWN);
275 PG_RETURN_NULL();
276 }
277
278 /* Condition precision */
279 if (precision < 0)
280 precision = 0;
281
282 if (VARSIZE_ANY_EXHDR(prefix_text) > 0)
283 {
284 /* +2 is one for the ':' and one for term null */
285 prefixbuf = palloc(VARSIZE_ANY_EXHDR(prefix_text)+2);
286 memcpy(prefixbuf, VARDATA(prefix_text),
287 VARSIZE_ANY_EXHDR(prefix_text));
288 /* add colon and null terminate */
289 prefixbuf[VARSIZE_ANY_EXHDR(prefix_text)] = ':';
290 prefixbuf[VARSIZE_ANY_EXHDR(prefix_text)+1] = '\0';
291 prefix = prefixbuf;
292 }
293
294 lwgeom = lwgeom_from_gserialized(geom);
295
296 if (srid_from != srid_to)
297 {
298 LWPROJ *pj;
299 if (lwproj_lookup(srid_from, srid_to, &pj) == LW_FAILURE)
300 {
301 PG_FREE_IF_COPY(geom, 0);
302 elog(ERROR, "ST_AsKML: Failure reading projections from spatial_ref_sys.");
303 PG_RETURN_NULL();
304 }
305 lwgeom_transform(lwgeom, pj);
306 }
307
308 kml = lwgeom_to_kml2(lwgeom, precision, prefix);
309 if (kml)
310 PG_RETURN_TEXT_P(kml);
311 PG_RETURN_NULL();
312}
313
314/********************************************************************************
315 * PROJ database reading functions
316 */
317
318struct srs_entry {
321 double sort;
322};
323
324struct srs_data {
326 uint32_t num_entries;
327 uint32_t capacity;
329};
330
331static int
332srs_entry_cmp (const void *a, const void *b)
333{
334 const struct srs_entry *entry_a = (const struct srs_entry*)(a);
335 const struct srs_entry *entry_b = (const struct srs_entry*)(b);
336 if (entry_a->sort < entry_b->sort) return -1;
337 else if (entry_a->sort > entry_b->sort) return 1;
338 else return 0;
339}
340
341static Datum
342srs_tuple_from_entry(const struct srs_entry* entry, TupleDesc tuple_desc)
343{
344 HeapTuple tuple;
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};
350 const char * srtext;
351 const char * proj4text;
352 const char * srname;
353 double w_lon, s_lat, e_lon, n_lat;
354 int ok;
355
356 PJ *obj = proj_create_from_database(ctx,
357 text_to_cstring(entry->auth_name),
358 text_to_cstring(entry->auth_code),
359 PJ_CATEGORY_CRS, 0, empty_options);
360
361 if (!obj)
362 return (Datum) 0;
363
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);
368
369 if (entry->auth_name) {
370 tuple_data[0] = PointerGetDatum(entry->auth_name);
371 tuple_null[0] = false;
372 }
373
374 if (entry->auth_code) {
375 tuple_data[1] = PointerGetDatum(entry->auth_code);
376 tuple_null[1] = false;
377 }
378
379 if (srname) {
380 tuple_data[2] = PointerGetDatum(cstring_to_text(srname));
381 tuple_null[2] = false;
382 }
383
384 if (srtext) {
385 tuple_data[3] = PointerGetDatum(cstring_to_text(srtext));
386 tuple_null[3] = false;
387 }
388
389 if (proj4text) {
390 tuple_data[4] = PointerGetDatum(cstring_to_text(proj4text));
391 tuple_null[4] = false;
392 }
393
394 if (ok) {
395 LWPOINT *p_sw = lwpoint_make2d(4326, w_lon, s_lat);
396 LWPOINT *p_ne = lwpoint_make2d(4326, e_lon, n_lat);
397 GSERIALIZED *g_sw = geometry_serialize((LWGEOM*)p_sw);
398 GSERIALIZED *g_ne = geometry_serialize((LWGEOM*)p_ne);
399 tuple_data[5] = PointerGetDatum(g_sw);
400 tuple_null[5] = false;
401 tuple_data[6] = PointerGetDatum(g_ne);
402 tuple_null[6] = false;
403 }
404
405 tuple = heap_form_tuple(tuple_desc, tuple_data, tuple_null);
406 proj_destroy(obj);
407
408 return HeapTupleGetDatum(tuple);
409}
410
411static struct srs_data *
413{
414 struct srs_data *state = palloc0(sizeof(*state));
415 state->capacity = 8192;
416 state->num_entries = 0;
417 state->entries = palloc0(state->capacity * sizeof(*(state->entries)));
418 return state;
419}
420
421static void
423{
424 if (state->num_entries == state->capacity)
425 {
426 state->capacity *= 2;
427 state->entries = repalloc(state->entries, state->capacity * sizeof(*(state->entries)));
428 }
429 return;
430}
431
432static void
433srs_state_codes(const char* auth_name, struct srs_data *state)
434{
435 /*
436 * Only a subset of supported proj types actually
437 * show up in spatial_ref_sys
438 */
439 #define ntypes 3
440 PJ_TYPE types[ntypes] = {PJ_TYPE_PROJECTED_CRS, PJ_TYPE_GEOGRAPHIC_CRS, PJ_TYPE_COMPOUND_CRS};
441 uint32_t j;
442
443 for (j = 0; j < ntypes; j++)
444 {
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;
450 const char *code;
451 while(codes && *codes)
452 {
453 /* Read current code and move forward one entry */
454 code = *codes++;
455 /* Ensure there is space in the entry list */
456 srs_state_memcheck(state);
457
458 /* Write the entry into the entry list and increment */
459 state->entries[state->num_entries].auth_name = cstring_to_text(auth_name);
460 state->entries[state->num_entries].auth_code = cstring_to_text(code);
461 state->num_entries++;
462 }
463 /* Clean up system allocated memory */
464 proj_string_list_destroy(codes_ptr);
465 }
466}
467
468static void
469srs_find_planar(const char *auth_name, const LWGEOM *bounds, struct srs_data *state)
470{
471 int32_t srid_from = lwgeom_get_srid(bounds);
472 const int32_t srid_to = 4326;
473 GBOX gbox = *(lwgeom_get_bbox(bounds));
474 PJ_TYPE types[1] = {PJ_TYPE_PROJECTED_CRS};
475 PROJ_CRS_INFO **crs_list_ptr, **crs_list;
476 int crs_count;
477 PJ_CONTEXT *ctx = NULL;
478
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;
485
486#if POSTGIS_PROJ_VERSION >= 80100
487 params->celestial_body_name = "Earth";
488#endif
489
490 if (srid_from != srid_to)
491 {
492 LWPROJ *pj;
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);
496
497 box3d_transform(&gbox, pj);
498 }
499
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;
504
505 crs_list = crs_list_ptr = proj_get_crs_info_list_from_database(
506 ctx, auth_name, params, &crs_count);
507
508 /* TODO, throw out really huge / dumb areas? */
509
510 while (crs_list && *crs_list)
511 {
512 /* Read current crs and move forward one entry */
513 PROJ_CRS_INFO *crs = *crs_list++;
514
515 /* Read the corners of the CRS area of use */
516 double area;
517 double height = crs->north_lat_degree - crs->south_lat_degree;
518 double width = crs->east_lon_degree - crs->west_lon_degree;
519 if (width < 0.0)
520 width = 360 - (crs->west_lon_degree - crs->east_lon_degree);
521 area = width * height;
522
523 /* Ensure there is space in the entry list */
524 srs_state_memcheck(state);
525
526 /* Write the entry into the entry list and increment */
527 state->entries[state->num_entries].auth_name = cstring_to_text(crs->auth_name);
528 state->entries[state->num_entries].auth_code = cstring_to_text(crs->code);
529 state->entries[state->num_entries].sort = area;
530 state->num_entries++;
531 }
532
533 /* Put the list of entries into order of area size, smallest to largest */
534 qsort(state->entries, state->num_entries, sizeof(struct srs_data), srs_entry_cmp);
535
536 proj_crs_info_list_destroy(crs_list_ptr);
537 proj_get_crs_list_parameters_destroy(params);
538}
539
544Datum postgis_srs_entry(PG_FUNCTION_ARGS);
546Datum postgis_srs_entry(PG_FUNCTION_ARGS)
547{
548 Datum result;
549 struct srs_entry entry;
550 text* auth_name = PG_GETARG_TEXT_P(0);
551 text* auth_code = PG_GETARG_TEXT_P(1);
552 TupleDesc tuple_desc;
553
554 if (get_call_result_type(fcinfo, 0, &tuple_desc) != TYPEFUNC_COMPOSITE)
555 {
556 ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
557 errmsg("%s called with incompatible return type", __func__)));
558 }
559 BlessTupleDesc(tuple_desc);
560
561 entry.auth_name = auth_name;
562 entry.auth_code = auth_code;
563 result = srs_tuple_from_entry(&entry, tuple_desc);
564
565 if (result)
566 PG_RETURN_DATUM(srs_tuple_from_entry(&entry, tuple_desc));
567 else
568 PG_RETURN_NULL();
569}
570
571
572Datum postgis_srs_entry_all(PG_FUNCTION_ARGS);
574Datum postgis_srs_entry_all(PG_FUNCTION_ARGS)
575{
576 FuncCallContext *funcctx;
577 MemoryContext oldcontext;
578 struct srs_data *state;
579 Datum result;
580
581 /*
582 * On the first call, fill in the state with all
583 * of the auth_name/auth_srid pairings in the
584 * proj database. Then the per-call routine is just
585 * one isolated call per pair.
586 */
587 if (SRF_IS_FIRSTCALL())
588 {
589 funcctx = SRF_FIRSTCALL_INIT();
590 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
591
592 /*
593 * Could read all authorities from database, but includes
594 * authorities (IGN, OGC) that use non-integral values in
595 * auth_srid. So hand-coded list for now.
596 */
597 state = srs_state_init();
598 srs_state_codes("EPSG", state);
599 srs_state_codes("ESRI", state);
600 srs_state_codes("IAU_2015", state);
601
602 /*
603 * Read the TupleDesc from the FunctionCallInfo. The SQL definition
604 * of the function must have the right number of fields and types
605 * to match up to this C code.
606 */
607 if (get_call_result_type(fcinfo, 0, &funcctx->tuple_desc) != TYPEFUNC_COMPOSITE)
608 {
609 ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
610 errmsg("%s called with incompatible return type", __func__)));
611 }
612
613 BlessTupleDesc(funcctx->tuple_desc);
614 funcctx->user_fctx = state;
615 MemoryContextSwitchTo(oldcontext);
616 }
617
618 /* Stuff done on every call of the function */
619 funcctx = SRF_PERCALL_SETUP();
620 state = funcctx->user_fctx;
621
622 /* Exit when we've read all entries */
623 if (!state->num_entries || state->current_entry == state->num_entries)
624 {
625 SRF_RETURN_DONE(funcctx);
626 }
627
628 /* Lookup the srtext/proj4text for this entry */
630 state->entries + state->current_entry++,
631 funcctx->tuple_desc);
632
633 if (result)
634 SRF_RETURN_NEXT(funcctx, result);
635
636 /* Stop if lookup fails drastically */
637 SRF_RETURN_DONE(funcctx);
638}
639
640
641Datum postgis_srs_codes(PG_FUNCTION_ARGS);
643Datum postgis_srs_codes(PG_FUNCTION_ARGS)
644{
645 FuncCallContext *funcctx;
646 MemoryContext oldcontext;
647 struct srs_data *state;
648 Datum result;
649 text* auth_name = PG_GETARG_TEXT_P(0);
650 text* auth_code;
651
652 /*
653 * On the first call, fill in the state with all
654 * of the auth_name/auth_srid pairings in the
655 * proj database. Then the per-call routine is just
656 * one isolated call per pair.
657 */
658 if (SRF_IS_FIRSTCALL())
659 {
660 /*
661 * Only a subset of supported proj types actually
662 * show up in spatial_ref_sys
663 */
664 funcctx = SRF_FIRSTCALL_INIT();
665 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
666 state = srs_state_init();
667 srs_state_codes(text_to_cstring(auth_name), state);
668 funcctx->user_fctx = state;
669 MemoryContextSwitchTo(oldcontext);
670 }
671
672 /* Stuff done on every call of the function */
673 funcctx = SRF_PERCALL_SETUP();
674 state = funcctx->user_fctx;
675
676 /* Exit when we've read all entries */
677 if (!state->num_entries || state->current_entry == state->num_entries)
678 {
679 SRF_RETURN_DONE(funcctx);
680 }
681
682 /* Read the code for this entry */
683 auth_code = state->entries[state->current_entry++].auth_code;
684 result = PointerGetDatum(auth_code);
685
686 /* We are returning setof(text) */
687 if (result)
688 SRF_RETURN_NEXT(funcctx, result);
689
690 /* Stop if lookup fails drastically */
691 SRF_RETURN_DONE(funcctx);
692 SRF_RETURN_DONE(funcctx);
693}
694
695
700Datum postgis_srs_search(PG_FUNCTION_ARGS);
702Datum postgis_srs_search(PG_FUNCTION_ARGS)
703{
704 FuncCallContext *funcctx;
705 MemoryContext oldcontext;
706 struct srs_data *state;
707 Datum result;
708
709 /*
710 * On the first call, fill in the state with all
711 * of the auth_name/auth_srid pairings in the
712 * proj database. Then the per-call routine is just
713 * one isolated call per pair.
714 */
715 if (SRF_IS_FIRSTCALL())
716 {
717 GSERIALIZED *gbounds = PG_GETARG_GSERIALIZED_P(0);
718 LWGEOM *bounds = lwgeom_from_gserialized(gbounds);
719 text *auth_name = PG_GETARG_TEXT_P(1);
720
721 funcctx = SRF_FIRSTCALL_INIT();
722 oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
723
724 /*
725 * Could read all authorities from database, but includes
726 * authorities (IGN, OGC) that use non-integral values in
727 * auth_srid. So hand-coded list for now.
728 */
729 state = srs_state_init();
730
731 /* Run the Proj query */
732 srs_find_planar(text_to_cstring(auth_name), bounds, state);
733
734 /*
735 * Read the TupleDesc from the FunctionCallInfo. The SQL definition
736 * of the function must have the right number of fields and types
737 * to match up to this C code.
738 */
739 if (get_call_result_type(fcinfo, 0, &funcctx->tuple_desc) != TYPEFUNC_COMPOSITE)
740 {
741 ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
742 errmsg("%s called with incompatible return type", __func__)));
743 }
744
745 BlessTupleDesc(funcctx->tuple_desc);
746 funcctx->user_fctx = state;
747 MemoryContextSwitchTo(oldcontext);
748 }
749
750 /* Stuff done on every call of the function */
751 funcctx = SRF_PERCALL_SETUP();
752 state = funcctx->user_fctx;
753
754 /* Exit when we've read all entries */
755 if (!state->num_entries ||
756 state->current_entry == state->num_entries)
757 {
758 SRF_RETURN_DONE(funcctx);
759 }
760
761 /* Lookup the srtext/proj4text for this entry */
763 state->entries + state->current_entry++,
764 funcctx->tuple_desc);
765
766 if (result)
767 SRF_RETURN_NEXT(funcctx, result);
768
769 /* Stop if lookup fails drastically */
770 SRF_RETURN_DONE(funcctx);
771}
772
773
static uint8_t precision
Definition cu_in_twkb.c:25
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition cu_print.c:267
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.
Definition lwgeom.c:707
int32_t lwgeom_get_srid(const LWGEOM *geom)
Return SRID number.
Definition lwgeom.c:927
#define LW_FAILURE
Definition liblwgeom.h:96
int lwgeom_transform(LWGEOM *geom, LWPROJ *pj)
Transform (reproject) a geometry in-place.
void lwgeom_free(LWGEOM *geom)
Definition lwgeom.c:1218
lwvarlena_t * lwgeom_to_kml2(const LWGEOM *geom, int precision, const char *prefix)
Definition lwout_kml.c:44
int box3d_transform(GBOX *box, LWPROJ *pj)
LWPOINT * lwpoint_make2d(int32_t srid, double x, double y)
Definition lwpoint.c:163
int lwgeom_transform_from_str(LWGEOM *geom, const char *instr, const char *outstr)
int lwgeom_transform_pipeline(LWGEOM *geom, const char *pipeline, bool is_forward)
Transform (reproject) a geometry in-place using a PROJ pipeline.
const GBOX * lwgeom_get_bbox(const LWGEOM *lwgeom)
Get a non-empty geometry bounding box, computing and caching it if not already there.
Definition lwgeom.c:743
#define SRID_UNKNOWN
Unknown SRID value.
Definition liblwgeom.h:215
This library is the generic geometry handling section of PostGIS.
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)
#define ntypes
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)
static struct srs_data * srs_state_init()
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)
unsigned int int32
Definition shpopen.c:54
#define POSTGIS_PROJ_VERSION
Definition sqldefines.h:12
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.
const char * stringbuffer_getstring(stringbuffer_t *s)
Returns a reference to the internal string being managed by the stringbuffer.
void stringbuffer_init(stringbuffer_t *s)
static void stringbuffer_append(stringbuffer_t *s, const char *a)
Append the specified string to the stringbuffer_t.
double ymax
Definition liblwgeom.h:357
double xmax
Definition liblwgeom.h:355
double ymin
Definition liblwgeom.h:356
double xmin
Definition liblwgeom.h:354
GBOX * bbox
Definition liblwgeom.h:458
int32_t srid
Definition liblwgeom.h:460
struct srs_entry * entries
text * auth_name
text * auth_code
double sort