PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
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) */
48Datum LWGEOM_get_srid(PG_FUNCTION_ARGS);
49/* ---- SetSRID(geometry, integer) */
50Datum LWGEOM_set_srid(PG_FUNCTION_ARGS);
51/* ---- GeometryType(geometry) */
52Datum LWGEOM_getTYPE(PG_FUNCTION_ARGS);
53Datum geometry_geometrytype(PG_FUNCTION_ARGS);
54/* ---- NumPoints(geometry) */
55Datum LWGEOM_numpoints_linestring(PG_FUNCTION_ARGS);
56/* ---- NumGeometries(geometry) */
57Datum LWGEOM_numgeometries_collection(PG_FUNCTION_ARGS);
58/* ---- NumPatches(geometry) */
59Datum LWGEOM_numpatches(PG_FUNCTION_ARGS);
60/* ---- GeometryN(geometry, integer) */
61Datum LWGEOM_geometryn_collection(PG_FUNCTION_ARGS);
62/* ---- PatchN(geometry, integer) */
63Datum LWGEOM_patchn(PG_FUNCTION_ARGS);
64/* ---- Dimension(geometry) */
65Datum LWGEOM_dimension(PG_FUNCTION_ARGS);
66/* ---- ExteriorRing(geometry) */
67Datum LWGEOM_exteriorring_polygon(PG_FUNCTION_ARGS);
68/* ---- InteriorRingN(geometry, integer) */
69Datum LWGEOM_interiorringn_polygon(PG_FUNCTION_ARGS);
70/* ---- NumInteriorRings(geometry) */
71Datum LWGEOM_numinteriorrings_polygon(PG_FUNCTION_ARGS);
72/* ---- PointN(geometry, integer) */
73Datum LWGEOM_pointn_linestring(PG_FUNCTION_ARGS);
74/* ---- X(geometry) */
75Datum LWGEOM_x_point(PG_FUNCTION_ARGS);
76/* ---- Y(geometry) */
77Datum LWGEOM_y_point(PG_FUNCTION_ARGS);
78/* ---- Z(geometry) */
79Datum LWGEOM_z_point(PG_FUNCTION_ARGS);
80/* ---- M(geometry) */
81Datum LWGEOM_m_point(PG_FUNCTION_ARGS);
82/* ---- StartPoint(geometry) */
83Datum LWGEOM_startpoint_linestring(PG_FUNCTION_ARGS);
84/* ---- EndPoint(geometry) */
85Datum LWGEOM_endpoint_linestring(PG_FUNCTION_ARGS);
86/* ---- AsText(geometry) */
87Datum LWGEOM_asText(PG_FUNCTION_ARGS);
88/* ---- AsBinary(geometry, [XDR|NDR]) */
89Datum LWGEOM_asBinary(PG_FUNCTION_ARGS);
90/* ---- GeometryFromText(text, integer) */
91Datum LWGEOM_from_text(PG_FUNCTION_ARGS);
92/* ---- GeomFromWKB(bytea, integer) */
93Datum LWGEOM_from_WKB(PG_FUNCTION_ARGS);
94/* ---- IsClosed(geometry) */
95Datum LWGEOM_isclosed(PG_FUNCTION_ARGS);
96
97/*------------------------------------------------------------------*/
98
99/* getSRID(lwgeom) :: int4 */
101Datum 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 */
111Datum 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 */
121Datum 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 */
179static 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 */
198Datum 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
220Datum 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 */
245static int32
246lwgeom_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 {
260 ret = col ? col->ngeoms : 1;
261 }
262 else
263 {
264 ret = 1;
265 }
266 }
267 else
268 {
270 ret = col->ngeoms;
271 }
272
273 return ret;
274}
275
277Datum 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
294Datum 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 */
319static LWGEOM*
320lwgeom_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
373Datum 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 not returning the original geometry */
388 if (subgeom != lwgeom)
389 {
390 subgeom->srid = lwgeom->srid;
391 /* COMPUTE_BBOX==TAINTING */
392 if (lwgeom->bbox) lwgeom_add_bbox(subgeom);
393 }
394 result = geometry_serialize(subgeom);
395 PG_FREE_IF_COPY(geom, 0);
396 PG_RETURN_POINTER(result);
397}
398
401Datum LWGEOM_patchn(PG_FUNCTION_ARGS)
402{
403 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
404 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
405 GSERIALIZED *result = NULL;
406 int32 idx = PG_GETARG_INT32(1);
407 LWGEOM *subgeom = NULL;
408
409 if (!lwgeom_has_patches(lwgeom))
410 {
411 lwgeom_free(lwgeom);
412 PG_FREE_IF_COPY(geom, 0);
413 elog(ERROR, "ST_PatchN only supports TIN and PolyhedralSurface geometries");
414 }
415
416 /* Access patches individually */
417 subgeom = lwgeom_extract_geometry_n(lwgeom, idx, true);
418
419 if (!subgeom)
420 PG_RETURN_NULL();
421
422 /* If returning the original geometry */
423 if (subgeom == lwgeom)
424 PG_RETURN_POINTER(geom);
425
426 subgeom->srid = lwgeom->srid;
427 /* COMPUTE_BBOX==TAINTING */
428 if (lwgeom->bbox) lwgeom_add_bbox(subgeom);
429
430 result = geometry_serialize(subgeom);
431 lwgeom_free(lwgeom);
432 PG_FREE_IF_COPY(geom, 0);
433 PG_RETURN_POINTER(result);
434}
435
436
442Datum LWGEOM_dimension(PG_FUNCTION_ARGS)
443{
444 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
445 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
446 int dimension = -1;
447
448 dimension = lwgeom_dimension(lwgeom);
449 lwgeom_free(lwgeom);
450 PG_FREE_IF_COPY(geom, 0);
451
452 if ( dimension < 0 )
453 {
454 elog(NOTICE, "Could not compute geometry dimensions");
455 PG_RETURN_NULL();
456 }
457
458 PG_RETURN_INT32(dimension);
459}
460
461
468Datum LWGEOM_exteriorring_polygon(PG_FUNCTION_ARGS)
469{
470 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
472 POINTARRAY *extring;
473 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
474 LWLINE *line;
475 GBOX *bbox=NULL;
476
477 if ( ! lwgeom_has_rings(lwgeom) )
478 PG_RETURN_NULL();
479
480 if( lwgeom_is_empty(lwgeom) )
481 {
482 line = lwline_construct_empty(lwgeom->srid,
483 lwgeom_has_z(lwgeom),
484 lwgeom_has_m(lwgeom));
485 result = geometry_serialize(lwline_as_lwgeom(line));
486 }
487 else if ( lwgeom->type == POLYGONTYPE )
488 {
489 LWPOLY *poly = lwgeom_as_lwpoly(lwgeom);
490
491 /* Ok, now we have a polygon. Here is its exterior ring. */
492 extring = poly->rings[0];
493
494 /*
495 * This is a LWLINE constructed by exterior ring POINTARRAY
496 * If the input geom has a bbox, use it for
497 * the output geom, as exterior ring makes it up !
498 */
499 if ( poly->bbox )
500 bbox = gbox_copy(poly->bbox);
501
502 line = lwline_construct(poly->srid, bbox, extring);
503 result = geometry_serialize((LWGEOM *)line);
504
505 lwgeom_release((LWGEOM *)line);
506 }
507 else if ( lwgeom->type == TRIANGLETYPE )
508 {
509 LWTRIANGLE *triangle = lwgeom_as_lwtriangle(lwgeom);
510
511 /*
512 * This is a LWLINE constructed by exterior ring POINTARRAY
513 * If the input geom has a bbox, use it for
514 * the output geom, as exterior ring makes it up !
515 */
516 if ( triangle->bbox )
517 bbox = gbox_copy(triangle->bbox);
518 line = lwline_construct(triangle->srid, bbox, triangle->points);
519
520 result = geometry_serialize((LWGEOM *)line);
521
522 lwgeom_release((LWGEOM *)line);
523 }
524 else
525 {
526 LWCURVEPOLY *curvepoly = lwgeom_as_lwcurvepoly(lwgeom);
527 result = geometry_serialize(curvepoly->rings[0]);
528 }
529
530 lwgeom_free(lwgeom);
531 PG_FREE_IF_COPY(geom, 0);
532 PG_RETURN_POINTER(result);
533}
534
542Datum LWGEOM_numinteriorrings_polygon(PG_FUNCTION_ARGS)
543{
544 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
545 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
546 int type = lwgeom->type;
547 int result = -1;
548
549 if ( !lwgeom_has_rings(lwgeom) )
550 PG_RETURN_NULL();
551
552 if ( lwgeom_is_empty(lwgeom) || type == TRIANGLETYPE )
553 PG_RETURN_INT32(0);
554
555 /*
556 * POLYGON and TRIANGLE have same underlying structure
557 * with an array of nrings rings of POINTARRAY holding the
558 * rings
559 */
560 if (type == POLYGONTYPE )
561 {
562 const LWPOLY *poly = lwgeom_as_lwpoly(lwgeom);
563 result = poly->nrings - 1;
564 }
565 /*
566 * CURVEPOLYGON on the other hand is structured
567 * like a collection with each ring represented by
568 * a geometry in a list ngeoms long.
569 */
570 else if (type == CURVEPOLYTYPE)
571 {
572 const LWCURVEPOLY *curv = lwgeom_as_lwcurvepoly(lwgeom);
573 result = curv->nrings - 1;
574 }
575 /*
576 * If a new type is added to the zoo, we should error
577 * out.
578 */
579 else
580 {
581 elog(ERROR, "%s unsupported ring type %d", __func__, type);
582 }
583
584 lwgeom_free(lwgeom);
585 PG_FREE_IF_COPY(geom, 0);
586 if ( result < 0 )
587 PG_RETURN_NULL();
588 else
589 PG_RETURN_INT32(result);
590}
591
599Datum LWGEOM_interiorringn_polygon(PG_FUNCTION_ARGS)
600{
601 GSERIALIZED *geom;
602 int32 wanted_index;
603 LWCURVEPOLY *curvepoly = NULL;
604 LWPOLY *poly = NULL;
605 POINTARRAY *ring;
606 LWLINE *line;
607 LWGEOM *lwgeom;
609 GBOX *bbox = NULL;
610 int type;
611
612 POSTGIS_DEBUG(2, "LWGEOM_interiorringn_polygon called.");
613
614 wanted_index = PG_GETARG_INT32(1);
615 if ( wanted_index < 1 )
616 {
617 PG_RETURN_NULL(); /* index out of range */
618 }
619
620 geom = PG_GETARG_GSERIALIZED_P(0);
621 type = gserialized_get_type(geom);
622
623 if ( (type != POLYGONTYPE) && (type != CURVEPOLYTYPE) )
624 {
625 PG_FREE_IF_COPY(geom, 0);
626 PG_RETURN_NULL();
627 }
628
629 lwgeom = lwgeom_from_gserialized(geom);
630 if( lwgeom_is_empty(lwgeom) )
631 {
632 lwpoly_free(poly);
633 PG_FREE_IF_COPY(geom, 0);
634 PG_RETURN_NULL();
635 }
636
637 if ( type == POLYGONTYPE)
638 {
640
641 /* Ok, now we have a polygon. Let's see if it has enough holes */
642 if ( wanted_index >= (int32)poly->nrings )
643 {
644 lwpoly_free(poly);
645 PG_FREE_IF_COPY(geom, 0);
646 PG_RETURN_NULL();
647 }
648
649 ring = poly->rings[wanted_index];
650
651 /* COMPUTE_BBOX==TAINTING */
652 if ( poly->bbox )
653 {
654 bbox = lwalloc(sizeof(GBOX));
656 }
657
658 /* This is a LWLINE constructed by interior ring POINTARRAY */
659 line = lwline_construct(poly->srid, bbox, ring);
660
661
662 result = geometry_serialize((LWGEOM *)line);
663 lwline_release(line);
664 lwpoly_free(poly);
665 }
666 else
667 {
669
670 if (wanted_index >= (int32)curvepoly->nrings)
671 {
672 PG_FREE_IF_COPY(geom, 0);
673 lwgeom_release((LWGEOM *)curvepoly);
674 PG_RETURN_NULL();
675 }
676
677 result = geometry_serialize(curvepoly->rings[wanted_index]);
678 lwgeom_free((LWGEOM*)curvepoly);
679 }
680
681 PG_FREE_IF_COPY(geom, 0);
682 PG_RETURN_POINTER(result);
683}
684
691Datum LWGEOM_pointn_linestring(PG_FUNCTION_ARGS)
692{
693 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
694 int where = PG_GETARG_INT32(1);
695 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
696 LWPOINT *lwpoint = NULL;
697 int type = lwgeom->type;
698
699 /* If index is negative, count backward */
700 if( where < 1 )
701 {
702 int count = -1;
703 if ( type == LINETYPE || type == CIRCSTRINGTYPE || type == COMPOUNDTYPE )
704 count = lwgeom_count_vertices(lwgeom);
705 if(count >0)
706 {
707 /* only work if we found the total point number */
708 /* converting where to positive backward indexing, +1 because 1 indexing */
709 where = where + count + 1;
710 }
711 if (where < 1)
712 PG_RETURN_NULL();
713 }
714
715 if ( type == LINETYPE || type == CIRCSTRINGTYPE )
716 {
717 /* OGC index starts at one, so we subtract first. */
718 lwpoint = lwline_get_lwpoint((LWLINE*)lwgeom, where - 1);
719 }
720 else if ( type == COMPOUNDTYPE )
721 {
722 lwpoint = lwcompound_get_lwpoint((LWCOMPOUND*)lwgeom, where - 1);
723 }
724
725 lwgeom_free(lwgeom);
726 PG_FREE_IF_COPY(geom, 0);
727
728 if ( ! lwpoint )
729 PG_RETURN_NULL();
730
731 PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(lwpoint)));
732}
733
739Datum LWGEOM_x_point(PG_FUNCTION_ARGS)
740{
741 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
742 POINT4D pt;
743
744 if (gserialized_get_type(geom) != POINTTYPE)
745 lwpgerror("Argument to ST_X() must have type POINT");
746
748 {
749 PG_RETURN_NULL();
750 }
751 PG_RETURN_FLOAT8(pt.x);
752}
753
759Datum LWGEOM_y_point(PG_FUNCTION_ARGS)
760{
761 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
762 POINT4D pt;
763
764 if (gserialized_get_type(geom) != POINTTYPE)
765 lwpgerror("Argument to ST_Y() must have type POINT");
766
768 {
769 PG_RETURN_NULL();
770 }
771 PG_RETURN_FLOAT8(pt.y);
772}
773
780Datum LWGEOM_z_point(PG_FUNCTION_ARGS)
781{
782 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
783 POINT4D pt;
784
785 if (gserialized_get_type(geom) != POINTTYPE)
786 lwpgerror("Argument to ST_Z() must have type POINT");
787
788 if (!gserialized_has_z(geom) || (gserialized_peek_first_point(geom, &pt) == LW_FAILURE))
789 {
790 PG_RETURN_NULL();
791 }
792 PG_RETURN_FLOAT8(pt.z);
793}
794
800Datum LWGEOM_m_point(PG_FUNCTION_ARGS)
801{
802 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
803 POINT4D pt;
804
805 if (gserialized_get_type(geom) != POINTTYPE)
806 lwpgerror("Argument to ST_M() must have type POINT");
807
808 if (!gserialized_has_m(geom) || (gserialized_peek_first_point(geom, &pt) == LW_FAILURE))
809 {
810 PG_RETURN_NULL();
811 }
812 PG_RETURN_FLOAT8(pt.m);
813}
814
820Datum LWGEOM_startpoint_linestring(PG_FUNCTION_ARGS)
821{
822 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
823 GSERIALIZED *ret;
824 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
825 LWGEOM *lwpoint = NULL;
826 POINT4D pt;
827
828 if (lwgeom_startpoint(lwgeom, &pt) == LW_FAILURE)
829 {
830 PG_RETURN_NULL();
831 }
832
833 lwpoint = (LWGEOM *)lwpoint_make(lwgeom->srid, lwgeom_has_z(lwgeom), lwgeom_has_m(lwgeom), &pt);
834 ret = geometry_serialize(lwpoint);
835
836 lwgeom_free(lwgeom);
837 lwgeom_free(lwpoint);
838
839 PG_FREE_IF_COPY(geom, 0);
840 PG_RETURN_POINTER(ret);
841}
842
848Datum LWGEOM_endpoint_linestring(PG_FUNCTION_ARGS)
849{
850 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
851 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
852 LWPOINT *lwpoint = NULL;
853 int type = lwgeom->type;
854
855 if ( type == LINETYPE || type == CIRCSTRINGTYPE )
856 {
857 LWLINE *line = (LWLINE*)lwgeom;
858 if ( line->points )
859 lwpoint = lwline_get_lwpoint((LWLINE*)lwgeom, line->points->npoints - 1);
860 }
861 else if ( type == COMPOUNDTYPE )
862 {
863 lwpoint = lwcompound_get_endpoint((LWCOMPOUND*)lwgeom);
864 }
865
866 lwgeom_free(lwgeom);
867 PG_FREE_IF_COPY(geom, 0);
868
869 if ( ! lwpoint )
870 PG_RETURN_NULL();
871
872 PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(lwpoint)));
873}
874
883Datum LWGEOM_from_text(PG_FUNCTION_ARGS)
884{
885 text *wkttext = PG_GETARG_TEXT_P(0);
886 char *wkt = text_to_cstring(wkttext);
887 LWGEOM_PARSER_RESULT lwg_parser_result;
888 GSERIALIZED *geom_result = NULL;
889 LWGEOM *lwgeom;
890
891 POSTGIS_DEBUG(2, "LWGEOM_from_text");
892 POSTGIS_DEBUGF(3, "wkt: [%s]", wkt);
893
894 if (lwgeom_parse_wkt(&lwg_parser_result, wkt, LW_PARSER_CHECK_ALL) == LW_FAILURE )
895 PG_PARSER_ERROR(lwg_parser_result);
896
897 lwgeom = lwg_parser_result.geom;
898
899 if ( lwgeom->srid != SRID_UNKNOWN )
900 {
901 elog(WARNING, "OGC WKT expected, EWKT provided - use GeomFromEWKT() for this");
902 }
903
904 /* read user-requested SRID if any */
905 if ( PG_NARGS() > 1 )
906 lwgeom_set_srid(lwgeom, PG_GETARG_INT32(1));
907
908 geom_result = geometry_serialize(lwgeom);
909 lwgeom_parser_result_free(&lwg_parser_result);
910
911 PG_RETURN_POINTER(geom_result);
912}
913
924Datum LWGEOM_from_WKB(PG_FUNCTION_ARGS)
925{
926 bytea *bytea_wkb = PG_GETARG_BYTEA_P(0);
927 int32 srid = 0;
928 GSERIALIZED *geom;
929 LWGEOM *lwgeom;
930 uint8_t *wkb = (uint8_t*)VARDATA(bytea_wkb);
931
932 lwgeom = lwgeom_from_wkb(wkb, VARSIZE_ANY_EXHDR(bytea_wkb), LW_PARSER_CHECK_ALL);
933 if (!lwgeom)
934 lwpgerror("Unable to parse WKB");
935
936 geom = geometry_serialize(lwgeom);
937 lwgeom_free(lwgeom);
938 PG_FREE_IF_COPY(bytea_wkb, 0);
939
940 if ( gserialized_get_srid(geom) != SRID_UNKNOWN )
941 {
942 elog(WARNING, "OGC WKB expected, EWKB provided - use GeometryFromEWKB() for this");
943 }
944
945 if ( PG_NARGS() > 1 )
946 {
947 srid = PG_GETARG_INT32(1);
948 if ( srid != gserialized_get_srid(geom) )
949 gserialized_set_srid(geom, srid);
950 }
951
952 PG_RETURN_POINTER(geom);
953}
954
957Datum LWGEOM_asText(PG_FUNCTION_ARGS)
958{
959 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
960 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
961
962 int dbl_dig_for_wkt = OUT_DEFAULT_DECIMAL_DIGITS;
963 if (PG_NARGS() > 1) dbl_dig_for_wkt = PG_GETARG_INT32(1);
964
965 PG_RETURN_TEXT_P(lwgeom_to_wkt_varlena(lwgeom, WKT_ISO, dbl_dig_for_wkt));
966}
967
968
971Datum LWGEOM_asBinary(PG_FUNCTION_ARGS)
972{
973 GSERIALIZED *geom;
974 LWGEOM *lwgeom;
975 uint8_t variant = WKB_ISO;
976
977 if (PG_ARGISNULL(0))
978 PG_RETURN_NULL();
979
980 /* Get a 2D version of the geometry */
981 geom = PG_GETARG_GSERIALIZED_P(0);
982 lwgeom = lwgeom_from_gserialized(geom);
983
984
985 /* If user specified endianness, respect it */
986 if ( (PG_NARGS()>1) && (!PG_ARGISNULL(1)) )
987 {
988 text *wkb_endian = PG_GETARG_TEXT_P(1);
989
990 if ( ! strncmp(VARDATA(wkb_endian), "xdr", 3) ||
991 ! strncmp(VARDATA(wkb_endian), "XDR", 3) )
992 {
994 }
995 else
996 {
998 }
999 }
1000
1001 /* Write to WKB and free the geometry */
1002 PG_RETURN_BYTEA_P(lwgeom_to_wkb_varlena(lwgeom, variant));
1003}
1004
1005
1006
1014Datum LWGEOM_isclosed(PG_FUNCTION_ARGS)
1015{
1016 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
1017 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
1018 int closed = lwgeom_is_closed(lwgeom);
1019
1020 lwgeom_free(lwgeom);
1021 PG_FREE_IF_COPY(geom, 0);
1022 PG_RETURN_BOOL(closed);
1023}
static uint8_t variant
Definition cu_in_twkb.c:26
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition cu_print.c:267
int ptarray_calculate_gbox_cartesian(const POINTARRAY *pa, GBOX *gbox)
Calculate box (x/y) and add values to gbox.
Definition gbox.c:613
GBOX * gbox_copy(const GBOX *box)
Return a copy of the GBOX, based on dimensionality of flags.
Definition gbox.c:438
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)...
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
int gserialized_has_m(const GSERIALIZED *g)
Check if a GSERIALIZED has an M ordinate.
int gserialized_peek_first_point(const GSERIALIZED *g, POINT4D *out_point)
Pull the first point values of a GSERIALIZED.
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).
int gserialized_has_z(const GSERIALIZED *g)
Check if a GSERIALIZED has a Z ordinate.
uint32_t gserialized_get_type(const GSERIALIZED *g)
Extract the geometry type from the serialized form (it hides in the anonymous data area,...
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:1081
#define LW_PARSER_CHECK_ALL
Definition liblwgeom.h:2150
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition lwgeom.c:372
#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:1168
int lwgeom_startpoint(const LWGEOM *lwgeom, POINT4D *pt)
Definition lwgeom.c:2249
#define WKB_ISO
Definition liblwgeom.h:2210
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:1638
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:1174
#define LW_FAILURE
Definition liblwgeom.h:96
void lwgeom_free(LWGEOM *geom)
Definition lwgeom.c:1246
#define CURVEPOLYTYPE
Definition liblwgeom.h:111
LWPOINT * lwline_get_lwpoint(const LWLINE *line, uint32_t where)
Returns freshly allocated LWPOINT that corresponds to the index where.
Definition lwline.c:319
#define MULTILINETYPE
Definition liblwgeom.h:106
#define MULTISURFACETYPE
Definition liblwgeom.h:113
#define LINETYPE
Definition liblwgeom.h:103
LWCOLLECTION * lwgeom_as_lwcollection(const LWGEOM *lwgeom)
Definition lwgeom.c:261
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.
LWPOINT * lwcompound_get_lwpoint(const LWCOMPOUND *lwcmp, uint32_t where)
Definition lwcompound.c:241
lwvarlena_t * lwgeom_to_wkb_varlena(const LWGEOM *geom, uint8_t variant)
Definition lwout_wkb.c:851
LWCURVEPOLY * lwgeom_as_lwcurvepoly(const LWGEOM *lwgeom)
Definition lwgeom.c:234
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition lwgeom.c:962
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition liblwgeom.h:102
void * lwalloc(size_t size)
Definition lwutil.c:227
LWPOLY * lwgeom_as_lwpoly(const LWGEOM *lwgeom)
Definition lwgeom.c:243
LWPOINT * lwcompound_get_endpoint(const LWCOMPOUND *lwcmp)
Definition lwcompound.c:282
#define TINTYPE
Definition liblwgeom.h:116
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition lwline.c:42
#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:1337
int lwgeom_has_patches(const LWGEOM *geom)
Definition lwgeom.c:1154
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:1389
LWTRIANGLE * lwgeom_as_lwtriangle(const LWGEOM *lwgeom)
Definition lwgeom.c:252
lwvarlena_t * lwgeom_to_wkt_varlena(const LWGEOM *geom, uint8_t variant, int precision)
Definition lwout_wkt.c:721
#define POLYGONTYPE
Definition liblwgeom.h:104
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition lwgeom.c:367
#define POLYHEDRALSURFACETYPE
Definition liblwgeom.h:114
#define CIRCSTRINGTYPE
Definition liblwgeom.h:109
#define WKT_ISO
Definition liblwgeom.h:2219
#define WKB_NDR
Definition liblwgeom.h:2213
LWPOINT * lwpoint_make(int32_t srid, int hasz, int hasm, const POINT4D *p)
Definition lwpoint.c:206
#define MULTICURVETYPE
Definition liblwgeom.h:112
#define TRIANGLETYPE
Definition liblwgeom.h:115
void lwpoly_free(LWPOLY *poly)
Definition lwpoly.c:175
void lwgeom_release(LWGEOM *lwgeom)
Free the containing LWGEOM and the associated BOX.
Definition lwgeom.c:496
#define SRID_UNKNOWN
Unknown SRID value.
Definition liblwgeom.h:215
LWLINE * lwline_construct_empty(int32_t srid, char hasz, char hasm)
Definition lwline.c:55
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition lwgeom.c:969
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
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition lwgeom.c:723
void lwgeom_parser_result_free(LWGEOM_PARSER_RESULT *parser_result)
Definition lwin_wkt.c:921
#define WKB_XDR
Definition liblwgeom.h:2214
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:971
Datum LWGEOM_exteriorring_polygon(PG_FUNCTION_ARGS)
Definition lwgeom_ogc.c:468
Datum LWGEOM_from_WKB(PG_FUNCTION_ARGS)
Definition lwgeom_ogc.c:924
Datum LWGEOM_dimension(PG_FUNCTION_ARGS)
Definition lwgeom_ogc.c:442
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)
Datum LWGEOM_asText(PG_FUNCTION_ARGS)
Definition lwgeom_ogc.c:957
static int32 lwgeom_count_geometries(LWGEOM *lwgeom, bool patches_as_geometries)
Definition lwgeom_ogc.c:246
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:848
Datum LWGEOM_startpoint_linestring(PG_FUNCTION_ARGS)
Definition lwgeom_ogc.c:820
Datum LWGEOM_from_text(PG_FUNCTION_ARGS)
Definition lwgeom_ogc.c:883
Datum LWGEOM_pointn_linestring(PG_FUNCTION_ARGS)
Definition lwgeom_ogc.c:691
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:739
Datum LWGEOM_interiorringn_polygon(PG_FUNCTION_ARGS)
Definition lwgeom_ogc.c:599
Datum LWGEOM_y_point(PG_FUNCTION_ARGS)
Definition lwgeom_ogc.c:759
Datum LWGEOM_m_point(PG_FUNCTION_ARGS)
Definition lwgeom_ogc.c:800
Datum LWGEOM_numinteriorrings_polygon(PG_FUNCTION_ARGS)
Definition lwgeom_ogc.c:542
Datum LWGEOM_numgeometries_collection(PG_FUNCTION_ARGS)
Definition lwgeom_ogc.c:277
static LWGEOM * lwgeom_extract_geometry_n(LWGEOM *lwgeom, int32 idx, bool patches_as_geometries)
Definition lwgeom_ogc.c:320
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:401
Datum LWGEOM_z_point(PG_FUNCTION_ARGS)
Definition lwgeom_ogc.c:780
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
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:2157