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