PostGIS  2.2.7dev-r@@SVN_REVISION@@
lwgeom_export.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * PostGIS - Export functions for PostgreSQL/PostGIS
4  * Copyright 2009-2011 Olivier Courtin <olivier.courtin@oslandia.com>
5  *
6  * This is free software; you can redistribute and/or modify it under
7  * the terms of the GNU General Public Licence. See the COPYING file.
8  *
9  **********************************************************************/
10 
11 
16 #include "float.h" /* for DBL_DIG */
17 #include "postgres.h"
18 #include "executor/spi.h"
19 
20 #include "../postgis_config.h"
21 #include "lwgeom_pg.h"
22 #include "liblwgeom.h"
23 #include "lwgeom_export.h"
24 
25 Datum LWGEOM_asGML(PG_FUNCTION_ARGS);
26 Datum LWGEOM_asKML(PG_FUNCTION_ARGS);
27 Datum LWGEOM_asGeoJson(PG_FUNCTION_ARGS);
28 Datum LWGEOM_asGeoJson_old(PG_FUNCTION_ARGS);
29 Datum LWGEOM_asSVG(PG_FUNCTION_ARGS);
30 Datum LWGEOM_asX3D(PG_FUNCTION_ARGS);
31 Datum LWGEOM_asEncodedPolyline(PG_FUNCTION_ARGS);
32 
33 /*
34  * Retrieve an SRS from a given SRID
35  * Require valid spatial_ref_sys table entry
36  *
37  * Could return SRS as short one (i.e EPSG:4326)
38  * or as long one: (i.e urn:ogc:def:crs:EPSG::4326)
39  */
40 char * getSRSbySRID(int srid, bool short_crs)
41 {
42  char query[256];
43  char *srs, *srscopy;
44  int size, err;
45 
46  if (SPI_OK_CONNECT != SPI_connect ())
47  {
48  elog(NOTICE, "getSRSbySRID: could not connect to SPI manager");
49  SPI_finish();
50  return NULL;
51  }
52 
53  if (short_crs)
54  sprintf(query, "SELECT auth_name||':'||auth_srid \
55  FROM spatial_ref_sys WHERE srid='%d'", srid);
56  else
57  sprintf(query, "SELECT 'urn:ogc:def:crs:'||auth_name||'::'||auth_srid \
58  FROM spatial_ref_sys WHERE srid='%d'", srid);
59 
60  err = SPI_exec(query, 1);
61  if ( err < 0 )
62  {
63  elog(NOTICE, "getSRSbySRID: error executing query %d", err);
64  SPI_finish();
65  return NULL;
66  }
67 
68  /* no entry in spatial_ref_sys */
69  if (SPI_processed <= 0)
70  {
71  SPI_finish();
72  return NULL;
73  }
74 
75  /* get result */
76  srs = SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1);
77 
78  /* NULL result */
79  if ( ! srs )
80  {
81  SPI_finish();
82  return NULL;
83  }
84 
85  /* copy result to upper executor context */
86  size = strlen(srs)+1;
87  srscopy = SPI_palloc(size);
88  memcpy(srscopy, srs, size);
89 
90  /* disconnect from SPI */
91  SPI_finish();
92 
93  return srscopy;
94 }
95 
96 
97 /*
98 * Retrieve an SRID from a given SRS
99 * Require valid spatial_ref_sys table entry
100 *
101 */
102 int getSRIDbySRS(const char* srs)
103 {
104  char query[256];
105  int srid, err;
106 
107  if (srs == NULL)
108  return 0;
109 
110  if (SPI_OK_CONNECT != SPI_connect ())
111  {
112  elog(NOTICE, "getSRIDbySRS: could not connect to SPI manager");
113  SPI_finish();
114  return 0;
115  }
116  sprintf(query,
117  "SELECT srid "
118  "FROM spatial_ref_sys, "
119  "regexp_matches('%s', E'([a-z]+):([0-9]+)', 'gi') AS re "
120  "WHERE re[1] ILIKE auth_name AND int4(re[2]) = auth_srid", srs);
121 
122  err = SPI_exec(query, 1);
123  if ( err < 0 )
124  {
125  elog(NOTICE, "getSRIDbySRS: error executing query %d", err);
126  SPI_finish();
127  return 0;
128  }
129 
130  /* no entry in spatial_ref_sys */
131  if (SPI_processed <= 0)
132  {
133  sprintf(query,
134  "SELECT srid "
135  "FROM spatial_ref_sys, "
136  "regexp_matches('%s', E'urn:ogc:def:crs:([a-z]+):.*:([0-9]+)', 'gi') AS re "
137  "WHERE re[1] ILIKE auth_name AND int4(re[2]) = auth_srid", srs);
138 
139  err = SPI_exec(query, 1);
140  if ( err < 0 )
141  {
142  elog(NOTICE, "getSRIDbySRS: error executing query %d", err);
143  SPI_finish();
144  return 0;
145  }
146 
147  if (SPI_processed <= 0) {
148  SPI_finish();
149  return 0;
150  }
151  }
152 
153  srid = atoi(SPI_getvalue(SPI_tuptable->vals[0], SPI_tuptable->tupdesc, 1));
154  if ( ! srs )
155  {
156  SPI_finish();
157  return 0;
158  }
159 
160  SPI_finish();
161 
162  return srid;
163 }
164 
165 
170 Datum LWGEOM_asGML(PG_FUNCTION_ARGS)
171 {
172  GSERIALIZED *geom;
173  LWGEOM *lwgeom;
174  char *gml = NULL;
175  text *result;
176  int version;
177  char *srs;
178  int srid;
179  int option = 0;
180  int lwopts = LW_GML_IS_DIMS;
181  int precision = DBL_DIG;
182  static const char* default_prefix = "gml:"; /* default prefix */
183  const char* prefix = default_prefix;
184  const char* gml_id = NULL;
185  size_t len;
186  char *gml_id_buf, *prefix_buf;
187  text *prefix_text, *gml_id_text;
188 
189 
190  /* Get the version */
191  version = PG_GETARG_INT32(0);
192  if ( version != 2 && version != 3 )
193  {
194  elog(ERROR, "Only GML 2 and GML 3 are supported");
195  PG_RETURN_NULL();
196  }
197 
198  /* Get the geometry */
199  if ( PG_ARGISNULL(1) ) PG_RETURN_NULL();
200  geom = PG_GETARG_GSERIALIZED_P(1);
201 
202  /* Retrieve precision if any (default is max) */
203  if (PG_NARGS() >2 && !PG_ARGISNULL(2))
204  {
205  precision = PG_GETARG_INT32(2);
206  /* TODO: leave this to liblwgeom ? */
207  if ( precision > DBL_DIG )
208  precision = DBL_DIG;
209  else if ( precision < 0 ) precision = 0;
210  }
211 
212  /* retrieve option */
213  if (PG_NARGS() >3 && !PG_ARGISNULL(3))
214  option = PG_GETARG_INT32(3);
215 
216  /* retrieve prefix */
217  if (PG_NARGS() >4 && !PG_ARGISNULL(4))
218  {
219  prefix_text = PG_GETARG_TEXT_P(4);
220  if ( VARSIZE(prefix_text) == VARHDRSZ )
221  {
222  prefix = "";
223  }
224  else
225  {
226  len = VARSIZE(prefix_text)-VARHDRSZ;
227  prefix_buf = palloc(len + 2); /* +2 is one for the ':' and one for term null */
228  memcpy(prefix_buf, VARDATA(prefix_text), len);
229  /* add colon and null terminate */
230  prefix_buf[len] = ':';
231  prefix_buf[len+1] = '\0';
232  prefix = prefix_buf;
233  }
234  }
235 
236  if (PG_NARGS() >5 && !PG_ARGISNULL(5))
237  {
238  gml_id_text = PG_GETARG_TEXT_P(5);
239  if ( VARSIZE(gml_id_text) == VARHDRSZ )
240  {
241  gml_id = "";
242  }
243  else
244  {
245  len = VARSIZE(gml_id_text)-VARHDRSZ;
246  gml_id_buf = palloc(len+1);
247  memcpy(gml_id_buf, VARDATA(gml_id_text), len);
248  gml_id_buf[len] = '\0';
249  gml_id = gml_id_buf;
250  }
251  }
252 
253  srid = gserialized_get_srid(geom);
254  if (srid == SRID_UNKNOWN) srs = NULL;
255  else if (option & 1) srs = getSRSbySRID(srid, false);
256  else srs = getSRSbySRID(srid, true);
257 
258  if (option & 2) lwopts &= ~LW_GML_IS_DIMS;
259  if (option & 4) lwopts |= LW_GML_SHORTLINE;
260  if (option & 16) lwopts |= LW_GML_IS_DEGREE;
261  if (option & 32) lwopts |= LW_GML_EXTENT;
262 
263  lwgeom = lwgeom_from_gserialized(geom);
264 
265  if (version == 2 && lwopts & LW_GML_EXTENT)
266  gml = lwgeom_extent_to_gml2(lwgeom, srs, precision, prefix);
267  else if (version == 2)
268  gml = lwgeom_to_gml2(lwgeom, srs, precision, prefix);
269  else if (version == 3 && lwopts & LW_GML_EXTENT)
270  gml = lwgeom_extent_to_gml3(lwgeom, srs, precision, lwopts, prefix);
271  else if (version == 3)
272  gml = lwgeom_to_gml3(lwgeom, srs, precision, lwopts, prefix, gml_id);
273 
274  lwgeom_free(lwgeom);
275  PG_FREE_IF_COPY(geom, 1);
276 
277  /* Return null on null */
278  if ( ! gml )
279  PG_RETURN_NULL();
280 
281  result = cstring2text(gml);
282  lwfree(gml);
283  PG_RETURN_TEXT_P(result);
284 }
285 
286 
291 Datum LWGEOM_asKML(PG_FUNCTION_ARGS)
292 {
293  GSERIALIZED *geom;
294  LWGEOM *lwgeom;
295  char *kml;
296  text *result;
297  int version;
298  int precision = DBL_DIG;
299  static const char* default_prefix = ""; /* default prefix */
300  char *prefixbuf;
301  const char* prefix = default_prefix;
302  text *prefix_text;
303 
304 
305  /* Get the version */
306  version = PG_GETARG_INT32(0);
307  if ( version != 2)
308  {
309  elog(ERROR, "Only KML 2 is supported");
310  PG_RETURN_NULL();
311  }
312 
313  /* Get the geometry */
314  if ( PG_ARGISNULL(1) ) PG_RETURN_NULL();
315  geom = PG_GETARG_GSERIALIZED_P(1);
316 
317  /* Retrieve precision if any (default is max) */
318  if (PG_NARGS() >2 && !PG_ARGISNULL(2))
319  {
320  /* TODO: leave this to liblwgeom ? */
321  precision = PG_GETARG_INT32(2);
322  if ( precision > DBL_DIG )
323  precision = DBL_DIG;
324  else if ( precision < 0 ) precision = 0;
325  }
326 
327  /* retrieve prefix */
328  if (PG_NARGS() >3 && !PG_ARGISNULL(3))
329  {
330  prefix_text = PG_GETARG_TEXT_P(3);
331  if ( VARSIZE(prefix_text)-VARHDRSZ == 0 )
332  {
333  prefix = "";
334  }
335  else
336  {
337  /* +2 is one for the ':' and one for term null */
338  prefixbuf = palloc(VARSIZE(prefix_text)-VARHDRSZ+2);
339  memcpy(prefixbuf, VARDATA(prefix_text),
340  VARSIZE(prefix_text)-VARHDRSZ);
341  /* add colon and null terminate */
342  prefixbuf[VARSIZE(prefix_text)-VARHDRSZ] = ':';
343  prefixbuf[VARSIZE(prefix_text)-VARHDRSZ+1] = '\0';
344  prefix = prefixbuf;
345  }
346  }
347 
348  lwgeom = lwgeom_from_gserialized(geom);
349  kml = lwgeom_to_kml2(lwgeom, precision, prefix);
350  lwgeom_free(lwgeom);
351  PG_FREE_IF_COPY(geom, 1);
352 
353  if( ! kml )
354  PG_RETURN_NULL();
355 
356  result = cstring2text(kml);
357  lwfree(kml);
358 
359  PG_RETURN_POINTER(result);
360 }
361 
362 
370 Datum LWGEOM_asGeoJson_old(PG_FUNCTION_ARGS)
371 {
372  switch( PG_NARGS() )
373  {
374  case 2:
375  return DirectFunctionCall1(LWGEOM_asGeoJson, PG_GETARG_DATUM(1));
376  case 3:
377  return DirectFunctionCall2(LWGEOM_asGeoJson, PG_GETARG_DATUM(1), PG_GETARG_DATUM(2));
378  case 4:
379  return DirectFunctionCall3(LWGEOM_asGeoJson, PG_GETARG_DATUM(1), PG_GETARG_DATUM(2), PG_GETARG_DATUM(3));
380  default:
381  elog(ERROR, "bad call in %s", __func__);
382  }
383  PG_RETURN_NULL();
384 }
385 
390 Datum LWGEOM_asGeoJson(PG_FUNCTION_ARGS)
391 {
392  GSERIALIZED *geom;
393  LWGEOM *lwgeom;
394  char *geojson;
395  text *result;
396  int has_bbox = 0;
397  int precision = DBL_DIG;
398  char *srs = NULL;
399 
400  /* Get the geometry */
401  if ( PG_ARGISNULL(0) )
402  PG_RETURN_NULL();
403 
404  geom = PG_GETARG_GSERIALIZED_P(0);
405 
406  /* Retrieve precision if any (default is max) */
407  if ( PG_NARGS() > 1 && !PG_ARGISNULL(1) )
408  {
409  precision = PG_GETARG_INT32(1);
410  if ( precision > DBL_DIG )
411  precision = DBL_DIG;
412  else if ( precision < 0 )
413  precision = 0;
414  }
415 
416  /* Retrieve output option
417  * 0 = without option (default)
418  * 1 = bbox
419  * 2 = short crs
420  * 4 = long crs
421  */
422  if ( PG_NARGS() > 2 && !PG_ARGISNULL(2) )
423  {
424  int option = PG_GETARG_INT32(2);
425 
426  if ( option & 2 || option & 4 )
427  {
428  int srid = gserialized_get_srid(geom);
429  if ( srid != SRID_UNKNOWN )
430  {
431  if ( option & 2 )
432  srs = getSRSbySRID(srid, true);
433 
434  if ( option & 4 )
435  srs = getSRSbySRID(srid, false);
436 
437  if ( !srs )
438  {
439  elog(ERROR,
440  "SRID %i unknown in spatial_ref_sys table",
441  srid);
442  PG_RETURN_NULL();
443  }
444  }
445  }
446 
447  if (option & 1)
448  has_bbox = 1;
449  }
450 
451  lwgeom = lwgeom_from_gserialized(geom);
452  geojson = lwgeom_to_geojson(lwgeom, srs, precision, has_bbox);
453  lwgeom_free(lwgeom);
454 
455  if (srs) pfree(srs);
456 
457  result = cstring2text(geojson);
458  lwfree(geojson);
459 
460  PG_FREE_IF_COPY(geom, 0);
461  PG_RETURN_TEXT_P(result);
462 }
463 
464 
469 Datum LWGEOM_asSVG(PG_FUNCTION_ARGS)
470 {
471  GSERIALIZED *geom;
472  LWGEOM *lwgeom;
473  char *svg;
474  text *result;
475  int relative = 0;
476  int precision=DBL_DIG;
477 
478  if ( PG_ARGISNULL(0) ) PG_RETURN_NULL();
479 
480  geom = PG_GETARG_GSERIALIZED_P(0);
481 
482  /* check for relative path notation */
483  if ( PG_NARGS() > 1 && ! PG_ARGISNULL(1) )
484  relative = PG_GETARG_INT32(1) ? 1:0;
485 
486  if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
487  {
488  precision = PG_GETARG_INT32(2);
489  /* TODO: leave this to liblwgeom ? */
490  if ( precision > DBL_DIG )
491  precision = DBL_DIG;
492  else if ( precision < 0 ) precision = 0;
493  }
494 
495  lwgeom = lwgeom_from_gserialized(geom);
496  svg = lwgeom_to_svg(lwgeom, precision, relative);
497  result = cstring2text(svg);
498  lwgeom_free(lwgeom);
499  pfree(svg);
500  PG_FREE_IF_COPY(geom, 0);
501 
502  PG_RETURN_TEXT_P(result);
503 }
504 
509 Datum LWGEOM_asX3D(PG_FUNCTION_ARGS)
510 {
511  GSERIALIZED *geom;
512  LWGEOM *lwgeom;
513  char *x3d;
514  text *result;
515  int version;
516  char *srs;
517  int srid;
518  int option = 0;
519  int precision = DBL_DIG;
520  static const char* default_defid = "x3d:"; /* default defid */
521  char *defidbuf;
522  const char* defid = default_defid;
523  text *defid_text;
524 
525  /* Get the version */
526  version = PG_GETARG_INT32(0);
527  if ( version != 3 )
528  {
529  elog(ERROR, "Only X3D version 3 are supported");
530  PG_RETURN_NULL();
531  }
532 
533  /* Get the geometry */
534  if ( PG_ARGISNULL(1) ) PG_RETURN_NULL();
535  geom = PG_GETARG_GSERIALIZED_P(1);
536 
537  /* Retrieve precision if any (default is max) */
538  if (PG_NARGS() >2 && !PG_ARGISNULL(2))
539  {
540  precision = PG_GETARG_INT32(2);
541  /* TODO: leave this to liblwgeom ? */
542  if ( precision > DBL_DIG )
543  precision = DBL_DIG;
544  else if ( precision < 0 ) precision = 0;
545  }
546 
547  /* retrieve option */
548  if (PG_NARGS() >3 && !PG_ARGISNULL(3))
549  option = PG_GETARG_INT32(3);
550 
551 
552 
553  /* retrieve defid */
554  if (PG_NARGS() >4 && !PG_ARGISNULL(4))
555  {
556  defid_text = PG_GETARG_TEXT_P(4);
557  if ( VARSIZE(defid_text)-VARHDRSZ == 0 )
558  {
559  defid = "";
560  }
561  else
562  {
563  /* +2 is one for the ':' and one for term null */
564  defidbuf = palloc(VARSIZE(defid_text)-VARHDRSZ+2);
565  memcpy(defidbuf, VARDATA(defid_text),
566  VARSIZE(defid_text)-VARHDRSZ);
567  /* add colon and null terminate */
568  defidbuf[VARSIZE(defid_text)-VARHDRSZ] = ':';
569  defidbuf[VARSIZE(defid_text)-VARHDRSZ+1] = '\0';
570  defid = defidbuf;
571  }
572  }
573 
574  lwgeom = lwgeom_from_gserialized(geom);
575  srid = gserialized_get_srid(geom);
576  if (srid == SRID_UNKNOWN) srs = NULL;
577  else if (option & 1) srs = getSRSbySRID(srid, false);
578  else srs = getSRSbySRID(srid, true);
579 
580  if (option & LW_X3D_USE_GEOCOORDS) {
581  if (srid != 4326) {
582  PG_FREE_IF_COPY(geom, 0);
585  elog(ERROR, "Only SRID 4326 is supported for geocoordinates.");
586  PG_RETURN_NULL();
587  }
588  }
589 
590 
591  x3d = lwgeom_to_x3d3(lwgeom, srs, precision,option, defid);
592 
593  lwgeom_free(lwgeom);
594  PG_FREE_IF_COPY(geom, 1);
595 
596  result = cstring2text(x3d);
597  lwfree(x3d);
598 
599  PG_RETURN_TEXT_P(result);
600 }
601 
606 Datum LWGEOM_asEncodedPolyline(PG_FUNCTION_ARGS)
607 {
608  GSERIALIZED *geom;
609  LWGEOM *lwgeom;
610  char *encodedpolyline;
611  int precision = 5;
612  text *result;
613 
614  if ( PG_ARGISNULL(0) ) PG_RETURN_NULL();
615 
616  geom = PG_GETARG_GSERIALIZED_P(0);
617  if (gserialized_get_srid(geom) != 4326) {
618  PG_FREE_IF_COPY(geom, 0);
619  elog(ERROR, "Only SRID 4326 is supported.");
620  PG_RETURN_NULL();
621  }
622  lwgeom = lwgeom_from_gserialized(geom);
623  PG_FREE_IF_COPY(geom, 0);
624 
625  if (PG_NARGS() > 1 && !PG_ARGISNULL(1))
626  {
627  precision = PG_GETARG_INT32(1);
628  if ( precision < 0 ) precision = 5;
629  }
630 
631  encodedpolyline = lwgeom_to_encoded_polyline(lwgeom, precision);
632  lwgeom_free(lwgeom);
633 
634  result = cstring2text(encodedpolyline);
635  lwfree(encodedpolyline);
636 
637  PG_RETURN_TEXT_P(result);
638 }
char * lwgeom_to_gml2(const LWGEOM *geom, const char *srs, int precision, const char *prefix)
VERSION GML 2 takes a GEOMETRY and returns a GML2 representation.
Definition: lwout_gml.c:218
Datum LWGEOM_asX3D(PG_FUNCTION_ARGS)
#define LW_GML_SHORTLINE
For GML3, use rather than for lines.
Definition: liblwgeom.h:1473
char * lwgeom_to_x3d3(const LWGEOM *geom, char *srs, int precision, int opts, const char *defid)
Definition: lwout_x3d.c:48
void lwfree(void *mem)
Definition: lwutil.c:214
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
char * lwgeom_to_svg(const LWGEOM *geom, int precision, int relative)
Takes a GEOMETRY and returns a SVG representation.
Definition: lwout_svg.c:42
PG_FUNCTION_INFO_V1(LWGEOM_asGML)
Encode feature in GML.
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1050
Datum LWGEOM_asSVG(PG_FUNCTION_ARGS)
char * lwgeom_to_encoded_polyline(const LWGEOM *geom, int precision)
#define LW_X3D_USE_GEOCOORDS
Definition: liblwgeom.h:1488
LWGEOM * geom
Datum LWGEOM_asGeoJson_old(PG_FUNCTION_ARGS)
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:172
char * lwgeom_to_geojson(const LWGEOM *geo, char *srs, int precision, int has_bbox)
Takes a GEOMETRY and returns a GeoJson representation.
Definition: lwout_geojson.c:34
#define LW_GML_EXTENT
For GML2 and GML3, output only extent of geometry.
Definition: liblwgeom.h:1475
uint8_t precision
Definition: cu_in_twkb.c:25
Datum LWGEOM_asEncodedPolyline(PG_FUNCTION_ARGS)
Datum LWGEOM_asGeoJson(PG_FUNCTION_ARGS)
char * lwgeom_extent_to_gml2(const LWGEOM *geom, const char *srs, int precision, const char *prefix)
Definition: lwout_gml.c:185
int getSRIDbySRS(const char *srs)
char * lwgeom_extent_to_gml3(const LWGEOM *geom, const char *srs, int precision, int opts, const char *prefix)
Definition: lwout_gml.c:200
Datum LWGEOM_asKML(PG_FUNCTION_ARGS)
char * getSRSbySRID(int srid, bool short_crs)
Definition: lwgeom_export.c:40
#define LW_GML_IS_DIMS
Macros for specifying GML options.
Definition: liblwgeom.h:1469
char * lwgeom_to_gml3(const LWGEOM *geom, const char *srs, int precision, int opts, const char *prefix, const char *id)
Definition: lwout_gml.c:723
Datum LWGEOM_asGML(PG_FUNCTION_ARGS)
int32_t gserialized_get_srid(const GSERIALIZED *s)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
Definition: g_serialized.c:69
This library is the generic geometry handling section of PostGIS.
char * lwgeom_to_kml2(const LWGEOM *geom, int precision, const char *prefix)
Definition: lwout_kml.c:31
#define LW_GML_IS_DEGREE
For GML3 only, declare that datas are lat/lon.
Definition: liblwgeom.h:1471