PostGIS  3.7.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 
33 #include "access/gist.h"
34 #include "access/itup.h"
35 
36 #include "fmgr.h"
37 #include "utils/builtins.h"
38 #include "utils/elog.h"
39 
40 #include "../postgis_config.h"
41 
42 #include "liblwgeom.h"
43 #include "liblwgeom_internal.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 /* ---- NumPatches(geometry) */
59 Datum LWGEOM_numpatches(PG_FUNCTION_ARGS);
60 /* ---- GeometryN(geometry, integer) */
61 Datum LWGEOM_geometryn_collection(PG_FUNCTION_ARGS);
62 /* ---- PatchN(geometry, integer) */
63 Datum LWGEOM_patchn(PG_FUNCTION_ARGS);
64 /* ---- Dimension(geometry) */
65 Datum LWGEOM_dimension(PG_FUNCTION_ARGS);
66 /* ---- ExteriorRing(geometry) */
67 Datum LWGEOM_exteriorring_polygon(PG_FUNCTION_ARGS);
68 /* ---- InteriorRingN(geometry, integer) */
69 Datum LWGEOM_interiorringn_polygon(PG_FUNCTION_ARGS);
70 /* ---- NumInteriorRings(geometry) */
71 Datum LWGEOM_numinteriorrings_polygon(PG_FUNCTION_ARGS);
72 /* ---- PointN(geometry, integer) */
73 Datum LWGEOM_pointn_linestring(PG_FUNCTION_ARGS);
74 /* ---- X(geometry) */
75 Datum LWGEOM_x_point(PG_FUNCTION_ARGS);
76 /* ---- Y(geometry) */
77 Datum LWGEOM_y_point(PG_FUNCTION_ARGS);
78 /* ---- Z(geometry) */
79 Datum LWGEOM_z_point(PG_FUNCTION_ARGS);
80 /* ---- M(geometry) */
81 Datum LWGEOM_m_point(PG_FUNCTION_ARGS);
82 /* ---- StartPoint(geometry) */
83 Datum LWGEOM_startpoint_linestring(PG_FUNCTION_ARGS);
84 /* ---- EndPoint(geometry) */
85 Datum LWGEOM_endpoint_linestring(PG_FUNCTION_ARGS);
86 /* ---- AsText(geometry) */
87 Datum LWGEOM_asText(PG_FUNCTION_ARGS);
88 /* ---- AsBinary(geometry, [XDR|NDR]) */
89 Datum LWGEOM_asBinary(PG_FUNCTION_ARGS);
90 /* ---- GeometryFromText(text, integer) */
91 Datum LWGEOM_from_text(PG_FUNCTION_ARGS);
92 /* ---- GeomFromWKB(bytea, integer) */
93 Datum LWGEOM_from_WKB(PG_FUNCTION_ARGS);
94 /* ---- IsClosed(geometry) */
95 Datum LWGEOM_isclosed(PG_FUNCTION_ARGS);
96 
97 /*------------------------------------------------------------------*/
98 
99 /* getSRID(lwgeom) :: int4 */
101 Datum LWGEOM_get_srid(PG_FUNCTION_ARGS)
102 {
103  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_HEADER(0);
104  int32_t srid = gserialized_get_srid(geom);
105  PG_FREE_IF_COPY(geom,0);
106  PG_RETURN_INT32(srid);
107 }
108 
109 /* setSRID(lwgeom, int4) :: lwgeom */
111 Datum LWGEOM_set_srid(PG_FUNCTION_ARGS)
112 {
113  GSERIALIZED *g = (GSERIALIZED *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
114  int32_t srid = PG_GETARG_INT32(1);
115  gserialized_set_srid(g, srid);
116  PG_RETURN_POINTER(g);
117 }
118 
119 /* returns a string representation of this geometry's type */
121 Datum LWGEOM_getTYPE(PG_FUNCTION_ARGS)
122 {
123  GSERIALIZED *gser;
124  text *text_ob;
125  char *result;
126  uint8_t type;
127  static int maxtyplen = 20;
128 
129  gser = PG_GETARG_GSERIALIZED_HEADER(0);
130  text_ob = palloc0(VARHDRSZ + maxtyplen);
131  result = VARDATA(text_ob);
132 
133  type = gserialized_get_type(gser);
134 
135  if (type == POINTTYPE)
136  strcpy(result,"POINT");
137  else if (type == MULTIPOINTTYPE)
138  strcpy(result,"MULTIPOINT");
139  else if (type == LINETYPE)
140  strcpy(result,"LINESTRING");
141  else if (type == CIRCSTRINGTYPE)
142  strcpy(result,"CIRCULARSTRING");
143  else if (type == COMPOUNDTYPE)
144  strcpy(result, "COMPOUNDCURVE");
145  else if (type == MULTILINETYPE)
146  strcpy(result,"MULTILINESTRING");
147  else if (type == MULTICURVETYPE)
148  strcpy(result, "MULTICURVE");
149  else if (type == POLYGONTYPE)
150  strcpy(result,"POLYGON");
151  else if (type == TRIANGLETYPE)
152  strcpy(result,"TRIANGLE");
153  else if (type == CURVEPOLYTYPE)
154  strcpy(result,"CURVEPOLYGON");
155  else if (type == MULTIPOLYGONTYPE)
156  strcpy(result,"MULTIPOLYGON");
157  else if (type == MULTISURFACETYPE)
158  strcpy(result, "MULTISURFACE");
159  else if (type == COLLECTIONTYPE)
160  strcpy(result,"GEOMETRYCOLLECTION");
161  else if (type == POLYHEDRALSURFACETYPE)
162  strcpy(result,"POLYHEDRALSURFACE");
163  else if (type == TINTYPE)
164  strcpy(result,"TIN");
165  else
166  strcpy(result,"UNKNOWN");
167 
168  if ( gserialized_has_m(gser) && ! gserialized_has_z(gser) )
169  strcat(result, "M");
170 
171  SET_VARSIZE(text_ob, strlen(result) + VARHDRSZ); /* size of string */
172 
173  PG_FREE_IF_COPY(gser, 0);
174 
175  PG_RETURN_TEXT_P(text_ob);
176 }
177 
178 /* Matches lwutil.c::lwgeomTypeName */
179 static char *stTypeName[] = {"Unknown",
180  "ST_Point",
181  "ST_LineString",
182  "ST_Polygon",
183  "ST_MultiPoint",
184  "ST_MultiLineString",
185  "ST_MultiPolygon",
186  "ST_GeometryCollection",
187  "ST_CircularString",
188  "ST_CompoundCurve",
189  "ST_CurvePolygon",
190  "ST_MultiCurve",
191  "ST_MultiSurface",
192  "ST_PolyhedralSurface",
193  "ST_Triangle",
194  "ST_Tin"};
195 
196 /* returns a string representation of this geometry's type */
198 Datum geometry_geometrytype(PG_FUNCTION_ARGS)
199 {
200  GSERIALIZED *gser;
201  text *type_text;
202 
203  /* Read just the header from the toasted tuple */
204  gser = PG_GETARG_GSERIALIZED_HEADER(0);
205 
206  /* Build a text type to store things in */
207  type_text = cstring_to_text(stTypeName[gserialized_get_type(gser)]);
208 
209  PG_FREE_IF_COPY(gser, 0);
210  PG_RETURN_TEXT_P(type_text);
211 }
212 
213 
214 
220 Datum LWGEOM_numpoints_linestring(PG_FUNCTION_ARGS)
221 {
222  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
223  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
224  int count = -1;
225  int type = lwgeom->type;
226 
227  if ( type == LINETYPE || type == CIRCSTRINGTYPE || type == COMPOUNDTYPE )
228  count = lwgeom_count_vertices(lwgeom);
229 
230  lwgeom_free(lwgeom);
231  PG_FREE_IF_COPY(geom, 0);
232 
233  /* OGC says this functions is only valid on LINESTRING */
234  if ( count < 0 )
235  PG_RETURN_NULL();
236 
237  PG_RETURN_INT32(count);
238 }
239 
240 /*
241  * Count geometries with patches option
242  * patches_as_geometries = true: count patches as separate geometries (for ST_NumPatches)
243  * patches_as_geometries = false: treat TIN/PolyhedralSurface as unitary geometries (for ST_NumGeometries)
244  */
245 static int32
246 lwgeom_count_geometries(LWGEOM *lwgeom, bool patches_as_geometries)
247 {
248  int32 ret = 0;
249 
250  if (lwgeom_is_empty(lwgeom))
251  {
252  ret = 0;
253  }
254  else if (lwgeom_is_unitary(lwgeom))
255  {
256  /* If it's a TIN or PolyhedralSurface and we want to count patches */
257  if (lwgeom_has_patches(lwgeom) && patches_as_geometries)
258  {
259  LWCOLLECTION *col = lwgeom_as_lwcollection(lwgeom);
260  ret = col ? col->ngeoms : 1;
261  }
262  else
263  {
264  ret = 1;
265  }
266  }
267  else
268  {
269  LWCOLLECTION *col = lwgeom_as_lwcollection(lwgeom);
270  ret = col->ngeoms;
271  }
272 
273  return ret;
274 }
275 
277 Datum LWGEOM_numgeometries_collection(PG_FUNCTION_ARGS)
278 {
279  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
280  LWGEOM *lwgeom;
281  int32 ret = 0;
282 
283  lwgeom = lwgeom_from_gserialized(geom);
284 
285  /* TIN and PolyhedralSurface count as 1 geometry, not their patch count */
286  ret = lwgeom_count_geometries(lwgeom, false);
287 
288  lwgeom_free(lwgeom);
289  PG_FREE_IF_COPY(geom, 0);
290  PG_RETURN_INT32(ret);
291 }
292 
294 Datum LWGEOM_numpatches(PG_FUNCTION_ARGS)
295 {
296  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
297  LWGEOM *lwgeom;
298  int32 ret = 0;
299 
300  lwgeom = lwgeom_from_gserialized(geom);
301 
302  if (!lwgeom_has_patches(lwgeom))
303  {
304  lwgeom_free(lwgeom);
305  PG_FREE_IF_COPY(geom, 0);
306  elog(ERROR, "ST_NumPatches only supports TIN and PolyhedralSurface geometries");
307  }
308 
309  ret = lwgeom_count_geometries(lwgeom, true);
310 
311  lwgeom_free(lwgeom);
312  PG_FREE_IF_COPY(geom, 0);
313  PG_RETURN_INT32(ret);
314 }
315 
316 /*
317  * Extract geometry at given index with patches option
318  */
319 static LWGEOM*
320 lwgeom_extract_geometry_n(LWGEOM *lwgeom, int32 idx, bool patches_as_geometries)
321 {
322  LWCOLLECTION *coll = NULL;
323  LWGEOM *subgeom = NULL;
324 
325  /* Empty returns NULL */
326  if (lwgeom_is_empty(lwgeom))
327  return NULL;
328 
329  /* Unitary geometries */
330  if (lwgeom_is_unitary(lwgeom))
331  {
332  /* If it's a TIN or PolyhedralSurface and we want to access patches */
333  if (lwgeom_has_patches(lwgeom) && patches_as_geometries)
334  {
335  coll = lwgeom_as_lwcollection(lwgeom);
336  if (!coll)
337  {
338  /* Single patch case */
339  if (idx == 1)
340  return lwgeom;
341  else
342  return NULL;
343  }
344  }
345  else
346  {
347  /* Standard unitary geometry handling */
348  if (idx == 1)
349  return lwgeom;
350  else
351  return NULL;
352  }
353  }
354  else
355  {
356  coll = lwgeom_as_lwcollection(lwgeom);
357  }
358 
359  if (!coll)
360  return NULL;
361 
362  /* Handle out-of-range index value */
363  idx -= 1;
364  if (idx < 0 || idx >= (int32) coll->ngeoms)
365  return NULL;
366 
367  subgeom = coll->geoms[idx];
368  return subgeom;
369 }
370 
373 Datum LWGEOM_geometryn_collection(PG_FUNCTION_ARGS)
374 {
375  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
376  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
377  GSERIALIZED *result = NULL;
378  int32 idx = PG_GETARG_INT32(1);
379  LWGEOM *subgeom = NULL;
380 
381  /* TIN and PolyhedralSurface are treated as unitary geometries */
382  subgeom = lwgeom_extract_geometry_n(lwgeom, idx, false);
383 
384  if (!subgeom)
385  PG_RETURN_NULL();
386 
387  /* If returning the original geometry */
388  if (subgeom == lwgeom)
389  {
390  lwgeom_free(lwgeom);
391  PG_FREE_IF_COPY(geom, 0);
392  PG_RETURN_POINTER(geom);
393  }
394 
395  subgeom->srid = lwgeom->srid;
396  /* COMPUTE_BBOX==TAINTING */
397  if (lwgeom->bbox) lwgeom_add_bbox(subgeom);
398 
399  result = geometry_serialize(subgeom);
400  lwgeom_free(lwgeom);
401  PG_FREE_IF_COPY(geom, 0);
402  PG_RETURN_POINTER(result);
403 }
404 
407 Datum LWGEOM_patchn(PG_FUNCTION_ARGS)
408 {
409  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
410  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
411  GSERIALIZED *result = NULL;
412  int32 idx = PG_GETARG_INT32(1);
413  LWGEOM *subgeom = NULL;
414 
415  if (!lwgeom_has_patches(lwgeom))
416  {
417  lwgeom_free(lwgeom);
418  PG_FREE_IF_COPY(geom, 0);
419  elog(ERROR, "ST_PatchN only supports TIN and PolyhedralSurface geometries");
420  }
421 
422  /* Access patches individually */
423  subgeom = lwgeom_extract_geometry_n(lwgeom, idx, true);
424 
425  if (!subgeom)
426  PG_RETURN_NULL();
427 
428  /* If returning the original geometry */
429  if (subgeom == lwgeom)
430  PG_RETURN_POINTER(geom);
431 
432  subgeom->srid = lwgeom->srid;
433  /* COMPUTE_BBOX==TAINTING */
434  if (lwgeom->bbox) lwgeom_add_bbox(subgeom);
435 
436  result = geometry_serialize(subgeom);
437  lwgeom_free(lwgeom);
438  PG_FREE_IF_COPY(geom, 0);
439  PG_RETURN_POINTER(result);
440 }
441 
442 
448 Datum LWGEOM_dimension(PG_FUNCTION_ARGS)
449 {
450  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
451  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
452  int dimension = -1;
453 
454  dimension = lwgeom_dimension(lwgeom);
455  lwgeom_free(lwgeom);
456  PG_FREE_IF_COPY(geom, 0);
457 
458  if ( dimension < 0 )
459  {
460  elog(NOTICE, "Could not compute geometry dimensions");
461  PG_RETURN_NULL();
462  }
463 
464  PG_RETURN_INT32(dimension);
465 }
466 
467 
474 Datum LWGEOM_exteriorring_polygon(PG_FUNCTION_ARGS)
475 {
476  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
478  POINTARRAY *extring;
479  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
480  LWLINE *line;
481  GBOX *bbox=NULL;
482 
483  if ( ! lwgeom_has_rings(lwgeom) )
484  PG_RETURN_NULL();
485 
486  if( lwgeom_is_empty(lwgeom) )
487  {
488  line = lwline_construct_empty(lwgeom->srid,
489  lwgeom_has_z(lwgeom),
490  lwgeom_has_m(lwgeom));
491  result = geometry_serialize(lwline_as_lwgeom(line));
492  }
493  else if ( lwgeom->type == POLYGONTYPE )
494  {
495  LWPOLY *poly = lwgeom_as_lwpoly(lwgeom);
496 
497  /* Ok, now we have a polygon. Here is its exterior ring. */
498  extring = poly->rings[0];
499 
500  /*
501  * This is a LWLINE constructed by exterior ring POINTARRAY
502  * If the input geom has a bbox, use it for
503  * the output geom, as exterior ring makes it up !
504  */
505  if ( poly->bbox )
506  bbox = gbox_copy(poly->bbox);
507 
508  line = lwline_construct(poly->srid, bbox, extring);
509  result = geometry_serialize((LWGEOM *)line);
510 
511  lwgeom_release((LWGEOM *)line);
512  }
513  else if ( lwgeom->type == TRIANGLETYPE )
514  {
515  LWTRIANGLE *triangle = lwgeom_as_lwtriangle(lwgeom);
516 
517  /*
518  * This is a LWLINE constructed by exterior ring POINTARRAY
519  * If the input geom has a bbox, use it for
520  * the output geom, as exterior ring makes it up !
521  */
522  if ( triangle->bbox )
523  bbox = gbox_copy(triangle->bbox);
524  line = lwline_construct(triangle->srid, bbox, triangle->points);
525 
526  result = geometry_serialize((LWGEOM *)line);
527 
528  lwgeom_release((LWGEOM *)line);
529  }
530  else
531  {
532  LWCURVEPOLY *curvepoly = lwgeom_as_lwcurvepoly(lwgeom);
533  result = geometry_serialize(curvepoly->rings[0]);
534  }
535 
536  lwgeom_free(lwgeom);
537  PG_FREE_IF_COPY(geom, 0);
538  PG_RETURN_POINTER(result);
539 }
540 
548 Datum LWGEOM_numinteriorrings_polygon(PG_FUNCTION_ARGS)
549 {
550  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
551  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
552  int type = lwgeom->type;
553  int result = -1;
554 
555  if ( !lwgeom_has_rings(lwgeom) )
556  PG_RETURN_NULL();
557 
558  if ( lwgeom_is_empty(lwgeom) || type == TRIANGLETYPE )
559  PG_RETURN_INT32(0);
560 
561  /*
562  * POLYGON and TRIANGLE have same underlying structure
563  * with an array of nrings rings of POINTARRAY holding the
564  * rings
565  */
566  if (type == POLYGONTYPE )
567  {
568  const LWPOLY *poly = lwgeom_as_lwpoly(lwgeom);
569  result = poly->nrings - 1;
570  }
571  /*
572  * CURVEPOLYGON on the other hand is structured
573  * like a collection with each ring represented by
574  * a geometry in a list ngeoms long.
575  */
576  else if (type == CURVEPOLYTYPE)
577  {
578  const LWCURVEPOLY *curv = lwgeom_as_lwcurvepoly(lwgeom);
579  result = curv->nrings - 1;
580  }
581  /*
582  * If a new type is added to the zoo, we should error
583  * out.
584  */
585  else
586  {
587  elog(ERROR, "%s unsupported ring type %d", __func__, type);
588  }
589 
590  lwgeom_free(lwgeom);
591  PG_FREE_IF_COPY(geom, 0);
592  if ( result < 0 )
593  PG_RETURN_NULL();
594  else
595  PG_RETURN_INT32(result);
596 }
597 
605 Datum LWGEOM_interiorringn_polygon(PG_FUNCTION_ARGS)
606 {
607  GSERIALIZED *geom;
608  int32 wanted_index;
609  LWCURVEPOLY *curvepoly = NULL;
610  LWPOLY *poly = NULL;
611  POINTARRAY *ring;
612  LWLINE *line;
613  LWGEOM *lwgeom;
615  GBOX *bbox = NULL;
616  int type;
617 
618  POSTGIS_DEBUG(2, "LWGEOM_interiorringn_polygon called.");
619 
620  wanted_index = PG_GETARG_INT32(1);
621  if ( wanted_index < 1 )
622  {
623  PG_RETURN_NULL(); /* index out of range */
624  }
625 
626  geom = PG_GETARG_GSERIALIZED_P(0);
627  type = gserialized_get_type(geom);
628 
629  if ( (type != POLYGONTYPE) && (type != CURVEPOLYTYPE) )
630  {
631  PG_FREE_IF_COPY(geom, 0);
632  PG_RETURN_NULL();
633  }
634 
635  lwgeom = lwgeom_from_gserialized(geom);
636  if( lwgeom_is_empty(lwgeom) )
637  {
638  lwpoly_free(poly);
639  PG_FREE_IF_COPY(geom, 0);
640  PG_RETURN_NULL();
641  }
642 
643  if ( type == POLYGONTYPE)
644  {
646 
647  /* Ok, now we have a polygon. Let's see if it has enough holes */
648  if ( wanted_index >= (int32)poly->nrings )
649  {
650  lwpoly_free(poly);
651  PG_FREE_IF_COPY(geom, 0);
652  PG_RETURN_NULL();
653  }
654 
655  ring = poly->rings[wanted_index];
656 
657  /* COMPUTE_BBOX==TAINTING */
658  if ( poly->bbox )
659  {
660  bbox = lwalloc(sizeof(GBOX));
662  }
663 
664  /* This is a LWLINE constructed by interior ring POINTARRAY */
665  line = lwline_construct(poly->srid, bbox, ring);
666 
667 
668  result = geometry_serialize((LWGEOM *)line);
669  lwline_release(line);
670  lwpoly_free(poly);
671  }
672  else
673  {
675 
676  if (wanted_index >= (int32)curvepoly->nrings)
677  {
678  PG_FREE_IF_COPY(geom, 0);
679  lwgeom_release((LWGEOM *)curvepoly);
680  PG_RETURN_NULL();
681  }
682 
683  result = geometry_serialize(curvepoly->rings[wanted_index]);
684  lwgeom_free((LWGEOM*)curvepoly);
685  }
686 
687  PG_FREE_IF_COPY(geom, 0);
688  PG_RETURN_POINTER(result);
689 }
690 
697 Datum LWGEOM_pointn_linestring(PG_FUNCTION_ARGS)
698 {
699  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
700  int where = PG_GETARG_INT32(1);
701  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
702  LWPOINT *lwpoint = NULL;
703  int type = lwgeom->type;
704 
705  /* If index is negative, count backward */
706  if( where < 1 )
707  {
708  int count = -1;
709  if ( type == LINETYPE || type == CIRCSTRINGTYPE || type == COMPOUNDTYPE )
710  count = lwgeom_count_vertices(lwgeom);
711  if(count >0)
712  {
713  /* only work if we found the total point number */
714  /* converting where to positive backward indexing, +1 because 1 indexing */
715  where = where + count + 1;
716  }
717  if (where < 1)
718  PG_RETURN_NULL();
719  }
720 
721  if ( type == LINETYPE || type == CIRCSTRINGTYPE )
722  {
723  /* OGC index starts at one, so we subtract first. */
724  lwpoint = lwline_get_lwpoint((LWLINE*)lwgeom, where - 1);
725  }
726  else if ( type == COMPOUNDTYPE )
727  {
728  lwpoint = lwcompound_get_lwpoint((LWCOMPOUND*)lwgeom, where - 1);
729  }
730 
731  lwgeom_free(lwgeom);
732  PG_FREE_IF_COPY(geom, 0);
733 
734  if ( ! lwpoint )
735  PG_RETURN_NULL();
736 
737  PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(lwpoint)));
738 }
739 
745 Datum LWGEOM_x_point(PG_FUNCTION_ARGS)
746 {
747  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
748  POINT4D pt;
749 
750  if (gserialized_get_type(geom) != POINTTYPE)
751  lwpgerror("Argument to ST_X() must have type POINT");
752 
753  if (gserialized_peek_first_point(geom, &pt) == LW_FAILURE)
754  {
755  PG_RETURN_NULL();
756  }
757  PG_RETURN_FLOAT8(pt.x);
758 }
759 
765 Datum LWGEOM_y_point(PG_FUNCTION_ARGS)
766 {
767  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
768  POINT4D pt;
769 
770  if (gserialized_get_type(geom) != POINTTYPE)
771  lwpgerror("Argument to ST_Y() must have type POINT");
772 
773  if (gserialized_peek_first_point(geom, &pt) == LW_FAILURE)
774  {
775  PG_RETURN_NULL();
776  }
777  PG_RETURN_FLOAT8(pt.y);
778 }
779 
786 Datum LWGEOM_z_point(PG_FUNCTION_ARGS)
787 {
788  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
789  POINT4D pt;
790 
791  if (gserialized_get_type(geom) != POINTTYPE)
792  lwpgerror("Argument to ST_Z() must have type POINT");
793 
794  if (!gserialized_has_z(geom) || (gserialized_peek_first_point(geom, &pt) == LW_FAILURE))
795  {
796  PG_RETURN_NULL();
797  }
798  PG_RETURN_FLOAT8(pt.z);
799 }
800 
806 Datum LWGEOM_m_point(PG_FUNCTION_ARGS)
807 {
808  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
809  POINT4D pt;
810 
811  if (gserialized_get_type(geom) != POINTTYPE)
812  lwpgerror("Argument to ST_M() must have type POINT");
813 
814  if (!gserialized_has_m(geom) || (gserialized_peek_first_point(geom, &pt) == LW_FAILURE))
815  {
816  PG_RETURN_NULL();
817  }
818  PG_RETURN_FLOAT8(pt.m);
819 }
820 
826 Datum LWGEOM_startpoint_linestring(PG_FUNCTION_ARGS)
827 {
828  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
829  GSERIALIZED *ret;
830  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
831  LWGEOM *lwpoint = NULL;
832  POINT4D pt;
833 
834  if (lwgeom_startpoint(lwgeom, &pt) == LW_FAILURE)
835  {
836  PG_RETURN_NULL();
837  }
838 
839  lwpoint = (LWGEOM *)lwpoint_make(lwgeom->srid, lwgeom_has_z(lwgeom), lwgeom_has_m(lwgeom), &pt);
840  ret = geometry_serialize(lwpoint);
841 
842  lwgeom_free(lwgeom);
843  lwgeom_free(lwpoint);
844 
845  PG_FREE_IF_COPY(geom, 0);
846  PG_RETURN_POINTER(ret);
847 }
848 
854 Datum LWGEOM_endpoint_linestring(PG_FUNCTION_ARGS)
855 {
856  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
857  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
858  LWPOINT *lwpoint = NULL;
859  int type = lwgeom->type;
860 
861  if ( type == LINETYPE || type == CIRCSTRINGTYPE )
862  {
863  LWLINE *line = (LWLINE*)lwgeom;
864  if ( line->points )
865  lwpoint = lwline_get_lwpoint((LWLINE*)lwgeom, line->points->npoints - 1);
866  }
867  else if ( type == COMPOUNDTYPE )
868  {
869  lwpoint = lwcompound_get_endpoint((LWCOMPOUND*)lwgeom);
870  }
871 
872  lwgeom_free(lwgeom);
873  PG_FREE_IF_COPY(geom, 0);
874 
875  if ( ! lwpoint )
876  PG_RETURN_NULL();
877 
878  PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(lwpoint)));
879 }
880 
889 Datum LWGEOM_from_text(PG_FUNCTION_ARGS)
890 {
891  text *wkttext = PG_GETARG_TEXT_P(0);
892  char *wkt = text_to_cstring(wkttext);
893  LWGEOM_PARSER_RESULT lwg_parser_result;
894  GSERIALIZED *geom_result = NULL;
895  LWGEOM *lwgeom;
896 
897  POSTGIS_DEBUG(2, "LWGEOM_from_text");
898  POSTGIS_DEBUGF(3, "wkt: [%s]", wkt);
899 
900  if (lwgeom_parse_wkt(&lwg_parser_result, wkt, LW_PARSER_CHECK_ALL) == LW_FAILURE )
901  PG_PARSER_ERROR(lwg_parser_result);
902 
903  lwgeom = lwg_parser_result.geom;
904 
905  if ( lwgeom->srid != SRID_UNKNOWN )
906  {
907  elog(WARNING, "OGC WKT expected, EWKT provided - use GeomFromEWKT() for this");
908  }
909 
910  /* read user-requested SRID if any */
911  if ( PG_NARGS() > 1 )
912  lwgeom_set_srid(lwgeom, PG_GETARG_INT32(1));
913 
914  geom_result = geometry_serialize(lwgeom);
915  lwgeom_parser_result_free(&lwg_parser_result);
916 
917  PG_RETURN_POINTER(geom_result);
918 }
919 
930 Datum LWGEOM_from_WKB(PG_FUNCTION_ARGS)
931 {
932  bytea *bytea_wkb = PG_GETARG_BYTEA_P(0);
933  int32 srid = 0;
934  GSERIALIZED *geom;
935  LWGEOM *lwgeom;
936  uint8_t *wkb = (uint8_t*)VARDATA(bytea_wkb);
937 
938  lwgeom = lwgeom_from_wkb(wkb, VARSIZE_ANY_EXHDR(bytea_wkb), LW_PARSER_CHECK_ALL);
939  if (!lwgeom)
940  lwpgerror("Unable to parse WKB");
941 
942  geom = geometry_serialize(lwgeom);
943  lwgeom_free(lwgeom);
944  PG_FREE_IF_COPY(bytea_wkb, 0);
945 
946  if ( gserialized_get_srid(geom) != SRID_UNKNOWN )
947  {
948  elog(WARNING, "OGC WKB expected, EWKB provided - use GeometryFromEWKB() for this");
949  }
950 
951  if ( PG_NARGS() > 1 )
952  {
953  srid = PG_GETARG_INT32(1);
954  if ( srid != gserialized_get_srid(geom) )
955  gserialized_set_srid(geom, srid);
956  }
957 
958  PG_RETURN_POINTER(geom);
959 }
960 
963 Datum LWGEOM_asText(PG_FUNCTION_ARGS)
964 {
965  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
966  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
967 
968  int dbl_dig_for_wkt = OUT_DEFAULT_DECIMAL_DIGITS;
969  if (PG_NARGS() > 1) dbl_dig_for_wkt = PG_GETARG_INT32(1);
970 
971  PG_RETURN_TEXT_P(lwgeom_to_wkt_varlena(lwgeom, WKT_ISO, dbl_dig_for_wkt));
972 }
973 
974 
977 Datum LWGEOM_asBinary(PG_FUNCTION_ARGS)
978 {
979  GSERIALIZED *geom;
980  LWGEOM *lwgeom;
981  uint8_t variant = WKB_ISO;
982 
983  if (PG_ARGISNULL(0))
984  PG_RETURN_NULL();
985 
986  /* Get a 2D version of the geometry */
987  geom = PG_GETARG_GSERIALIZED_P(0);
988  lwgeom = lwgeom_from_gserialized(geom);
989 
990 
991  /* If user specified endianness, respect it */
992  if ( (PG_NARGS()>1) && (!PG_ARGISNULL(1)) )
993  {
994  text *wkb_endian = PG_GETARG_TEXT_P(1);
995 
996  if ( ! strncmp(VARDATA(wkb_endian), "xdr", 3) ||
997  ! strncmp(VARDATA(wkb_endian), "XDR", 3) )
998  {
999  variant = variant | WKB_XDR;
1000  }
1001  else
1002  {
1003  variant = variant | WKB_NDR;
1004  }
1005  }
1006 
1007  /* Write to WKB and free the geometry */
1008  PG_RETURN_BYTEA_P(lwgeom_to_wkb_varlena(lwgeom, variant));
1009 }
1010 
1011 
1012 
1020 Datum LWGEOM_isclosed(PG_FUNCTION_ARGS)
1021 {
1022  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
1023  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
1024  int closed = lwgeom_is_closed(lwgeom);
1025 
1026  lwgeom_free(lwgeom);
1027  PG_FREE_IF_COPY(geom, 0);
1028  PG_RETURN_BOOL(closed);
1029 }
static uint8_t variant
Definition: cu_in_twkb.c:26
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition: cu_print.c:267
GBOX * gbox_copy(const GBOX *box)
Return a copy of the GBOX, based on dimensionality of flags.
Definition: gbox.c:438
int ptarray_calculate_gbox_cartesian(const POINTARRAY *pa, GBOX *gbox)
Calculate box (x/y) and add values to gbox.
Definition: gbox.c:613
int32_t gserialized_get_srid(const GSERIALIZED *g)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
Definition: gserialized.c:155
int gserialized_has_m(const GSERIALIZED *g)
Check if a GSERIALIZED has an M ordinate.
Definition: gserialized.c:214
int gserialized_peek_first_point(const GSERIALIZED *g, POINT4D *out_point)
Pull the first point values of a GSERIALIZED.
Definition: gserialized.c:286
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
Definition: gserialized.c:268
void gserialized_set_srid(GSERIALIZED *g, int32_t srid)
Write the SRID into the serialized form (it is packed into three bytes so this is a handy function).
Definition: gserialized.c:167
int gserialized_has_z(const GSERIALIZED *g)
Check if a GSERIALIZED has a Z ordinate.
Definition: gserialized.c:203
uint32_t gserialized_get_type(const GSERIALIZED *g)
Extract the geometry type from the serialized form (it hides in the anonymous data area,...
Definition: gserialized.c:118
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:1053
#define LW_PARSER_CHECK_ALL
Definition: liblwgeom.h:2147
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:339
#define COLLECTIONTYPE
Definition: liblwgeom.h:108
#define COMPOUNDTYPE
Definition: liblwgeom.h:110
int lwgeom_is_unitary(const LWGEOM *geom)
Determine whether a Geometry is a bag of sub-geometries.
Definition: lwgeom.c:1140
int lwgeom_startpoint(const LWGEOM *lwgeom, POINT4D *pt)
Definition: lwgeom.c:2221
#define WKB_ISO
Definition: liblwgeom.h:2207
void lwgeom_set_srid(LWGEOM *geom, int32_t srid)
Set the SRID on an LWGEOM For collections, only the parent gets an SRID, all the children get SRID_UN...
Definition: lwgeom.c:1610
int lwgeom_has_rings(const LWGEOM *geom)
Is this a type that has rings enclosing an area, but is not a collection of areas?...
Definition: lwgeom.c:1146
#define LW_FAILURE
Definition: liblwgeom.h:96
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1218
#define CURVEPOLYTYPE
Definition: liblwgeom.h:111
#define MULTILINETYPE
Definition: liblwgeom.h:106
LWPOINT * lwcompound_get_lwpoint(const LWCOMPOUND *lwcmp, uint32_t where)
Definition: lwcompound.c:256
#define MULTISURFACETYPE
Definition: liblwgeom.h:113
#define LINETYPE
Definition: liblwgeom.h:103
void lwline_release(LWLINE *lwline)
Definition: lwline.c:125
#define MULTIPOINTTYPE
Definition: liblwgeom.h:105
int lwgeom_parse_wkt(LWGEOM_PARSER_RESULT *parser_result, char *wktstr, int parse_flags)
Parse a WKT geometry string into an LWGEOM structure.
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition: lwgeom.c:934
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:102
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:42
LWTRIANGLE * lwgeom_as_lwtriangle(const LWGEOM *lwgeom)
Definition: lwgeom.c:224
#define TINTYPE
Definition: liblwgeom.h:116
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:107
uint32_t lwgeom_count_vertices(const LWGEOM *geom)
Count the total number of vertices in any LWGEOM.
Definition: lwgeom.c:1309
int lwgeom_has_patches(const LWGEOM *geom)
Definition: lwgeom.c:1126
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:1361
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:344
#define POLYGONTYPE
Definition: liblwgeom.h:104
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:114
LWCURVEPOLY * lwgeom_as_lwcurvepoly(const LWGEOM *lwgeom)
Definition: lwgeom.c:206
#define CIRCSTRINGTYPE
Definition: liblwgeom.h:109
#define WKT_ISO
Definition: liblwgeom.h:2216
#define WKB_NDR
Definition: liblwgeom.h:2210
#define MULTICURVETYPE
Definition: liblwgeom.h:112
#define TRIANGLETYPE
Definition: liblwgeom.h:115
void * lwalloc(size_t size)
Definition: lwutil.c:227
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
Definition: lwgeom.c:233
void lwpoly_free(LWPOLY *poly)
Definition: lwpoly.c:175
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
Definition: lwgeom.c:215
void lwgeom_release(LWGEOM *lwgeom)
Free the containing LWGEOM and the associated BOX.
Definition: lwgeom.c:468
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:215
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:842
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition: lwgeom.c:941
lwvarlena_t * lwgeom_to_wkb_varlena(const LWGEOM *geom, uint8_t variant)
Definition: lwout_wkb.c:851
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition: lwgeom.c:695
LWLINE * lwline_construct_empty(int32_t srid, char hasz, char hasm)
Definition: lwline.c:55
void lwgeom_parser_result_free(LWGEOM_PARSER_RESULT *parser_result)
Definition: lwin_wkt.c:921
LWPOINT * lwcompound_get_endpoint(const LWCOMPOUND *lwcmp)
Definition: lwcompound.c:297
#define WKB_XDR
Definition: liblwgeom.h:2211
LWPOINT * lwpoint_make(int32_t srid, int hasz, int hasm, const POINT4D *p)
Definition: lwpoint.c:206
lwvarlena_t * lwgeom_to_wkt_varlena(const LWGEOM *geom, uint8_t variant, int precision)
Definition: lwout_wkt.c:721
LWPOINT * lwline_get_lwpoint(const LWLINE *line, uint32_t where)
Returns freshly allocated LWPOINT that corresponds to the index where.
Definition: lwline.c:309
This library is the generic geometry handling section of PostGIS.
#define OUT_DEFAULT_DECIMAL_DIGITS
Datum LWGEOM_asBinary(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:977
Datum LWGEOM_exteriorring_polygon(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:474
Datum LWGEOM_from_WKB(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:930
Datum LWGEOM_dimension(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:448
PG_FUNCTION_INFO_V1(LWGEOM_get_srid)
Datum LWGEOM_get_srid(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:101
Datum LWGEOM_isclosed(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:1020
Datum LWGEOM_asText(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:963
static int32 lwgeom_count_geometries(LWGEOM *lwgeom, bool patches_as_geometries)
Definition: lwgeom_ogc.c:246
static LWGEOM * lwgeom_extract_geometry_n(LWGEOM *lwgeom, int32 idx, bool patches_as_geometries)
Definition: lwgeom_ogc.c:320
static char * stTypeName[]
Definition: lwgeom_ogc.c:179
Datum LWGEOM_numpatches(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:294
Datum LWGEOM_endpoint_linestring(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:854
Datum LWGEOM_startpoint_linestring(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:826
Datum LWGEOM_from_text(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:889
Datum LWGEOM_pointn_linestring(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:697
Datum LWGEOM_numpoints_linestring(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:220
Datum LWGEOM_geometryn_collection(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:373
Datum geometry_geometrytype(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:198
Datum LWGEOM_x_point(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:745
Datum LWGEOM_interiorringn_polygon(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:605
Datum LWGEOM_y_point(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:765
Datum LWGEOM_m_point(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:806
Datum LWGEOM_numinteriorrings_polygon(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:548
Datum LWGEOM_numgeometries_collection(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:277
Datum LWGEOM_getTYPE(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:121
Datum LWGEOM_set_srid(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:111
Datum LWGEOM_patchn(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:407
Datum LWGEOM_z_point(PG_FUNCTION_ARGS)
Definition: lwgeom_ogc.c:786
static int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members)
Definition: lwinline.h:199
int count
Definition: genraster.py:57
type
Definition: ovdump.py:42
unsigned int int32
Definition: shpopen.c:54
uint32_t ngeoms
Definition: liblwgeom.h:580
LWGEOM ** geoms
Definition: liblwgeom.h:575
LWGEOM ** rings
Definition: liblwgeom.h:603
uint32_t nrings
Definition: liblwgeom.h:608
uint8_t type
Definition: liblwgeom.h:462
GBOX * bbox
Definition: liblwgeom.h:458
int32_t srid
Definition: liblwgeom.h:460
POINTARRAY * points
Definition: liblwgeom.h:483
POINTARRAY ** rings
Definition: liblwgeom.h:519
uint32_t nrings
Definition: liblwgeom.h:524
GBOX * bbox
Definition: liblwgeom.h:518
int32_t srid
Definition: liblwgeom.h:520
int32_t srid
Definition: liblwgeom.h:496
GBOX * bbox
Definition: liblwgeom.h:494
POINTARRAY * points
Definition: liblwgeom.h:495
double m
Definition: liblwgeom.h:414
double x
Definition: liblwgeom.h:414
double z
Definition: liblwgeom.h:414
double y
Definition: liblwgeom.h:414
uint32_t npoints
Definition: liblwgeom.h:427
Parser result structure: returns the result of attempting to convert (E)WKT/(E)WKB to LWGEOM.
Definition: liblwgeom.h:2154