PostGIS  3.3.9dev-r@@SVN_REVISION@@
lwgeom_export.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 2009-2011 Olivier Courtin <olivier.courtin@oslandia.com>
22  *
23  **********************************************************************/
24 
25 
26 
31 #include "postgres.h"
32 #include "catalog/pg_type.h" /* for INT4OID */
33 #include "executor/spi.h"
34 #include "utils/builtins.h"
35 #include "utils/jsonb.h"
36 
37 #include "../postgis_config.h"
38 #include "lwgeom_cache.h"
39 #include "lwgeom_pg.h"
40 #include "liblwgeom.h"
41 #include "liblwgeom_internal.h"
42 
43 Datum LWGEOM_asGML(PG_FUNCTION_ARGS);
44 Datum LWGEOM_asGeoJson(PG_FUNCTION_ARGS);
45 Datum LWGEOM_asGeoJson_old(PG_FUNCTION_ARGS);
46 Datum LWGEOM_asSVG(PG_FUNCTION_ARGS);
47 Datum LWGEOM_asX3D(PG_FUNCTION_ARGS);
48 Datum LWGEOM_asEncodedPolyline(PG_FUNCTION_ARGS);
49 Datum geometry_to_json(PG_FUNCTION_ARGS);
50 Datum geometry_to_jsonb(PG_FUNCTION_ARGS);
51 
56 Datum LWGEOM_asGML(PG_FUNCTION_ARGS)
57 {
58  GSERIALIZED *geom;
59  LWGEOM *lwgeom;
60  lwvarlena_t *v = NULL;
61  int version;
62  const char *srs;
63  int32_t srid;
64  int option = 0;
65  int lwopts = LW_GML_IS_DIMS;
67  static const char* default_prefix = "gml:"; /* default prefix */
68  const char* prefix = default_prefix;
69  const char* gml_id = NULL;
70  size_t len;
71  char *gml_id_buf, *prefix_buf;
72  text *prefix_text, *gml_id_text;
73 
74  /*
75  * Two potential callers, one starts with GML version,
76  * one starts with geometry, and we check for initial
77  * argument type and then dynamically change what args
78  * we read based on presence/absence
79  */
80  Oid first_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
81  int argnum = 0;
82  if (first_type != INT4OID)
83  {
84  version = 2;
85  }
86  else
87  {
88  /* Get the version */
89  version = PG_GETARG_INT32(argnum++);
90  if (version != 2 && version != 3)
91  {
92  elog(ERROR, "Only GML 2 and GML 3 are supported");
93  PG_RETURN_NULL();
94  }
95  }
96 
97  /* Get the geometry */
98  if (PG_ARGISNULL(argnum))
99  PG_RETURN_NULL();
100  geom = PG_GETARG_GSERIALIZED_P(argnum++);
101 
102  /* Retrieve precision if any (default is max) */
103  if (PG_NARGS() > argnum && !PG_ARGISNULL(argnum))
104  {
105  precision = PG_GETARG_INT32(argnum);
106  }
107  argnum++;
108 
109  /* retrieve option */
110  if (PG_NARGS() > argnum && !PG_ARGISNULL(argnum))
111  option = PG_GETARG_INT32(argnum);
112  argnum++;
113 
114  /* retrieve prefix */
115  if (PG_NARGS() > argnum && !PG_ARGISNULL(argnum))
116  {
117  prefix_text = PG_GETARG_TEXT_P(argnum);
118  if ( VARSIZE(prefix_text) == VARHDRSZ )
119  {
120  prefix = "";
121  }
122  else
123  {
124  len = VARSIZE_ANY_EXHDR(prefix_text);
125  prefix_buf = palloc(len + 2); /* +2 is one for the ':' and one for term null */
126  memcpy(prefix_buf, VARDATA(prefix_text), len);
127  /* add colon and null terminate */
128  prefix_buf[len] = ':';
129  prefix_buf[len+1] = '\0';
130  prefix = prefix_buf;
131  }
132  }
133  argnum++;
134 
135  if (PG_NARGS() > argnum && !PG_ARGISNULL(argnum))
136  {
137  gml_id_text = PG_GETARG_TEXT_P(argnum);
138  if ( VARSIZE(gml_id_text) == VARHDRSZ )
139  {
140  gml_id = "";
141  }
142  else
143  {
144  len = VARSIZE_ANY_EXHDR(gml_id_text);
145  gml_id_buf = palloc(len+1);
146  memcpy(gml_id_buf, VARDATA(gml_id_text), len);
147  gml_id_buf[len] = '\0';
148  gml_id = gml_id_buf;
149  }
150  }
151  argnum++;
152 
153  srid = gserialized_get_srid(geom);
154  if (srid == SRID_UNKNOWN) srs = NULL;
155  else if (option & 1)
156  srs = GetSRSCacheBySRID(fcinfo, srid, false);
157  else
158  srs = GetSRSCacheBySRID(fcinfo, srid, true);
159 
160  if (option & 2) lwopts &= ~LW_GML_IS_DIMS;
161  if (option & 4) lwopts |= LW_GML_SHORTLINE;
162  if (option & 8)
163  {
164  elog(ERROR,
165  "Options %d passed to ST_AsGML(geometry) sets "
166  "unsupported value 8",
167  option);
168  PG_RETURN_NULL();
169  }
170  if (option & 16) lwopts |= LW_GML_IS_DEGREE;
171  if (option & 32) lwopts |= LW_GML_EXTENT;
172 
173  lwgeom = lwgeom_from_gserialized(geom);
174 
175  if (version == 2)
176  {
177  if (lwopts & LW_GML_EXTENT)
178  v = lwgeom_extent_to_gml2(lwgeom, srs, precision, prefix);
179  else
180  v = lwgeom_to_gml2(lwgeom, srs, precision, prefix);
181  }
182  if (version == 3)
183  {
184  if (lwopts & LW_GML_EXTENT)
185  v = lwgeom_extent_to_gml3(lwgeom, srs, precision, lwopts, prefix);
186  else
187  v = lwgeom_to_gml3(lwgeom, srs, precision, lwopts, prefix, gml_id);
188  }
189 
190  if (!v)
191  PG_RETURN_NULL();
192  PG_RETURN_TEXT_P(v);
193 }
194 
195 
200 Datum LWGEOM_asGeoJson(PG_FUNCTION_ARGS)
201 {
202  GSERIALIZED *geom;
203  LWGEOM *lwgeom;
205  int output_bbox = LW_FALSE;
206  int output_long_crs = LW_FALSE;
207  int output_short_crs = LW_FALSE;
208  int output_guess_short_srid = LW_FALSE;
209  const char *srs = NULL;
210  int32_t srid;
211 
212  /* Get the geometry */
213  if (PG_ARGISNULL(0))
214  PG_RETURN_NULL();
215 
216  geom = PG_GETARG_GSERIALIZED_P(0);
217  srid = gserialized_get_srid(geom);
218 
219  /* Retrieve precision if any (default is max) */
220  if ( PG_NARGS() > 1 && !PG_ARGISNULL(1) )
221  {
222  precision = PG_GETARG_INT32(1);
223  }
224 
225  /* Retrieve output option
226  * 0 = without option
227  * 1 = bbox
228  * 2 = short crs
229  * 4 = long crs
230  * 8 = guess if CRS is needed (default)
231  */
232  if (PG_NARGS() > 2 && !PG_ARGISNULL(2))
233  {
234  int option = PG_GETARG_INT32(2);
235  output_guess_short_srid = (option & 8) ? LW_TRUE : LW_FALSE;
236  output_short_crs = (option & 2) ? LW_TRUE : LW_FALSE;
237  output_long_crs = (option & 4) ? LW_TRUE : LW_FALSE;
238  output_bbox = (option & 1) ? LW_TRUE : LW_FALSE;
239  }
240  else
241  output_guess_short_srid = LW_TRUE;
242 
243  if (output_guess_short_srid && srid != WGS84_SRID && srid != SRID_UNKNOWN)
244  output_short_crs = LW_TRUE;
245 
246  if (srid != SRID_UNKNOWN && (output_short_crs || output_long_crs))
247  {
248  srs = GetSRSCacheBySRID(fcinfo, srid, !output_long_crs);
249 
250  if (!srs)
251  {
252  elog(ERROR, "SRID %i unknown in spatial_ref_sys table", srid);
253  PG_RETURN_NULL();
254  }
255  }
256 
257  lwgeom = lwgeom_from_gserialized(geom);
258  PG_RETURN_TEXT_P(lwgeom_to_geojson(lwgeom, srs, precision, output_bbox));
259 }
260 
261 
266 Datum geometry_to_json(PG_FUNCTION_ARGS)
267 {
268  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
269  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
270  const char *srs = NULL;
271  lwvarlena_t *geojson;
272  if (lwgeom->srid != SRID_UNKNOWN)
273  {
274  const int short_crs = LW_TRUE;
275  srs = GetSRSCacheBySRID(fcinfo, lwgeom->srid, short_crs);
276  }
277  geojson = lwgeom_to_geojson(lwgeom, srs, 15, 0);
278  lwgeom_free(lwgeom);
279  PG_FREE_IF_COPY(geom, 0);
280  PG_RETURN_TEXT_P(geojson);
281 }
282 
284 Datum geometry_to_jsonb(PG_FUNCTION_ARGS)
285 {
286  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
287  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
288  const char *srs = NULL;
289  char *cstr;
290  lwvarlena_t *geojson;
291  if (lwgeom->srid != SRID_UNKNOWN)
292  {
293  const int short_crs = LW_TRUE;
294  srs = GetSRSCacheBySRID(fcinfo, lwgeom->srid, short_crs);
295  }
296  geojson = lwgeom_to_geojson(lwgeom, srs, 15, 0);
297  lwgeom_free(lwgeom);
298  cstr = palloc0(VARSIZE_ANY_EXHDR(geojson) + 1);
299  memcpy(cstr, VARDATA(geojson), VARSIZE_ANY_EXHDR(geojson));
300  PG_RETURN_DATUM(DirectFunctionCall1(jsonb_in, PointerGetDatum(cstr)));
301 }
302 
303 
308 Datum LWGEOM_asSVG(PG_FUNCTION_ARGS)
309 {
310  GSERIALIZED *geom;
311  LWGEOM *lwgeom;
312  int relative = 0;
314 
315  if ( PG_ARGISNULL(0) ) PG_RETURN_NULL();
316 
317  geom = PG_GETARG_GSERIALIZED_P(0);
318 
319  /* check for relative path notation */
320  if ( PG_NARGS() > 1 && ! PG_ARGISNULL(1) )
321  relative = PG_GETARG_INT32(1) ? 1:0;
322 
323  if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
324  {
325  precision = PG_GETARG_INT32(2);
326  }
327 
328  lwgeom = lwgeom_from_gserialized(geom);
329  PG_RETURN_TEXT_P(lwgeom_to_svg(lwgeom, precision, relative));
330 }
331 
336 Datum LWGEOM_asX3D(PG_FUNCTION_ARGS)
337 {
338  GSERIALIZED *geom;
339  LWGEOM *lwgeom;
340  int version;
341  int option = 0;
343  static const char* default_defid = "x3d:"; /* default defid */
344  char *defidbuf;
345  const char* defid = default_defid;
346  text *defid_text;
347 
348  /* Get the version */
349  version = PG_GETARG_INT32(0);
350  if ( version != 3 )
351  {
352  elog(ERROR, "Only X3D version 3 are supported");
353  PG_RETURN_NULL();
354  }
355 
356  /* Get the geometry */
357  if ( PG_ARGISNULL(1) ) PG_RETURN_NULL();
358  geom = PG_GETARG_GSERIALIZED_P(1);
359 
360  /* Retrieve precision if any (default is max) */
361  if (PG_NARGS() >2 && !PG_ARGISNULL(2))
362  {
363  precision = PG_GETARG_INT32(2);
364  }
365 
366  /* retrieve option */
367  if (PG_NARGS() >3 && !PG_ARGISNULL(3))
368  option = PG_GETARG_INT32(3);
369 
370 
371  /* retrieve defid */
372  if (PG_NARGS() >4 && !PG_ARGISNULL(4))
373  {
374  defid_text = PG_GETARG_TEXT_P(4);
375  if ( VARSIZE_ANY_EXHDR(defid_text) == 0 )
376  {
377  defid = "";
378  }
379  else
380  {
381  /* +2 is one for the ':' and one for term null */
382  defidbuf = palloc(VARSIZE_ANY_EXHDR(defid_text)+2);
383  memcpy(defidbuf, VARDATA(defid_text),
384  VARSIZE_ANY_EXHDR(defid_text));
385  /* add colon and null terminate */
386  defidbuf[VARSIZE_ANY_EXHDR(defid_text)] = ':';
387  defidbuf[VARSIZE_ANY_EXHDR(defid_text)+1] = '\0';
388  defid = defidbuf;
389  }
390  }
391 
392  lwgeom = lwgeom_from_gserialized(geom);
393 
394  if (option & LW_X3D_USE_GEOCOORDS) {
395  if (lwgeom->srid != 4326)
396  {
397  PG_FREE_IF_COPY(geom, 1);
400  elog(ERROR, "Only SRID 4326 is supported for geocoordinates.");
401  PG_RETURN_NULL();
402  }
403  }
404 
405  PG_RETURN_TEXT_P(lwgeom_to_x3d3(lwgeom, precision, option, defid));
406 }
407 
412 Datum LWGEOM_asEncodedPolyline(PG_FUNCTION_ARGS)
413 {
414  GSERIALIZED *geom;
415  LWGEOM *lwgeom;
416  int precision = 5;
417 
418  if ( PG_ARGISNULL(0) ) PG_RETURN_NULL();
419 
420  geom = PG_GETARG_GSERIALIZED_P(0);
421  if (gserialized_get_srid(geom) != 4326) {
422  PG_FREE_IF_COPY(geom, 0);
423  elog(ERROR, "Only SRID 4326 is supported.");
424  PG_RETURN_NULL();
425  }
426  lwgeom = lwgeom_from_gserialized(geom);
427 
428  if (PG_NARGS() > 1 && !PG_ARGISNULL(1))
429  {
430  precision = PG_GETARG_INT32(1);
431  if ( precision < 0 ) precision = 5;
432  }
433 
434  PG_RETURN_TEXT_P(lwgeom_to_encoded_polyline(lwgeom, precision));
435 }
static uint8_t precision
Definition: cu_in_twkb.c:25
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)...
Definition: gserialized.c:126
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
Definition: gserialized.c:239
#define WGS84_SRID
Definition: liblwgeom.h:164
#define LW_FALSE
Definition: liblwgeom.h:109
#define LW_GML_IS_DEGREE
For GML3 only, declare that datas are lat/lon.
Definition: liblwgeom.h:1692
lwvarlena_t * lwgeom_to_svg(const LWGEOM *geom, int precision, int relative)
Takes a GEOMETRY and returns a SVG representation.
Definition: lwout_svg.c:56
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1155
lwvarlena_t * lwgeom_to_geojson(const LWGEOM *geo, const char *srs, int precision, int has_bbox)
Takes a GEOMETRY and returns a GeoJson representation.
Definition: lwout_geojson.c:49
#define LW_GML_SHORTLINE
For GML3, use <LineString> rather than <Curve> for lines.
Definition: liblwgeom.h:1694
lwvarlena_t * lwgeom_to_encoded_polyline(const LWGEOM *geom, int precision)
lwvarlena_t * 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:259
#define LW_GML_EXTENT
For GML2 and GML3, output only extent of geometry.
Definition: liblwgeom.h:1696
lwvarlena_t * lwgeom_extent_to_gml3(const LWGEOM *geom, const char *srs, int precision, int opts, const char *prefix)
Definition: lwout_gml.c:247
lwvarlena_t * lwgeom_extent_to_gml2(const LWGEOM *geom, const char *srs, int precision, const char *prefix)
Definition: lwout_gml.c:240
#define LW_GML_IS_DIMS
Macros for specifying GML options.
Definition: liblwgeom.h:1690
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:108
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:230
#define LW_X3D_USE_GEOCOORDS
Definition: liblwgeom.h:1709
lwvarlena_t * lwgeom_to_x3d3(const LWGEOM *geom, int precision, int opts, const char *defid)
Definition: lwout_x3d.c:37
lwvarlena_t * lwgeom_to_gml3(const LWGEOM *geom, const char *srs, int precision, int opts, const char *prefix, const char *id)
Definition: lwout_gml.c:727
This library is the generic geometry handling section of PostGIS.
#define OUT_DEFAULT_DECIMAL_DIGITS
Datum geometry_to_json(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(LWGEOM_asGML)
Encode feature in GML.
Datum LWGEOM_asGeoJson_old(PG_FUNCTION_ARGS)
Datum LWGEOM_asEncodedPolyline(PG_FUNCTION_ARGS)
Datum LWGEOM_asGML(PG_FUNCTION_ARGS)
Definition: lwgeom_export.c:56
Datum LWGEOM_asSVG(PG_FUNCTION_ARGS)
Datum geometry_to_jsonb(PG_FUNCTION_ARGS)
Datum LWGEOM_asGeoJson(PG_FUNCTION_ARGS)
Datum LWGEOM_asX3D(PG_FUNCTION_ARGS)
int32_t srid
Definition: liblwgeom.h:475