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