PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
lwgeom_functions_basic.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-2006 Refractions Research Inc.
22 * Copyright 2017-2018 Daniel Baston <dbaston@gmail.com>
23 *
24 **********************************************************************/
25
26#include "postgres.h"
27#include "fmgr.h"
28#include "utils/array.h"
29#include "utils/builtins.h"
30#include "utils/elog.h"
31#include "utils/geo_decls.h"
32
33#include "../postgis_config.h"
34#include "liblwgeom.h"
35#include "liblwgeom_internal.h"
36#include "lwgeom_pg.h"
37
38#include <math.h>
39#include <float.h>
40#include <string.h>
41#include <stdio.h>
42
43#define xstr(s) str(s)
44#define str(s) #s
45
46Datum LWGEOM_mem_size(PG_FUNCTION_ARGS);
47Datum LWGEOM_summary(PG_FUNCTION_ARGS);
48Datum LWGEOM_npoints(PG_FUNCTION_ARGS);
49Datum LWGEOM_nrings(PG_FUNCTION_ARGS);
50Datum ST_Area(PG_FUNCTION_ARGS);
51Datum postgis_scripts_released(PG_FUNCTION_ARGS);
52Datum postgis_version(PG_FUNCTION_ARGS);
53Datum postgis_liblwgeom_version(PG_FUNCTION_ARGS);
54Datum postgis_lib_version(PG_FUNCTION_ARGS);
55Datum postgis_svn_version(PG_FUNCTION_ARGS);
56Datum postgis_lib_revision(PG_FUNCTION_ARGS);
57Datum postgis_libxml_version(PG_FUNCTION_ARGS);
58Datum postgis_lib_build_date(PG_FUNCTION_ARGS);
59Datum LWGEOM_length2d_linestring(PG_FUNCTION_ARGS);
60Datum LWGEOM_length_linestring(PG_FUNCTION_ARGS);
61Datum LWGEOM_perimeter2d_poly(PG_FUNCTION_ARGS);
62Datum LWGEOM_perimeter_poly(PG_FUNCTION_ARGS);
63
64Datum LWGEOM_maxdistance2d_linestring(PG_FUNCTION_ARGS);
65Datum ST_Distance(PG_FUNCTION_ARGS);
66Datum LWGEOM_closestpoint(PG_FUNCTION_ARGS);
67Datum LWGEOM_shortestline2d(PG_FUNCTION_ARGS);
68Datum LWGEOM_longestline2d(PG_FUNCTION_ARGS);
69Datum LWGEOM_dwithin(PG_FUNCTION_ARGS);
70
71Datum LWGEOM_maxdistance3d(PG_FUNCTION_ARGS);
72Datum LWGEOM_mindistance3d(PG_FUNCTION_ARGS);
73Datum LWGEOM_closestpoint3d(PG_FUNCTION_ARGS);
74Datum LWGEOM_shortestline3d(PG_FUNCTION_ARGS);
75Datum LWGEOM_longestline3d(PG_FUNCTION_ARGS);
76Datum LWGEOM_dwithin3d(PG_FUNCTION_ARGS);
77Datum LWGEOM_dfullywithin3d(PG_FUNCTION_ARGS);
78
79Datum LWGEOM_inside_circle_point(PG_FUNCTION_ARGS);
80Datum LWGEOM_collect(PG_FUNCTION_ARGS);
81Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS);
82Datum LWGEOM_expand(PG_FUNCTION_ARGS);
83Datum LWGEOM_to_BOX(PG_FUNCTION_ARGS);
84Datum LWGEOM_envelope(PG_FUNCTION_ARGS);
85Datum LWGEOM_isempty(PG_FUNCTION_ARGS);
86Datum LWGEOM_segmentize2d(PG_FUNCTION_ARGS);
87Datum LWGEOM_reverse(PG_FUNCTION_ARGS);
88Datum LWGEOM_force_clockwise_poly(PG_FUNCTION_ARGS);
89Datum LWGEOM_force_sfs(PG_FUNCTION_ARGS);
90Datum LWGEOM_noop(PG_FUNCTION_ARGS);
91Datum LWGEOM_zmflag(PG_FUNCTION_ARGS);
92Datum LWGEOM_hasz(PG_FUNCTION_ARGS);
93Datum LWGEOM_hasm(PG_FUNCTION_ARGS);
94Datum LWGEOM_ndims(PG_FUNCTION_ARGS);
95Datum LWGEOM_makepoint(PG_FUNCTION_ARGS);
96Datum LWGEOM_makepoint3dm(PG_FUNCTION_ARGS);
97Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS);
98Datum LWGEOM_makeline(PG_FUNCTION_ARGS);
99Datum LWGEOM_makepoly(PG_FUNCTION_ARGS);
100Datum LWGEOM_line_from_mpoint(PG_FUNCTION_ARGS);
101Datum LWGEOM_addpoint(PG_FUNCTION_ARGS);
102Datum LWGEOM_removepoint(PG_FUNCTION_ARGS);
103Datum LWGEOM_setpoint_linestring(PG_FUNCTION_ARGS);
104Datum LWGEOM_asEWKT(PG_FUNCTION_ARGS);
105Datum LWGEOM_hasBBOX(PG_FUNCTION_ARGS);
106Datum LWGEOM_azimuth(PG_FUNCTION_ARGS);
107Datum geometry_project_direction(PG_FUNCTION_ARGS);
108Datum geometry_project_geometry(PG_FUNCTION_ARGS);
109Datum geometry_line_extend(PG_FUNCTION_ARGS);
110Datum LWGEOM_angle(PG_FUNCTION_ARGS);
111Datum LWGEOM_affine(PG_FUNCTION_ARGS);
112Datum LWGEOM_longitude_shift(PG_FUNCTION_ARGS);
113Datum optimistic_overlap(PG_FUNCTION_ARGS);
114Datum ST_GeoHash(PG_FUNCTION_ARGS);
115Datum ST_MakeEnvelope(PG_FUNCTION_ARGS);
116Datum ST_TileEnvelope(PG_FUNCTION_ARGS);
117Datum ST_CollectionExtract(PG_FUNCTION_ARGS);
118Datum ST_CollectionHomogenize(PG_FUNCTION_ARGS);
119Datum ST_IsCollection(PG_FUNCTION_ARGS);
120Datum ST_QuantizeCoordinates(PG_FUNCTION_ARGS);
121Datum ST_WrapX(PG_FUNCTION_ARGS);
122Datum ST_Scroll(PG_FUNCTION_ARGS);
123Datum LWGEOM_FilterByM(PG_FUNCTION_ARGS);
124Datum ST_Point(PG_FUNCTION_ARGS);
125Datum ST_PointZ(PG_FUNCTION_ARGS);
126Datum ST_PointM(PG_FUNCTION_ARGS);
127Datum ST_PointZM(PG_FUNCTION_ARGS);
128
129/*------------------------------------------------------------------*/
130
133Datum LWGEOM_mem_size(PG_FUNCTION_ARGS)
134{
135 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
136 size_t size = VARSIZE(geom);
137 PG_FREE_IF_COPY(geom, 0);
138 PG_RETURN_INT32(size);
139}
140
143Datum LWGEOM_summary(PG_FUNCTION_ARGS)
144{
145 text *summary;
146 GSERIALIZED *g = PG_GETARG_GSERIALIZED_P(0);
148 char *lwresult = lwgeom_summary(lwg, 0);
149 uint32_t gver = gserialized_get_version(g);
150 size_t result_sz = strlen(lwresult) + 8;
151 char *result;
152 if (gver == 0)
153 {
154 result = lwalloc(result_sz + 2);
155 snprintf(result, result_sz, "0:%s", lwresult);
156 }
157 else
158 {
159 result = lwalloc(result_sz);
160 snprintf(result, result_sz, "%s", lwresult);
161 }
162 lwgeom_free(lwg);
163 lwfree(lwresult);
164
165 /* create a text obj to return */
166 summary = cstring_to_text(result);
167 lwfree(result);
168
169 PG_FREE_IF_COPY(g, 0);
170 PG_RETURN_TEXT_P(summary);
171}
172
174Datum postgis_version(PG_FUNCTION_ARGS)
175{
176 char *ver = POSTGIS_VERSION;
177 text *result = cstring_to_text(ver);
178 PG_RETURN_TEXT_P(result);
179}
180
182Datum postgis_liblwgeom_version(PG_FUNCTION_ARGS)
183{
184 const char *ver = lwgeom_version();
185 text *result = cstring_to_text(ver);
186 PG_RETURN_TEXT_P(result);
187}
188
190Datum postgis_lib_version(PG_FUNCTION_ARGS)
191{
192 char *ver = POSTGIS_LIB_VERSION;
193 text *result = cstring_to_text(ver);
194 PG_RETURN_TEXT_P(result);
195}
196
198Datum postgis_lib_revision(PG_FUNCTION_ARGS)
199{
200 static char *rev = xstr(POSTGIS_REVISION);
201 char ver[32];
202 if (rev && rev[0] != '\0')
203 {
204 snprintf(ver, 32, "%s", rev);
205 ver[31] = '\0';
206 PG_RETURN_TEXT_P(cstring_to_text(ver));
207 }
208 else PG_RETURN_NULL();
209}
210
212Datum postgis_lib_build_date(PG_FUNCTION_ARGS)
213{
214 char *ver = POSTGIS_BUILD_DATE;
215 text *result = cstring_to_text(ver);
216 PG_RETURN_TEXT_P(result);
217}
218
220Datum postgis_scripts_released(PG_FUNCTION_ARGS)
221{
222 char ver[64];
223 text *result;
224
225 snprintf(ver, 64, "%s %s", POSTGIS_LIB_VERSION, xstr(POSTGIS_REVISION));
226 ver[63] = '\0';
227
228 result = cstring_to_text(ver);
229 PG_RETURN_TEXT_P(result);
230}
231
233Datum postgis_libxml_version(PG_FUNCTION_ARGS)
234{
235 char *ver = POSTGIS_LIBXML2_VERSION;
236 text *result = cstring_to_text(ver);
237 PG_RETURN_TEXT_P(result);
238}
239
242Datum LWGEOM_npoints(PG_FUNCTION_ARGS)
243{
244 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
245 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
246 int npoints = 0;
247
248 npoints = lwgeom_count_vertices(lwgeom);
249 lwgeom_free(lwgeom);
250
251 PG_FREE_IF_COPY(geom, 0);
252 PG_RETURN_INT32(npoints);
253}
254
257Datum LWGEOM_nrings(PG_FUNCTION_ARGS)
258{
259 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
260 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
261 int nrings = 0;
262
263 nrings = lwgeom_count_rings(lwgeom);
264 lwgeom_free(lwgeom);
265
266 PG_FREE_IF_COPY(geom, 0);
267 PG_RETURN_INT32(nrings);
268}
269
277Datum ST_Area(PG_FUNCTION_ARGS)
278{
279 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
280 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
281 double area = 0.0;
282
283 area = lwgeom_area(lwgeom);
284
285 lwgeom_free(lwgeom);
286 PG_FREE_IF_COPY(geom, 0);
287
288 PG_RETURN_FLOAT8(area);
289}
290
299Datum LWGEOM_length2d_linestring(PG_FUNCTION_ARGS)
300{
301 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
302 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
303 double dist = lwgeom_length_2d(lwgeom);
304 lwgeom_free(lwgeom);
305 PG_FREE_IF_COPY(geom, 0);
306 PG_RETURN_FLOAT8(dist);
307}
308
317Datum LWGEOM_length_linestring(PG_FUNCTION_ARGS)
318{
319 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
320 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
321 double dist = lwgeom_length(lwgeom);
322 lwgeom_free(lwgeom);
323 PG_FREE_IF_COPY(geom, 0);
324 PG_RETURN_FLOAT8(dist);
325}
326
335Datum LWGEOM_perimeter_poly(PG_FUNCTION_ARGS)
336{
337 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
338 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
339 double perimeter = 0.0;
340
341 perimeter = lwgeom_perimeter(lwgeom);
342 PG_FREE_IF_COPY(geom, 0);
343 PG_RETURN_FLOAT8(perimeter);
344}
345
354Datum LWGEOM_perimeter2d_poly(PG_FUNCTION_ARGS)
355{
356 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
357 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
358 double perimeter = 0.0;
359
360 perimeter = lwgeom_perimeter_2d(lwgeom);
361 PG_FREE_IF_COPY(geom, 0);
362 PG_RETURN_FLOAT8(perimeter);
363}
364
365/* transform input geometry to 2d if not 2d already */
367Datum LWGEOM_force_2d(PG_FUNCTION_ARGS)
368{
369 GSERIALIZED *pg_geom_in = PG_GETARG_GSERIALIZED_P(0);
370 GSERIALIZED *pg_geom_out;
371 LWGEOM *lwg_in, *lwg_out;
372
373 /* already 2d */
374 if (gserialized_ndims(pg_geom_in) == 2)
375 PG_RETURN_POINTER(pg_geom_in);
376
377 lwg_in = lwgeom_from_gserialized(pg_geom_in);
378 lwg_out = lwgeom_force_2d(lwg_in);
379 pg_geom_out = geometry_serialize(lwg_out);
380 lwgeom_free(lwg_out);
381 lwgeom_free(lwg_in);
382
383 PG_FREE_IF_COPY(pg_geom_in, 0);
384 PG_RETURN_POINTER(pg_geom_out);
385}
386
387/* transform input geometry to 3dz if not 3dz already */
389Datum LWGEOM_force_3dz(PG_FUNCTION_ARGS)
390{
391 GSERIALIZED *pg_geom_in = PG_GETARG_GSERIALIZED_P(0);
392 GSERIALIZED *pg_geom_out;
393 LWGEOM *lwg_in, *lwg_out;
394 double z = PG_NARGS() < 2 ? 0 : PG_GETARG_FLOAT8(1);
395
396 /* already 3d */
397 if (gserialized_ndims(pg_geom_in) == 3 && gserialized_has_z(pg_geom_in))
398 PG_RETURN_POINTER(pg_geom_in);
399
400 lwg_in = lwgeom_from_gserialized(pg_geom_in);
401 lwg_out = lwgeom_force_3dz(lwg_in, z);
402 pg_geom_out = geometry_serialize(lwg_out);
403 lwgeom_free(lwg_out);
404 lwgeom_free(lwg_in);
405
406 PG_FREE_IF_COPY(pg_geom_in, 0);
407 PG_RETURN_POINTER(pg_geom_out);
408}
409
412Datum LWGEOM_force_3dm(PG_FUNCTION_ARGS)
413{
414 GSERIALIZED *pg_geom_in = PG_GETARG_GSERIALIZED_P(0);
415 GSERIALIZED *pg_geom_out;
416 LWGEOM *lwg_in, *lwg_out;
417 double m = PG_NARGS() < 2 ? 0 : PG_GETARG_FLOAT8(1);
418
419 /* already 3d */
420 if (gserialized_ndims(pg_geom_in) == 3 && gserialized_has_m(pg_geom_in))
421 PG_RETURN_POINTER(pg_geom_in);
422
423 lwg_in = lwgeom_from_gserialized(pg_geom_in);
424 lwg_out = lwgeom_force_3dm(lwg_in, m);
425 pg_geom_out = geometry_serialize(lwg_out);
426 lwgeom_free(lwg_out);
427 lwgeom_free(lwg_in);
428
429 PG_FREE_IF_COPY(pg_geom_in, 0);
430 PG_RETURN_POINTER(pg_geom_out);
431}
432
433/* transform input geometry to 4d if not 4d already */
435Datum LWGEOM_force_4d(PG_FUNCTION_ARGS)
436{
437 GSERIALIZED *pg_geom_in = PG_GETARG_GSERIALIZED_P(0);
438 GSERIALIZED *pg_geom_out;
439 LWGEOM *lwg_in, *lwg_out;
440 double z = PG_NARGS() < 3 ? 0 : PG_GETARG_FLOAT8(1);
441 double m = PG_NARGS() < 3 ? 0 : PG_GETARG_FLOAT8(2);
442
443 /* already 4d */
444 if (gserialized_ndims(pg_geom_in) == 4)
445 PG_RETURN_POINTER(pg_geom_in);
446
447 lwg_in = lwgeom_from_gserialized(pg_geom_in);
448 lwg_out = lwgeom_force_4d(lwg_in, z, m);
449 pg_geom_out = geometry_serialize(lwg_out);
450 lwgeom_free(lwg_out);
451 lwgeom_free(lwg_in);
452
453 PG_FREE_IF_COPY(pg_geom_in, 0);
454 PG_RETURN_POINTER(pg_geom_out);
455}
456
459Datum LWGEOM_force_collection(PG_FUNCTION_ARGS)
460{
461 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
463 LWGEOM **lwgeoms;
464 LWGEOM *lwgeom;
465 int32_t srid;
466 GBOX *bbox;
467
468 POSTGIS_DEBUG(2, "LWGEOM_force_collection called");
469
470 /*
471 * This funx is a no-op only if a bbox cache is already present
472 * in input. If bbox cache is not there we'll need to handle
473 * automatic bbox addition FOR_COMPLEX_GEOMS.
474 */
476 {
477 PG_RETURN_POINTER(geom);
478 }
479
480 /* deserialize into lwgeoms[0] */
481 lwgeom = lwgeom_from_gserialized(geom);
482
483 /* already a multi*, just make it a collection */
484 if (lwgeom_is_collection(lwgeom))
485 {
486 lwgeom->type = COLLECTIONTYPE;
487 }
488
489 /* single geom, make it a collection */
490 else
491 {
492 srid = lwgeom->srid;
493 /* We transfer bbox ownership from input to output */
494 bbox = lwgeom->bbox;
495 lwgeom->srid = SRID_UNKNOWN;
496 lwgeom->bbox = NULL;
497 lwgeoms = palloc(sizeof(LWGEOM *));
498 lwgeoms[0] = lwgeom;
499 lwgeom = (LWGEOM *)lwcollection_construct(COLLECTIONTYPE, srid, bbox, 1, lwgeoms);
500 }
501
502 result = geometry_serialize(lwgeom);
503 lwgeom_free(lwgeom);
504
505 PG_FREE_IF_COPY(geom, 0);
506 PG_RETURN_POINTER(result);
507}
508
511Datum LWGEOM_force_multi(PG_FUNCTION_ARGS)
512{
513 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
515 LWGEOM *lwgeom;
516 LWGEOM *ogeom;
517
518 POSTGIS_DEBUG(2, "LWGEOM_force_multi called");
519
520 /*
521 ** This funx is a no-op only if a bbox cache is already present
522 ** in input. If bbox cache is not there we'll need to handle
523 ** automatic bbox addition FOR_COMPLEX_GEOMS.
524 */
525 if (gserialized_has_bbox(geom))
526 {
527 switch (gserialized_get_type(geom))
528 {
529 case MULTIPOINTTYPE:
530 case MULTILINETYPE:
531 case MULTIPOLYGONTYPE:
532 case COLLECTIONTYPE:
533 case MULTICURVETYPE:
534 case MULTISURFACETYPE:
535 case TINTYPE:
536 PG_RETURN_POINTER(geom);
537 default:
538 break;
539 }
540 }
541
542 /* deserialize into lwgeoms[0] */
543 lwgeom = lwgeom_from_gserialized(geom);
544 ogeom = lwgeom_as_multi(lwgeom);
545
546 result = geometry_serialize(ogeom);
547
548 PG_FREE_IF_COPY(geom, 0);
549
550 PG_RETURN_POINTER(result);
551}
552
555Datum LWGEOM_force_curve(PG_FUNCTION_ARGS)
556{
557 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
559 LWGEOM *lwgeom;
560 LWGEOM *ogeom;
561
562 POSTGIS_DEBUG(2, "LWGEOM_force_curve called");
563
564 /* TODO: early out if input is already a curve */
565
566 lwgeom = lwgeom_from_gserialized(geom);
567 ogeom = lwgeom_as_curve(lwgeom);
568
569 result = geometry_serialize(ogeom);
570
571 PG_FREE_IF_COPY(geom, 0);
572
573 PG_RETURN_POINTER(result);
574}
575
578Datum LWGEOM_force_sfs(PG_FUNCTION_ARGS)
579{
580 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
582 LWGEOM *lwgeom;
583 LWGEOM *ogeom;
584 text *ver;
585 int version = 110; /* default version is SFS 1.1 */
586
587 POSTGIS_DEBUG(2, "LWGEOM_force_sfs called");
588
589 /* If user specified version, respect it */
590 if ((PG_NARGS() > 1) && (!PG_ARGISNULL(1)))
591 {
592 ver = PG_GETARG_TEXT_P(1);
593
594 if (!strncmp(VARDATA(ver), "1.2", 3))
595 {
596 version = 120;
597 }
598 }
599
600 lwgeom = lwgeom_from_gserialized(geom);
601 ogeom = lwgeom_force_sfs(lwgeom, version);
602
603 result = geometry_serialize(ogeom);
604
605 PG_FREE_IF_COPY(geom, 0);
606
607 PG_RETURN_POINTER(result);
608}
609
615Datum LWGEOM_closestpoint(PG_FUNCTION_ARGS)
616{
618 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
619 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
620 LWGEOM *point;
621 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
622 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
623 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
624
625 point = lwgeom_closest_point(lwgeom1, lwgeom2);
626
627 if (lwgeom_is_empty(point))
628 PG_RETURN_NULL();
629
630 result = geometry_serialize(point);
631 lwgeom_free(point);
632 lwgeom_free(lwgeom1);
633 lwgeom_free(lwgeom2);
634
635 PG_FREE_IF_COPY(geom1, 0);
636 PG_FREE_IF_COPY(geom2, 1);
637 PG_RETURN_POINTER(result);
638}
639
644Datum LWGEOM_shortestline2d(PG_FUNCTION_ARGS)
645{
647 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
648 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
649 LWGEOM *theline;
650 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
651 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
652 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
653
654 theline = lwgeom_closest_line(lwgeom1, lwgeom2);
655
656 if (lwgeom_is_empty(theline))
657 PG_RETURN_NULL();
658
659 result = geometry_serialize(theline);
660 lwgeom_free(theline);
661 lwgeom_free(lwgeom1);
662 lwgeom_free(lwgeom2);
663
664 PG_FREE_IF_COPY(geom1, 0);
665 PG_FREE_IF_COPY(geom2, 1);
666 PG_RETURN_POINTER(result);
667}
668
673Datum LWGEOM_longestline2d(PG_FUNCTION_ARGS)
674{
676 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
677 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
678 LWGEOM *theline;
679 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
680 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
681 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
682
683 theline = lwgeom_furthest_line(lwgeom1, lwgeom2);
684
685 if (lwgeom_is_empty(theline))
686 PG_RETURN_NULL();
687
688 result = geometry_serialize(theline);
689 lwgeom_free(theline);
690 lwgeom_free(lwgeom1);
691 lwgeom_free(lwgeom2);
692
693 PG_FREE_IF_COPY(geom1, 0);
694 PG_FREE_IF_COPY(geom2, 1);
695 PG_RETURN_POINTER(result);
696}
701Datum ST_Distance(PG_FUNCTION_ARGS)
702{
703 double mindist;
704 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
705 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
706 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
707 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
708 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
709
710 mindist = lwgeom_mindistance2d(lwgeom1, lwgeom2);
711
712 lwgeom_free(lwgeom1);
713 lwgeom_free(lwgeom2);
714
715 PG_FREE_IF_COPY(geom1, 0);
716 PG_FREE_IF_COPY(geom2, 1);
717
718 /* if called with empty geometries the ingoing mindistance is untouched, and makes us return NULL*/
719 if (mindist < FLT_MAX)
720 PG_RETURN_FLOAT8(mindist);
721
722 PG_RETURN_NULL();
723}
724
731Datum LWGEOM_dwithin(PG_FUNCTION_ARGS)
732{
733 double mindist;
734 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
735 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
736 double tolerance = PG_GETARG_FLOAT8(2);
737 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
738 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
739
740 if (tolerance < 0)
741 {
742 elog(ERROR, "Tolerance cannot be less than zero\n");
743 PG_RETURN_NULL();
744 }
745
746 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
747
748 if (lwgeom_is_empty(lwgeom1) || lwgeom_is_empty(lwgeom2))
749 {
750 PG_RETURN_BOOL(false);
751 }
752
753 mindist = lwgeom_mindistance2d_tolerance(lwgeom1, lwgeom2, tolerance);
754
755 PG_FREE_IF_COPY(geom1, 0);
756 PG_FREE_IF_COPY(geom2, 1);
757 /*empty geometries cases should be right handled since return from underlying
758 functions should be FLT_MAX which causes false as answer*/
759 PG_RETURN_BOOL(tolerance >= mindist);
760}
761
766Datum LWGEOM_maxdistance2d_linestring(PG_FUNCTION_ARGS)
767{
768 double maxdist;
769 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
770 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
771 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
772 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
773 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
774
775 maxdist = lwgeom_maxdistance2d(lwgeom1, lwgeom2);
776
777 PG_FREE_IF_COPY(geom1, 0);
778 PG_FREE_IF_COPY(geom2, 1);
779
780 /*if called with empty geometries the ingoing mindistance is untouched, and makes us return NULL*/
781 if (maxdist > -1)
782 PG_RETURN_FLOAT8(maxdist);
783
784 PG_RETURN_NULL();
785}
786
792Datum LWGEOM_closestpoint3d(PG_FUNCTION_ARGS)
793{
795 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
796 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
797 LWGEOM *point;
798 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
799 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
800 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
801
802 point = lwgeom_closest_point_3d(lwgeom1, lwgeom2);
803 // point = lw_dist3d_distancepoint(lwgeom1, lwgeom2, lwgeom1->srid, DIST_MIN);
804
805 if (lwgeom_is_empty(point))
806 PG_RETURN_NULL();
807
808 result = geometry_serialize(point);
809
810 lwgeom_free(point);
811 lwgeom_free(lwgeom1);
812 lwgeom_free(lwgeom2);
813
814 PG_FREE_IF_COPY(geom1, 0);
815 PG_FREE_IF_COPY(geom2, 1);
816 PG_RETURN_POINTER(result);
817}
818
823Datum LWGEOM_shortestline3d(PG_FUNCTION_ARGS)
824{
826 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
827 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
828 LWGEOM *theline;
829 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
830 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
831 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
832
833 theline = lwgeom_closest_line_3d(lwgeom1, lwgeom2);
834 // theline = lw_dist3d_distanceline(lwgeom1, lwgeom2, lwgeom1->srid, DIST_MIN);
835
836 if (lwgeom_is_empty(theline))
837 PG_RETURN_NULL();
838
839 result = geometry_serialize(theline);
840
841 lwgeom_free(theline);
842 lwgeom_free(lwgeom1);
843 lwgeom_free(lwgeom2);
844
845 PG_FREE_IF_COPY(geom1, 0);
846 PG_FREE_IF_COPY(geom2, 1);
847 PG_RETURN_POINTER(result);
848}
849
854Datum LWGEOM_longestline3d(PG_FUNCTION_ARGS)
855{
857 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
858 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
859 LWGEOM *theline;
860 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
861 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
862 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
863
864 theline = lwgeom_furthest_line_3d(lwgeom1, lwgeom2);
865 // theline = lw_dist3d_distanceline(lwgeom1, lwgeom2, lwgeom1->srid, DIST_MAX);
866
867 if (lwgeom_is_empty(theline))
868 PG_RETURN_NULL();
869
870 result = geometry_serialize(theline);
871
872 lwgeom_free(theline);
873 lwgeom_free(lwgeom1);
874 lwgeom_free(lwgeom2);
875
876 PG_FREE_IF_COPY(geom1, 0);
877 PG_FREE_IF_COPY(geom2, 1);
878 PG_RETURN_POINTER(result);
879}
884Datum ST_3DDistance(PG_FUNCTION_ARGS)
885{
886 double mindist;
887 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
888 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
889 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
890 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
891 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
892
893 mindist = lwgeom_mindistance3d(lwgeom1, lwgeom2);
894
895 PG_FREE_IF_COPY(geom1, 0);
896 PG_FREE_IF_COPY(geom2, 1);
897
898 /*if called with empty geometries the ingoing mindistance is untouched, and makes us return NULL*/
899 if (mindist < FLT_MAX)
900 PG_RETURN_FLOAT8(mindist);
901
902 PG_RETURN_NULL();
903}
904
905/* intersects3d through dwithin */
907Datum ST_3DIntersects(PG_FUNCTION_ARGS)
908{
909 double mindist;
910 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
911 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
912 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
913 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
914 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
915
916 mindist = lwgeom_mindistance3d_tolerance(lwgeom1, lwgeom2, 0.0);
917
918 PG_FREE_IF_COPY(geom1, 0);
919 PG_FREE_IF_COPY(geom2, 1);
920 /*empty geometries cases should be right handled since return from underlying
921 functions should be FLT_MAX which causes false as answer*/
922 PG_RETURN_BOOL(0.0 == mindist);
923}
924
925
932Datum LWGEOM_dwithin3d(PG_FUNCTION_ARGS)
933{
934 double mindist;
935 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
936 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
937 double tolerance = PG_GETARG_FLOAT8(2);
938 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
939 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
940
941 if (tolerance < 0)
942 {
943 elog(ERROR, "Tolerance cannot be less than zero\n");
944 PG_RETURN_NULL();
945 }
946
947 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
948
949 mindist = lwgeom_mindistance3d_tolerance(lwgeom1, lwgeom2, tolerance);
950
951 PG_FREE_IF_COPY(geom1, 0);
952 PG_FREE_IF_COPY(geom2, 1);
953
954 /*empty geometries cases should be right handled since return from underlying
955 functions should be FLT_MAX which causes false as answer*/
956 PG_RETURN_BOOL(tolerance >= mindist);
957}
958
965Datum LWGEOM_dfullywithin3d(PG_FUNCTION_ARGS)
966{
967 double maxdist;
968 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
969 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
970 double tolerance = PG_GETARG_FLOAT8(2);
971 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
972 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
973
974 if (tolerance < 0)
975 {
976 elog(ERROR, "Tolerance cannot be less than zero\n");
977 PG_RETURN_NULL();
978 }
979
980 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
981 maxdist = lwgeom_maxdistance3d_tolerance(lwgeom1, lwgeom2, tolerance);
982
983 PG_FREE_IF_COPY(geom1, 0);
984 PG_FREE_IF_COPY(geom2, 1);
985
986 /*If function is feed with empty geometries we should return false*/
987 if (maxdist > -1)
988 PG_RETURN_BOOL(tolerance >= maxdist);
989
990 PG_RETURN_BOOL(LW_FALSE);
991}
992
997Datum LWGEOM_maxdistance3d(PG_FUNCTION_ARGS)
998{
999 double maxdist;
1000 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
1001 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
1002 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
1003 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
1004
1005 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
1006
1007 maxdist = lwgeom_maxdistance3d(lwgeom1, lwgeom2);
1008
1009 PG_FREE_IF_COPY(geom1, 0);
1010 PG_FREE_IF_COPY(geom2, 1);
1011
1012 /*if called with empty geometries the ingoing mindistance is untouched, and makes us return NULL*/
1013 if (maxdist > -1)
1014 PG_RETURN_FLOAT8(maxdist);
1015
1016 PG_RETURN_NULL();
1017}
1018
1020Datum LWGEOM_longitude_shift(PG_FUNCTION_ARGS)
1021{
1022 GSERIALIZED *geom;
1023 LWGEOM *lwgeom;
1024 GSERIALIZED *ret;
1025
1026 POSTGIS_DEBUG(2, "LWGEOM_longitude_shift called.");
1027
1028 geom = PG_GETARG_GSERIALIZED_P_COPY(0);
1029 lwgeom = lwgeom_from_gserialized(geom);
1030
1031 /* Drop bbox, will be recomputed */
1032 lwgeom_drop_bbox(lwgeom);
1033
1034 /* Modify geometry */
1035 lwgeom_longitude_shift(lwgeom);
1036
1037 /* Construct GSERIALIZED */
1038 ret = geometry_serialize(lwgeom);
1039
1040 /* Release deserialized geometry */
1041 lwgeom_free(lwgeom);
1042
1043 /* Release detoasted geometry */
1044 pfree(geom);
1045
1046 PG_RETURN_POINTER(ret);
1047}
1048
1050Datum ST_WrapX(PG_FUNCTION_ARGS)
1051{
1052 Datum gdatum;
1053 GSERIALIZED *geom_in;
1054 LWGEOM *lwgeom_in, *lwgeom_out;
1055 GSERIALIZED *geom_out;
1056 double cutx;
1057 double amount;
1058
1059 POSTGIS_DEBUG(2, "ST_WrapX called.");
1060
1061 gdatum = PG_GETARG_DATUM(0);
1062 cutx = PG_GETARG_FLOAT8(1);
1063 amount = PG_GETARG_FLOAT8(2);
1064
1065 // if ( ! amount ) PG_RETURN_DATUM(gdatum);
1066
1067 geom_in = ((GSERIALIZED *)PG_DETOAST_DATUM(gdatum));
1068 lwgeom_in = lwgeom_from_gserialized(geom_in);
1069
1070 lwgeom_out = lwgeom_wrapx(lwgeom_in, cutx, amount);
1071 geom_out = geometry_serialize(lwgeom_out);
1072
1073 lwgeom_free(lwgeom_in);
1074 lwgeom_free(lwgeom_out);
1075 PG_FREE_IF_COPY(geom_in, 0);
1076
1077 PG_RETURN_POINTER(geom_out);
1078}
1079
1081Datum ST_Scroll(PG_FUNCTION_ARGS)
1082{
1083 Datum datum_line, datum_point;
1084 GSERIALIZED *ser_line, *ser_point;
1085 LWGEOM *lwgeom_line, *lwgeom_point;
1086 LWLINE *line;
1087 LWPOINT *point;
1088 POINT4D p;
1089 GSERIALIZED *ser_out;
1090 int rv;
1091
1092 POSTGIS_DEBUG(2, "ST_Scroll called.");
1093
1094 datum_line = PG_GETARG_DATUM(0);
1095 datum_point = PG_GETARG_DATUM(1);
1096
1097 ser_line = ((GSERIALIZED *)PG_DETOAST_DATUM(datum_line));
1098 lwgeom_line = lwgeom_from_gserialized(ser_line);
1099 line = lwgeom_as_lwline(lwgeom_line);
1100 if ( ! line ) {
1101 lwpgerror("First argument must be a line");
1102 PG_RETURN_NULL();
1103 }
1104
1105 ser_point = ((GSERIALIZED *)PG_DETOAST_DATUM(datum_point));
1106 lwgeom_point = lwgeom_from_gserialized(ser_point);
1107 point = lwgeom_as_lwpoint(lwgeom_point);
1108 if ( ! point ) {
1109 lwpgerror("Second argument must be a point");
1110 PG_RETURN_NULL();
1111 }
1112 if ( ! lwpoint_getPoint4d_p(point, &p) ) {
1113 lwpgerror("Second argument must be a non-empty point");
1114 PG_RETURN_NULL();
1115 }
1116
1117 rv = ptarray_scroll_in_place(line->points, &p);
1118 if ( LW_FAILURE == rv ) {
1119 PG_RETURN_NULL();
1120 }
1121
1122 ser_out = geometry_serialize(lwgeom_line);
1123
1124 lwgeom_free(lwgeom_point);
1125 PG_FREE_IF_COPY(ser_line, 0);
1126 PG_FREE_IF_COPY(ser_point, 0);
1127
1128 PG_RETURN_POINTER(ser_out);
1129}
1130
1132Datum LWGEOM_inside_circle_point(PG_FUNCTION_ARGS)
1133{
1134 GSERIALIZED *geom;
1135 double cx = PG_GETARG_FLOAT8(1);
1136 double cy = PG_GETARG_FLOAT8(2);
1137 double rr = PG_GETARG_FLOAT8(3);
1138 LWPOINT *lwpoint;
1139 LWGEOM *lwgeom;
1140 int inside;
1141
1142 geom = PG_GETARG_GSERIALIZED_P(0);
1143 lwgeom = lwgeom_from_gserialized(geom);
1144 lwpoint = lwgeom_as_lwpoint(lwgeom);
1145 if (lwpoint == NULL || lwgeom_is_empty(lwgeom))
1146 {
1147 PG_FREE_IF_COPY(geom, 0);
1148 PG_RETURN_NULL(); /* not a point */
1149 }
1150
1151 inside = lwpoint_inside_circle(lwpoint, cx, cy, rr);
1152 lwpoint_free(lwpoint);
1153
1154 PG_FREE_IF_COPY(geom, 0);
1155 PG_RETURN_BOOL(inside);
1156}
1157
1166Datum LWGEOM_collect(PG_FUNCTION_ARGS)
1167{
1168 GSERIALIZED *gser1, *gser2, *result;
1169 LWGEOM *lwgeoms[2], *outlwg;
1170 uint32 type1, type2;
1171 uint8_t outtype;
1172 int32_t srid;
1173
1174 POSTGIS_DEBUG(2, "LWGEOM_collect called.");
1175
1176 /* return null if both geoms are null */
1177 if (PG_ARGISNULL(0) && PG_ARGISNULL(1))
1178 PG_RETURN_NULL();
1179
1180 /* Return the second geom if the first geom is null */
1181 if (PG_ARGISNULL(0))
1182 PG_RETURN_DATUM(PG_GETARG_DATUM(1));
1183
1184 /* Return the first geom if the second geom is null */
1185 if (PG_ARGISNULL(1))
1186 PG_RETURN_DATUM(PG_GETARG_DATUM(0));
1187
1188 gser1 = PG_GETARG_GSERIALIZED_P(0);
1189 gser2 = PG_GETARG_GSERIALIZED_P(1);
1190 gserialized_error_if_srid_mismatch(gser1, gser2, __func__);
1191
1192 POSTGIS_DEBUGF(3,
1193 "LWGEOM_collect(%s, %s): call",
1196
1197 if ((gserialized_has_z(gser1) != gserialized_has_z(gser2)) ||
1198 (gserialized_has_m(gser1) != gserialized_has_m(gser2)))
1199 {
1200 elog(ERROR, "Cannot ST_Collect geometries with differing dimensionality.");
1201 PG_RETURN_NULL();
1202 }
1203
1204 srid = gserialized_get_srid(gser1);
1205
1206 lwgeoms[0] = lwgeom_from_gserialized(gser1);
1207 lwgeoms[1] = lwgeom_from_gserialized(gser2);
1208
1209 type1 = lwgeoms[0]->type;
1210 type2 = lwgeoms[1]->type;
1211
1212 if ((type1 == type2) && (!lwgeom_is_collection(lwgeoms[0])))
1213 outtype = lwtype_get_collectiontype(type1);
1214 else
1215 outtype = COLLECTIONTYPE;
1216
1217 POSTGIS_DEBUGF(3, " outtype = %d", outtype);
1218
1219 /* Drop input geometries bbox and SRID */
1220 lwgeom_drop_bbox(lwgeoms[0]);
1221 lwgeom_drop_srid(lwgeoms[0]);
1222 lwgeom_drop_bbox(lwgeoms[1]);
1223 lwgeom_drop_srid(lwgeoms[1]);
1224
1225 outlwg = (LWGEOM *)lwcollection_construct(outtype, srid, NULL, 2, lwgeoms);
1226 result = geometry_serialize(outlwg);
1227
1228 lwgeom_free(lwgeoms[0]);
1229 lwgeom_free(lwgeoms[1]);
1230
1231 PG_FREE_IF_COPY(gser1, 0);
1232 PG_FREE_IF_COPY(gser2, 1);
1233
1234 PG_RETURN_POINTER(result);
1235}
1236
1247Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS)
1248{
1249 ArrayType *array;
1250 int nelems;
1251 /*GSERIALIZED **geoms; */
1252 GSERIALIZED *result = NULL;
1253 LWGEOM **lwgeoms, *outlwg;
1254 uint32 outtype;
1255 int count;
1256 int32_t srid = SRID_UNKNOWN;
1257 GBOX *box = NULL;
1258
1259 ArrayIterator iterator;
1260 Datum value;
1261 bool isnull;
1262
1263 POSTGIS_DEBUG(2, "LWGEOM_collect_garray called.");
1264
1265 if (PG_ARGISNULL(0))
1266 PG_RETURN_NULL();
1267
1268 /* Get actual ArrayType */
1269 array = PG_GETARG_ARRAYTYPE_P(0);
1270 nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
1271
1272 POSTGIS_DEBUGF(3,
1273 " array is %d-bytes in size, %ld w/out header",
1274 ARR_SIZE(array),
1275 ARR_SIZE(array) - ARR_OVERHEAD_NONULLS(ARR_NDIM(array)));
1276
1277 POSTGIS_DEBUGF(3, "LWGEOM_collect_garray: array has %d elements", nelems);
1278
1279 /* Return null on 0-elements input array */
1280 if (nelems == 0)
1281 PG_RETURN_NULL();
1282
1283 /*
1284 * Deserialize all geometries in array into the lwgeoms pointers
1285 * array. Check input types to form output type.
1286 */
1287 lwgeoms = palloc(sizeof(LWGEOM *) * nelems);
1288 count = 0;
1289 outtype = 0;
1290
1291 iterator = array_create_iterator(array, 0, NULL);
1292
1293 while (array_iterate(iterator, &value, &isnull))
1294 {
1295 GSERIALIZED *geom;
1296 uint8_t intype;
1297
1298 /* Don't do anything for NULL values */
1299 if (isnull)
1300 continue;
1301
1302 geom = (GSERIALIZED *)DatumGetPointer(value);
1303 intype = gserialized_get_type(geom);
1304
1305 lwgeoms[count] = lwgeom_from_gserialized(geom);
1306
1307 POSTGIS_DEBUGF(3, "%s: geom %d deserialized", __func__, count);
1308
1309 if (!count)
1310 {
1311 /* Get first geometry SRID */
1312 srid = lwgeoms[count]->srid;
1313
1314 /* COMPUTE_BBOX WHEN_SIMPLE */
1315 if (lwgeoms[count]->bbox)
1316 box = gbox_copy(lwgeoms[count]->bbox);
1317 }
1318 else
1319 {
1320 /* Check SRID homogeneity */
1322
1323 /* COMPUTE_BBOX WHEN_SIMPLE */
1324 if (box)
1325 {
1326 if (lwgeoms[count]->bbox)
1327 gbox_merge(lwgeoms[count]->bbox, box);
1328 else
1329 {
1330 pfree(box);
1331 box = NULL;
1332 }
1333 }
1334 }
1335
1336 lwgeom_drop_srid(lwgeoms[count]);
1337 lwgeom_drop_bbox(lwgeoms[count]);
1338
1339 /* Output type not initialized */
1340 if (!outtype)
1341 {
1342 outtype = lwtype_get_collectiontype(intype);
1343 }
1344 /* Input type not compatible with output */
1345 /* make output type a collection */
1346 else if (outtype != COLLECTIONTYPE && lwtype_get_collectiontype(intype) != outtype)
1347 {
1348 outtype = COLLECTIONTYPE;
1349 }
1350
1351 count++;
1352 }
1353 array_free_iterator(iterator);
1354
1355 POSTGIS_DEBUGF(3, "LWGEOM_collect_garray: outtype = %d", outtype);
1356
1357 /* If we have been passed a complete set of NULLs then return NULL */
1358 if (!outtype)
1359 {
1360 PG_RETURN_NULL();
1361 }
1362 else
1363 {
1364 outlwg = (LWGEOM *)lwcollection_construct(outtype, srid, box, count, lwgeoms);
1365
1366 result = geometry_serialize(outlwg);
1367
1368 PG_RETURN_POINTER(result);
1369 }
1370}
1371
1377Datum LWGEOM_line_from_mpoint(PG_FUNCTION_ARGS)
1378{
1379 GSERIALIZED *ingeom, *result;
1380 LWLINE *lwline;
1381 LWMPOINT *mpoint;
1382
1383 POSTGIS_DEBUG(2, "LWGEOM_line_from_mpoint called");
1384
1385 /* Get input GSERIALIZED and deserialize it */
1386 ingeom = PG_GETARG_GSERIALIZED_P(0);
1387
1388 if (gserialized_get_type(ingeom) != MULTIPOINTTYPE)
1389 {
1390 elog(ERROR, "makeline: input must be a multipoint");
1391 PG_RETURN_NULL(); /* input is not a multipoint */
1392 }
1393
1395 lwline = lwline_from_lwmpoint(mpoint->srid, mpoint);
1396 if (!lwline)
1397 {
1398 PG_FREE_IF_COPY(ingeom, 0);
1399 elog(ERROR, "makeline: lwline_from_lwmpoint returned NULL");
1400 PG_RETURN_NULL();
1401 }
1402
1403 result = geometry_serialize(lwline_as_lwgeom(lwline));
1404
1405 PG_FREE_IF_COPY(ingeom, 0);
1406 lwline_free(lwline);
1407
1408 PG_RETURN_POINTER(result);
1409}
1410
1417Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS)
1418{
1419 ArrayType *array;
1420 int nelems;
1421 GSERIALIZED *result = NULL;
1422 LWGEOM **geoms;
1423 LWGEOM *outlwg;
1424 uint32 ngeoms;
1425 int32_t srid = SRID_UNKNOWN;
1426
1427 ArrayIterator iterator;
1428 Datum value;
1429 bool isnull;
1430
1431 POSTGIS_DEBUGF(2, "%s called", __func__);
1432
1433 /* Return null on null input */
1434 if (PG_ARGISNULL(0))
1435 PG_RETURN_NULL();
1436
1437 /* Get actual ArrayType */
1438 array = PG_GETARG_ARRAYTYPE_P(0);
1439
1440 /* Get number of geometries in array */
1441 nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
1442
1443 POSTGIS_DEBUGF(3, "%s: array has %d elements", __func__, nelems);
1444
1445 /* Return null on 0-elements input array */
1446 if (nelems == 0)
1447 PG_RETURN_NULL();
1448
1449 /*
1450 * Deserialize all point geometries in array into the
1451 * geoms pointers array.
1452 * Count actual number of points.
1453 */
1454
1455 /* possibly more then required */
1456 geoms = palloc(sizeof(LWGEOM *) * nelems);
1457 ngeoms = 0;
1458
1459 iterator = array_create_iterator(array, 0, NULL);
1460
1461 while (array_iterate(iterator, &value, &isnull))
1462 {
1463 GSERIALIZED *geom;
1464
1465 if (isnull)
1466 continue;
1467
1468 geom = (GSERIALIZED *)DatumGetPointer(value);
1469
1470 if (gserialized_get_type(geom) != POINTTYPE &&
1472 gserialized_get_type(geom) != LINETYPE &&
1474 {
1475 continue;
1476 }
1477
1478 geoms[ngeoms++] = lwgeom_from_gserialized(geom);
1479
1480 /* Check SRID homogeneity */
1481 if (ngeoms == 1)
1482 {
1483 /* Get first geometry SRID */
1484 srid = geoms[ngeoms - 1]->srid;
1485 /* TODO: also get ZMflags */
1486 }
1487 else
1489
1490 POSTGIS_DEBUGF(3, "%s: element %d deserialized", __func__, ngeoms);
1491 }
1492 array_free_iterator(iterator);
1493
1494 /* Return null on 0-points input array */
1495 if (ngeoms == 0)
1496 {
1497 /* TODO: should we return LINESTRING EMPTY here ? */
1498 elog(NOTICE, "No points or linestrings in input array");
1499 PG_RETURN_NULL();
1500 }
1501
1502 POSTGIS_DEBUGF(3, "LWGEOM_makeline_garray: elements: %d", ngeoms);
1503
1504 outlwg = (LWGEOM *)lwline_from_lwgeom_array(srid, ngeoms, geoms);
1505
1506 result = geometry_serialize(outlwg);
1507
1508 PG_RETURN_POINTER(result);
1509}
1510
1516Datum LWGEOM_makeline(PG_FUNCTION_ARGS)
1517{
1518 GSERIALIZED *pglwg1, *pglwg2;
1519 GSERIALIZED *result = NULL;
1520 LWGEOM *lwgeoms[2];
1521 LWLINE *outline;
1522
1523 POSTGIS_DEBUG(2, "LWGEOM_makeline called.");
1524
1525 /* Get input datum */
1526 pglwg1 = PG_GETARG_GSERIALIZED_P(0);
1527 pglwg2 = PG_GETARG_GSERIALIZED_P(1);
1528
1529 if ((gserialized_get_type(pglwg1) != POINTTYPE && gserialized_get_type(pglwg1) != LINETYPE) ||
1531 {
1532 elog(ERROR, "Input geometries must be points or lines");
1533 PG_RETURN_NULL();
1534 }
1535
1536 gserialized_error_if_srid_mismatch(pglwg1, pglwg2, __func__);
1537
1538 lwgeoms[0] = lwgeom_from_gserialized(pglwg1);
1539 lwgeoms[1] = lwgeom_from_gserialized(pglwg2);
1540
1541 outline = lwline_from_lwgeom_array(lwgeoms[0]->srid, 2, lwgeoms);
1542
1543 result = geometry_serialize((LWGEOM *)outline);
1544
1545 PG_FREE_IF_COPY(pglwg1, 0);
1546 PG_FREE_IF_COPY(pglwg2, 1);
1547 lwgeom_free(lwgeoms[0]);
1548 lwgeom_free(lwgeoms[1]);
1549
1550 PG_RETURN_POINTER(result);
1551}
1552
1558Datum LWGEOM_makepoly(PG_FUNCTION_ARGS)
1559{
1560 GSERIALIZED *pglwg1;
1561 ArrayType *array = NULL;
1562 GSERIALIZED *result = NULL;
1563 const LWLINE *shell = NULL;
1564 const LWLINE **holes = NULL;
1565 LWPOLY *outpoly;
1566 uint32 nholes = 0;
1567 uint32 i;
1568 size_t offset = 0;
1569
1570 POSTGIS_DEBUG(2, "LWGEOM_makepoly called.");
1571
1572 /* Get input shell */
1573 pglwg1 = PG_GETARG_GSERIALIZED_P(0);
1574 if (gserialized_get_type(pglwg1) != LINETYPE)
1575 {
1576 lwpgerror("Shell is not a line");
1577 }
1579
1580 /* Get input holes if any */
1581 if (PG_NARGS() > 1)
1582 {
1583 array = PG_GETARG_ARRAYTYPE_P(1);
1584 nholes = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
1585 holes = lwalloc(sizeof(LWLINE *) * nholes);
1586 for (i = 0; i < nholes; i++)
1587 {
1588#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
1589#pragma GCC diagnostic push
1590#pragma GCC diagnostic ignored "-Wsign-compare"
1591#endif
1592 GSERIALIZED *g = (GSERIALIZED *)(ARR_DATA_PTR(array) + offset);
1593#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
1594#pragma GCC diagnostic pop
1595#endif
1596 LWLINE *hole;
1597 offset += INTALIGN(VARSIZE(g));
1599 {
1600 lwpgerror("Hole %d is not a line", i);
1601 }
1603 holes[i] = hole;
1604 }
1605 }
1606
1607 outpoly = lwpoly_from_lwlines(shell, nholes, holes);
1608 POSTGIS_DEBUGF(3, "%s", lwgeom_summary((LWGEOM *)outpoly, 0));
1609 result = geometry_serialize((LWGEOM *)outpoly);
1610
1611 lwline_free((LWLINE *)shell);
1612 PG_FREE_IF_COPY(pglwg1, 0);
1613
1614 for (i = 0; i < nholes; i++)
1615 {
1616 lwline_free((LWLINE *)holes[i]);
1617 }
1618
1619 PG_RETURN_POINTER(result);
1620}
1621
1628Datum LWGEOM_expand(PG_FUNCTION_ARGS)
1629{
1630 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
1631 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
1632 int32_t srid = lwgeom_get_srid(lwgeom);
1633 LWPOLY *poly;
1635 GBOX gbox;
1636
1637 POSTGIS_DEBUG(2, "LWGEOM_expand called.");
1638
1639 /* Can't expand an empty */
1640 if (lwgeom_is_empty(lwgeom))
1641 {
1642 lwgeom_free(lwgeom);
1643 PG_RETURN_POINTER(geom);
1644 }
1645
1646 /* Can't expand something with no gbox! */
1647 if (LW_FAILURE == lwgeom_calculate_gbox(lwgeom, &gbox))
1648 {
1649 lwgeom_free(lwgeom);
1650 PG_RETURN_POINTER(geom);
1651 }
1652
1653 if (PG_NARGS() == 2)
1654 {
1655 /* Expand the box the same amount in all directions */
1656 double d = PG_GETARG_FLOAT8(1);
1657 gbox_expand(&gbox, d);
1658 }
1659 else
1660 {
1661 double dx = PG_GETARG_FLOAT8(1);
1662 double dy = PG_GETARG_FLOAT8(2);
1663 double dz = PG_GETARG_FLOAT8(3);
1664 double dm = PG_GETARG_FLOAT8(4);
1665
1666 gbox_expand_xyzm(&gbox, dx, dy, dz, dm);
1667 }
1668
1669 {
1670 POINT4D p1 = {gbox.xmin, gbox.ymin, gbox.zmin, gbox.mmin};
1671 POINT4D p2 = {gbox.xmin, gbox.ymax, gbox.zmin, gbox.mmin};
1672 POINT4D p3 = {gbox.xmax, gbox.ymax, gbox.zmax, gbox.mmax};
1673 POINT4D p4 = {gbox.xmax, gbox.ymin, gbox.zmax, gbox.mmax};
1674
1675 poly = lwpoly_construct_rectangle(lwgeom_has_z(lwgeom), lwgeom_has_m(lwgeom), &p1, &p2, &p3, &p4);
1676 }
1677
1679 lwgeom_set_srid(lwpoly_as_lwgeom(poly), srid);
1680
1681 /* Construct GSERIALIZED */
1682 result = geometry_serialize(lwpoly_as_lwgeom(poly));
1683
1685 lwgeom_free(lwgeom);
1686 PG_FREE_IF_COPY(geom, 0);
1687
1688 PG_RETURN_POINTER(result);
1689}
1690
1693Datum LWGEOM_to_BOX(PG_FUNCTION_ARGS)
1694{
1695 GSERIALIZED *pg_lwgeom = PG_GETARG_GSERIALIZED_P(0);
1696 LWGEOM *lwgeom = lwgeom_from_gserialized(pg_lwgeom);
1697 GBOX gbox;
1698 int result;
1699 BOX *out = NULL;
1700
1701 /* Zero out flags */
1702 gbox_init(&gbox);
1703
1704 /* Calculate the GBOX of the geometry */
1705 result = lwgeom_calculate_gbox(lwgeom, &gbox);
1706
1707 /* Clean up memory */
1708 lwfree(lwgeom);
1709 PG_FREE_IF_COPY(pg_lwgeom, 0);
1710
1711 /* Null on failure */
1712 if (!result)
1713 PG_RETURN_NULL();
1714
1715 out = lwalloc(sizeof(BOX));
1716 out->low.x = gbox.xmin;
1717 out->low.y = gbox.ymin;
1718 out->high.x = gbox.xmax;
1719 out->high.y = gbox.ymax;
1720 PG_RETURN_POINTER(out);
1721}
1722
1729Datum LWGEOM_envelope(PG_FUNCTION_ARGS)
1730{
1731 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
1732 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
1733 int32_t srid = lwgeom->srid;
1734 POINT4D pt;
1735 GBOX box;
1736 POINTARRAY *pa;
1738
1739 if (lwgeom_is_empty(lwgeom))
1740 {
1741 /* must be the EMPTY geometry */
1742 PG_RETURN_POINTER(geom);
1743 }
1744
1745 if (lwgeom_calculate_gbox(lwgeom, &box) == LW_FAILURE)
1746 {
1747 /* must be the EMPTY geometry */
1748 PG_RETURN_POINTER(geom);
1749 }
1750
1751 /*
1752 * Alter envelope type so that a valid geometry is always
1753 * returned depending upon the size of the geometry. The
1754 * code makes the following assumptions:
1755 * - If the bounding box is a single point then return a
1756 * POINT geometry
1757 * - If the bounding box represents either a horizontal or
1758 * vertical line, return a LINESTRING geometry
1759 * - Otherwise return a POLYGON
1760 */
1761
1762 if ((box.xmin == box.xmax) && (box.ymin == box.ymax))
1763 {
1764 /* Construct and serialize point */
1765 LWPOINT *point = lwpoint_make2d(srid, box.xmin, box.ymin);
1766 result = geometry_serialize(lwpoint_as_lwgeom(point));
1767 lwpoint_free(point);
1768 }
1769 else if ((box.xmin == box.xmax) || (box.ymin == box.ymax))
1770 {
1771 LWLINE *line;
1772 /* Construct point array */
1773 pa = ptarray_construct_empty(0, 0, 2);
1774
1775 /* Assign coordinates to POINT2D array */
1776 pt.x = box.xmin;
1777 pt.y = box.ymin;
1778 ptarray_append_point(pa, &pt, LW_TRUE);
1779 pt.x = box.xmax;
1780 pt.y = box.ymax;
1781 ptarray_append_point(pa, &pt, LW_TRUE);
1782
1783 /* Construct and serialize linestring */
1784 line = lwline_construct(srid, NULL, pa);
1785 result = geometry_serialize(lwline_as_lwgeom(line));
1786 lwline_free(line);
1787 }
1788 else
1789 {
1790 LWPOLY *poly;
1791 POINTARRAY **ppa = lwalloc(sizeof(POINTARRAY *));
1792 pa = ptarray_construct_empty(0, 0, 5);
1793 ppa[0] = pa;
1794
1795 /* Assign coordinates to POINT2D array */
1796 pt.x = box.xmin;
1797 pt.y = box.ymin;
1798 ptarray_append_point(pa, &pt, LW_TRUE);
1799 pt.x = box.xmin;
1800 pt.y = box.ymax;
1801 ptarray_append_point(pa, &pt, LW_TRUE);
1802 pt.x = box.xmax;
1803 pt.y = box.ymax;
1804 ptarray_append_point(pa, &pt, LW_TRUE);
1805 pt.x = box.xmax;
1806 pt.y = box.ymin;
1807 ptarray_append_point(pa, &pt, LW_TRUE);
1808 pt.x = box.xmin;
1809 pt.y = box.ymin;
1810 ptarray_append_point(pa, &pt, LW_TRUE);
1811
1812 /* Construct polygon */
1813 poly = lwpoly_construct(srid, NULL, 1, ppa);
1814 result = geometry_serialize(lwpoly_as_lwgeom(poly));
1815 lwpoly_free(poly);
1816 }
1817
1818 PG_FREE_IF_COPY(geom, 0);
1819
1820 PG_RETURN_POINTER(result);
1821}
1822
1824Datum LWGEOM_isempty(PG_FUNCTION_ARGS)
1825{
1826 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
1827 PG_RETURN_BOOL(gserialized_is_empty(geom));
1828}
1829
1837Datum LWGEOM_segmentize2d(PG_FUNCTION_ARGS)
1838{
1839 GSERIALIZED *outgeom, *ingeom;
1840 double dist;
1841 LWGEOM *inlwgeom, *outlwgeom;
1842 int type;
1843
1844 POSTGIS_DEBUG(2, "LWGEOM_segmentize2d called");
1845
1846 ingeom = PG_GETARG_GSERIALIZED_P(0);
1847 dist = PG_GETARG_FLOAT8(1);
1848 type = gserialized_get_type(ingeom);
1849
1850 /* Avoid types we cannot segmentize. */
1851 if ((type == POINTTYPE) || (type == MULTIPOINTTYPE) || (type == TRIANGLETYPE) || (type == TINTYPE) ||
1852 (type == POLYHEDRALSURFACETYPE))
1853 {
1854 PG_RETURN_POINTER(ingeom);
1855 }
1856
1857 if (dist <= 0)
1858 {
1859 /* Protect from knowingly infinite loops, see #1799 */
1860 /* Note that we'll end out of memory anyway for other small distances */
1861 elog(ERROR, "ST_Segmentize: invalid max_distance %g (must be >= 0)", dist);
1862 PG_RETURN_NULL();
1863 }
1864
1865 LWGEOM_INIT();
1866
1867 inlwgeom = lwgeom_from_gserialized(ingeom);
1868 if (lwgeom_is_empty(inlwgeom))
1869 {
1870 /* Should only happen on interruption */
1871 lwgeom_free(inlwgeom);
1872 PG_RETURN_POINTER(ingeom);
1873 }
1874
1875 outlwgeom = lwgeom_segmentize2d(inlwgeom, dist);
1876 if (!outlwgeom)
1877 {
1878 /* Should only happen on interruption */
1879 PG_FREE_IF_COPY(ingeom, 0);
1880 PG_RETURN_NULL();
1881 }
1882
1883 /* Copy input bounding box if any */
1884 if (inlwgeom->bbox)
1885 outlwgeom->bbox = gbox_copy(inlwgeom->bbox);
1886
1887 outgeom = geometry_serialize(outlwgeom);
1888
1889 // lwgeom_free(outlwgeom); /* TODO fix lwgeom_clone / ptarray_clone_deep for consistent semantics */
1890 lwgeom_free(inlwgeom);
1891
1892 PG_FREE_IF_COPY(ingeom, 0);
1893
1894 PG_RETURN_POINTER(outgeom);
1895}
1896
1899Datum LWGEOM_reverse(PG_FUNCTION_ARGS)
1900{
1901 GSERIALIZED *geom;
1902 LWGEOM *lwgeom;
1903
1904 POSTGIS_DEBUG(2, "LWGEOM_reverse called");
1905
1906 geom = PG_GETARG_GSERIALIZED_P_COPY(0);
1907
1908 lwgeom = lwgeom_from_gserialized(geom);
1910
1911 geom = geometry_serialize(lwgeom);
1912
1913 PG_RETURN_POINTER(geom);
1914}
1915
1918Datum LWGEOM_force_clockwise_poly(PG_FUNCTION_ARGS)
1919{
1920 GSERIALIZED *ingeom, *outgeom;
1921 LWGEOM *lwgeom;
1922
1923 POSTGIS_DEBUG(2, "LWGEOM_force_clockwise_poly called");
1924
1925 ingeom = PG_GETARG_GSERIALIZED_P_COPY(0);
1926
1927 lwgeom = lwgeom_from_gserialized(ingeom);
1928 lwgeom_force_clockwise(lwgeom);
1929
1930 outgeom = geometry_serialize(lwgeom);
1931
1932 lwgeom_free(lwgeom);
1933 PG_FREE_IF_COPY(ingeom, 0);
1934 PG_RETURN_POINTER(outgeom);
1935}
1936
1937
1943Datum ST_ForcePolygonCCW(PG_FUNCTION_ARGS)
1944{
1945 GSERIALIZED *ingeom, *outgeom;
1946 LWGEOM *lwgeom;
1947
1948 POSTGIS_DEBUG(2, "ST_ForcePolygonCCW called");
1949
1950 ingeom = PG_GETARG_GSERIALIZED_P_COPY(0);
1951
1952 lwgeom = lwgeom_from_gserialized(ingeom);
1954
1955 outgeom = geometry_serialize(lwgeom);
1956
1957 lwgeom_free(lwgeom);
1958 PG_FREE_IF_COPY(ingeom, 0);
1959 PG_RETURN_POINTER(outgeom);
1960}
1961
1964Datum LWGEOM_noop(PG_FUNCTION_ARGS)
1965{
1966 GSERIALIZED *in = PG_GETARG_GSERIALIZED_P(0);
1967 LWGEOM *lwgeom = lwgeom_from_gserialized(in);
1968 GSERIALIZED *out = geometry_serialize(lwgeom);
1969 PG_RETURN_POINTER(out);
1970}
1971
1972Datum ST_Normalize(PG_FUNCTION_ARGS);
1974Datum ST_Normalize(PG_FUNCTION_ARGS)
1975{
1976 GSERIALIZED *in, *out;
1977 LWGEOM *lwgeom_in, *lwgeom_out;
1978
1979 POSTGIS_DEBUG(2, "ST_Normalize called");
1980
1981 in = PG_GETARG_GSERIALIZED_P_COPY(0);
1982
1983 lwgeom_in = lwgeom_from_gserialized(in);
1984 POSTGIS_DEBUGF(3, "Deserialized: %s", lwgeom_summary(lwgeom_in, 0));
1985
1986 lwgeom_out = lwgeom_normalize(lwgeom_in);
1987 POSTGIS_DEBUGF(3, "Normalized: %s", lwgeom_summary(lwgeom_out, 0));
1988
1989 out = geometry_serialize(lwgeom_out);
1990 lwgeom_free(lwgeom_in);
1991 lwgeom_free(lwgeom_out);
1992
1993 PG_FREE_IF_COPY(in, 0);
1994
1995 PG_RETURN_POINTER(out);
1996}
1997
2006Datum LWGEOM_zmflag(PG_FUNCTION_ARGS)
2007{
2008 GSERIALIZED *in = PG_GETARG_GSERIALIZED_HEADER(0);
2009 int ret = 0;
2010
2011 if (gserialized_has_z(in))
2012 ret += 2;
2013 if (gserialized_has_m(in))
2014 ret += 1;
2015 PG_FREE_IF_COPY(in, 0);
2016 PG_RETURN_INT16(ret);
2017}
2018
2020Datum LWGEOM_hasz(PG_FUNCTION_ARGS)
2021{
2022 GSERIALIZED *in = PG_GETARG_GSERIALIZED_HEADER(0);
2023 PG_RETURN_BOOL(gserialized_has_z(in));
2024}
2025
2027Datum LWGEOM_hasm(PG_FUNCTION_ARGS)
2028{
2029 GSERIALIZED *in = PG_GETARG_GSERIALIZED_HEADER(0);
2030 PG_RETURN_BOOL(gserialized_has_m(in));
2031}
2032
2034Datum LWGEOM_hasBBOX(PG_FUNCTION_ARGS)
2035{
2036 GSERIALIZED *in = PG_GETARG_GSERIALIZED_HEADER(0);
2037 char res = gserialized_has_bbox(in);
2038 PG_FREE_IF_COPY(in, 0);
2039 PG_RETURN_BOOL(res);
2040}
2041
2044Datum LWGEOM_ndims(PG_FUNCTION_ARGS)
2045{
2046 GSERIALIZED *in = PG_GETARG_GSERIALIZED_HEADER(0);
2047 int ret = gserialized_ndims(in);
2048 PG_FREE_IF_COPY(in, 0);
2049 PG_RETURN_INT16(ret);
2050}
2051
2054Datum LWGEOM_same(PG_FUNCTION_ARGS)
2055{
2056 GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
2057 GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
2058
2059 PG_RETURN_BOOL(gserialized_cmp(g1, g2) == 0);
2060}
2061
2063Datum ST_MakeEnvelope(PG_FUNCTION_ARGS)
2064{
2065 LWPOLY *poly;
2067 double x1, y1, x2, y2;
2068 int32_t srid = SRID_UNKNOWN;
2069
2070 POSTGIS_DEBUG(2, "ST_MakeEnvelope called");
2071
2072 x1 = PG_GETARG_FLOAT8(0);
2073 y1 = PG_GETARG_FLOAT8(1);
2074 x2 = PG_GETARG_FLOAT8(2);
2075 y2 = PG_GETARG_FLOAT8(3);
2076 if (PG_NARGS() > 4)
2077 {
2078 srid = PG_GETARG_INT32(4);
2079 }
2080
2081 poly = lwpoly_construct_envelope(srid, x1, y1, x2, y2);
2082
2083 result = geometry_serialize(lwpoly_as_lwgeom(poly));
2084 lwpoly_free(poly);
2085
2086 PG_RETURN_POINTER(result);
2087}
2088
2089
2091Datum ST_TileEnvelope(PG_FUNCTION_ARGS)
2092{
2093 GSERIALIZED *bounds;
2094 uint32_t zoomu;
2095 int32_t x, y, zoom;
2096 uint32_t worldTileSize;
2097 double tileGeoSizeX, tileGeoSizeY;
2098 double boundsWidth, boundsHeight;
2099 double x1, y1, x2, y2;
2100 double margin;
2101 /* This is broken, since 3857 doesn't mean "web mercator", it means
2102 the contents of the row in spatial_ref_sys with srid = 3857.
2103 For practical purposes this will work, but in good implementation
2104 we should de-reference in spatial ref sys to confirm that the
2105 srid of the object is EPSG:3857. */
2106 int32_t srid;
2107 GBOX bbox;
2108 LWGEOM *g = NULL;
2109
2110 POSTGIS_DEBUG(2, "ST_TileEnvelope called");
2111
2112 zoom = PG_GETARG_INT32(0);
2113 x = PG_GETARG_INT32(1);
2114 y = PG_GETARG_INT32(2);
2115
2116 bounds = PG_GETARG_GSERIALIZED_P(3);
2117 /*
2118 * We deserialize the geometry and recalculate the bounding box here to get
2119 * 64b floating point precision. The serialized bbox has 32b float is not
2120 * precise enough with big numbers such as the ones used in the default
2121 * parameters, e.g: -20037508.3427892 is transformed into -20037510
2122 */
2123 g = lwgeom_from_gserialized(bounds);
2124 if (lwgeom_calculate_gbox(g, &bbox) != LW_SUCCESS)
2125 elog(ERROR, "%s: Unable to compute bbox", __func__);
2126 srid = g->srid;
2127 lwgeom_free(g);
2128
2129 /* Avoid crashing with old signature (old sql code with 3 args, new C code with 4) */
2130 margin = PG_NARGS() < 4 ? 0 : PG_GETARG_FLOAT8(4);
2131 /* shrinking by more than 50% would eliminate the tile outright */
2132 if (margin < -0.5)
2133 elog(ERROR, "%s: Margin must not be less than -50%%, margin=%f", __func__, margin);
2134
2135 boundsWidth = bbox.xmax - bbox.xmin;
2136 boundsHeight = bbox.ymax - bbox.ymin;
2137 if (boundsWidth <= 0 || boundsHeight <= 0)
2138 elog(ERROR, "%s: Geometric bounds are too small", __func__);
2139
2140 if (zoom < 0 || zoom >= 32)
2141 elog(ERROR, "%s: Invalid tile zoom value, %d", __func__, zoom);
2142
2143 zoomu = (uint32_t)zoom;
2144 worldTileSize = 0x01u << (zoomu > 31 ? 31 : zoomu);
2145
2146 if (x < 0 || (uint32_t)x >= worldTileSize)
2147 elog(ERROR, "%s: Invalid tile x value, %d", __func__, x);
2148 if (y < 0 || (uint32_t)y >= worldTileSize)
2149 elog(ERROR, "%s: Invalid tile y value, %d", __func__, y);
2150
2151 tileGeoSizeX = boundsWidth / worldTileSize;
2152 tileGeoSizeY = boundsHeight / worldTileSize;
2153
2154 /*
2155 * 1 margin (100%) is the same as a single tile width
2156 * if the size of the tile with margins span more than the total number of tiles,
2157 * reset x1/x2 to the bounds
2158 */
2159 if ((1 + margin * 2) > worldTileSize)
2160 {
2161 x1 = bbox.xmin;
2162 x2 = bbox.xmax;
2163 }
2164 else
2165 {
2166 x1 = bbox.xmin + tileGeoSizeX * (x - margin);
2167 x2 = bbox.xmin + tileGeoSizeX * (x + 1 + margin);
2168 }
2169
2170 y1 = bbox.ymax - tileGeoSizeY * (y + 1 + margin);
2171 y2 = bbox.ymax - tileGeoSizeY * (y - margin);
2172
2173 /* Clip the final tile bounds to the bounds of the tile plane */
2174 if (y1 < bbox.ymin) y1 = bbox.ymin;
2175 if (y2 > bbox.ymax) y2 = bbox.ymax;
2176 if (x1 < bbox.xmin) x1 = bbox.xmin;
2177 if (x2 > bbox.xmax) x2 = bbox.xmax;
2178
2179 PG_RETURN_POINTER(
2180 geometry_serialize(
2183 srid, x1, y1, x2, y2))));
2184}
2185
2186
2188Datum ST_IsCollection(PG_FUNCTION_ARGS)
2189{
2190 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_HEADER(0);
2191 uint32_t lwtype = gserialized_get_type(geom);
2192 PG_RETURN_BOOL(!lwtype_is_unitary(lwtype));
2193}
2194
2196Datum LWGEOM_makepoint(PG_FUNCTION_ARGS)
2197{
2198 double x, y, z, m;
2199 LWPOINT *point;
2201
2202 POSTGIS_DEBUG(2, "LWGEOM_makepoint called");
2203
2204 x = PG_GETARG_FLOAT8(0);
2205 y = PG_GETARG_FLOAT8(1);
2206
2207 if (PG_NARGS() == 2)
2208 point = lwpoint_make2d(SRID_UNKNOWN, x, y);
2209 else if (PG_NARGS() == 3)
2210 {
2211 z = PG_GETARG_FLOAT8(2);
2212 point = lwpoint_make3dz(SRID_UNKNOWN, x, y, z);
2213 }
2214 else if (PG_NARGS() == 4)
2215 {
2216 z = PG_GETARG_FLOAT8(2);
2217 m = PG_GETARG_FLOAT8(3);
2218 point = lwpoint_make4d(SRID_UNKNOWN, x, y, z, m);
2219 }
2220 else
2221 {
2222 elog(ERROR, "LWGEOM_makepoint: unsupported number of args: %d", PG_NARGS());
2223 PG_RETURN_NULL();
2224 }
2225
2226 result = geometry_serialize((LWGEOM *)point);
2227
2228 PG_RETURN_POINTER(result);
2229}
2230
2232Datum ST_Point(PG_FUNCTION_ARGS)
2233{
2234 double x = PG_GETARG_FLOAT8(0);
2235 double y = PG_GETARG_FLOAT8(1);
2236 int srid = PG_GETARG_INT32(2);
2237 LWPOINT *point = lwpoint_make2d(srid, x, y);
2238 GSERIALIZED *result = geometry_serialize((LWGEOM *)point);
2239 PG_RETURN_POINTER(result);
2240}
2241
2243Datum ST_PointZ(PG_FUNCTION_ARGS)
2244{
2245 double x = PG_GETARG_FLOAT8(0);
2246 double y = PG_GETARG_FLOAT8(1);
2247 double z = PG_GETARG_FLOAT8(2);
2248 int srid = PG_GETARG_INT32(3);
2249 LWPOINT *point = lwpoint_make3dz(srid, x, y, z);
2250 GSERIALIZED *result = geometry_serialize((LWGEOM *)point);
2251 PG_RETURN_POINTER(result);
2252}
2253
2255Datum ST_PointM(PG_FUNCTION_ARGS)
2256{
2257 double x = PG_GETARG_FLOAT8(0);
2258 double y = PG_GETARG_FLOAT8(1);
2259 double m = PG_GETARG_FLOAT8(2);
2260 int srid = PG_GETARG_INT32(3);
2261 LWPOINT *point = lwpoint_make3dm(srid, x, y, m);
2262 GSERIALIZED *result = geometry_serialize((LWGEOM *)point);
2263 PG_RETURN_POINTER(result);
2264}
2265
2267Datum ST_PointZM(PG_FUNCTION_ARGS)
2268{
2269 double x = PG_GETARG_FLOAT8(0);
2270 double y = PG_GETARG_FLOAT8(1);
2271 double z = PG_GETARG_FLOAT8(2);
2272 double m = PG_GETARG_FLOAT8(3);
2273 int srid = PG_GETARG_INT32(4);
2274 LWPOINT *point = lwpoint_make4d(srid, x, y, z, m);
2275 GSERIALIZED *result = geometry_serialize((LWGEOM *)point);
2276 PG_RETURN_POINTER(result);
2277}
2278
2279
2281Datum LWGEOM_makepoint3dm(PG_FUNCTION_ARGS)
2282{
2283 double x, y, m;
2284 LWPOINT *point;
2286
2287 POSTGIS_DEBUG(2, "LWGEOM_makepoint3dm called.");
2288
2289 x = PG_GETARG_FLOAT8(0);
2290 y = PG_GETARG_FLOAT8(1);
2291 m = PG_GETARG_FLOAT8(2);
2292
2293 point = lwpoint_make3dm(SRID_UNKNOWN, x, y, m);
2294 result = geometry_serialize((LWGEOM *)point);
2295
2296 PG_RETURN_POINTER(result);
2297}
2298
2300Datum LWGEOM_addpoint(PG_FUNCTION_ARGS)
2301{
2302 GSERIALIZED *pglwg1, *pglwg2, *result;
2303 LWPOINT *point;
2304 LWLINE *line, *linecopy;
2305 uint32_t uwhere = 0;
2306
2307 POSTGIS_DEBUGF(2, "%s called.", __func__);
2308
2309 pglwg1 = PG_GETARG_GSERIALIZED_P(0);
2310 pglwg2 = PG_GETARG_GSERIALIZED_P(1);
2311
2312 if (gserialized_get_type(pglwg1) != LINETYPE)
2313 {
2314 elog(ERROR, "First argument must be a LINESTRING");
2315 PG_RETURN_NULL();
2316 }
2317
2318 if (gserialized_get_type(pglwg2) != POINTTYPE)
2319 {
2320 elog(ERROR, "Second argument must be a POINT");
2321 PG_RETURN_NULL();
2322 }
2323
2324 if (gserialized_is_empty(pglwg2))
2325 {
2326 PG_RETURN_POINTER(pglwg1);
2327 }
2328
2330
2331 if (PG_NARGS() <= 2)
2332 {
2333 uwhere = line->points->npoints;
2334 }
2335 else
2336 {
2337 int32 where = PG_GETARG_INT32(2);
2338 if (where == -1)
2339 {
2340 uwhere = line->points->npoints;
2341 }
2342 else if (where < 0 || where > (int32)line->points->npoints)
2343 {
2344 elog(ERROR, "%s: Invalid offset", __func__);
2345 PG_RETURN_NULL();
2346 }
2347 else
2348 {
2349 uwhere = where;
2350 }
2351 }
2352
2355 lwline_free(line);
2356
2357 if (lwline_add_lwpoint(linecopy, point, uwhere) == LW_FAILURE)
2358 {
2359 elog(ERROR, "Point insert failed");
2360 PG_RETURN_NULL();
2361 }
2362
2363 result = geometry_serialize(lwline_as_lwgeom(linecopy));
2364
2365 /* Release memory */
2366 PG_FREE_IF_COPY(pglwg1, 0);
2367 PG_FREE_IF_COPY(pglwg2, 1);
2368 lwpoint_free(point);
2369
2370 PG_RETURN_POINTER(result);
2371}
2372
2374Datum LWGEOM_removepoint(PG_FUNCTION_ARGS)
2375{
2376 GSERIALIZED *pglwg1, *result;
2377 LWLINE *line, *outline;
2378 int32 which;
2379
2380 POSTGIS_DEBUG(2, "LWGEOM_removepoint called.");
2381
2382 pglwg1 = PG_GETARG_GSERIALIZED_P(0);
2383 which = PG_GETARG_INT32(1);
2384
2385 if (gserialized_get_type(pglwg1) != LINETYPE)
2386 {
2387 elog(ERROR, "First argument must be a LINESTRING");
2388 PG_RETURN_NULL();
2389 }
2390
2392
2393 if (which < 0 || (uint32_t)which > line->points->npoints - 1)
2394 {
2395 elog(ERROR, "Point index out of range (%u..%u)", 0, line->points->npoints - 1);
2396 PG_RETURN_NULL();
2397 }
2398
2399 if (line->points->npoints < 3)
2400 {
2401 elog(ERROR, "Can't remove points from a single segment line");
2402 PG_RETURN_NULL();
2403 }
2404
2405 outline = lwline_removepoint(line, (uint32_t)which);
2406 /* Release memory */
2407 lwline_free(line);
2408
2409 result = geometry_serialize((LWGEOM *)outline);
2410 lwline_free(outline);
2411
2412 PG_FREE_IF_COPY(pglwg1, 0);
2413 PG_RETURN_POINTER(result);
2414}
2415
2417Datum LWGEOM_setpoint_linestring(PG_FUNCTION_ARGS)
2418{
2419 GSERIALIZED *pglwg1, *pglwg2, *result;
2420 LWGEOM *lwg;
2421 LWLINE *line;
2422 LWPOINT *lwpoint;
2423 POINT4D newpoint;
2424 int64_t which;
2425
2426 POSTGIS_DEBUG(2, "LWGEOM_setpoint_linestring called.");
2427
2428 /* we copy input as we're going to modify it */
2429 pglwg1 = PG_GETARG_GSERIALIZED_P_COPY(0);
2430
2431 which = PG_GETARG_INT32(1);
2432 pglwg2 = PG_GETARG_GSERIALIZED_P(2);
2433
2434 /* Extract a POINT4D from the point */
2435 lwg = lwgeom_from_gserialized(pglwg2);
2436 lwpoint = lwgeom_as_lwpoint(lwg);
2437 if (!lwpoint)
2438 {
2439 elog(ERROR, "Third argument must be a POINT");
2440 PG_RETURN_NULL();
2441 }
2442 getPoint4d_p(lwpoint->point, 0, &newpoint);
2443 lwpoint_free(lwpoint);
2444 PG_FREE_IF_COPY(pglwg2, 2);
2445
2446 lwg = lwgeom_from_gserialized(pglwg1);
2447 line = lwgeom_as_lwline(lwg);
2448
2449 if (!line)
2450 {
2451 elog(ERROR, "First argument must be a LINESTRING");
2452 PG_RETURN_NULL();
2453 }
2454
2455 if ( line->points->npoints < 1 ) {
2456 elog(ERROR, "Line has no points");
2457 PG_RETURN_NULL();
2458 }
2459
2460 if (which < 0)
2461 {
2462 /* Use backward indexing for negative values */
2463 which += (int64_t)line->points->npoints;
2464 }
2465 if ((uint32_t)which > line->points->npoints - 1)
2466 {
2467 elog(ERROR, "abs(Point index) out of range (-)(%u..%u)", 0, line->points->npoints - 1);
2468 PG_RETURN_NULL();
2469 }
2470
2471 /*
2472 * This will change pointarray of the serialized pglwg1,
2473 */
2474 lwline_setPoint4d(line, (uint32_t)which, &newpoint);
2475 result = geometry_serialize((LWGEOM *)line);
2476
2477 /* Release memory */
2478 lwline_free(line);
2479 pfree(pglwg1); /* we forced copy, POINARRAY is released now */
2480
2481 PG_RETURN_POINTER(result);
2482}
2483
2484/* convert LWGEOM to ewkt (in TEXT format) */
2486Datum LWGEOM_asEWKT(PG_FUNCTION_ARGS)
2487{
2488 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
2489 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
2490
2492 if (PG_NARGS() > 1)
2493 precision = PG_GETARG_INT32(1);
2494
2495 PG_RETURN_TEXT_P(lwgeom_to_wkt_varlena(lwgeom, WKT_EXTENDED, precision));
2496}
2497
2505Datum LWGEOM_azimuth(PG_FUNCTION_ARGS)
2506{
2507 GSERIALIZED *geom;
2508 LWPOINT *lwpoint;
2509 POINT2D p1, p2;
2510 double result;
2511 int32_t srid;
2512
2513 /* Extract first point */
2514 geom = PG_GETARG_GSERIALIZED_P(0);
2516 if (!lwpoint)
2517 {
2518 PG_FREE_IF_COPY(geom, 0);
2519 lwpgerror("Argument must be POINT geometries");
2520 PG_RETURN_NULL();
2521 }
2522 srid = lwpoint->srid;
2523 if (!getPoint2d_p(lwpoint->point, 0, &p1))
2524 {
2525 PG_FREE_IF_COPY(geom, 0);
2526 lwpgerror("Error extracting point");
2527 PG_RETURN_NULL();
2528 }
2529 lwpoint_free(lwpoint);
2530 PG_FREE_IF_COPY(geom, 0);
2531
2532 /* Extract second point */
2533 geom = PG_GETARG_GSERIALIZED_P(1);
2535 if (!lwpoint)
2536 {
2537 PG_FREE_IF_COPY(geom, 1);
2538 lwpgerror("Argument must be POINT geometries");
2539 PG_RETURN_NULL();
2540 }
2541 if (lwpoint->srid != srid)
2542 {
2543 PG_FREE_IF_COPY(geom, 1);
2544 lwpgerror("Operation on mixed SRID geometries");
2545 PG_RETURN_NULL();
2546 }
2547 if (!getPoint2d_p(lwpoint->point, 0, &p2))
2548 {
2549 PG_FREE_IF_COPY(geom, 1);
2550 lwpgerror("Error extracting point");
2551 PG_RETURN_NULL();
2552 }
2553 lwpoint_free(lwpoint);
2554 PG_FREE_IF_COPY(geom, 1);
2555
2556 /* Standard return value for equality case */
2557 if ((p1.x == p2.x) && (p1.y == p2.y))
2558 {
2559 PG_RETURN_NULL();
2560 }
2561
2562 /* Compute azimuth */
2563 if (!azimuth_pt_pt(&p1, &p2, &result))
2564 {
2565 PG_RETURN_NULL();
2566 }
2567
2568 PG_RETURN_FLOAT8(result);
2569}
2570
2571
2580Datum geometry_project_direction(PG_FUNCTION_ARGS)
2581{
2582 GSERIALIZED *geom1, *geom2;
2583 LWPOINT *lwpoint1, *lwpoint2;
2584 LWGEOM *lwgeom1, *lwgeom2;
2585 double distance, azimuth;
2586
2587 geom1 = PG_GETARG_GSERIALIZED_P(0);
2588 distance = PG_GETARG_FLOAT8(1);
2589 azimuth = PG_GETARG_FLOAT8(2);
2590 lwgeom1 = lwgeom_from_gserialized(geom1);
2591 lwpoint1 = lwgeom_as_lwpoint(lwgeom1);
2592
2593 if (!lwpoint1)
2594 lwpgerror("Argument must be POINT geometry");
2595
2596 if (lwgeom_is_empty(lwgeom1))
2597 PG_RETURN_NULL();
2598
2599 lwpoint2 = lwpoint_project(lwpoint1, distance, azimuth);
2600 lwgeom2 = lwpoint_as_lwgeom(lwpoint2);
2601 geom2 = geometry_serialize(lwgeom2);
2602 PG_RETURN_POINTER(geom2);
2603}
2604
2605
2614Datum geometry_project_geometry(PG_FUNCTION_ARGS)
2615{
2616 GSERIALIZED *geom1, *geom2, *geom3;
2617 LWPOINT *lwpoint1, *lwpoint2, *lwpoint3;
2618 LWGEOM *lwgeom1, *lwgeom2, *lwgeom3;
2619 double distance;
2620
2621 geom1 = PG_GETARG_GSERIALIZED_P(0);
2622 geom2 = PG_GETARG_GSERIALIZED_P(1);
2623 distance = PG_GETARG_FLOAT8(2);
2624
2625 lwgeom1 = lwgeom_from_gserialized(geom1);
2626 lwpoint1 = lwgeom_as_lwpoint(lwgeom1);
2627 lwgeom2 = lwgeom_from_gserialized(geom2);
2628 lwpoint2 = lwgeom_as_lwpoint(lwgeom2);
2629
2630 if (!(lwpoint1 && lwpoint2))
2631 lwpgerror("Arguments must be POINT geometries");
2632
2633 if (lwgeom_is_empty(lwgeom1) || lwgeom_is_empty(lwgeom2))
2634 PG_RETURN_NULL();
2635
2636 if (lwpoint_same2d(lwpoint1, lwpoint2))
2637 PG_RETURN_POINTER(geom2);
2638
2639 lwpoint3 = lwpoint_project_lwpoint(lwpoint1, lwpoint2, distance);
2640 lwgeom3 = lwpoint_as_lwgeom(lwpoint3);
2641 geom3 = geometry_serialize(lwgeom3);
2642
2643 PG_RETURN_POINTER(geom3);
2644}
2645
2646
2647
2655Datum geometry_line_extend(PG_FUNCTION_ARGS)
2656{
2657 GSERIALIZED *geom1, *geom2;
2658 LWLINE *lwline1, *lwline2;
2659 LWGEOM *lwgeom1, *lwgeom2;
2660 double distance_forward, distance_backward;
2661
2662 geom1 = PG_GETARG_GSERIALIZED_P(0);
2663 distance_forward = PG_GETARG_FLOAT8(1);
2664 distance_backward = PG_GETARG_FLOAT8(2);
2665
2666 lwgeom1 = lwgeom_from_gserialized(geom1);
2667 lwline1 = lwgeom_as_lwline(lwgeom1);
2668 if (!lwline1)
2669 lwpgerror("Argument must be LINESTRING geometry");
2670
2671 if (lwline_is_empty(lwline1))
2672 PG_RETURN_NULL();
2673
2674 if (lwline_length_2d(lwline1) <= 0.0)
2675 PG_RETURN_POINTER(geom1);
2676
2677 lwline2 = lwline_extend(lwline1, distance_forward, distance_backward);
2678 lwgeom2 = lwline_as_lwgeom(lwline2);
2679 geom2 = geometry_serialize(lwgeom2);
2680
2681 PG_RETURN_POINTER(geom2);
2682}
2683
2684
2685
2694Datum LWGEOM_angle(PG_FUNCTION_ARGS)
2695{
2696 GSERIALIZED *seri_geoms[4];
2697 LWGEOM *geom_unser;
2698 LWPOINT *lwpoint;
2699 POINT2D points[4];
2700 double az1, az2;
2701 double result;
2702 int32_t srids[4];
2703 int i = 0;
2704 int j = 0;
2705 int err_code = 0;
2706 int n_args = PG_NARGS();
2707
2708 /* no deserialize, checking for common error first*/
2709 for (i = 0; i < n_args; i++)
2710 {
2711 seri_geoms[i] = PG_GETARG_GSERIALIZED_P(i);
2712 if (gserialized_is_empty(seri_geoms[i]))
2713 { /* empty geom */
2714 if (i == 3)
2715 {
2716 n_args = 3;
2717 }
2718 else
2719 {
2720 err_code = 1;
2721 break;
2722 }
2723 }
2724 else
2725 {
2726 if (gserialized_get_type(seri_geoms[i]) != POINTTYPE)
2727 { /* geom type */
2728 err_code = 2;
2729 break;
2730 }
2731 else
2732 {
2733 srids[i] = gserialized_get_srid(seri_geoms[i]);
2734 if (srids[0] != srids[i])
2735 { /* error on srid*/
2736 err_code = 3;
2737 break;
2738 }
2739 }
2740 }
2741 }
2742 if (err_code > 0)
2743 switch (err_code)
2744 {
2745 default: /*always executed*/
2746 for (j = 0; j <= i; j++)
2747 PG_FREE_IF_COPY(seri_geoms[j], j);
2748 /*FALLTHROUGH*/
2749 case 1:
2750 lwpgerror("Empty geometry");
2751 PG_RETURN_NULL();
2752 break;
2753
2754 case 2:
2755 lwpgerror("Argument must be POINT geometries");
2756 PG_RETURN_NULL();
2757 break;
2758
2759 case 3:
2760 lwpgerror("Operation on mixed SRID geometries");
2761 PG_RETURN_NULL();
2762 break;
2763 }
2764 /* extract points */
2765 for (i = 0; i < n_args; i++)
2766 {
2767 geom_unser = lwgeom_from_gserialized(seri_geoms[i]);
2768 lwpoint = lwgeom_as_lwpoint(geom_unser);
2769 if (!lwpoint)
2770 {
2771 for (j = 0; j < n_args; j++)
2772 PG_FREE_IF_COPY(seri_geoms[j], j);
2773 lwpgerror("Error unserializing geometry");
2774 PG_RETURN_NULL();
2775 }
2776
2777 if (!getPoint2d_p(lwpoint->point, 0, &points[i]))
2778 {
2779 /* // can't free serialized geom, it might be needed by lw
2780 for (j=0;j<n_args;j++)
2781 PG_FREE_IF_COPY(seri_geoms[j], j); */
2782 lwpgerror("Error extracting point");
2783 PG_RETURN_NULL();
2784 }
2785 /* lwfree(geom_unser);don't do, lw may rely on this memory
2786 lwpoint_free(lwpoint); dont do , this memory is needed ! */
2787 }
2788 /* // can't free serialized geom, it might be needed by lw
2789 for (j=0;j<n_args;j++)
2790 PG_FREE_IF_COPY(seri_geoms[j], j); */
2791
2792 /* compute azimuth for the 2 pairs of points
2793 * note that angle is not defined identically for 3 points or 4 points*/
2794 if (n_args == 3)
2795 { /* we rely on azimuth to complain if points are identical */
2796 if (!azimuth_pt_pt(&points[0], &points[1], &az1))
2797 PG_RETURN_NULL();
2798 if (!azimuth_pt_pt(&points[2], &points[1], &az2))
2799 PG_RETURN_NULL();
2800 }
2801 else
2802 {
2803 if (!azimuth_pt_pt(&points[0], &points[1], &az1))
2804 PG_RETURN_NULL();
2805 if (!azimuth_pt_pt(&points[2], &points[3], &az2))
2806 PG_RETURN_NULL();
2807 }
2808 result = az2 - az1;
2809 result += (result < 0) * 2 * M_PI; /* we dont want negative angle*/
2810 PG_RETURN_FLOAT8(result);
2811}
2812
2813/*
2814 * optimistic_overlap(Polygon P1, Multipolygon MP2, double dist)
2815 * returns true if P1 overlaps MP2
2816 * method: bbox check -
2817 * is separation < dist? no - return false (quick)
2818 * yes - return distance(P1,MP2) < dist
2819 */
2821Datum optimistic_overlap(PG_FUNCTION_ARGS)
2822{
2823 GSERIALIZED *pg_geom1 = PG_GETARG_GSERIALIZED_P(0);
2824 GSERIALIZED *pg_geom2 = PG_GETARG_GSERIALIZED_P(1);
2825 double dist = PG_GETARG_FLOAT8(2);
2826 GBOX g1_bvol;
2827 double calc_dist;
2828 LWGEOM *geom1 = lwgeom_from_gserialized(pg_geom1);
2829 LWGEOM *geom2 = lwgeom_from_gserialized(pg_geom2);
2830 gserialized_error_if_srid_mismatch(pg_geom1, pg_geom2, __func__);
2831
2832 if (geom1->type != POLYGONTYPE)
2833 {
2834 elog(ERROR, "optimistic_overlap: first arg isn't a polygon\n");
2835 PG_RETURN_NULL();
2836 }
2837
2838 if (geom2->type != POLYGONTYPE && geom2->type != MULTIPOLYGONTYPE)
2839 {
2840 elog(ERROR, "optimistic_overlap: 2nd arg isn't a [multi-]polygon\n");
2841 PG_RETURN_NULL();
2842 }
2843
2844 /*bbox check */
2845 gserialized_get_gbox_p(pg_geom1, &g1_bvol);
2846
2847 g1_bvol.xmin = g1_bvol.xmin - dist;
2848 g1_bvol.ymin = g1_bvol.ymin - dist;
2849 g1_bvol.xmax = g1_bvol.xmax + dist;
2850 g1_bvol.ymax = g1_bvol.ymax + dist;
2851
2852 if ((g1_bvol.xmin > geom2->bbox->xmax) || (g1_bvol.xmax < geom2->bbox->xmin) ||
2853 (g1_bvol.ymin > geom2->bbox->ymax) || (g1_bvol.ymax < geom2->bbox->ymin))
2854 {
2855 PG_RETURN_BOOL(false); /*bbox not overlap */
2856 }
2857
2858 /*
2859 * compute distances
2860 * should be a fast calc if they actually do intersect
2861 */
2862 calc_dist =
2863 DatumGetFloat8(DirectFunctionCall2(ST_Distance, PointerGetDatum(pg_geom1), PointerGetDatum(pg_geom2)));
2864
2865 PG_RETURN_BOOL(calc_dist < dist);
2866}
2867
2868/*affine transform geometry */
2870Datum LWGEOM_affine(PG_FUNCTION_ARGS)
2871{
2872 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P_COPY(0);
2873 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
2874 GSERIALIZED *ret;
2875 AFFINE affine;
2876
2877 affine.afac = PG_GETARG_FLOAT8(1);
2878 affine.bfac = PG_GETARG_FLOAT8(2);
2879 affine.cfac = PG_GETARG_FLOAT8(3);
2880 affine.dfac = PG_GETARG_FLOAT8(4);
2881 affine.efac = PG_GETARG_FLOAT8(5);
2882 affine.ffac = PG_GETARG_FLOAT8(6);
2883 affine.gfac = PG_GETARG_FLOAT8(7);
2884 affine.hfac = PG_GETARG_FLOAT8(8);
2885 affine.ifac = PG_GETARG_FLOAT8(9);
2886 affine.xoff = PG_GETARG_FLOAT8(10);
2887 affine.yoff = PG_GETARG_FLOAT8(11);
2888 affine.zoff = PG_GETARG_FLOAT8(12);
2889
2890 POSTGIS_DEBUG(2, "LWGEOM_affine called.");
2891
2892 lwgeom_affine(lwgeom, &affine);
2893
2894 /* COMPUTE_BBOX TAINTING */
2895 if (lwgeom->bbox)
2896 {
2897 lwgeom_refresh_bbox(lwgeom);
2898 }
2899 ret = geometry_serialize(lwgeom);
2900
2901 /* Release memory */
2902 lwgeom_free(lwgeom);
2903 PG_FREE_IF_COPY(geom, 0);
2904
2905 PG_RETURN_POINTER(ret);
2906}
2907
2909Datum ST_GeoHash(PG_FUNCTION_ARGS)
2910{
2911
2912 GSERIALIZED *geom = NULL;
2913 int precision = 0;
2914 lwvarlena_t *geohash = NULL;
2915
2916 if (PG_ARGISNULL(0))
2917 {
2918 PG_RETURN_NULL();
2919 }
2920
2921 geom = PG_GETARG_GSERIALIZED_P(0);
2922
2923 if (!PG_ARGISNULL(1))
2924 {
2925 precision = PG_GETARG_INT32(1);
2926 }
2927
2929 if (geohash)
2930 PG_RETURN_TEXT_P(geohash);
2931 PG_RETURN_NULL();
2932}
2933
2935Datum _ST_SortableHash(PG_FUNCTION_ARGS)
2936{
2937 if (PG_ARGISNULL(0))
2938 PG_RETURN_NULL();
2939 PG_RETURN_INT64(gserialized_get_sortable_hash(PG_GETARG_GSERIALIZED_P(0)));
2940}
2941
2943Datum ST_CollectionExtract(PG_FUNCTION_ARGS)
2944{
2945 GSERIALIZED *gser_in, *gser_out;
2946 LWGEOM *lwg_in = NULL;
2947 LWGEOM *lwg_out = NULL;
2948 int extype = 0;
2949
2950 if (PG_NARGS() > 1)
2951 extype = PG_GETARG_INT32(1);
2952
2953 /* Ensure the right type was input */
2954 if (!(extype == 0 || extype == POINTTYPE || extype == LINETYPE || extype == POLYGONTYPE))
2955 {
2956 elog(ERROR, "ST_CollectionExtract: only point, linestring and polygon may be extracted");
2957 PG_RETURN_NULL();
2958 }
2959
2960 gser_in = PG_GETARG_GSERIALIZED_P(0);
2961 lwg_in = lwgeom_from_gserialized(gser_in);
2962
2963 /* Mirror non-collections right back */
2964 if (!lwgeom_is_collection(lwg_in))
2965 {
2966 /* Non-collections of the matching type go back */
2967 if (lwg_in->type == extype || !extype)
2968 {
2969 lwgeom_free(lwg_in);
2970 PG_RETURN_POINTER(gser_in);
2971 }
2972 /* Others go back as EMPTY */
2973 else
2974 {
2975 lwg_out = lwgeom_construct_empty(extype, lwg_in->srid, lwgeom_has_z(lwg_in), lwgeom_has_m(lwg_in));
2976 PG_RETURN_POINTER(geometry_serialize(lwg_out));
2977 }
2978 }
2979
2980 lwg_out = (LWGEOM*)lwcollection_extract((LWCOLLECTION*)lwg_in, extype);
2981
2982 gser_out = geometry_serialize(lwg_out);
2983 lwgeom_free(lwg_in);
2984 lwgeom_free(lwg_out);
2985 PG_RETURN_POINTER(gser_out);
2986}
2987
2989Datum ST_CollectionHomogenize(PG_FUNCTION_ARGS)
2990{
2991 GSERIALIZED *input = PG_GETARG_GSERIALIZED_P(0);
2992 GSERIALIZED *output;
2993 LWGEOM *lwgeom = lwgeom_from_gserialized(input);
2994 LWGEOM *lwoutput = NULL;
2995
2996 lwoutput = lwgeom_homogenize(lwgeom);
2997 lwgeom_free(lwgeom);
2998
2999 if (!lwoutput)
3000 {
3001 PG_FREE_IF_COPY(input, 0);
3002 PG_RETURN_NULL();
3003 }
3004
3005 output = geometry_serialize(lwoutput);
3006 lwgeom_free(lwoutput);
3007
3008 PG_FREE_IF_COPY(input, 0);
3009 PG_RETURN_POINTER(output);
3010}
3011
3012Datum ST_RemoveRepeatedPoints(PG_FUNCTION_ARGS);
3014Datum ST_RemoveRepeatedPoints(PG_FUNCTION_ARGS)
3015{
3016 GSERIALIZED *g_in = PG_GETARG_GSERIALIZED_P_COPY(0);
3017 uint32_t type = gserialized_get_type(g_in);
3018 GSERIALIZED *g_out;
3019 LWGEOM *lwgeom_in = NULL;
3020 double tolerance = 0.0;
3021 int modified = LW_FALSE;
3022
3023 /* Don't even start to think about points */
3024 if (type == POINTTYPE)
3025 PG_RETURN_POINTER(g_in);
3026
3027 if (PG_NARGS() > 1 && !PG_ARGISNULL(1))
3028 tolerance = PG_GETARG_FLOAT8(1);
3029
3030 lwgeom_in = lwgeom_from_gserialized(g_in);
3031 modified = lwgeom_remove_repeated_points_in_place(lwgeom_in, tolerance);
3032 if (!modified)
3033 {
3034 /* Since there were no changes, we can return the input to avoid the serialization */
3035 PG_RETURN_POINTER(g_in);
3036 }
3037
3038 g_out = geometry_serialize(lwgeom_in);
3039
3040 pfree(g_in);
3041 PG_RETURN_POINTER(g_out);
3042}
3043
3044Datum ST_FlipCoordinates(PG_FUNCTION_ARGS);
3046Datum ST_FlipCoordinates(PG_FUNCTION_ARGS)
3047{
3048 GSERIALIZED *in = PG_GETARG_GSERIALIZED_P_COPY(0);
3049 GSERIALIZED *out;
3050 LWGEOM *lwgeom = lwgeom_from_gserialized(in);
3051
3053 out = geometry_serialize(lwgeom);
3054
3055 lwgeom_free(lwgeom);
3056 PG_FREE_IF_COPY(in, 0);
3057
3058 PG_RETURN_POINTER(out);
3059}
3060
3061static LWORD
3063{
3064 if (n == 'x' || n == 'X')
3065 return LWORD_X;
3066 if (n == 'y' || n == 'Y')
3067 return LWORD_Y;
3068 if (n == 'z' || n == 'Z')
3069 return LWORD_Z;
3070 if (n == 'm' || n == 'M')
3071 return LWORD_M;
3072 lwpgerror("Invalid ordinate name '%c'. Expected x,y,z or m", n);
3073 return (LWORD)-1;
3074}
3075
3076Datum ST_SwapOrdinates(PG_FUNCTION_ARGS);
3078Datum ST_SwapOrdinates(PG_FUNCTION_ARGS)
3079{
3080 GSERIALIZED *in;
3081 GSERIALIZED *out;
3082 LWGEOM *lwgeom;
3083 const char *ospec;
3084 LWORD o1, o2;
3085
3086 ospec = PG_GETARG_CSTRING(1);
3087 if (strlen(ospec) != 2)
3088 {
3089 lwpgerror(
3090 "Invalid ordinate specification. "
3091 "Need two letters from the set (x,y,z,m). "
3092 "Got '%s'",
3093 ospec);
3094 PG_RETURN_NULL();
3095 }
3096 o1 = ordname2ordval(ospec[0]);
3097 o2 = ordname2ordval(ospec[1]);
3098
3099 in = PG_GETARG_GSERIALIZED_P_COPY(0);
3100
3101 /* Check presence of given ordinates */
3102 if ((o1 == LWORD_M || o2 == LWORD_M) && !gserialized_has_m(in))
3103 {
3104 lwpgerror("Geometry does not have an M ordinate");
3105 PG_RETURN_NULL();
3106 }
3107 if ((o1 == LWORD_Z || o2 == LWORD_Z) && !gserialized_has_z(in))
3108 {
3109 lwpgerror("Geometry does not have a Z ordinate");
3110 PG_RETURN_NULL();
3111 }
3112
3113 /* Nothing to do if swapping the same ordinate, pity for the copy... */
3114 if (o1 == o2)
3115 PG_RETURN_POINTER(in);
3116
3117 lwgeom = lwgeom_from_gserialized(in);
3118 lwgeom_swap_ordinates(lwgeom, o1, o2);
3119 out = geometry_serialize(lwgeom);
3120 lwgeom_free(lwgeom);
3121 PG_FREE_IF_COPY(in, 0);
3122 PG_RETURN_POINTER(out);
3123}
3124
3125/*
3126 * ST_BoundingDiagonal(inp geometry, fits boolean)
3127 */
3128Datum ST_BoundingDiagonal(PG_FUNCTION_ARGS);
3130Datum ST_BoundingDiagonal(PG_FUNCTION_ARGS)
3131{
3132 GSERIALIZED *geom_out;
3133 bool fits = PG_GETARG_BOOL(1);
3134 LWGEOM *lwgeom_out = NULL;
3135
3136 GBOX gbox = {0};
3137 int hasz;
3138 int hasm;
3139 int32_t srid;
3140
3141 POINT4D pt;
3142 POINTARRAY *pa;
3143
3144 if (fits)
3145 {
3146 GSERIALIZED *geom_in = PG_GETARG_GSERIALIZED_P(0);
3147 LWGEOM *lwgeom_in = lwgeom_from_gserialized(geom_in);
3148 lwgeom_calculate_gbox(lwgeom_in, &gbox);
3149 hasz = FLAGS_GET_Z(lwgeom_in->flags);
3150 hasm = FLAGS_GET_M(lwgeom_in->flags);
3151 srid = lwgeom_in->srid;
3152 }
3153 else
3154 {
3155 uint8_t type;
3156 lwflags_t flags;
3157 int res = gserialized_datum_get_internals_p(PG_GETARG_DATUM(0), &gbox, &flags, &type, &srid);
3158 hasz = FLAGS_GET_Z(flags);
3159 hasm = FLAGS_GET_M(flags);
3160 if (res == LW_FAILURE)
3161 {
3162 lwgeom_out = lwgeom_construct_empty(LINETYPE, srid, hasz, hasm);
3163 }
3164 }
3165
3166 if (!lwgeom_out)
3167 {
3168 pa = ptarray_construct_empty(hasz, hasm, 2);
3169 pt.x = gbox.xmin;
3170 pt.y = gbox.ymin;
3171 pt.z = gbox.zmin;
3172 pt.m = gbox.mmin;
3173 ptarray_append_point(pa, &pt, LW_TRUE);
3174 pt.x = gbox.xmax;
3175 pt.y = gbox.ymax;
3176 pt.z = gbox.zmax;
3177 pt.m = gbox.mmax;
3178 ptarray_append_point(pa, &pt, LW_TRUE);
3179 lwgeom_out = lwline_as_lwgeom(lwline_construct(srid, NULL, pa));
3180 }
3181
3182 geom_out = geometry_serialize(lwgeom_out);
3183 lwgeom_free(lwgeom_out);
3184
3185 PG_RETURN_POINTER(geom_out);
3186}
3187
3188Datum ST_Scale(PG_FUNCTION_ARGS);
3190Datum ST_Scale(PG_FUNCTION_ARGS)
3191{
3192 GSERIALIZED *geom;
3193 GSERIALIZED *geom_scale = PG_GETARG_GSERIALIZED_P(1);
3194 GSERIALIZED *geom_origin = NULL;
3195 LWGEOM *lwg, *lwg_scale, *lwg_origin;
3196 LWPOINT *lwpt_scale, *lwpt_origin;
3197 POINT4D origin;
3198 POINT4D factors;
3199 bool translate = false;
3200 GSERIALIZED *ret;
3201 AFFINE aff;
3202
3203 /* Make sure we have a valid scale input */
3204 lwg_scale = lwgeom_from_gserialized(geom_scale);
3205 lwpt_scale = lwgeom_as_lwpoint(lwg_scale);
3206 if (!lwpt_scale)
3207 {
3208 lwgeom_free(lwg_scale);
3209 PG_FREE_IF_COPY(geom_scale, 1);
3210 lwpgerror("Scale factor geometry parameter must be a point");
3211 PG_RETURN_NULL();
3212 }
3213
3214 /* Geom Will be modified in place, so take a copy */
3215 geom = PG_GETARG_GSERIALIZED_P_COPY(0);
3216 lwg = lwgeom_from_gserialized(geom);
3217
3218 /* Empty point, return input untouched */
3219 if (lwgeom_is_empty(lwg))
3220 {
3221 lwgeom_free(lwg_scale);
3222 lwgeom_free(lwg);
3223 PG_FREE_IF_COPY(geom_scale, 1);
3224 PG_RETURN_POINTER(geom);
3225 }
3226
3227 /* Once we read the scale data into local static point, we can */
3228 /* free the lwgeom */
3229 lwpoint_getPoint4d_p(lwpt_scale, &factors);
3230 if (!lwgeom_has_z(lwg_scale))
3231 factors.z = 1.0;
3232 if (!lwgeom_has_m(lwg_scale))
3233 factors.m = 1.0;
3234 lwgeom_free(lwg_scale);
3235
3236 /* Do we have the optional false origin? */
3237 if (PG_NARGS() > 2 && !PG_ARGISNULL(2))
3238 {
3239 geom_origin = PG_GETARG_GSERIALIZED_P(2);
3240 lwg_origin = lwgeom_from_gserialized(geom_origin);
3241 lwpt_origin = lwgeom_as_lwpoint(lwg_origin);
3242 if (lwpt_origin)
3243 {
3244 lwpoint_getPoint4d_p(lwpt_origin, &origin);
3245 translate = true;
3246 }
3247 /* Free the false origin inputs */
3248 lwgeom_free(lwg_origin);
3249 PG_FREE_IF_COPY(geom_origin, 2);
3250 }
3251
3252 /* If we have false origin, translate to it before scaling */
3253 if (translate)
3254 {
3255 /* Initialize affine */
3256 memset(&aff, 0, sizeof(AFFINE));
3257 /* Set rotation/scale/sheer matrix to no-op */
3258 aff.afac = aff.efac = aff.ifac = 1.0;
3259 /* Strip false origin from all coordinates */
3260 aff.xoff = -1 * origin.x;
3261 aff.yoff = -1 * origin.y;
3262 aff.zoff = -1 * origin.z;
3263 lwgeom_affine(lwg, &aff);
3264 }
3265
3266 lwgeom_scale(lwg, &factors);
3267
3268 /* Return to original origin after scaling */
3269 if (translate)
3270 {
3271 aff.xoff *= -1;
3272 aff.yoff *= -1;
3273 aff.zoff *= -1;
3274 lwgeom_affine(lwg, &aff);
3275 }
3276
3277 /* Cleanup and return */
3278 ret = geometry_serialize(lwg);
3279 lwgeom_free(lwg);
3280 PG_FREE_IF_COPY(geom, 0);
3281 PG_FREE_IF_COPY(geom_scale, 1);
3282 PG_RETURN_POINTER(ret);
3283}
3284
3285Datum ST_Points(PG_FUNCTION_ARGS);
3287Datum ST_Points(PG_FUNCTION_ARGS)
3288{
3289 if (PG_ARGISNULL(0))
3290 {
3291 PG_RETURN_NULL();
3292 }
3293 else
3294 {
3295 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
3296 GSERIALIZED *ret;
3297 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
3299
3300 lwgeom_free(lwgeom);
3301
3302 ret = geometry_serialize(lwmpoint_as_lwgeom(result));
3304 PG_RETURN_POINTER(ret);
3305 }
3306}
3307
3309Datum ST_QuantizeCoordinates(PG_FUNCTION_ARGS)
3310{
3311 GSERIALIZED *input;
3313 LWGEOM *g;
3314 int32_t prec_x;
3315 int32_t prec_y;
3316 int32_t prec_z;
3317 int32_t prec_m;
3318
3319 if (PG_ARGISNULL(0))
3320 PG_RETURN_NULL();
3321 if (PG_ARGISNULL(1))
3322 {
3323 lwpgerror("Must specify precision");
3324 PG_RETURN_NULL();
3325 }
3326 else
3327 {
3328 prec_x = PG_GETARG_INT32(1);
3329 }
3330 prec_y = PG_ARGISNULL(2) ? prec_x : PG_GETARG_INT32(2);
3331 prec_z = PG_ARGISNULL(3) ? prec_x : PG_GETARG_INT32(3);
3332 prec_m = PG_ARGISNULL(4) ? prec_x : PG_GETARG_INT32(4);
3333
3334 input = PG_GETARG_GSERIALIZED_P_COPY(0);
3335
3336 g = lwgeom_from_gserialized(input);
3337
3338 lwgeom_trim_bits_in_place(g, prec_x, prec_y, prec_z, prec_m);
3339
3340 result = geometry_serialize(g);
3341 lwgeom_free(g);
3342 PG_FREE_IF_COPY(input, 0);
3343 PG_RETURN_POINTER(result);
3344}
3345
3346/*
3347 * ST_FilterByM(in geometry, val double precision)
3348 */
3350Datum LWGEOM_FilterByM(PG_FUNCTION_ARGS)
3351{
3352 GSERIALIZED *geom_in;
3353 GSERIALIZED *geom_out;
3354 LWGEOM *lwgeom_in;
3355 LWGEOM *lwgeom_out;
3356 double min, max;
3357 int returnm;
3358 int hasm;
3359
3360 if (PG_NARGS() > 0 && !PG_ARGISNULL(0))
3361 {
3362 geom_in = PG_GETARG_GSERIALIZED_P(0);
3363 }
3364 else
3365 {
3366 PG_RETURN_NULL();
3367 }
3368
3369 if (PG_NARGS() > 1 && !PG_ARGISNULL(1))
3370 min = PG_GETARG_FLOAT8(1);
3371 else
3372 {
3373 min = DBL_MIN;
3374 }
3375 if (PG_NARGS() > 2 && !PG_ARGISNULL(2))
3376 max = PG_GETARG_FLOAT8(2);
3377 else
3378 {
3379 max = DBL_MAX;
3380 }
3381 if (PG_NARGS() > 3 && !PG_ARGISNULL(3) && PG_GETARG_BOOL(3))
3382 returnm = 1;
3383 else
3384 {
3385 returnm = 0;
3386 }
3387
3388 if (min > max)
3389 {
3390 elog(ERROR, "Min-value cannot be larger than Max value\n");
3391 PG_RETURN_NULL();
3392 }
3393
3394 lwgeom_in = lwgeom_from_gserialized(geom_in);
3395
3396 hasm = lwgeom_has_m(lwgeom_in);
3397
3398 if (!hasm)
3399 {
3400 elog(NOTICE, "No M-value, No vertex removed\n");
3401 PG_RETURN_POINTER(geom_in);
3402 }
3403
3404 lwgeom_out = lwgeom_filter_m(lwgeom_in, min, max, returnm);
3405
3406 geom_out = geometry_serialize(lwgeom_out);
3407 lwgeom_free(lwgeom_out);
3408 PG_RETURN_POINTER(geom_out);
3409}
3410
3412Datum boundary(PG_FUNCTION_ARGS)
3413{
3414 GSERIALIZED *geom1;
3416 LWGEOM *lwgeom, *lwresult;
3417
3418 geom1 = PG_GETARG_GSERIALIZED_P(0);
3419
3420 /* Empty.Boundary() == Empty, but of other dimension, so can't shortcut */
3421
3422 lwgeom = lwgeom_from_gserialized(geom1);
3423 lwresult = lwgeom_boundary(lwgeom);
3424 if (!lwresult)
3425 {
3426 lwgeom_free(lwgeom);
3427 PG_RETURN_NULL();
3428 }
3429
3430 result = geometry_serialize(lwresult);
3431
3432 lwgeom_free(lwgeom);
3433 lwgeom_free(lwresult);
3434
3435 PG_RETURN_POINTER(result);
3436}
static uint8_t precision
Definition cu_in_twkb.c:25
char result[OUT_DOUBLE_BUFFER_SIZE]
Definition cu_print.c:267
int gbox_merge(const GBOX *new_box, GBOX *merge_box)
Update the merged GBOX to be large enough to include itself and the new box.
Definition gbox.c:257
void gbox_expand(GBOX *g, double d)
Move the box minimums down and the maximums up by the distance provided.
Definition gbox.c:97
void gbox_init(GBOX *gbox)
Zero out all the entries in the GBOX.
Definition gbox.c:40
void gbox_expand_xyzm(GBOX *g, double dx, double dy, double dz, double dm)
Move the box minimums down and the maximums up by the distances provided.
Definition gbox.c:115
GBOX * gbox_copy(const GBOX *box)
Return a copy of the GBOX, based on dimensionality of flags.
Definition gbox.c:438
void gserialized_error_if_srid_mismatch(const GSERIALIZED *g1, const GSERIALIZED *g2, const char *funcname)
void gserialized_error_if_srid_mismatch_reference(const GSERIALIZED *g1, const int32_t srid2, const char *funcname)
int gserialized_has_bbox(const GSERIALIZED *g)
Check if a GSERIALIZED has a bounding box without deserializing first.
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)...
int gserialized_ndims(const GSERIALIZED *g)
Return the number of dimensions (2, 3, 4) in a geometry.
uint32_t gserialized_get_version(const GSERIALIZED *g)
Return the serialization version.
Definition gserialized.c:71
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
int gserialized_get_gbox_p(const GSERIALIZED *g, GBOX *gbox)
Read the box from the GSERIALIZED or calculate it if necessary.
Definition gserialized.c:94
int gserialized_has_m(const GSERIALIZED *g)
Check if a GSERIALIZED has an M ordinate.
int gserialized_is_empty(const GSERIALIZED *g)
Check if a GSERIALIZED is empty without deserializing first.
int gserialized_has_z(const GSERIALIZED *g)
Check if a GSERIALIZED has a Z ordinate.
uint64_t gserialized_get_sortable_hash(const GSERIALIZED *g)
Return a sortable key based on gserialized.
uint32_t gserialized_get_type(const GSERIALIZED *g)
Extract the geometry type from the serialized form (it hides in the anonymous data area,...
int gserialized_cmp(const GSERIALIZED *g1, const GSERIALIZED *g2)
Return -1 if g1 is "less than" g2, 1 if g1 is "greater than" g2 and 0 if g1 and g2 are the "same".
int gserialized_datum_get_internals_p(Datum gsdatum, GBOX *gbox, lwflags_t *flags, uint8_t *type, int32_t *srid)
Peak into a GSERIALIZED datum to find its bounding box and some other metadata.
lwvarlena_t * lwgeom_geohash(const LWGEOM *lwgeom, int precision)
Calculate the GeoHash (http://geohash.org) string for a geometry.
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition lwutil.c:216
LWLINE * lwline_removepoint(LWLINE *line, uint32_t which)
Definition lwline.c:357
LWGEOM * lwmpoint_as_lwgeom(const LWMPOINT *obj)
Definition lwgeom.c:332
void lwgeom_refresh_bbox(LWGEOM *lwgeom)
Drop current bbox and calculate a fresh one.
Definition lwgeom.c:735
int lwpoint_getPoint4d_p(const LWPOINT *point, POINT4D *out)
Definition lwpoint.c:57
LWCOLLECTION * lwcollection_construct(uint8_t type, int32_t srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition lwgeom.c:372
#define LW_FALSE
Definition liblwgeom.h:94
uint32_t lwtype_get_collectiontype(uint8_t type)
Given an lwtype number, what homogeneous collection can hold it?
Definition lwgeom.c:1222
@ LWORD_Z
Definition liblwgeom.h:133
@ LWORD_M
Definition liblwgeom.h:134
@ LWORD_Y
Definition liblwgeom.h:132
@ LWORD_X
Definition liblwgeom.h:131
#define COLLECTIONTYPE
Definition liblwgeom.h:108
LWLINE * lwline_from_lwgeom_array(int32_t srid, uint32_t ngeoms, LWGEOM **geoms)
Definition lwline.c:151
int32_t lwgeom_get_srid(const LWGEOM *geom)
Return SRID number.
Definition lwgeom.c:955
LWPOINT * lwpoint_make4d(int32_t srid, double x, double y, double z, double m)
Definition lwpoint.c:195
double lwgeom_maxdistance2d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing max distance calculation.
Definition measures.c:180
LWGEOM * lwgeom_closest_point(const LWGEOM *lw1, const LWGEOM *lw2)
Definition measures.c:55
LWPOINT * lwpoint_make3dz(int32_t srid, double x, double y, double z)
Definition lwpoint.c:173
int azimuth_pt_pt(const POINT2D *p1, const POINT2D *p2, double *ret)
Compute the azimuth of segment AB in radians.
Definition measures.c:2408
void lwmpoint_free(LWMPOINT *mpt)
Definition lwmpoint.c:72
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
void lwgeom_trim_bits_in_place(LWGEOM *geom, int32_t prec_x, int32_t prec_y, int32_t prec_z, int32_t prec_m)
Trim the bits of an LWGEOM in place, to optimize it for compression.
Definition lwgeom.c:2693
void lwpoint_free(LWPOINT *pt)
Definition lwpoint.c:213
LWPOINT * lwpoint_project(const LWPOINT *lwpoint1, double distance, double azimuth)
Definition lwpoint.c:290
void lwgeom_longitude_shift(LWGEOM *lwgeom)
Definition lwgeom.c:1036
#define LW_FAILURE
Definition liblwgeom.h:96
const char * lwgeom_version(void)
Return lwgeom version string (not to be freed)
Definition lwgeom_api.c:38
void lwgeom_free(LWGEOM *geom)
Definition lwgeom.c:1246
LWGEOM * lwgeom_closest_line(const LWGEOM *lw1, const LWGEOM *lw2)
Definition measures.c:43
LWGEOM * lwgeom_as_multi(const LWGEOM *lwgeom)
Create a new LWGEOM of the appropriate MULTI* type.
Definition lwgeom.c:408
double lwgeom_maxdistance3d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling 3d max distance calculations and dfullywithin calculations.
Definition measures3d.c:344
char * lwgeom_summary(const LWGEOM *lwgeom, int offset)
#define MULTILINETYPE
Definition liblwgeom.h:106
LWGEOM * lwgeom_boundary(LWGEOM *lwgeom)
Definition lwgeom.c:2714
LWPOLY * lwpoly_from_lwlines(const LWLINE *shell, uint32_t nholes, const LWLINE **holes)
Definition lwpoly.c:359
double lwgeom_perimeter_2d(const LWGEOM *geom)
Definition lwgeom.c:2044
int lwpoint_inside_circle(const LWPOINT *p, double cx, double cy, double rad)
Definition lwgeom.c:690
#define MULTISURFACETYPE
Definition liblwgeom.h:113
#define LINETYPE
Definition liblwgeom.h:103
#define WKT_EXTENDED
Definition liblwgeom.h:2221
#define LW_SUCCESS
Definition liblwgeom.h:97
LWGEOM * lwgeom_force_3dz(const LWGEOM *geom, double zval)
Definition lwgeom.c:827
uint16_t lwflags_t
Definition liblwgeom.h:299
LWGEOM * lwgeom_furthest_line_3d(LWGEOM *lw1, LWGEOM *lw2)
Definition measures3d.c:116
#define MULTIPOINTTYPE
Definition liblwgeom.h:105
LWGEOM * lwgeom_as_curve(const LWGEOM *lwgeom)
Create a new LWGEOM of the appropriate CURVE* type.
Definition lwgeom.c:448
int lwgeom_remove_repeated_points_in_place(LWGEOM *in, double tolerance)
Definition lwgeom.c:1695
LWGEOM * lwgeom_force_sfs(LWGEOM *geom, int version)
Definition lwgeom.c:877
int getPoint2d_p(const POINTARRAY *pa, uint32_t n, POINT2D *point)
Definition lwgeom_api.c:342
LWGEOM * lwgeom_closest_point_3d(const LWGEOM *lw1, const LWGEOM *lw2)
Definition measures3d.c:122
LWGEOM * lwgeom_force_2d(const LWGEOM *geom)
Strip out the Z/M components of an LWGEOM.
Definition lwgeom.c:821
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
Definition ptarray.c:59
double lwgeom_length(const LWGEOM *geom)
Definition lwgeom.c:2066
LWGEOM * lwgeom_normalize(const LWGEOM *geom)
LWGEOM * lwgeom_homogenize(const LWGEOM *geom)
LWPOLY * lwpoly_construct_envelope(int32_t srid, double x1, double y1, double x2, double y2)
Definition lwpoly.c:98
LWPOINT * lwpoint_make3dm(int32_t srid, double x, double y, double m)
Definition lwpoint.c:184
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 lwgeom_drop_bbox(LWGEOM *lwgeom)
Call this function to drop BBOX and SRID from LWGEOM.
Definition lwgeom.c:710
#define FLAGS_GET_Z(flags)
Definition liblwgeom.h:165
void lwgeom_scale(LWGEOM *geom, const POINT4D *factors)
Definition lwgeom.c:2165
void * lwalloc(size_t size)
Definition lwutil.c:227
double lwgeom_area(const LWGEOM *geom)
Definition lwgeom.c:1999
#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
void lwfree(void *mem)
Definition lwutil.c:248
double lwgeom_mindistance2d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling min distance calculations and dwithin calculations.
Definition measures.c:222
LWPOINT * lwpoint_make2d(int32_t srid, double x, double y)
Definition lwpoint.c:163
int lwgeom_is_collection(const LWGEOM *lwgeom)
Determine whether a LWGEOM contains sub-geometries or not This basically just checks that the struct ...
Definition lwgeom.c:1125
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
LWLINE * lwline_extend(const LWLINE *line, double distance_forward, double distance_backward)
Extend the ends of a line.
Definition lwline.c:682
double lwgeom_mindistance3d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling 3d min distance calculations and dwithin calculations.
Definition measures3d.c:476
void lwgeom_swap_ordinates(LWGEOM *in, LWORD o1, LWORD o2)
Swap ordinate values in every vertex of the geometry.
Definition lwgeom.c:1569
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition lwgeom.c:367
void lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
Definition lwgeom.c:2111
#define POLYHEDRALSURFACETYPE
Definition liblwgeom.h:114
double lwgeom_length_2d(const LWGEOM *geom)
Definition lwgeom.c:2088
uint32_t lwgeom_count_rings(const LWGEOM *geom)
Count the total number of rings in any LWGEOM.
Definition lwgeom.c:1447
double lwgeom_mindistance2d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing min distance calculation.
Definition measures.c:212
#define FLAGS_GET_M(flags)
Definition liblwgeom.h:166
void lwgeom_force_clockwise(LWGEOM *lwgeom)
Definition lwgeom.c:73
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
Definition lwgeom_api.c:125
int lwtype_is_unitary(uint32_t lwtype)
Definition lwgeom.c:1132
LWPOLY * lwpoly_construct_rectangle(char hasz, char hasm, POINT4D *p1, POINT4D *p2, POINT4D *p3, POINT4D *p4)
Definition lwpoly.c:80
LWPOLY * lwpoly_construct(int32_t srid, GBOX *bbox, uint32_t nrings, POINTARRAY **points)
Definition lwpoly.c:43
int lwgeom_calculate_gbox(const LWGEOM *lwgeom, GBOX *gbox)
Calculate bounding box of a geometry, automatically taking into account whether it is cartesian or ge...
Definition lwgeom.c:783
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition lwgeom.c:207
void lwline_setPoint4d(LWLINE *line, uint32_t which, POINT4D *newpoint)
Definition lwline.c:374
int ptarray_append_point(POINTARRAY *pa, const POINT4D *pt, int allow_duplicates)
Append a point to the end of an existing POINTARRAY If allow_duplicate is LW_FALSE,...
Definition ptarray.c:147
LWGEOM * lwgeom_construct_empty(uint8_t type, int32_t srid, char hasz, char hasm)
Definition lwgeom.c:2219
#define MULTICURVETYPE
Definition liblwgeom.h:112
#define TRIANGLETYPE
Definition liblwgeom.h:115
LWMPOINT * lwgeom_as_lwmpoint(const LWGEOM *lwgeom)
Definition lwgeom.c:270
LWGEOM * lwgeom_wrapx(const LWGEOM *lwgeom, double cutx, double amount)
wrap geometry on given cut x value
void lwpoly_free(LWPOLY *poly)
Definition lwpoly.c:175
LWGEOM * lwgeom_furthest_line(const LWGEOM *lw1, const LWGEOM *lw2)
Definition measures.c:49
#define LW_TRUE
Return types for functions with status returns.
Definition liblwgeom.h:93
LWMPOINT * lwmpoint_from_lwgeom(const LWGEOM *g)
Definition lwmpoint.c:93
double lwgeom_maxdistance3d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing 3d max distance calculation.
Definition measures3d.c:334
#define SRID_UNKNOWN
Unknown SRID value.
Definition liblwgeom.h:215
double lwgeom_perimeter(const LWGEOM *geom)
Definition lwgeom.c:2022
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition lwgeom.c:969
LWGEOM * lwgeom_force_4d(const LWGEOM *geom, double zval, double mval)
Definition lwgeom.c:839
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition lwgeom.c:357
LWGEOM * lwgeom_force_3dm(const LWGEOM *geom, double mval)
Definition lwgeom.c:833
LWCOLLECTION * lwcollection_extract(const LWCOLLECTION *col, uint32_t type)
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition lwgeom.c:723
void lwline_free(LWLINE *line)
Definition lwline.c:67
LWGEOM * lwgeom_closest_line_3d(const LWGEOM *lw1, const LWGEOM *lw2)
Definition measures3d.c:110
LWPOINT * lwpoint_project_lwpoint(const LWPOINT *lwpoint1, const LWPOINT *lwpoint2, double distance)
Definition lwpoint.c:277
LWLINE * lwline_from_lwmpoint(int32_t srid, const LWMPOINT *mpoint)
Definition lwline.c:285
LWGEOM * lwgeom_filter_m(LWGEOM *geom, double min, double max, int returnm)
Definition lwmval.c:221
LWGEOM * lwgeom_segmentize2d(const LWGEOM *line, double dist)
Definition lwgeom.c:799
void lwgeom_force_counterclockwise(LWGEOM *lwgeom)
Definition lwgeom.c:79
int lwline_add_lwpoint(LWLINE *line, LWPOINT *point, uint32_t where)
Add a LWPOINT to an LWLINE.
Definition lwline.c:337
void lwgeom_drop_srid(LWGEOM *lwgeom)
Definition lwgeom.c:793
void lwgeom_reverse_in_place(LWGEOM *lwgeom)
Reverse vertex order of LWGEOM.
Definition lwgeom.c:131
double lwgeom_mindistance3d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing 3d min distance calculation.
Definition measures3d.c:369
LWGEOM * lwgeom_clone_deep(const LWGEOM *lwgeom)
Deep clone an LWGEOM, everything is copied.
Definition lwgeom.c:557
enum LWORD_T LWORD
Ordinate names.
This library is the generic geometry handling section of PostGIS.
double lwline_length_2d(const LWLINE *line)
Definition lwline.c:530
#define OUT_DEFAULT_DECIMAL_DIGITS
int lwline_is_empty(const LWLINE *line)
int ptarray_scroll_in_place(POINTARRAY *pa, const POINT4D *newbase)
Definition ptarray.c:2337
char lwpoint_same2d(const LWPOINT *p1, const LWPOINT *p2)
Definition lwpoint.c:271
Datum LWGEOM_FilterByM(PG_FUNCTION_ARGS)
Datum LWGEOM_isempty(PG_FUNCTION_ARGS)
Datum LWGEOM_perimeter2d_poly(PG_FUNCTION_ARGS)
Datum LWGEOM_force_3dm(PG_FUNCTION_ARGS)
Datum LWGEOM_force_2d(PG_FUNCTION_ARGS)
Datum ST_PointZM(PG_FUNCTION_ARGS)
Datum LWGEOM_makepoly(PG_FUNCTION_ARGS)
Datum LWGEOM_makepoint(PG_FUNCTION_ARGS)
Datum ST_3DIntersects(PG_FUNCTION_ARGS)
Datum LWGEOM_force_3dz(PG_FUNCTION_ARGS)
Datum LWGEOM_force_multi(PG_FUNCTION_ARGS)
Datum ST_Scroll(PG_FUNCTION_ARGS)
Datum LWGEOM_segmentize2d(PG_FUNCTION_ARGS)
Datum ST_PointM(PG_FUNCTION_ARGS)
Datum LWGEOM_dfullywithin3d(PG_FUNCTION_ARGS)
Datum ST_Area(PG_FUNCTION_ARGS)
Datum ST_CollectionHomogenize(PG_FUNCTION_ARGS)
Datum LWGEOM_shortestline3d(PG_FUNCTION_ARGS)
Datum postgis_lib_revision(PG_FUNCTION_ARGS)
Datum LWGEOM_maxdistance2d_linestring(PG_FUNCTION_ARGS)
Datum LWGEOM_removepoint(PG_FUNCTION_ARGS)
Datum LWGEOM_noop(PG_FUNCTION_ARGS)
Datum postgis_scripts_released(PG_FUNCTION_ARGS)
Datum geometry_project_direction(PG_FUNCTION_ARGS)
Datum LWGEOM_affine(PG_FUNCTION_ARGS)
Datum ST_RemoveRepeatedPoints(PG_FUNCTION_ARGS)
Datum ST_BoundingDiagonal(PG_FUNCTION_ARGS)
Datum LWGEOM_longitude_shift(PG_FUNCTION_ARGS)
Datum ST_PointZ(PG_FUNCTION_ARGS)
Datum ST_QuantizeCoordinates(PG_FUNCTION_ARGS)
Datum postgis_version(PG_FUNCTION_ARGS)
Datum postgis_liblwgeom_version(PG_FUNCTION_ARGS)
Datum LWGEOM_force_4d(PG_FUNCTION_ARGS)
Datum LWGEOM_nrings(PG_FUNCTION_ARGS)
Datum ST_Points(PG_FUNCTION_ARGS)
Datum LWGEOM_zmflag(PG_FUNCTION_ARGS)
Datum ST_ForcePolygonCCW(PG_FUNCTION_ARGS)
Datum ST_GeoHash(PG_FUNCTION_ARGS)
Datum ST_TileEnvelope(PG_FUNCTION_ARGS)
Datum ST_IsCollection(PG_FUNCTION_ARGS)
Datum ST_3DDistance(PG_FUNCTION_ARGS)
Datum LWGEOM_mem_size(PG_FUNCTION_ARGS)
Datum postgis_svn_version(PG_FUNCTION_ARGS)
Datum LWGEOM_makeline(PG_FUNCTION_ARGS)
Datum LWGEOM_ndims(PG_FUNCTION_ARGS)
Datum ST_Scale(PG_FUNCTION_ARGS)
Datum LWGEOM_force_curve(PG_FUNCTION_ARGS)
Datum LWGEOM_setpoint_linestring(PG_FUNCTION_ARGS)
Datum LWGEOM_dwithin3d(PG_FUNCTION_ARGS)
Datum _ST_SortableHash(PG_FUNCTION_ARGS)
Datum LWGEOM_shortestline2d(PG_FUNCTION_ARGS)
Datum LWGEOM_perimeter_poly(PG_FUNCTION_ARGS)
Datum LWGEOM_envelope(PG_FUNCTION_ARGS)
Datum LWGEOM_force_collection(PG_FUNCTION_ARGS)
Datum ST_MakeEnvelope(PG_FUNCTION_ARGS)
Datum LWGEOM_force_clockwise_poly(PG_FUNCTION_ARGS)
Datum LWGEOM_hasm(PG_FUNCTION_ARGS)
Datum LWGEOM_to_BOX(PG_FUNCTION_ARGS)
Datum LWGEOM_azimuth(PG_FUNCTION_ARGS)
Datum ST_Normalize(PG_FUNCTION_ARGS)
Datum optimistic_overlap(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(LWGEOM_mem_size)
find the size of geometry
Datum ST_CollectionExtract(PG_FUNCTION_ARGS)
Datum LWGEOM_asEWKT(PG_FUNCTION_ARGS)
Datum LWGEOM_angle(PG_FUNCTION_ARGS)
Datum LWGEOM_inside_circle_point(PG_FUNCTION_ARGS)
Datum postgis_lib_build_date(PG_FUNCTION_ARGS)
Datum ST_Point(PG_FUNCTION_ARGS)
Datum geometry_project_geometry(PG_FUNCTION_ARGS)
Datum boundary(PG_FUNCTION_ARGS)
Datum LWGEOM_line_from_mpoint(PG_FUNCTION_ARGS)
Datum LWGEOM_collect(PG_FUNCTION_ARGS)
Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS)
Datum LWGEOM_hasBBOX(PG_FUNCTION_ARGS)
Datum LWGEOM_same(PG_FUNCTION_ARGS)
Datum ST_SwapOrdinates(PG_FUNCTION_ARGS)
Datum LWGEOM_reverse(PG_FUNCTION_ARGS)
Datum LWGEOM_hasz(PG_FUNCTION_ARGS)
Datum postgis_lib_version(PG_FUNCTION_ARGS)
Datum LWGEOM_addpoint(PG_FUNCTION_ARGS)
Datum LWGEOM_longestline2d(PG_FUNCTION_ARGS)
Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS)
Datum LWGEOM_force_sfs(PG_FUNCTION_ARGS)
Datum LWGEOM_length2d_linestring(PG_FUNCTION_ARGS)
Datum ST_FlipCoordinates(PG_FUNCTION_ARGS)
Datum LWGEOM_closestpoint(PG_FUNCTION_ARGS)
Datum LWGEOM_expand(PG_FUNCTION_ARGS)
Datum ST_Distance(PG_FUNCTION_ARGS)
Datum LWGEOM_longestline3d(PG_FUNCTION_ARGS)
Datum LWGEOM_length_linestring(PG_FUNCTION_ARGS)
Datum geometry_line_extend(PG_FUNCTION_ARGS)
static LWORD ordname2ordval(char n)
#define xstr(s)
Datum LWGEOM_npoints(PG_FUNCTION_ARGS)
Datum ST_WrapX(PG_FUNCTION_ARGS)
Datum LWGEOM_makepoint3dm(PG_FUNCTION_ARGS)
Datum LWGEOM_dwithin(PG_FUNCTION_ARGS)
Datum LWGEOM_mindistance3d(PG_FUNCTION_ARGS)
Datum postgis_libxml_version(PG_FUNCTION_ARGS)
Datum LWGEOM_maxdistance3d(PG_FUNCTION_ARGS)
Datum LWGEOM_closestpoint3d(PG_FUNCTION_ARGS)
Datum LWGEOM_summary(PG_FUNCTION_ARGS)
static LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
Definition lwinline.h:127
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
static double distance(double x1, double y1, double x2, double y2)
Definition lwtree.c:1032
unsigned int int32
Definition shpopen.c:54
#define POSTGIS_LIB_VERSION
Definition sqldefines.h:13
#define POSTGIS_LIBXML2_VERSION
Definition sqldefines.h:14
double gfac
Definition liblwgeom.h:332
double zoff
Definition liblwgeom.h:332
double bfac
Definition liblwgeom.h:332
double ifac
Definition liblwgeom.h:332
double xoff
Definition liblwgeom.h:332
double dfac
Definition liblwgeom.h:332
double afac
Definition liblwgeom.h:332
double ffac
Definition liblwgeom.h:332
double cfac
Definition liblwgeom.h:332
double hfac
Definition liblwgeom.h:332
double efac
Definition liblwgeom.h:332
double yoff
Definition liblwgeom.h:332
double ymax
Definition liblwgeom.h:357
double zmax
Definition liblwgeom.h:359
double xmax
Definition liblwgeom.h:355
double zmin
Definition liblwgeom.h:358
double mmax
Definition liblwgeom.h:361
double ymin
Definition liblwgeom.h:356
double xmin
Definition liblwgeom.h:354
double mmin
Definition liblwgeom.h:360
uint8_t type
Definition liblwgeom.h:462
GBOX * bbox
Definition liblwgeom.h:458
int32_t srid
Definition liblwgeom.h:460
lwflags_t flags
Definition liblwgeom.h:461
POINTARRAY * points
Definition liblwgeom.h:483
int32_t srid
Definition liblwgeom.h:534
POINTARRAY * point
Definition liblwgeom.h:471
int32_t srid
Definition liblwgeom.h:472
double y
Definition liblwgeom.h:390
double x
Definition liblwgeom.h:390
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