PostGIS  2.1.10dev-r@@SVN_REVISION@@
lwgeom_ogc.c
Go to the documentation of this file.
1 /**********************************************************************
2  * $Id: lwgeom_ogc.c 13254 2015-02-20 18:23:13Z pramsey $
3  *
4  * PostGIS - Spatial Types for PostgreSQL
5  * http://postgis.net
6  * Copyright 2001-2005 Refractions Research Inc.
7  *
8  * This is free software; you can redistribute and/or modify it under
9  * the terms of the GNU General Public Licence. See the COPYING file.
10  *
11  **********************************************************************/
12 
13 #include "postgres.h"
14 
15 #include <math.h>
16 #include <float.h>
17 #include <string.h>
18 #include <stdio.h>
19 #include <errno.h>
20 
21 #include "access/gist.h"
22 #include "access/itup.h"
23 
24 #include "fmgr.h"
25 #include "utils/elog.h"
26 
27 #include "../postgis_config.h"
28 
29 #include "liblwgeom.h"
30 #include "lwgeom_pg.h"
31 
32 
33 /* ---- SRID(geometry) */
34 Datum LWGEOM_get_srid(PG_FUNCTION_ARGS);
35 /* ---- SetSRID(geometry, integer) */
36 Datum LWGEOM_set_srid(PG_FUNCTION_ARGS);
37 /* ---- GeometryType(geometry) */
38 Datum LWGEOM_getTYPE(PG_FUNCTION_ARGS);
39 Datum geometry_geometrytype(PG_FUNCTION_ARGS);
40 /* ---- NumPoints(geometry) */
41 Datum LWGEOM_numpoints_linestring(PG_FUNCTION_ARGS);
42 /* ---- NumGeometries(geometry) */
43 Datum LWGEOM_numgeometries_collection(PG_FUNCTION_ARGS);
44 /* ---- GeometryN(geometry, integer) */
45 Datum LWGEOM_geometryn_collection(PG_FUNCTION_ARGS);
46 /* ---- Dimension(geometry) */
47 Datum LWGEOM_dimension(PG_FUNCTION_ARGS);
48 /* ---- ExteriorRing(geometry) */
49 Datum LWGEOM_exteriorring_polygon(PG_FUNCTION_ARGS);
50 /* ---- InteriorRingN(geometry, integer) */
51 Datum LWGEOM_interiorringn_polygon(PG_FUNCTION_ARGS);
52 /* ---- NumInteriorRings(geometry) */
53 Datum LWGEOM_numinteriorrings_polygon(PG_FUNCTION_ARGS);
54 /* ---- PointN(geometry, integer) */
55 Datum LWGEOM_pointn_linestring(PG_FUNCTION_ARGS);
56 /* ---- X(geometry) */
57 Datum LWGEOM_x_point(PG_FUNCTION_ARGS);
58 /* ---- Y(geometry) */
59 Datum LWGEOM_y_point(PG_FUNCTION_ARGS);
60 /* ---- Z(geometry) */
61 Datum LWGEOM_z_point(PG_FUNCTION_ARGS);
62 /* ---- M(geometry) */
63 Datum LWGEOM_m_point(PG_FUNCTION_ARGS);
64 /* ---- StartPoint(geometry) */
65 Datum LWGEOM_startpoint_linestring(PG_FUNCTION_ARGS);
66 /* ---- EndPoint(geometry) */
67 Datum LWGEOM_endpoint_linestring(PG_FUNCTION_ARGS);
68 /* ---- AsText(geometry) */
69 Datum LWGEOM_asText(PG_FUNCTION_ARGS);
70 /* ---- AsBinary(geometry, [XDR|NDR]) */
71 Datum LWGEOM_asBinary(PG_FUNCTION_ARGS);
72 /* ---- GeometryFromText(text, integer) */
73 Datum LWGEOM_from_text(PG_FUNCTION_ARGS);
74 /* ---- GeomFromWKB(bytea, integer) */
75 Datum LWGEOM_from_WKB(PG_FUNCTION_ARGS);
76 /* ---- IsClosed(geometry) */
77 Datum LWGEOM_isclosed(PG_FUNCTION_ARGS);
78 
79 /*------------------------------------------------------------------*/
80 
81 /* getSRID(lwgeom) :: int4 */
83 Datum LWGEOM_get_srid(PG_FUNCTION_ARGS)
84 {
85  GSERIALIZED *geom=(GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
86  int srid = gserialized_get_srid (geom);
87  PG_FREE_IF_COPY(geom,0);
88  PG_RETURN_INT32(srid);
89 }
90 
91 /* setSRID(lwgeom, int4) :: lwgeom */
93 Datum LWGEOM_set_srid(PG_FUNCTION_ARGS)
94 {
96  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
97  int srid = PG_GETARG_INT32(1);
98  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
99  lwgeom_set_srid(lwgeom, srid);
100  result = geometry_serialize(lwgeom);
101  lwgeom_free(lwgeom);
102  PG_FREE_IF_COPY(geom, 0);
103  PG_RETURN_POINTER(result);
104 }
105 
106 /* returns a string representation of this geometry's type */
108 Datum LWGEOM_getTYPE(PG_FUNCTION_ARGS)
109 {
110  GSERIALIZED *gser;
111  text *text_ob;
112  char *result;
113  uint8_t type;
114  static int maxtyplen = 20;
115 
116  gser = (GSERIALIZED*)PG_DETOAST_DATUM_SLICE(PG_GETARG_DATUM(0), 0, gserialized_max_header_size());
117  text_ob = palloc0(VARHDRSZ + maxtyplen);
118  result = VARDATA(text_ob);
119 
120  type = gserialized_get_type(gser);
121 
122  if (type == POINTTYPE)
123  strcpy(result,"POINT");
124  else if (type == MULTIPOINTTYPE)
125  strcpy(result,"MULTIPOINT");
126  else if (type == LINETYPE)
127  strcpy(result,"LINESTRING");
128  else if (type == CIRCSTRINGTYPE)
129  strcpy(result,"CIRCULARSTRING");
130  else if (type == COMPOUNDTYPE)
131  strcpy(result, "COMPOUNDCURVE");
132  else if (type == MULTILINETYPE)
133  strcpy(result,"MULTILINESTRING");
134  else if (type == MULTICURVETYPE)
135  strcpy(result, "MULTICURVE");
136  else if (type == POLYGONTYPE)
137  strcpy(result,"POLYGON");
138  else if (type == TRIANGLETYPE)
139  strcpy(result,"TRIANGLE");
140  else if (type == CURVEPOLYTYPE)
141  strcpy(result,"CURVEPOLYGON");
142  else if (type == MULTIPOLYGONTYPE)
143  strcpy(result,"MULTIPOLYGON");
144  else if (type == MULTISURFACETYPE)
145  strcpy(result, "MULTISURFACE");
146  else if (type == COLLECTIONTYPE)
147  strcpy(result,"GEOMETRYCOLLECTION");
148  else if (type == POLYHEDRALSURFACETYPE)
149  strcpy(result,"POLYHEDRALSURFACE");
150  else if (type == TINTYPE)
151  strcpy(result,"TIN");
152  else
153  strcpy(result,"UNKNOWN");
154 
155  if ( gserialized_has_m(gser) && ! gserialized_has_z(gser) )
156  strcat(result, "M");
157 
158  SET_VARSIZE(text_ob, strlen(result) + VARHDRSZ); /* size of string */
159 
160  PG_FREE_IF_COPY(gser, 0);
161 
162  PG_RETURN_TEXT_P(text_ob);
163 }
164 
165 
166 /* returns a string representation of this geometry's type */
168 Datum geometry_geometrytype(PG_FUNCTION_ARGS)
169 {
170  GSERIALIZED *gser;
171  text *type_text;
172  char *type_str = palloc(32);
173 
174  /* Read just the header from the toasted tuple */
175  gser = (GSERIALIZED*)PG_DETOAST_DATUM_SLICE(PG_GETARG_DATUM(0), 0, gserialized_max_header_size());
176 
177  /* Make it empty string to start */
178  *type_str = 0;
179 
180  /* Build up the output string */
181  strncat(type_str, "ST_", 32);
182  strncat(type_str, lwtype_name(gserialized_get_type(gser)), 32);
183 
184  /* Build a text type to store things in */
185  type_text = cstring2text(type_str);
186  pfree(type_str);
187 
188  PG_FREE_IF_COPY(gser, 0);
189  PG_RETURN_TEXT_P(type_text);
190 }
191 
192 
193 
199 Datum LWGEOM_numpoints_linestring(PG_FUNCTION_ARGS)
200 {
201  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
202  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
203  int count = -1;
204 
205  if ( lwgeom->type == LINETYPE || lwgeom->type == CIRCSTRINGTYPE )
206  count = lwgeom_count_vertices(lwgeom);
207 
208  lwgeom_free(lwgeom);
209  PG_FREE_IF_COPY(geom, 0);
210 
211  /* OGC says this functions is only valid on LINESTRING */
212  if ( count < 0 )
213  PG_RETURN_NULL();
214 
215  PG_RETURN_INT32(count);
216 }
217 
219 Datum LWGEOM_numgeometries_collection(PG_FUNCTION_ARGS)
220 {
221  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
222  LWGEOM *lwgeom;
223  int32 ret = 1;
224 
225  lwgeom = lwgeom_from_gserialized(geom);
226  if ( lwgeom_is_empty(lwgeom) )
227  {
228  ret = 0;
229  }
230  else if ( lwgeom_is_collection(lwgeom) )
231  {
232  LWCOLLECTION *col = lwgeom_as_lwcollection(lwgeom);
233  ret = col->ngeoms;
234  }
235  lwgeom_free(lwgeom);
236  PG_FREE_IF_COPY(geom, 0);
237  PG_RETURN_INT32(ret);
238 }
239 
242 Datum LWGEOM_geometryn_collection(PG_FUNCTION_ARGS)
243 {
244  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
246  int type = gserialized_get_type(geom);
247  int32 idx;
248  LWCOLLECTION *coll;
249  LWGEOM *subgeom;
250 
251  POSTGIS_DEBUG(2, "LWGEOM_geometryn_collection called.");
252 
253  /* elog(NOTICE, "GeometryN called"); */
254 
255  idx = PG_GETARG_INT32(1);
256  idx -= 1; /* index is 1-based */
257 
258  /* call is valid on multi* geoms only */
259  if (type==POINTTYPE || type==LINETYPE || type==CIRCSTRINGTYPE ||
260  type==COMPOUNDTYPE || type==POLYGONTYPE ||
261  type==CURVEPOLYTYPE || type==TRIANGLETYPE)
262  {
263  if ( idx == 0 ) PG_RETURN_POINTER(geom);
264  PG_RETURN_NULL();
265  }
266 
268 
269  if ( idx < 0 ) PG_RETURN_NULL();
270  if ( idx >= coll->ngeoms ) PG_RETURN_NULL();
271 
272  subgeom = coll->geoms[idx];
273  subgeom->srid = coll->srid;
274 
275  /* COMPUTE_BBOX==TAINTING */
276  if ( coll->bbox ) lwgeom_add_bbox(subgeom);
277 
278  result = geometry_serialize(subgeom);
279 
280  lwcollection_free(coll);
281  PG_FREE_IF_COPY(geom, 0);
282 
283  PG_RETURN_POINTER(result);
284 
285 }
286 
287 
293 Datum LWGEOM_dimension(PG_FUNCTION_ARGS)
294 {
295  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
296  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
297  int dimension = -1;
298 
299  dimension = lwgeom_dimension(lwgeom);
300  lwgeom_free(lwgeom);
301  PG_FREE_IF_COPY(geom, 0);
302 
303  if ( dimension < 0 )
304  {
305  elog(NOTICE, "Could not compute geometry dimensions");
306  PG_RETURN_NULL();
307  }
308 
309  PG_RETURN_INT32(dimension);
310 }
311 
312 
319 Datum LWGEOM_exteriorring_polygon(PG_FUNCTION_ARGS)
320 {
321  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
323  POINTARRAY *extring;
324  LWGEOM *lwgeom;
325  LWLINE *line;
326  GBOX *bbox=NULL;
327  int type = gserialized_get_type(geom);
328 
329  POSTGIS_DEBUG(2, "LWGEOM_exteriorring_polygon called.");
330 
331  if ( (type != POLYGONTYPE) &&
332  (type != CURVEPOLYTYPE) &&
333  (type != TRIANGLETYPE))
334  {
335  elog(ERROR, "ExteriorRing: geom is not a polygon");
336  PG_RETURN_NULL();
337  }
338 
339  lwgeom = lwgeom_from_gserialized(geom);
340 
341  if( lwgeom_is_empty(lwgeom) )
342  {
343  line = lwline_construct_empty(lwgeom->srid,
344  lwgeom_has_z(lwgeom),
345  lwgeom_has_m(lwgeom));
346  result = geometry_serialize(lwline_as_lwgeom(line));
347  }
348  else if ( lwgeom->type == POLYGONTYPE )
349  {
350  LWPOLY *poly = lwgeom_as_lwpoly(lwgeom);
351 
352  /* Ok, now we have a polygon. Here is its exterior ring. */
353  extring = poly->rings[0];
354 
355  /*
356  * This is a LWLINE constructed by exterior ring POINTARRAY
357  * If the input geom has a bbox, use it for
358  * the output geom, as exterior ring makes it up !
359  */
360  if ( poly->bbox )
361  bbox = gbox_copy(poly->bbox);
362 
363  line = lwline_construct(poly->srid, bbox, extring);
364  result = geometry_serialize((LWGEOM *)line);
365 
366  lwgeom_release((LWGEOM *)line);
367  }
368  else if ( lwgeom->type == TRIANGLETYPE )
369  {
370  LWTRIANGLE *triangle = lwgeom_as_lwtriangle(lwgeom);
371 
372  /*
373  * This is a LWLINE constructed by exterior ring POINTARRAY
374  * If the input geom has a bbox, use it for
375  * the output geom, as exterior ring makes it up !
376  */
377  if ( triangle->bbox )
378  bbox = gbox_copy(triangle->bbox);
379  line = lwline_construct(triangle->srid, bbox, triangle->points);
380 
381  result = geometry_serialize((LWGEOM *)line);
382 
383  lwgeom_release((LWGEOM *)line);
384  }
385  else
386  {
387  LWCURVEPOLY *curvepoly = lwgeom_as_lwcurvepoly(lwgeom);
388  result = geometry_serialize(curvepoly->rings[0]);
389  }
390 
391  lwgeom_free(lwgeom);
392  PG_FREE_IF_COPY(geom, 0);
393  PG_RETURN_POINTER(result);
394 }
395 
403 Datum LWGEOM_numinteriorrings_polygon(PG_FUNCTION_ARGS)
404 {
405  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
406  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
407  LWPOLY *poly = NULL;
408  LWCURVEPOLY *curvepoly = NULL;
409  int result = -1;
410 
411  if ( lwgeom->type == POLYGONTYPE )
412  {
413  poly = lwgeom_as_lwpoly(lwgeom);
414  result = poly->nrings - 1;
415  }
416  else if ( lwgeom->type == CURVEPOLYTYPE )
417  {
418  curvepoly = lwgeom_as_lwcurvepoly(lwgeom);
419  result = curvepoly->nrings - 1;
420  }
421 
422  lwgeom_free(lwgeom);
423  PG_FREE_IF_COPY(geom, 0);
424 
425  if ( result < 0 )
426  PG_RETURN_NULL();
427 
428  PG_RETURN_INT32(result);
429 }
430 
438 Datum LWGEOM_interiorringn_polygon(PG_FUNCTION_ARGS)
439 {
440  GSERIALIZED *geom;
441  int32 wanted_index;
442  LWCURVEPOLY *curvepoly = NULL;
443  LWPOLY *poly = NULL;
444  POINTARRAY *ring;
445  LWLINE *line;
446  LWGEOM *lwgeom;
448  GBOX *bbox = NULL;
449  int type;
450 
451  POSTGIS_DEBUG(2, "LWGEOM_interierringn_polygon called.");
452 
453  wanted_index = PG_GETARG_INT32(1);
454  if ( wanted_index < 1 )
455  {
456  /* elog(ERROR, "InteriorRingN: ring number is 1-based"); */
457  PG_RETURN_NULL(); /* index out of range */
458  }
459 
460  geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
461  type = gserialized_get_type(geom);
462 
463  if ( (type != POLYGONTYPE) && (type != CURVEPOLYTYPE) )
464  {
465  elog(ERROR, "InteriorRingN: geom is not a polygon");
466  PG_FREE_IF_COPY(geom, 0);
467  PG_RETURN_NULL();
468  }
469 
470  lwgeom = lwgeom_from_gserialized(geom);
471  if( lwgeom_is_empty(lwgeom) )
472  {
473  lwpoly_free(poly);
474  PG_FREE_IF_COPY(geom, 0);
475  PG_RETURN_NULL();
476  }
477 
478  if ( type == POLYGONTYPE)
479  {
481 
482  /* Ok, now we have a polygon. Let's see if it has enough holes */
483  if ( wanted_index >= poly->nrings )
484  {
485  lwpoly_free(poly);
486  PG_FREE_IF_COPY(geom, 0);
487  PG_RETURN_NULL();
488  }
489 
490  ring = poly->rings[wanted_index];
491 
492  /* COMPUTE_BBOX==TAINTING */
493  if ( poly->bbox )
494  {
495  bbox = lwalloc(sizeof(GBOX));
497  }
498 
499  /* This is a LWLINE constructed by interior ring POINTARRAY */
500  line = lwline_construct(poly->srid, bbox, ring);
501 
502 
503  result = geometry_serialize((LWGEOM *)line);
504  lwline_release(line);
505  lwpoly_free(poly);
506  }
507  else
508  {
510 
511  if (wanted_index >= curvepoly->nrings)
512  {
513  PG_FREE_IF_COPY(geom, 0);
514  lwgeom_release((LWGEOM *)curvepoly);
515  PG_RETURN_NULL();
516  }
517 
518  result = geometry_serialize(curvepoly->rings[wanted_index]);
519  lwgeom_free((LWGEOM*)curvepoly);
520  }
521 
522  PG_FREE_IF_COPY(geom, 0);
523  PG_RETURN_POINTER(result);
524 }
525 
532 Datum LWGEOM_pointn_linestring(PG_FUNCTION_ARGS)
533 {
534  GSERIALIZED *geom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
535  int where = PG_GETARG_INT32(1);
536  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
537  LWPOINT *lwpoint = NULL;
538  int type = lwgeom->type;
539 
540  /* Can't handle crazy index! */
541  if ( where < 1 )
542  PG_RETURN_NULL();
543 
544  if ( type == LINETYPE || type == CIRCSTRINGTYPE )
545  {
546  /* OGC index starts at one, so we substract first. */
547  lwpoint = lwline_get_lwpoint((LWLINE*)lwgeom, where - 1);
548  }
549 
550  lwgeom_free(lwgeom);
551  PG_FREE_IF_COPY(geom, 0);
552 
553  if ( ! lwpoint )
554  PG_RETURN_NULL();
555 
556  PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(lwpoint)));
557 }
558 
564 Datum LWGEOM_x_point(PG_FUNCTION_ARGS)
565 {
566  GSERIALIZED *geom;
567  LWGEOM *lwgeom;
568  LWPOINT *point = NULL;
569  POINT2D p;
570 
571  geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
572 
573  if ( gserialized_get_type(geom) != POINTTYPE )
574  lwerror("Argument to X() must be a point");
575 
576  lwgeom = lwgeom_from_gserialized(geom);
577  point = lwgeom_as_lwpoint(lwgeom);
578 
579  if ( lwgeom_is_empty(lwgeom) )
580  PG_RETURN_NULL();
581 
582  getPoint2d_p(point->point, 0, &p);
583 
584  PG_FREE_IF_COPY(geom, 0);
585  PG_RETURN_FLOAT8(p.x);
586 }
587 
593 Datum LWGEOM_y_point(PG_FUNCTION_ARGS)
594 {
595  GSERIALIZED *geom;
596  LWPOINT *point = NULL;
597  LWGEOM *lwgeom;
598  POINT2D p;
599 
600  geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
601 
602  if ( gserialized_get_type(geom) != POINTTYPE )
603  lwerror("Argument to Y() must be a point");
604 
605  lwgeom = lwgeom_from_gserialized(geom);
606  point = lwgeom_as_lwpoint(lwgeom);
607 
608  if ( lwgeom_is_empty(lwgeom) )
609  PG_RETURN_NULL();
610 
611  getPoint2d_p(point->point, 0, &p);
612 
613  PG_FREE_IF_COPY(geom, 0);
614 
615  PG_RETURN_FLOAT8(p.y);
616 }
617 
624 Datum LWGEOM_z_point(PG_FUNCTION_ARGS)
625 {
626  GSERIALIZED *geom;
627  LWPOINT *point = NULL;
628  LWGEOM *lwgeom;
629  POINT3DZ p;
630 
631  geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
632 
633  if ( gserialized_get_type(geom) != POINTTYPE )
634  lwerror("Argument to Z() must be a point");
635 
636  lwgeom = lwgeom_from_gserialized(geom);
637  point = lwgeom_as_lwpoint(lwgeom);
638 
639  if ( lwgeom_is_empty(lwgeom) )
640  PG_RETURN_NULL();
641 
642  /* no Z in input */
643  if ( ! gserialized_has_z(geom) ) PG_RETURN_NULL();
644 
645  getPoint3dz_p(point->point, 0, &p);
646 
647  PG_FREE_IF_COPY(geom, 0);
648 
649  PG_RETURN_FLOAT8(p.z);
650 }
651 
657 Datum LWGEOM_m_point(PG_FUNCTION_ARGS)
658 {
659  GSERIALIZED *geom;
660  LWPOINT *point = NULL;
661  LWGEOM *lwgeom;
662  POINT3DM p;
663 
664  geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
665 
666  if ( gserialized_get_type(geom) != POINTTYPE )
667  lwerror("Argument to M() must be a point");
668 
669  lwgeom = lwgeom_from_gserialized(geom);
670  point = lwgeom_as_lwpoint(lwgeom);
671 
672  if ( lwgeom_is_empty(lwgeom) )
673  PG_RETURN_NULL();
674 
675  /* no M in input */
676  if ( ! FLAGS_GET_M(point->flags) ) PG_RETURN_NULL();
677 
678  getPoint3dm_p(point->point, 0, &p);
679 
680  PG_FREE_IF_COPY(geom, 0);
681 
682  PG_RETURN_FLOAT8(p.m);
683 }
684 
691 Datum LWGEOM_startpoint_linestring(PG_FUNCTION_ARGS)
692 {
693  GSERIALIZED *geom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
694  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
695  LWPOINT *lwpoint = NULL;
696  int type = lwgeom->type;
697 
698  if ( type == LINETYPE || type == CIRCSTRINGTYPE )
699  {
700  lwpoint = lwline_get_lwpoint((LWLINE*)lwgeom, 0);
701  }
702 
703  lwgeom_free(lwgeom);
704  PG_FREE_IF_COPY(geom, 0);
705 
706  if ( ! lwpoint )
707  PG_RETURN_NULL();
708 
709  PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(lwpoint)));
710 }
711 
717 Datum LWGEOM_endpoint_linestring(PG_FUNCTION_ARGS)
718 {
719  GSERIALIZED *geom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
720  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
721  LWPOINT *lwpoint = NULL;
722  int type = lwgeom->type;
723 
724  if ( type == LINETYPE || type == CIRCSTRINGTYPE )
725  {
726  LWLINE *line = (LWLINE*)lwgeom;
727  if ( line->points )
728  lwpoint = lwline_get_lwpoint((LWLINE*)lwgeom, line->points->npoints - 1);
729  }
730 
731  lwgeom_free(lwgeom);
732  PG_FREE_IF_COPY(geom, 0);
733 
734  if ( ! lwpoint )
735  PG_RETURN_NULL();
736 
737  PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(lwpoint)));
738 }
739 
748 Datum LWGEOM_from_text(PG_FUNCTION_ARGS)
749 {
750  text *wkttext = PG_GETARG_TEXT_P(0);
751  char *wkt = text2cstring(wkttext);
752  LWGEOM_PARSER_RESULT lwg_parser_result;
753  GSERIALIZED *geom_result = NULL;
754  LWGEOM *lwgeom;
755 
756  POSTGIS_DEBUG(2, "LWGEOM_from_text");
757  POSTGIS_DEBUGF(3, "wkt: [%s]", wkt);
758 
759  if (lwgeom_parse_wkt(&lwg_parser_result, wkt, LW_PARSER_CHECK_ALL) == LW_FAILURE)
760  PG_PARSER_ERROR(lwg_parser_result);
761 
762  lwgeom = lwg_parser_result.geom;
763 
764  if ( lwgeom->srid != SRID_UNKNOWN )
765  {
766  elog(WARNING, "OGC WKT expected, EWKT provided - use GeomFromEWKT() for this");
767  }
768 
769  /* read user-requested SRID if any */
770  if ( PG_NARGS() > 1 )
771  lwgeom_set_srid(lwgeom, PG_GETARG_INT32(1));
772 
773  geom_result = geometry_serialize(lwgeom);
774  lwgeom_parser_result_free(&lwg_parser_result);
775 
776  PG_RETURN_POINTER(geom_result);
777 }
778 
789 Datum LWGEOM_from_WKB(PG_FUNCTION_ARGS)
790 {
791  bytea *bytea_wkb = (bytea*)PG_GETARG_BYTEA_P(0);
792  int32 srid = 0;
793  GSERIALIZED *geom;
794  LWGEOM *lwgeom;
795  uint8_t *wkb = (uint8_t*)VARDATA(bytea_wkb);
796 
797  lwgeom = lwgeom_from_wkb(wkb, VARSIZE(bytea_wkb)-VARHDRSZ, LW_PARSER_CHECK_ALL);
798 
799  if ( lwgeom_needs_bbox(lwgeom) )
800  lwgeom_add_bbox(lwgeom);
801 
802  geom = geometry_serialize(lwgeom);
803  lwgeom_free(lwgeom);
804  PG_FREE_IF_COPY(bytea_wkb, 0);
805 
806  if ( gserialized_get_srid(geom) != SRID_UNKNOWN )
807  {
808  elog(WARNING, "OGC WKB expected, EWKB provided - use GeometryFromEWKB() for this");
809  }
810 
811  if ( PG_NARGS() > 1 )
812  {
813  srid = PG_GETARG_INT32(1);
814  if ( srid != gserialized_get_srid(geom) )
815  gserialized_set_srid(geom, srid);
816  }
817 
818  PG_RETURN_POINTER(geom);
819 }
820 
823 Datum LWGEOM_asText(PG_FUNCTION_ARGS)
824 {
825  GSERIALIZED *geom;
826  LWGEOM *lwgeom;
827  char *wkt;
828  size_t wkt_size;
829  text *result;
830 
831  POSTGIS_DEBUG(2, "Called.");
832 
833  geom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
834  lwgeom = lwgeom_from_gserialized(geom);
835 
836  /* Write to WKT and free the geometry */
837  wkt = lwgeom_to_wkt(lwgeom, WKT_ISO, DBL_DIG, &wkt_size);
838  lwgeom_free(lwgeom);
839  POSTGIS_DEBUGF(3, "WKT size = %u, WKT length = %u", (unsigned int)wkt_size, (unsigned int)strlen(wkt));
840 
841  /* Write to text and free the WKT */
842  result = cstring2text(wkt);
843  pfree(wkt);
844 
845  /* Return the text */
846  PG_FREE_IF_COPY(geom, 0);
847  PG_RETURN_TEXT_P(result);
848 }
849 
850 
853 Datum LWGEOM_asBinary(PG_FUNCTION_ARGS)
854 {
855  GSERIALIZED *geom;
856  LWGEOM *lwgeom;
857  uint8_t *wkb;
858  size_t wkb_size;
859  bytea *result;
860  uint8_t variant = WKB_ISO;
861 
862  /* Get a 2D version of the geometry */
863  geom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
864  lwgeom = lwgeom_from_gserialized(geom);
865 
866  /* If user specified endianness, respect it */
867  if ( (PG_NARGS()>1) && (!PG_ARGISNULL(1)) )
868  {
869  text *wkb_endian = PG_GETARG_TEXT_P(1);
870 
871  if ( ! strncmp(VARDATA(wkb_endian), "xdr", 3) ||
872  ! strncmp(VARDATA(wkb_endian), "XDR", 3) )
873  {
874  variant = variant | WKB_XDR;
875  }
876  else
877  {
878  variant = variant | WKB_NDR;
879  }
880  }
881 
882  /* Write to WKB and free the geometry */
883  wkb = lwgeom_to_wkb(lwgeom, variant, &wkb_size);
884  lwgeom_free(lwgeom);
885 
886  /* Write to text and free the WKT */
887  result = palloc(wkb_size + VARHDRSZ);
888  memcpy(VARDATA(result), wkb, wkb_size);
889  SET_VARSIZE(result, wkb_size + VARHDRSZ);
890  pfree(wkb);
891 
892  /* Return the text */
893  PG_FREE_IF_COPY(geom, 0);
894  PG_RETURN_BYTEA_P(result);
895 }
896 
897 
898 
906 Datum LWGEOM_isclosed(PG_FUNCTION_ARGS)
907 {
908  GSERIALIZED *geom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
909  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
910  int closed = lwgeom_is_closed(lwgeom);
911 
912  lwgeom_free(lwgeom);
913  PG_FREE_IF_COPY(geom, 0);
914  PG_RETURN_BOOL(closed);
915 }
#define LINETYPE
Definition: liblwgeom.h:61
int ptarray_calculate_gbox_cartesian(const POINTARRAY *pa, GBOX *gbox)
Calculate box (x/y) and add values to gbox.
Definition: g_box.c:471
GBOX * gbox_copy(const GBOX *box)
Return a copy of the GBOX, based on dimensionality of flags.
Definition: g_box.c:362
uint32_t gserialized_get_type(const GSERIALIZED *s)
Extract the geometry type from the serialized form (it hides in the anonymous data area...
Definition: g_serialized.c:56
double z
Definition: liblwgeom.h:290
Datum LWGEOM_pointn_linestring(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:532
int lwgeom_is_closed(const LWGEOM *geom)
Return true or false depending on whether a geometry is a linear feature that closes on itself...
Definition: lwgeom.c:903
LWPOINT * lwline_get_lwpoint(LWLINE *line, int where)
Returns freshly allocated LWPOINT that corresponds to the index where.
Definition: lwline.c:294
POINTARRAY * points
Definition: liblwgeom.h:389
LWLINE * lwline_construct_empty(int srid, char hasz, char hasm)
Definition: lwline.c:51
#define MULTICURVETYPE
Definition: liblwgeom.h:70
#define WKB_NDR
Definition: liblwgeom.h:1770
int lwgeom_is_collection(const LWGEOM *lwgeom)
Determine whether a LWGEOM can contain sub-geometries or not.
Definition: lwgeom.c:947
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition: lwout_wkt.c:655
Datum LWGEOM_asBinary(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:853
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
LWGEOM ** rings
Definition: liblwgeom.h:491
int npoints
Definition: liblwgeom.h:327
int gserialized_has_m(const GSERIALIZED *gser)
Check if a GSERIALIZED has an M ordinate.
Definition: g_serialized.c:30
#define POLYGONTYPE
Definition: liblwgeom.h:62
#define CURVEPOLYTYPE
Definition: liblwgeom.h:69
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1006
#define COMPOUNDTYPE
Definition: liblwgeom.h:68
#define MULTIPOINTTYPE
Definition: liblwgeom.h:63
Datum LWGEOM_y_point(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:593
GBOX * bbox
Definition: liblwgeom.h:461
LWCURVEPOLY * lwgeom_as_lwcurvepoly(const LWGEOM *lwgeom)
Definition: lwgeom.c:116
void gserialized_set_srid(GSERIALIZED *s, int32_t srid)
Write the SRID into the serialized form (it is packed into three bytes so this is a handy function)...
Definition: g_serialized.c:87
#define TRIANGLETYPE
Definition: liblwgeom.h:73
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:72
GBOX * bbox
Definition: liblwgeom.h:387
void lwgeom_parser_result_free(LWGEOM_PARSER_RESULT *parser_result)
Definition: lwin_wkt.c:825
int getPoint3dm_p(const POINTARRAY *pa, int n, POINT3DM *point)
Definition: lwgeom_api.c:355
Datum LWGEOM_z_point(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:624
GBOX * bbox
Definition: liblwgeom.h:409
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
Definition: lwgeom.c:125
Datum LWGEOM_numgeometries_collection(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:219
LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
Definition: lwgeom.c:80
POINTARRAY * point
Definition: liblwgeom.h:367
Datum LWGEOM_numpoints_linestring(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:199
int gserialized_has_z(const GSERIALIZED *gser)
Check if a GSERIALIZED has a Z ordinate.
Definition: g_serialized.c:25
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition: lwgeom.c:792
char ** result
Definition: liblwgeom.h:218
int32_t srid
Definition: liblwgeom.h:355
PG_FUNCTION_INFO_V1(LWGEOM_get_srid)
Datum LWGEOM_get_srid(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:83
#define LW_FAILURE
Definition: liblwgeom.h:54
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:67
double x
Definition: liblwgeom.h:284
Datum LWGEOM_m_point(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:657
Datum LWGEOM_asText(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:823
Datum LWGEOM_interiorringn_polygon(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:438
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:164
#define WKT_ISO
Definition: liblwgeom.h:1776
uint8_t * lwgeom_to_wkb(const LWGEOM *geom, uint8_t variant, size_t *size_out)
Convert LWGEOM to a char* in WKB format.
Definition: lwout_wkb.c:692
int getPoint3dz_p(const POINTARRAY *pa, int n, POINT3DZ *point)
Definition: lwgeom_api.c:305
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:249
double m
Definition: liblwgeom.h:302
int lwgeom_parse_wkt(LWGEOM_PARSER_RESULT *parser_result, char *wktstr, int parse_flags)
Parse a WKT geometry string into an LWGEOM structure.
void lwpoly_free(LWPOLY *poly)
Definition: lwpoly.c:79
Parser result structure: returns the result of attempting to convert (E)WKT/(E)WKB to LWGEOM...
Definition: liblwgeom.h:1713
LWLINE * lwline_construct(int srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:29
LWGEOM ** geoms
Definition: liblwgeom.h:465
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:154
#define TINTYPE
Definition: liblwgeom.h:74
Datum LWGEOM_exteriorring_polygon(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:319
Datum LWGEOM_dimension(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:293
char * text2cstring(const text *textptr)
POINTARRAY ** rings
Definition: liblwgeom.h:413
int count
Definition: genraster.py:57
Datum LWGEOM_x_point(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:564
int nrings
Definition: liblwgeom.h:411
int32_t srid
Definition: liblwgeom.h:462
double y
Definition: liblwgeom.h:284
Datum LWGEOM_set_srid(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:93
int getPoint2d_p(const POINTARRAY *pa, int n, POINT2D *point)
Definition: lwgeom_api.c:434
#define WKB_ISO
Definition: liblwgeom.h:1767
Datum geometry_geometrytype(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:168
Datum LWGEOM_from_WKB(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:789
Datum LWGEOM_isclosed(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:906
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:65
Datum LWGEOM_from_text(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:748
uint8_t flags
Definition: liblwgeom.h:364
LWTRIANGLE * lwgeom_as_lwtriangle(const LWGEOM *lwgeom)
Definition: lwgeom.c:134
Datum LWGEOM_startpoint_linestring(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:691
#define MULTISURFACETYPE
Definition: liblwgeom.h:71
int32_t srid
Definition: liblwgeom.h:410
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
Definition: lwgeom.c:143
int lwgeom_dimension(const LWGEOM *geom)
For an LWGEOM, returns 0 for points, 1 for lines, 2 for polygons, 3 for volume, and the max dimension...
Definition: lwgeom.c:1124
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:60
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition: lwgeom.c:555
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:107
#define WKB_XDR
Definition: liblwgeom.h:1771
void lwgeom_release(LWGEOM *lwgeom)
Free the containing LWGEOM and the associated BOX.
Definition: lwgeom.c:328
uint8_t type
Definition: liblwgeom.h:352
void lwcollection_free(LWCOLLECTION *col)
Definition: lwcollection.c:316
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:254
void lwgeom_set_srid(LWGEOM *geom, int srid)
Set the SRID on an LWGEOM For collections, only the parent gets an SRID, all the children get SRID_UN...
#define CIRCSTRINGTYPE
Definition: liblwgeom.h:67
void * lwalloc(size_t size)
Definition: lwutil.c:175
int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members) ...
Definition: lwgeom.c:1229
#define LW_PARSER_CHECK_ALL
Definition: liblwgeom.h:1707
Datum LWGEOM_geometryn_collection(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:242
int lwgeom_count_vertices(const LWGEOM *geom)
Count the total number of vertices in any LWGEOM.
Definition: lwgeom.c:1072
LWGEOM * lwgeom_from_wkb(const uint8_t *wkb, const size_t wkb_size, const char check)
WKB inputs must have a declared size, to prevent malformed WKB from reading off the end of the memory...
Definition: lwin_wkb.c:728
#define MULTILINETYPE
Definition: liblwgeom.h:64
Datum LWGEOM_getTYPE(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:108
Datum LWGEOM_numinteriorrings_polygon(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:403
void lwline_release(LWLINE *lwline)
Definition: lwline.c:121
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition: lwgeom.c:799
Datum LWGEOM_endpoint_linestring(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:717
int lwgeom_needs_bbox(const LWGEOM *geom)
Check whether or not a lwgeom is big enough to warrant a bounding box.
Definition: lwgeom.c:1059
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:70
int32_t srid
Definition: liblwgeom.h:388
#define COLLECTIONTYPE
Definition: liblwgeom.h:66
This library is the generic geometry handling section of PostGIS.
uint32_t gserialized_max_header_size(void)
Returns the size in bytes to read from toast to get the basic information from a geometry: GSERIALIZE...
Definition: g_serialized.c:50
POINTARRAY * points
Definition: liblwgeom.h:378