root/trunk/postgis/lwgeom_ogc.c

Revision 9324, 22.7 KB (checked in by pramsey, 3 months ago)

Try again with line endings, this time using eol-style instead of eol-type (#1605)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
  • Property svn:mime-type set to text/plain
Line 
1/**********************************************************************
2 * $Id$
3 *
4 * PostGIS - Spatial Types for PostgreSQL
5 * http://postgis.refractions.net
6 * Copyright 2001-2005 Refractions Research Inc.
7 *
8 * This is free software; you can redistribute and/or modify it under
9 * the terms of the GNU General Public Licence. See the COPYING file.
10 *
11 **********************************************************************/
12
13#include "postgres.h"
14
15#include <math.h>
16#include <float.h>
17#include <string.h>
18#include <stdio.h>
19#include <errno.h>
20
21#include "access/gist.h"
22#include "access/itup.h"
23
24#include "fmgr.h"
25#include "utils/elog.h"
26
27#include "../postgis_config.h"
28
29#include "liblwgeom.h"
30#include "lwgeom_pg.h"
31
32
33/* ---- SRID(geometry) */
34Datum LWGEOM_get_srid(PG_FUNCTION_ARGS);
35/* ---- SetSRID(geometry, integer) */
36Datum LWGEOM_set_srid(PG_FUNCTION_ARGS);
37/* ---- GeometryType(geometry) */
38Datum LWGEOM_getTYPE(PG_FUNCTION_ARGS);
39Datum geometry_geometrytype(PG_FUNCTION_ARGS);
40/* ---- NumPoints(geometry) */
41Datum LWGEOM_numpoints_linestring(PG_FUNCTION_ARGS);
42/* ---- NumGeometries(geometry) */
43Datum LWGEOM_numgeometries_collection(PG_FUNCTION_ARGS);
44/* ---- GeometryN(geometry, integer) */
45Datum LWGEOM_geometryn_collection(PG_FUNCTION_ARGS);
46/* ---- Dimension(geometry) */
47Datum LWGEOM_dimension(PG_FUNCTION_ARGS);
48/* ---- ExteriorRing(geometry) */
49Datum LWGEOM_exteriorring_polygon(PG_FUNCTION_ARGS);
50/* ---- InteriorRingN(geometry, integer) */
51Datum LWGEOM_interiorringn_polygon(PG_FUNCTION_ARGS);
52/* ---- NumInteriorRings(geometry) */
53Datum LWGEOM_numinteriorrings_polygon(PG_FUNCTION_ARGS);
54/* ---- PointN(geometry, integer) */
55Datum LWGEOM_pointn_linestring(PG_FUNCTION_ARGS);
56/* ---- X(geometry) */
57Datum LWGEOM_x_point(PG_FUNCTION_ARGS);
58/* ---- Y(geometry) */
59Datum LWGEOM_y_point(PG_FUNCTION_ARGS);
60/* ---- Z(geometry) */
61Datum LWGEOM_z_point(PG_FUNCTION_ARGS);
62/* ---- M(geometry) */
63Datum LWGEOM_m_point(PG_FUNCTION_ARGS);
64/* ---- StartPoint(geometry) */
65Datum LWGEOM_startpoint_linestring(PG_FUNCTION_ARGS);
66/* ---- EndPoint(geometry) */
67Datum LWGEOM_endpoint_linestring(PG_FUNCTION_ARGS);
68/* ---- AsText(geometry) */
69Datum LWGEOM_asText(PG_FUNCTION_ARGS);
70/* ---- AsBinary(geometry, [XDR|NDR]) */
71Datum LWGEOM_asBinary(PG_FUNCTION_ARGS);
72/* ---- GeometryFromText(text, integer) */
73Datum LWGEOM_from_text(PG_FUNCTION_ARGS);
74/* ---- GeomFromWKB(bytea, integer) */
75Datum LWGEOM_from_WKB(PG_FUNCTION_ARGS);
76/* ---- IsClosed(geometry) */
77Datum LWGEOM_isclosed(PG_FUNCTION_ARGS);
78
79/*------------------------------------------------------------------*/
80
81/* getSRID(lwgeom) :: int4 */
82PG_FUNCTION_INFO_V1(LWGEOM_get_srid);
83Datum LWGEOM_get_srid(PG_FUNCTION_ARGS)
84{
85        GSERIALIZED *geom=(GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
86        int srid = gserialized_get_srid (geom);
87        PG_FREE_IF_COPY(geom,0);
88        PG_RETURN_INT32(srid);
89}
90
91/* setSRID(lwgeom, int4) :: lwgeom */
92PG_FUNCTION_INFO_V1(LWGEOM_set_srid);
93Datum LWGEOM_set_srid(PG_FUNCTION_ARGS)
94{
95        GSERIALIZED *result;
96        GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
97        int srid = PG_GETARG_INT32(1);
98        LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
99        lwgeom_set_srid(lwgeom, srid);
100        result = geometry_serialize(lwgeom);
101        lwgeom_free(lwgeom);
102        PG_FREE_IF_COPY(geom, 0);
103        PG_RETURN_POINTER(result);
104}
105
106/* returns a string representation of this geometry's type */
107PG_FUNCTION_INFO_V1(LWGEOM_getTYPE);
108Datum LWGEOM_getTYPE(PG_FUNCTION_ARGS)
109{
110        GSERIALIZED *lwgeom;
111        char *text_ob;
112        char *result;
113        int32 size;
114        uint8_t type;
115
116        lwgeom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
117        text_ob = lwalloc(20+VARHDRSZ);
118        result = text_ob+VARHDRSZ;
119
120        type = gserialized_get_type(lwgeom);
121
122        memset(VARDATA(text_ob), 0, 20);
123
124        if (type == POINTTYPE)
125                strcpy(result,"POINT");
126        else if (type == MULTIPOINTTYPE)
127                strcpy(result,"MULTIPOINT");
128        else if (type == LINETYPE)
129                strcpy(result,"LINESTRING");
130        else if (type == CIRCSTRINGTYPE)
131                strcpy(result,"CIRCULARSTRING");
132        else if (type == COMPOUNDTYPE)
133                strcpy(result, "COMPOUNDCURVE");
134        else if (type == MULTILINETYPE)
135                strcpy(result,"MULTILINESTRING");
136        else if (type == MULTICURVETYPE)
137                strcpy(result, "MULTICURVE");
138        else if (type == POLYGONTYPE)
139                strcpy(result,"POLYGON");
140        else if (type == TRIANGLETYPE)
141                strcpy(result,"TRIANGLE");
142        else if (type == CURVEPOLYTYPE)
143                strcpy(result,"CURVEPOLYGON");
144        else if (type == MULTIPOLYGONTYPE)
145                strcpy(result,"MULTIPOLYGON");
146        else if (type == MULTISURFACETYPE)
147                strcpy(result, "MULTISURFACE");
148        else if (type == COLLECTIONTYPE)
149                strcpy(result,"GEOMETRYCOLLECTION");
150        else if (type == POLYHEDRALSURFACETYPE)
151                strcpy(result,"POLYHEDRALSURFACE");
152        else if (type == TINTYPE)
153                strcpy(result,"TIN");
154        else
155                strcpy(result,"UNKNOWN");
156
157        if ( gserialized_has_m(lwgeom) && ! gserialized_has_z(lwgeom) )
158                strcat(result, "M");
159
160        size = strlen(result) + VARHDRSZ ;
161        SET_VARSIZE(text_ob, size); /* size of string */
162
163        PG_FREE_IF_COPY(lwgeom, 0);
164
165        PG_RETURN_POINTER(text_ob);
166}
167
168
169/* returns a string representation of this geometry's type */
170PG_FUNCTION_INFO_V1(geometry_geometrytype);
171Datum geometry_geometrytype(PG_FUNCTION_ARGS)
172{
173        GSERIALIZED *lwgeom;
174        text *type_text;
175        char *type_str = palloc(32);
176
177        lwgeom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
178
179        /* Make it empty string to start */
180        *type_str = 0;
181
182        /* Build up the output string */
183        strncat(type_str, "ST_", 32);
184        strncat(type_str, lwtype_name(gserialized_get_type(lwgeom)), 32);
185       
186        /* Build a text type to store things in */
187        type_text = cstring2text(type_str);
188        pfree(type_str);
189
190        PG_FREE_IF_COPY(lwgeom, 0);
191        PG_RETURN_TEXT_P(type_text);
192}
193
194
195
196/**
197* numpoints(LINESTRING) -- return the number of points in the
198* linestring, or NULL if it is not a linestring
199*/
200PG_FUNCTION_INFO_V1(LWGEOM_numpoints_linestring);
201Datum LWGEOM_numpoints_linestring(PG_FUNCTION_ARGS)
202{
203        GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
204        LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
205        int count = -1;
206       
207        if ( lwgeom->type == LINETYPE )
208                count = lwgeom_count_vertices(lwgeom);
209
210        lwgeom_free(lwgeom);
211        PG_FREE_IF_COPY(geom, 0);
212
213        /* OGC says this functions is only valid on LINESTRING */
214        if ( count < 0 )
215                PG_RETURN_NULL();
216
217        PG_RETURN_INT32(count);
218}
219
220PG_FUNCTION_INFO_V1(LWGEOM_numgeometries_collection);
221Datum LWGEOM_numgeometries_collection(PG_FUNCTION_ARGS)
222{
223        GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
224        LWGEOM *lwgeom;
225        int32 ret = 1;
226
227        lwgeom = lwgeom_from_gserialized(geom);
228        if ( lwgeom_is_empty(lwgeom) )
229        {
230                ret = 0;
231        }
232        else if ( lwgeom_is_collection(lwgeom) )
233        {
234                LWCOLLECTION *col = lwgeom_as_lwcollection(lwgeom);
235                ret = col->ngeoms;
236        }
237        lwgeom_free(lwgeom);
238        PG_FREE_IF_COPY(geom, 0);
239        PG_RETURN_INT32(ret);
240}
241
242/** 1-based offset */
243PG_FUNCTION_INFO_V1(LWGEOM_geometryn_collection);
244Datum LWGEOM_geometryn_collection(PG_FUNCTION_ARGS)
245{
246        GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
247        GSERIALIZED *result;
248        int type = gserialized_get_type(geom);
249        int32 idx;
250        LWCOLLECTION *coll;
251        LWGEOM *subgeom;
252
253        POSTGIS_DEBUG(2, "LWGEOM_geometryn_collection called.");
254
255        /* elog(NOTICE, "GeometryN called"); */
256
257        idx = PG_GETARG_INT32(1);
258        idx -= 1; /* index is 1-based */
259
260        /* call is valid on multi* geoms only */
261        if (type==POINTTYPE || type==LINETYPE || type==CIRCSTRINGTYPE ||
262                type==COMPOUNDTYPE || type==POLYGONTYPE ||
263                type==CURVEPOLYTYPE || type==TRIANGLETYPE)
264        {
265                if ( idx == 0 ) PG_RETURN_POINTER(geom);
266                PG_RETURN_NULL();
267        }
268
269        coll = lwgeom_as_lwcollection(lwgeom_from_gserialized(geom));
270
271        if ( idx < 0 ) PG_RETURN_NULL();
272        if ( idx >= coll->ngeoms ) PG_RETURN_NULL();
273
274        subgeom = coll->geoms[idx];
275        subgeom->srid = coll->srid;
276
277        /* COMPUTE_BBOX==TAINTING */
278        if ( coll->bbox ) lwgeom_add_bbox(subgeom);
279
280        result = geometry_serialize(subgeom);
281
282        lwcollection_free(coll);
283        PG_FREE_IF_COPY(geom, 0);
284
285        PG_RETURN_POINTER(result);
286
287}
288
289
290/** @brief
291*               returns 0 for points, 1 for lines, 2 for polygons, 3 for volume.
292*               returns max dimension for a collection.
293*/
294PG_FUNCTION_INFO_V1(LWGEOM_dimension);
295Datum LWGEOM_dimension(PG_FUNCTION_ARGS)
296{
297        GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
298        LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
299        int dimension = -1;
300
301        dimension = lwgeom_dimension(lwgeom);
302        lwgeom_free(lwgeom);
303        PG_FREE_IF_COPY(geom, 0);
304       
305        if ( dimension < 0 )
306        {
307                elog(NOTICE, "Could not compute geometry dimensions");
308                PG_RETURN_NULL();
309        }
310
311        PG_RETURN_INT32(dimension);
312}
313
314
315/**
316 * exteriorRing(GEOMETRY) -- find the first polygon in GEOMETRY
317 *      @return its exterior ring (as a linestring).
318 *              Return NULL if there is no POLYGON(..) in (first level of) GEOMETRY.
319 */
320PG_FUNCTION_INFO_V1(LWGEOM_exteriorring_polygon);
321Datum LWGEOM_exteriorring_polygon(PG_FUNCTION_ARGS)
322{
323        GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
324        GSERIALIZED *result;
325        POINTARRAY *extring;
326        LWGEOM *lwgeom;
327        LWLINE *line;
328        GBOX *bbox=NULL;
329        int type = gserialized_get_type(geom);
330
331        POSTGIS_DEBUG(2, "LWGEOM_exteriorring_polygon called.");
332
333        if ( (type != POLYGONTYPE) &&
334             (type != CURVEPOLYTYPE) &&
335             (type != TRIANGLETYPE))
336        {
337                elog(ERROR, "ExteriorRing: geom is not a polygon");
338                PG_RETURN_NULL();
339        }
340       
341        lwgeom = lwgeom_from_gserialized(geom);
342       
343        if( lwgeom_is_empty(lwgeom) )
344        {
345                line = lwline_construct_empty(lwgeom->srid,
346                                              lwgeom_has_z(lwgeom),
347                                              lwgeom_has_m(lwgeom));
348                result = geometry_serialize(lwline_as_lwgeom(line));
349        }
350        else if ( lwgeom->type == POLYGONTYPE )
351        {
352                LWPOLY *poly = lwgeom_as_lwpoly(lwgeom);
353
354                /* Ok, now we have a polygon. Here is its exterior ring. */
355                extring = poly->rings[0];
356
357                /*
358                * This is a LWLINE constructed by exterior ring POINTARRAY
359                * If the input geom has a bbox, use it for
360                * the output geom, as exterior ring makes it up !
361                */
362                if ( poly->bbox )
363                        bbox = gbox_copy(poly->bbox);
364
365                line = lwline_construct(poly->srid, bbox, extring);
366                result = geometry_serialize((LWGEOM *)line);
367
368                lwgeom_release((LWGEOM *)line);
369        }
370        else if ( lwgeom->type == TRIANGLETYPE )
371        {
372                LWTRIANGLE *triangle = lwgeom_as_lwtriangle(lwgeom);
373
374                /*
375                * This is a LWLINE constructed by exterior ring POINTARRAY
376                * If the input geom has a bbox, use it for
377                * the output geom, as exterior ring makes it up !
378                */
379                if ( triangle->bbox )
380                        bbox = gbox_copy(triangle->bbox);
381                line = lwline_construct(triangle->srid, bbox, triangle->points);
382
383                result = geometry_serialize((LWGEOM *)line);
384
385                lwgeom_release((LWGEOM *)line);
386        }
387        else
388        {
389                LWCURVEPOLY *curvepoly = lwgeom_as_lwcurvepoly(lwgeom);
390                result = geometry_serialize(curvepoly->rings[0]);
391        }
392
393        lwgeom_free(lwgeom);
394        PG_FREE_IF_COPY(geom, 0);
395        PG_RETURN_POINTER(result);
396}
397
398/**
399* NumInteriorRings(GEOMETRY) defined for Polygon and
400* and CurvePolygon.
401*
402* @return the number of its interior rings (holes). NULL if not a polygon.
403*/
404PG_FUNCTION_INFO_V1(LWGEOM_numinteriorrings_polygon);
405Datum LWGEOM_numinteriorrings_polygon(PG_FUNCTION_ARGS)
406{
407        GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
408        LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
409        LWPOLY *poly = NULL;
410        LWCURVEPOLY *curvepoly = NULL;
411        int result = -1;
412
413        if ( lwgeom->type == POLYGONTYPE )
414        {
415                poly = lwgeom_as_lwpoly(lwgeom);
416                result = poly->nrings - 1;
417        }
418        else if ( lwgeom->type == CURVEPOLYTYPE )
419        {
420                curvepoly = lwgeom_as_lwcurvepoly(lwgeom);
421                result = curvepoly->nrings - 1;
422        }
423       
424        lwgeom_free(lwgeom);
425        PG_FREE_IF_COPY(geom, 0);
426       
427        if ( result < 0 )
428                PG_RETURN_NULL();
429
430        PG_RETURN_INT32(result);
431}
432
433/**
434 * InteriorRingN(GEOMETRY) -- find the first polygon in GEOMETRY, Index is 1-based.
435 * @return its Nth interior ring (as a linestring).
436 *              Return NULL if there is no POLYGON(..) in (first level of) GEOMETRY.
437 *
438 */
439PG_FUNCTION_INFO_V1(LWGEOM_interiorringn_polygon);
440Datum LWGEOM_interiorringn_polygon(PG_FUNCTION_ARGS)
441{
442        GSERIALIZED *geom;
443        int32 wanted_index;
444        LWCURVEPOLY *curvepoly = NULL;
445        LWPOLY *poly = NULL;
446        POINTARRAY *ring;
447        LWLINE *line;
448        LWGEOM *lwgeom;
449        GSERIALIZED *result;
450        GBOX *bbox = NULL;
451        int type;
452
453        POSTGIS_DEBUG(2, "LWGEOM_interierringn_polygon called.");
454
455        wanted_index = PG_GETARG_INT32(1);
456        if ( wanted_index < 1 )
457        {
458                /* elog(ERROR, "InteriorRingN: ring number is 1-based"); */
459                PG_RETURN_NULL(); /* index out of range */
460        }
461
462        geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
463        type = gserialized_get_type(geom);
464
465        if ( (type != POLYGONTYPE) && (type != CURVEPOLYTYPE) )
466        {
467                elog(ERROR, "InteriorRingN: geom is not a polygon");
468                PG_FREE_IF_COPY(geom, 0);
469                PG_RETURN_NULL();
470        }
471       
472        lwgeom = lwgeom_from_gserialized(geom);
473        if( lwgeom_is_empty(lwgeom) )
474        {
475                lwpoly_free(poly);
476                PG_FREE_IF_COPY(geom, 0);
477                PG_RETURN_NULL();
478        }
479       
480        if ( type == POLYGONTYPE)
481        {
482                poly = lwgeom_as_lwpoly(lwgeom_from_gserialized(geom));
483
484                /* Ok, now we have a polygon. Let's see if it has enough holes */
485                if ( wanted_index >= poly->nrings )
486                {
487                        lwpoly_free(poly);
488                        PG_FREE_IF_COPY(geom, 0);
489                        PG_RETURN_NULL();
490                }
491
492                ring = poly->rings[wanted_index];
493
494                /* COMPUTE_BBOX==TAINTING */
495                if ( poly->bbox )
496                {
497                        bbox = lwalloc(sizeof(GBOX));
498                        ptarray_calculate_gbox_cartesian(ring, bbox);
499                }
500
501                /* This is a LWLINE constructed by interior ring POINTARRAY */
502                line = lwline_construct(poly->srid, bbox, ring);
503
504
505                result = geometry_serialize((LWGEOM *)line);
506                lwline_release(line);
507                lwpoly_free(poly);
508        }
509        else
510        {
511                curvepoly = lwgeom_as_lwcurvepoly(lwgeom_from_gserialized(geom));
512
513                if (wanted_index >= curvepoly->nrings)
514                {
515                        PG_FREE_IF_COPY(geom, 0);
516                        lwgeom_release((LWGEOM *)curvepoly);
517                        PG_RETURN_NULL();
518                }
519
520                result = geometry_serialize(curvepoly->rings[wanted_index]);
521                lwgeom_free((LWGEOM*)curvepoly);
522        }
523
524        PG_FREE_IF_COPY(geom, 0);
525        PG_RETURN_POINTER(result);
526}
527
528/**
529 * PointN(GEOMETRY,INTEGER) -- find the first linestring in GEOMETRY,
530 * @return the point at index INTEGER (1 is 1st point).  Return NULL if
531 *              there is no LINESTRING(..) in GEOMETRY or INTEGER is out of bounds.
532 */
533PG_FUNCTION_INFO_V1(LWGEOM_pointn_linestring);
534Datum LWGEOM_pointn_linestring(PG_FUNCTION_ARGS)
535{
536        GSERIALIZED *geom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
537        int where = PG_GETARG_INT32(1);
538        LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
539        LWPOINT *lwpoint = NULL;
540        int type = lwgeom->type;
541       
542        /* Can't handle crazy index! */
543        if ( where < 1 )
544                PG_RETURN_NULL();
545
546        if ( type == LINETYPE || type == CIRCSTRINGTYPE )
547        {
548                /* OGC index starts at one, so we substract first. */
549                lwpoint = lwline_get_lwpoint((LWLINE*)lwgeom, where - 1);
550        }
551
552        lwgeom_free(lwgeom);
553        PG_FREE_IF_COPY(geom, 0);
554
555        if ( ! lwpoint )
556                PG_RETURN_NULL();
557
558        PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(lwpoint)));
559}
560
561/**
562 * X(GEOMETRY) -- return X value of the point.
563 * @return an error if input is not a point.
564 */
565PG_FUNCTION_INFO_V1(LWGEOM_x_point);
566Datum LWGEOM_x_point(PG_FUNCTION_ARGS)
567{
568        GSERIALIZED *geom;
569        LWGEOM *lwgeom;
570        LWPOINT *point = NULL;
571        POINT2D p;
572
573        geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
574
575        if ( gserialized_get_type(geom) != POINTTYPE )
576                lwerror("Argument to X() must be a point");
577
578        lwgeom = lwgeom_from_gserialized(geom);
579        point = lwgeom_as_lwpoint(lwgeom);
580       
581        if ( lwgeom_is_empty(lwgeom) )
582                PG_RETURN_NULL();
583
584        getPoint2d_p(point->point, 0, &p);
585
586        PG_FREE_IF_COPY(geom, 0);
587        PG_RETURN_FLOAT8(p.x);
588}
589
590/**
591 * Y(GEOMETRY) -- return Y value of the point.
592 *      Raise an error if input is not a point.
593 */
594PG_FUNCTION_INFO_V1(LWGEOM_y_point);
595Datum LWGEOM_y_point(PG_FUNCTION_ARGS)
596{
597        GSERIALIZED *geom;
598        LWPOINT *point = NULL;
599        LWGEOM *lwgeom;
600        POINT2D p;
601
602        geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
603
604        if ( gserialized_get_type(geom) != POINTTYPE )
605                lwerror("Argument to Y() must be a point");
606
607        lwgeom = lwgeom_from_gserialized(geom);
608        point = lwgeom_as_lwpoint(lwgeom);
609       
610        if ( lwgeom_is_empty(lwgeom) )
611                PG_RETURN_NULL();
612
613        getPoint2d_p(point->point, 0, &p);
614
615        PG_FREE_IF_COPY(geom, 0);
616
617        PG_RETURN_FLOAT8(p.y);
618}
619
620/**
621 * Z(GEOMETRY) -- return Z value of the point.
622 * @return NULL if there is no Z in the point.
623 *              Raise an error if input is not a point.
624 */
625PG_FUNCTION_INFO_V1(LWGEOM_z_point);
626Datum LWGEOM_z_point(PG_FUNCTION_ARGS)
627{
628        GSERIALIZED *geom;
629        LWPOINT *point = NULL;
630        LWGEOM *lwgeom;
631        POINT3DZ p;
632
633        geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
634
635        if ( gserialized_get_type(geom) != POINTTYPE )
636                lwerror("Argument to Z() must be a point");
637
638        lwgeom = lwgeom_from_gserialized(geom);
639        point = lwgeom_as_lwpoint(lwgeom);
640       
641        if ( lwgeom_is_empty(lwgeom) )
642                PG_RETURN_NULL();
643
644        /* no Z in input */
645        if ( ! gserialized_has_z(geom) ) PG_RETURN_NULL();
646
647        getPoint3dz_p(point->point, 0, &p);
648
649        PG_FREE_IF_COPY(geom, 0);
650
651        PG_RETURN_FLOAT8(p.z);
652}
653
654/**  M(GEOMETRY) -- find the first POINT(..) in GEOMETRY, returns its M value.
655 * @return NULL if there is no POINT(..) in GEOMETRY.
656 *              Return NULL if there is no M in this geometry.
657 */
658PG_FUNCTION_INFO_V1(LWGEOM_m_point);
659Datum LWGEOM_m_point(PG_FUNCTION_ARGS)
660{
661        GSERIALIZED *geom;
662        LWPOINT *point = NULL;
663        LWGEOM *lwgeom;
664        POINT3DM p;
665
666        geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
667
668        if ( gserialized_get_type(geom) != POINTTYPE )
669                lwerror("Argument to M() must be a point");
670
671        lwgeom = lwgeom_from_gserialized(geom);
672        point = lwgeom_as_lwpoint(lwgeom);
673       
674        if ( lwgeom_is_empty(lwgeom) )
675                PG_RETURN_NULL();
676
677        /* no M in input */
678        if ( ! FLAGS_GET_M(point->flags) ) PG_RETURN_NULL();
679
680        getPoint3dm_p(point->point, 0, &p);
681
682        PG_FREE_IF_COPY(geom, 0);
683
684        PG_RETURN_FLOAT8(p.m);
685}
686
687/**
688* ST_StartPoint(GEOMETRY)
689* @return the first point of a linestring.
690*               Return NULL if there is no LINESTRING
691*/
692PG_FUNCTION_INFO_V1(LWGEOM_startpoint_linestring);
693Datum LWGEOM_startpoint_linestring(PG_FUNCTION_ARGS)
694{
695        GSERIALIZED *geom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
696        LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
697        LWPOINT *lwpoint = NULL;
698        int type = lwgeom->type;
699
700        if ( type == LINETYPE || type == CIRCSTRINGTYPE )
701        {
702                lwpoint = lwline_get_lwpoint((LWLINE*)lwgeom, 0);
703        }
704
705        lwgeom_free(lwgeom);
706        PG_FREE_IF_COPY(geom, 0);
707
708        if ( ! lwpoint )
709                PG_RETURN_NULL();
710
711        PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(lwpoint)));
712}
713
714/** EndPoint(GEOMETRY) -- find the first linestring in GEOMETRY,
715 * @return the last point.
716 *      Return NULL if there is no LINESTRING(..) in GEOMETRY
717 */
718PG_FUNCTION_INFO_V1(LWGEOM_endpoint_linestring);
719Datum LWGEOM_endpoint_linestring(PG_FUNCTION_ARGS)
720{
721        GSERIALIZED *geom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
722        LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
723        LWPOINT *lwpoint = NULL;
724        int type = lwgeom->type;
725
726        if ( type == LINETYPE || type == CIRCSTRINGTYPE )
727        {
728                LWLINE *line = (LWLINE*)lwgeom;
729                if ( line->points )
730                        lwpoint = lwline_get_lwpoint((LWLINE*)lwgeom, line->points->npoints - 1);
731        }
732
733        lwgeom_free(lwgeom);
734        PG_FREE_IF_COPY(geom, 0);
735
736        if ( ! lwpoint )
737                PG_RETURN_NULL();
738
739        PG_RETURN_POINTER(geometry_serialize(lwpoint_as_lwgeom(lwpoint)));
740}
741
742/**
743 * @brief Returns a geometry Given an OGC WKT (and optionally a SRID)
744 * @return a geometry.
745 * @note Note that this is a a stricter version
746 *              of geometry_in, where we refuse to
747 *              accept (HEX)WKB or EWKT.
748 */
749PG_FUNCTION_INFO_V1(LWGEOM_from_text);
750Datum LWGEOM_from_text(PG_FUNCTION_ARGS)
751{
752        text *wkttext = PG_GETARG_TEXT_P(0);
753        char *wkt = text2cstring(wkttext);
754        LWGEOM_PARSER_RESULT lwg_parser_result;
755        GSERIALIZED *geom_result = NULL;
756        LWGEOM *lwgeom;
757
758        POSTGIS_DEBUG(2, "LWGEOM_from_text");
759        POSTGIS_DEBUGF(3, "wkt: [%s]", wkt);
760
761        if (lwgeom_parse_wkt(&lwg_parser_result, wkt, LW_PARSER_CHECK_ALL) == LW_FAILURE)
762                PG_PARSER_ERROR(lwg_parser_result);
763
764        lwgeom = lwg_parser_result.geom;
765
766        if ( lwgeom->srid != SRID_UNKNOWN )
767        {
768                elog(WARNING, "OGC WKT expected, EWKT provided - use GeomFromEWKT() for this");
769        }
770
771        /* read user-requested SRID if any */
772        if ( PG_NARGS() > 1 )
773                lwgeom_set_srid(lwgeom, PG_GETARG_INT32(1));
774
775        geom_result = geometry_serialize(lwgeom);
776        lwgeom_parser_result_free(&lwg_parser_result);
777
778        PG_RETURN_POINTER(geom_result);
779}
780
781/**
782 * Given an OGC WKB (and optionally a SRID)
783 *              return a geometry.
784 *
785 * @note that this is a wrapper around
786 *              LWGEOMFromWKB, where we refuse to
787 *              accept EWKB.
788 */
789PG_FUNCTION_INFO_V1(LWGEOM_from_WKB);
790Datum LWGEOM_from_WKB(PG_FUNCTION_ARGS)
791{
792        GSERIALIZED *geom;
793        int32 srid;
794        GSERIALIZED *result = NULL;
795
796        geom = (GSERIALIZED *)DatumGetPointer(DirectFunctionCall1(
797                                                LWGEOMFromWKB, PG_GETARG_DATUM(0)));
798
799        if ( gserialized_get_srid(geom) != SRID_UNKNOWN )
800        {
801                elog(WARNING, "OGC WKB expected, EWKB provided - use GeometryFromEWKB() for this");
802        }
803
804
805        /* read user-requested SRID if any */
806        if ( PG_NARGS() > 1 )
807        {
808                srid = PG_GETARG_INT32(1);
809                if ( srid != gserialized_get_srid(geom) )
810                        gserialized_set_srid(geom, srid);
811        }
812
813        if ( ! result ) result = geom;
814
815        PG_RETURN_POINTER(result);
816}
817
818/** convert LWGEOM to wkt (in TEXT format) */
819PG_FUNCTION_INFO_V1(LWGEOM_asText);
820Datum LWGEOM_asText(PG_FUNCTION_ARGS)
821{
822        GSERIALIZED *geom;
823        LWGEOM *lwgeom;
824        char *wkt;
825        size_t wkt_size;
826        text *result;
827
828        POSTGIS_DEBUG(2, "Called.");
829
830        geom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
831        lwgeom = lwgeom_from_gserialized(geom);
832
833        /* Write to WKT and free the geometry */
834        wkt = lwgeom_to_wkt(lwgeom, WKT_ISO, DBL_DIG, &wkt_size);
835        lwgeom_free(lwgeom);
836        POSTGIS_DEBUGF(3, "WKT size = %d, WKT length = %d", wkt_size, strlen(wkt));
837
838        /* Write to text and free the WKT */
839        result = cstring2text(wkt);
840        pfree(wkt);
841
842        /* Return the text */
843        PG_FREE_IF_COPY(geom, 0);
844        PG_RETURN_TEXT_P(result);
845}
846
847
848/** convert LWGEOM to wkb (in BINARY format) */
849PG_FUNCTION_INFO_V1(LWGEOM_asBinary);
850Datum LWGEOM_asBinary(PG_FUNCTION_ARGS)
851{
852        GSERIALIZED *geom;
853        LWGEOM *lwgeom;
854        uint8_t *wkb;
855        size_t wkb_size;
856        bytea *result;
857        uint8_t variant = WKB_ISO;
858
859        /* Get a 2D version of the geometry */
860        geom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
861        lwgeom = lwgeom_from_gserialized(geom);
862
863        /* If user specified endianness, respect it */
864        if ( (PG_NARGS()>1) && (!PG_ARGISNULL(1)) )
865        {
866                text *wkb_endian = PG_GETARG_TEXT_P(1);
867
868                if  ( ! strncmp(VARDATA(wkb_endian), "xdr", 3) ||
869                      ! strncmp(VARDATA(wkb_endian), "XDR", 3) )
870                {
871                        variant = variant | WKB_XDR;
872                }
873                else
874                {
875                        variant = variant | WKB_NDR;
876                }
877        }
878       
879        /* Write to WKB and free the geometry */
880        wkb = lwgeom_to_wkb(lwgeom, variant, &wkb_size);
881        lwgeom_free(lwgeom);
882
883        /* Write to text and free the WKT */
884        result = palloc(wkb_size + VARHDRSZ);
885        memcpy(VARDATA(result), wkb, wkb_size);
886        SET_VARSIZE(result, wkb_size + VARHDRSZ);
887        pfree(wkb);
888
889        /* Return the text */
890        PG_FREE_IF_COPY(geom, 0);
891        PG_RETURN_BYTEA_P(result);
892}
893
894
895
896/**
897 * @brief IsClosed(GEOMETRY) if geometry is a linestring then returns
898 *              startpoint == endpoint.  If its not a linestring then return NULL.
899 *              If it's a collection containing multiple linestrings,
900 * @return true only if all the linestrings have startpoint=endpoint.
901 */
902PG_FUNCTION_INFO_V1(LWGEOM_isclosed);
903Datum LWGEOM_isclosed(PG_FUNCTION_ARGS)
904{
905        GSERIALIZED *geom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
906        LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
907        int closed = lwgeom_is_closed(lwgeom);
908       
909        lwgeom_free(lwgeom);
910        PG_FREE_IF_COPY(geom, 0);
911        PG_RETURN_BOOL(closed);
912}       
Note: See TracBrowser for help on using the browser.