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