PostGIS  3.4.0dev-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  lwvarlena_t *geojson;
290  if (lwgeom->srid != SRID_UNKNOWN)
291  {
292  const int short_crs = LW_TRUE;
293  srs = GetSRSCacheBySRID(fcinfo, lwgeom->srid, short_crs);
294  }
295  geojson = lwgeom_to_geojson(lwgeom, srs, 15, 0);
296  lwgeom_free(lwgeom);
297  PG_RETURN_DATUM(DirectFunctionCall1(jsonb_in, PointerGetDatum(pstrdup(geojson->data))));
298 }
299 
300 
305 Datum LWGEOM_asSVG(PG_FUNCTION_ARGS)
306 {
307  GSERIALIZED *geom;
308  LWGEOM *lwgeom;
309  int relative = 0;
311 
312  if ( PG_ARGISNULL(0) ) PG_RETURN_NULL();
313 
314  geom = PG_GETARG_GSERIALIZED_P(0);
315 
316  /* check for relative path notation */
317  if ( PG_NARGS() > 1 && ! PG_ARGISNULL(1) )
318  relative = PG_GETARG_INT32(1) ? 1:0;
319 
320  if ( PG_NARGS() > 2 && ! PG_ARGISNULL(2) )
321  {
322  precision = PG_GETARG_INT32(2);
323  }
324 
325  lwgeom = lwgeom_from_gserialized(geom);
326  PG_RETURN_TEXT_P(lwgeom_to_svg(lwgeom, precision, relative));
327 }
328 
333 Datum LWGEOM_asX3D(PG_FUNCTION_ARGS)
334 {
335  GSERIALIZED *geom;
336  LWGEOM *lwgeom;
337  int version;
338  int option = 0;
340  static const char* default_defid = "x3d:"; /* default defid */
341  char *defidbuf;
342  const char* defid = default_defid;
343  text *defid_text;
344 
345  /* Get the version */
346  version = PG_GETARG_INT32(0);
347  if ( version != 3 )
348  {
349  elog(ERROR, "Only X3D version 3 are supported");
350  PG_RETURN_NULL();
351  }
352 
353  /* Get the geometry */
354  if ( PG_ARGISNULL(1) ) PG_RETURN_NULL();
355  geom = PG_GETARG_GSERIALIZED_P(1);
356 
357  /* Retrieve precision if any (default is max) */
358  if (PG_NARGS() >2 && !PG_ARGISNULL(2))
359  {
360  precision = PG_GETARG_INT32(2);
361  }
362 
363  /* retrieve option */
364  if (PG_NARGS() >3 && !PG_ARGISNULL(3))
365  option = PG_GETARG_INT32(3);
366 
367 
368  /* retrieve defid */
369  if (PG_NARGS() >4 && !PG_ARGISNULL(4))
370  {
371  defid_text = PG_GETARG_TEXT_P(4);
372  if ( VARSIZE_ANY_EXHDR(defid_text) == 0 )
373  {
374  defid = "";
375  }
376  else
377  {
378  /* +2 is one for the ':' and one for term null */
379  defidbuf = palloc(VARSIZE_ANY_EXHDR(defid_text)+2);
380  memcpy(defidbuf, VARDATA(defid_text),
381  VARSIZE_ANY_EXHDR(defid_text));
382  /* add colon and null terminate */
383  defidbuf[VARSIZE_ANY_EXHDR(defid_text)] = ':';
384  defidbuf[VARSIZE_ANY_EXHDR(defid_text)+1] = '\0';
385  defid = defidbuf;
386  }
387  }
388 
389  lwgeom = lwgeom_from_gserialized(geom);
390 
391  if (option & LW_X3D_USE_GEOCOORDS) {
392  if (lwgeom->srid != 4326)
393  {
394  PG_FREE_IF_COPY(geom, 0);
397  elog(ERROR, "Only SRID 4326 is supported for geocoordinates.");
398  PG_RETURN_NULL();
399  }
400  }
401 
402  PG_RETURN_TEXT_P(lwgeom_to_x3d3(lwgeom, precision, option, defid));
403 }
404 
409 Datum LWGEOM_asEncodedPolyline(PG_FUNCTION_ARGS)
410 {
411  GSERIALIZED *geom;
412  LWGEOM *lwgeom;
413  int precision = 5;
414 
415  if ( PG_ARGISNULL(0) ) PG_RETURN_NULL();
416 
417  geom = PG_GETARG_GSERIALIZED_P(0);
418  if (gserialized_get_srid(geom) != 4326) {
419  PG_FREE_IF_COPY(geom, 0);
420  elog(ERROR, "Only SRID 4326 is supported.");
421  PG_RETURN_NULL();
422  }
423  lwgeom = lwgeom_from_gserialized(geom);
424 
425  if (PG_NARGS() > 1 && !PG_ARGISNULL(1))
426  {
427  precision = PG_GETARG_INT32(1);
428  if ( precision < 0 ) precision = 5;
429  }
430 
431  PG_RETURN_TEXT_P(lwgeom_to_encoded_polyline(lwgeom, precision));
432 }
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:149
#define LW_FALSE
Definition: liblwgeom.h:94
#define LW_GML_IS_DEGREE
For GML3 only, declare that datas are lat/lon.
Definition: liblwgeom.h:1684
lwvarlena_t * lwgeom_to_svg(const LWGEOM *geom, int precision, int relative)
Takes a GEOMETRY and returns a SVG representation.
Definition: lwout_svg.c:559
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.
#define LW_GML_SHORTLINE
For GML3, use <LineString> rather than <Curve> for lines.
Definition: liblwgeom.h:1686
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)
Definition: lwout_gml.c:920
#define LW_GML_EXTENT
For GML2 and GML3, output only extent of geometry.
Definition: liblwgeom.h:1688
lwvarlena_t * lwgeom_extent_to_gml3(const LWGEOM *geom, const char *srs, int precision, int opts, const char *prefix)
Definition: lwout_gml.c:1081
lwvarlena_t * lwgeom_extent_to_gml2(const LWGEOM *geom, const char *srs, int precision, const char *prefix)
Definition: lwout_gml.c:1063
#define LW_GML_IS_DIMS
Macros for specifying GML options.
Definition: liblwgeom.h:1682
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:93
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:215
#define LW_X3D_USE_GEOCOORDS
Definition: liblwgeom.h:1701
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:978
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:460
char data[]
Definition: liblwgeom.h:308