PostGIS 3.6.2dev-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
1472 {
1473 continue;
1474 }
1475
1476 geoms[ngeoms++] = lwgeom_from_gserialized(geom);
1477
1478 /* Check SRID homogeneity */
1479 if (ngeoms == 1)
1480 {
1481 /* Get first geometry SRID */
1482 srid = geoms[ngeoms - 1]->srid;
1483 /* TODO: also get ZMflags */
1484 }
1485 else
1487
1488 POSTGIS_DEBUGF(3, "%s: element %d deserialized", __func__, ngeoms);
1489 }
1490 array_free_iterator(iterator);
1491
1492 /* Return null on 0-points input array */
1493 if (ngeoms == 0)
1494 {
1495 /* TODO: should we return LINESTRING EMPTY here ? */
1496 elog(NOTICE, "No points or linestrings in input array");
1497 PG_RETURN_NULL();
1498 }
1499
1500 POSTGIS_DEBUGF(3, "LWGEOM_makeline_garray: elements: %d", ngeoms);
1501
1502 outlwg = (LWGEOM *)lwline_from_lwgeom_array(srid, ngeoms, geoms);
1503
1504 result = geometry_serialize(outlwg);
1505
1506 PG_RETURN_POINTER(result);
1507}
1508
1514Datum LWGEOM_makeline(PG_FUNCTION_ARGS)
1515{
1516 GSERIALIZED *pglwg1, *pglwg2;
1517 GSERIALIZED *result = NULL;
1518 LWGEOM *lwgeoms[2];
1519 LWLINE *outline;
1520
1521 POSTGIS_DEBUG(2, "LWGEOM_makeline called.");
1522
1523 /* Get input datum */
1524 pglwg1 = PG_GETARG_GSERIALIZED_P(0);
1525 pglwg2 = PG_GETARG_GSERIALIZED_P(1);
1526
1527 if ((gserialized_get_type(pglwg1) != POINTTYPE && gserialized_get_type(pglwg1) != LINETYPE) ||
1529 {
1530 elog(ERROR, "Input geometries must be points or lines");
1531 PG_RETURN_NULL();
1532 }
1533
1534 gserialized_error_if_srid_mismatch(pglwg1, pglwg2, __func__);
1535
1536 lwgeoms[0] = lwgeom_from_gserialized(pglwg1);
1537 lwgeoms[1] = lwgeom_from_gserialized(pglwg2);
1538
1539 outline = lwline_from_lwgeom_array(lwgeoms[0]->srid, 2, lwgeoms);
1540
1541 result = geometry_serialize((LWGEOM *)outline);
1542
1543 PG_FREE_IF_COPY(pglwg1, 0);
1544 PG_FREE_IF_COPY(pglwg2, 1);
1545 lwgeom_free(lwgeoms[0]);
1546 lwgeom_free(lwgeoms[1]);
1547
1548 PG_RETURN_POINTER(result);
1549}
1550
1556Datum LWGEOM_makepoly(PG_FUNCTION_ARGS)
1557{
1558 GSERIALIZED *pglwg1;
1559 ArrayType *array = NULL;
1560 GSERIALIZED *result = NULL;
1561 const LWLINE *shell = NULL;
1562 const LWLINE **holes = NULL;
1563 LWPOLY *outpoly;
1564 uint32 nholes = 0;
1565 uint32 i;
1566 size_t offset = 0;
1567
1568 POSTGIS_DEBUG(2, "LWGEOM_makepoly called.");
1569
1570 /* Get input shell */
1571 pglwg1 = PG_GETARG_GSERIALIZED_P(0);
1572 if (gserialized_get_type(pglwg1) != LINETYPE)
1573 {
1574 lwpgerror("Shell is not a line");
1575 }
1577
1578 /* Get input holes if any */
1579 if (PG_NARGS() > 1)
1580 {
1581 array = PG_GETARG_ARRAYTYPE_P(1);
1582 nholes = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
1583 holes = lwalloc(sizeof(LWLINE *) * nholes);
1584 for (i = 0; i < nholes; i++)
1585 {
1586#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
1587#pragma GCC diagnostic push
1588#pragma GCC diagnostic ignored "-Wsign-compare"
1589#endif
1590 GSERIALIZED *g = (GSERIALIZED *)(ARR_DATA_PTR(array) + offset);
1591#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
1592#pragma GCC diagnostic pop
1593#endif
1594 LWLINE *hole;
1595 offset += INTALIGN(VARSIZE(g));
1597 {
1598 lwpgerror("Hole %d is not a line", i);
1599 }
1601 holes[i] = hole;
1602 }
1603 }
1604
1605 outpoly = lwpoly_from_lwlines(shell, nholes, holes);
1606 POSTGIS_DEBUGF(3, "%s", lwgeom_summary((LWGEOM *)outpoly, 0));
1607 result = geometry_serialize((LWGEOM *)outpoly);
1608
1609 lwline_free((LWLINE *)shell);
1610 PG_FREE_IF_COPY(pglwg1, 0);
1611
1612 for (i = 0; i < nholes; i++)
1613 {
1614 lwline_free((LWLINE *)holes[i]);
1615 }
1616
1617 PG_RETURN_POINTER(result);
1618}
1619
1626Datum LWGEOM_expand(PG_FUNCTION_ARGS)
1627{
1628 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
1629 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
1630 int32_t srid = lwgeom_get_srid(lwgeom);
1631 LWPOLY *poly;
1633 GBOX gbox;
1634
1635 POSTGIS_DEBUG(2, "LWGEOM_expand called.");
1636
1637 /* Can't expand an empty */
1638 if (lwgeom_is_empty(lwgeom))
1639 {
1640 lwgeom_free(lwgeom);
1641 PG_RETURN_POINTER(geom);
1642 }
1643
1644 /* Can't expand something with no gbox! */
1645 if (LW_FAILURE == lwgeom_calculate_gbox(lwgeom, &gbox))
1646 {
1647 lwgeom_free(lwgeom);
1648 PG_RETURN_POINTER(geom);
1649 }
1650
1651 if (PG_NARGS() == 2)
1652 {
1653 /* Expand the box the same amount in all directions */
1654 double d = PG_GETARG_FLOAT8(1);
1655 gbox_expand(&gbox, d);
1656 }
1657 else
1658 {
1659 double dx = PG_GETARG_FLOAT8(1);
1660 double dy = PG_GETARG_FLOAT8(2);
1661 double dz = PG_GETARG_FLOAT8(3);
1662 double dm = PG_GETARG_FLOAT8(4);
1663
1664 gbox_expand_xyzm(&gbox, dx, dy, dz, dm);
1665 }
1666
1667 {
1668 POINT4D p1 = {gbox.xmin, gbox.ymin, gbox.zmin, gbox.mmin};
1669 POINT4D p2 = {gbox.xmin, gbox.ymax, gbox.zmin, gbox.mmin};
1670 POINT4D p3 = {gbox.xmax, gbox.ymax, gbox.zmax, gbox.mmax};
1671 POINT4D p4 = {gbox.xmax, gbox.ymin, gbox.zmax, gbox.mmax};
1672
1673 poly = lwpoly_construct_rectangle(lwgeom_has_z(lwgeom), lwgeom_has_m(lwgeom), &p1, &p2, &p3, &p4);
1674 }
1675
1677 lwgeom_set_srid(lwpoly_as_lwgeom(poly), srid);
1678
1679 /* Construct GSERIALIZED */
1680 result = geometry_serialize(lwpoly_as_lwgeom(poly));
1681
1683 lwgeom_free(lwgeom);
1684 PG_FREE_IF_COPY(geom, 0);
1685
1686 PG_RETURN_POINTER(result);
1687}
1688
1691Datum LWGEOM_to_BOX(PG_FUNCTION_ARGS)
1692{
1693 GSERIALIZED *pg_lwgeom = PG_GETARG_GSERIALIZED_P(0);
1694 LWGEOM *lwgeom = lwgeom_from_gserialized(pg_lwgeom);
1695 GBOX gbox;
1696 int result;
1697 BOX *out = NULL;
1698
1699 /* Zero out flags */
1700 gbox_init(&gbox);
1701
1702 /* Calculate the GBOX of the geometry */
1703 result = lwgeom_calculate_gbox(lwgeom, &gbox);
1704
1705 /* Clean up memory */
1706 lwfree(lwgeom);
1707 PG_FREE_IF_COPY(pg_lwgeom, 0);
1708
1709 /* Null on failure */
1710 if (!result)
1711 PG_RETURN_NULL();
1712
1713 out = lwalloc(sizeof(BOX));
1714 out->low.x = gbox.xmin;
1715 out->low.y = gbox.ymin;
1716 out->high.x = gbox.xmax;
1717 out->high.y = gbox.ymax;
1718 PG_RETURN_POINTER(out);
1719}
1720
1727Datum LWGEOM_envelope(PG_FUNCTION_ARGS)
1728{
1729 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
1730 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
1731 int32_t srid = lwgeom->srid;
1732 POINT4D pt;
1733 GBOX box;
1734 POINTARRAY *pa;
1736
1737 if (lwgeom_is_empty(lwgeom))
1738 {
1739 /* must be the EMPTY geometry */
1740 PG_RETURN_POINTER(geom);
1741 }
1742
1743 if (lwgeom_calculate_gbox(lwgeom, &box) == LW_FAILURE)
1744 {
1745 /* must be the EMPTY geometry */
1746 PG_RETURN_POINTER(geom);
1747 }
1748
1749 /*
1750 * Alter envelope type so that a valid geometry is always
1751 * returned depending upon the size of the geometry. The
1752 * code makes the following assumptions:
1753 * - If the bounding box is a single point then return a
1754 * POINT geometry
1755 * - If the bounding box represents either a horizontal or
1756 * vertical line, return a LINESTRING geometry
1757 * - Otherwise return a POLYGON
1758 */
1759
1760 if ((box.xmin == box.xmax) && (box.ymin == box.ymax))
1761 {
1762 /* Construct and serialize point */
1763 LWPOINT *point = lwpoint_make2d(srid, box.xmin, box.ymin);
1764 result = geometry_serialize(lwpoint_as_lwgeom(point));
1765 lwpoint_free(point);
1766 }
1767 else if ((box.xmin == box.xmax) || (box.ymin == box.ymax))
1768 {
1769 LWLINE *line;
1770 /* Construct point array */
1771 pa = ptarray_construct_empty(0, 0, 2);
1772
1773 /* Assign coordinates to POINT2D array */
1774 pt.x = box.xmin;
1775 pt.y = box.ymin;
1776 ptarray_append_point(pa, &pt, LW_TRUE);
1777 pt.x = box.xmax;
1778 pt.y = box.ymax;
1779 ptarray_append_point(pa, &pt, LW_TRUE);
1780
1781 /* Construct and serialize linestring */
1782 line = lwline_construct(srid, NULL, pa);
1783 result = geometry_serialize(lwline_as_lwgeom(line));
1784 lwline_free(line);
1785 }
1786 else
1787 {
1788 LWPOLY *poly;
1789 POINTARRAY **ppa = lwalloc(sizeof(POINTARRAY *));
1790 pa = ptarray_construct_empty(0, 0, 5);
1791 ppa[0] = pa;
1792
1793 /* Assign coordinates to POINT2D array */
1794 pt.x = box.xmin;
1795 pt.y = box.ymin;
1796 ptarray_append_point(pa, &pt, LW_TRUE);
1797 pt.x = box.xmin;
1798 pt.y = box.ymax;
1799 ptarray_append_point(pa, &pt, LW_TRUE);
1800 pt.x = box.xmax;
1801 pt.y = box.ymax;
1802 ptarray_append_point(pa, &pt, LW_TRUE);
1803 pt.x = box.xmax;
1804 pt.y = box.ymin;
1805 ptarray_append_point(pa, &pt, LW_TRUE);
1806 pt.x = box.xmin;
1807 pt.y = box.ymin;
1808 ptarray_append_point(pa, &pt, LW_TRUE);
1809
1810 /* Construct polygon */
1811 poly = lwpoly_construct(srid, NULL, 1, ppa);
1812 result = geometry_serialize(lwpoly_as_lwgeom(poly));
1813 lwpoly_free(poly);
1814 }
1815
1816 PG_FREE_IF_COPY(geom, 0);
1817
1818 PG_RETURN_POINTER(result);
1819}
1820
1822Datum LWGEOM_isempty(PG_FUNCTION_ARGS)
1823{
1824 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
1825 PG_RETURN_BOOL(gserialized_is_empty(geom));
1826}
1827
1835Datum LWGEOM_segmentize2d(PG_FUNCTION_ARGS)
1836{
1837 GSERIALIZED *outgeom, *ingeom;
1838 double dist;
1839 LWGEOM *inlwgeom, *outlwgeom;
1840 int type;
1841
1842 POSTGIS_DEBUG(2, "LWGEOM_segmentize2d called");
1843
1844 ingeom = PG_GETARG_GSERIALIZED_P(0);
1845 dist = PG_GETARG_FLOAT8(1);
1846 type = gserialized_get_type(ingeom);
1847
1848 /* Avoid types we cannot segmentize. */
1849 if ((type == POINTTYPE) || (type == MULTIPOINTTYPE) || (type == TRIANGLETYPE) || (type == TINTYPE) ||
1850 (type == POLYHEDRALSURFACETYPE))
1851 {
1852 PG_RETURN_POINTER(ingeom);
1853 }
1854
1855 if (dist <= 0)
1856 {
1857 /* Protect from knowingly infinite loops, see #1799 */
1858 /* Note that we'll end out of memory anyway for other small distances */
1859 elog(ERROR, "ST_Segmentize: invalid max_distance %g (must be >= 0)", dist);
1860 PG_RETURN_NULL();
1861 }
1862
1863 LWGEOM_INIT();
1864
1865 inlwgeom = lwgeom_from_gserialized(ingeom);
1866 if (lwgeom_is_empty(inlwgeom))
1867 {
1868 /* Should only happen on interruption */
1869 lwgeom_free(inlwgeom);
1870 PG_RETURN_POINTER(ingeom);
1871 }
1872
1873 outlwgeom = lwgeom_segmentize2d(inlwgeom, dist);
1874 if (!outlwgeom)
1875 {
1876 /* Should only happen on interruption */
1877 PG_FREE_IF_COPY(ingeom, 0);
1878 PG_RETURN_NULL();
1879 }
1880
1881 /* Copy input bounding box if any */
1882 if (inlwgeom->bbox)
1883 outlwgeom->bbox = gbox_copy(inlwgeom->bbox);
1884
1885 outgeom = geometry_serialize(outlwgeom);
1886
1887 // lwgeom_free(outlwgeom); /* TODO fix lwgeom_clone / ptarray_clone_deep for consistent semantics */
1888 lwgeom_free(inlwgeom);
1889
1890 PG_FREE_IF_COPY(ingeom, 0);
1891
1892 PG_RETURN_POINTER(outgeom);
1893}
1894
1897Datum LWGEOM_reverse(PG_FUNCTION_ARGS)
1898{
1899 GSERIALIZED *geom;
1900 LWGEOM *lwgeom;
1901
1902 POSTGIS_DEBUG(2, "LWGEOM_reverse called");
1903
1904 geom = PG_GETARG_GSERIALIZED_P_COPY(0);
1905
1906 lwgeom = lwgeom_from_gserialized(geom);
1908
1909 geom = geometry_serialize(lwgeom);
1910
1911 PG_RETURN_POINTER(geom);
1912}
1913
1916Datum LWGEOM_force_clockwise_poly(PG_FUNCTION_ARGS)
1917{
1918 GSERIALIZED *ingeom, *outgeom;
1919 LWGEOM *lwgeom;
1920
1921 POSTGIS_DEBUG(2, "LWGEOM_force_clockwise_poly called");
1922
1923 ingeom = PG_GETARG_GSERIALIZED_P_COPY(0);
1924
1925 lwgeom = lwgeom_from_gserialized(ingeom);
1926 lwgeom_force_clockwise(lwgeom);
1927
1928 outgeom = geometry_serialize(lwgeom);
1929
1930 lwgeom_free(lwgeom);
1931 PG_FREE_IF_COPY(ingeom, 0);
1932 PG_RETURN_POINTER(outgeom);
1933}
1934
1937Datum LWGEOM_noop(PG_FUNCTION_ARGS)
1938{
1939 GSERIALIZED *in = PG_GETARG_GSERIALIZED_P(0);
1940 LWGEOM *lwgeom = lwgeom_from_gserialized(in);
1941 GSERIALIZED *out = geometry_serialize(lwgeom);
1942 PG_RETURN_POINTER(out);
1943}
1944
1945Datum ST_Normalize(PG_FUNCTION_ARGS);
1947Datum ST_Normalize(PG_FUNCTION_ARGS)
1948{
1949 GSERIALIZED *in, *out;
1950 LWGEOM *lwgeom_in, *lwgeom_out;
1951
1952 POSTGIS_DEBUG(2, "ST_Normalize called");
1953
1954 in = PG_GETARG_GSERIALIZED_P_COPY(0);
1955
1956 lwgeom_in = lwgeom_from_gserialized(in);
1957 POSTGIS_DEBUGF(3, "Deserialized: %s", lwgeom_summary(lwgeom_in, 0));
1958
1959 lwgeom_out = lwgeom_normalize(lwgeom_in);
1960 POSTGIS_DEBUGF(3, "Normalized: %s", lwgeom_summary(lwgeom_out, 0));
1961
1962 out = geometry_serialize(lwgeom_out);
1963 lwgeom_free(lwgeom_in);
1964 lwgeom_free(lwgeom_out);
1965
1966 PG_FREE_IF_COPY(in, 0);
1967
1968 PG_RETURN_POINTER(out);
1969}
1970
1979Datum LWGEOM_zmflag(PG_FUNCTION_ARGS)
1980{
1981 GSERIALIZED *in = PG_GETARG_GSERIALIZED_HEADER(0);
1982 int ret = 0;
1983
1984 if (gserialized_has_z(in))
1985 ret += 2;
1986 if (gserialized_has_m(in))
1987 ret += 1;
1988 PG_FREE_IF_COPY(in, 0);
1989 PG_RETURN_INT16(ret);
1990}
1991
1993Datum LWGEOM_hasz(PG_FUNCTION_ARGS)
1994{
1995 GSERIALIZED *in = PG_GETARG_GSERIALIZED_HEADER(0);
1996 PG_RETURN_BOOL(gserialized_has_z(in));
1997}
1998
2000Datum LWGEOM_hasm(PG_FUNCTION_ARGS)
2001{
2002 GSERIALIZED *in = PG_GETARG_GSERIALIZED_HEADER(0);
2003 PG_RETURN_BOOL(gserialized_has_m(in));
2004}
2005
2007Datum LWGEOM_hasBBOX(PG_FUNCTION_ARGS)
2008{
2009 GSERIALIZED *in = PG_GETARG_GSERIALIZED_HEADER(0);
2010 char res = gserialized_has_bbox(in);
2011 PG_FREE_IF_COPY(in, 0);
2012 PG_RETURN_BOOL(res);
2013}
2014
2017Datum LWGEOM_ndims(PG_FUNCTION_ARGS)
2018{
2019 GSERIALIZED *in = PG_GETARG_GSERIALIZED_HEADER(0);
2020 int ret = gserialized_ndims(in);
2021 PG_FREE_IF_COPY(in, 0);
2022 PG_RETURN_INT16(ret);
2023}
2024
2027Datum LWGEOM_same(PG_FUNCTION_ARGS)
2028{
2029 GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
2030 GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
2031
2032 PG_RETURN_BOOL(gserialized_cmp(g1, g2) == 0);
2033}
2034
2036Datum ST_MakeEnvelope(PG_FUNCTION_ARGS)
2037{
2038 LWPOLY *poly;
2040 double x1, y1, x2, y2;
2041 int32_t srid = SRID_UNKNOWN;
2042
2043 POSTGIS_DEBUG(2, "ST_MakeEnvelope called");
2044
2045 x1 = PG_GETARG_FLOAT8(0);
2046 y1 = PG_GETARG_FLOAT8(1);
2047 x2 = PG_GETARG_FLOAT8(2);
2048 y2 = PG_GETARG_FLOAT8(3);
2049 if (PG_NARGS() > 4)
2050 {
2051 srid = PG_GETARG_INT32(4);
2052 }
2053
2054 poly = lwpoly_construct_envelope(srid, x1, y1, x2, y2);
2055
2056 result = geometry_serialize(lwpoly_as_lwgeom(poly));
2057 lwpoly_free(poly);
2058
2059 PG_RETURN_POINTER(result);
2060}
2061
2062
2064Datum ST_TileEnvelope(PG_FUNCTION_ARGS)
2065{
2066 GSERIALIZED *bounds;
2067 uint32_t zoomu;
2068 int32_t x, y, zoom;
2069 uint32_t worldTileSize;
2070 double tileGeoSizeX, tileGeoSizeY;
2071 double boundsWidth, boundsHeight;
2072 double x1, y1, x2, y2;
2073 double margin;
2074 /* This is broken, since 3857 doesn't mean "web mercator", it means
2075 the contents of the row in spatial_ref_sys with srid = 3857.
2076 For practical purposes this will work, but in good implementation
2077 we should de-reference in spatial ref sys to confirm that the
2078 srid of the object is EPSG:3857. */
2079 int32_t srid;
2080 GBOX bbox;
2081 LWGEOM *g = NULL;
2082
2083 POSTGIS_DEBUG(2, "ST_TileEnvelope called");
2084
2085 zoom = PG_GETARG_INT32(0);
2086 x = PG_GETARG_INT32(1);
2087 y = PG_GETARG_INT32(2);
2088
2089 bounds = PG_GETARG_GSERIALIZED_P(3);
2090 /*
2091 * We deserialize the geometry and recalculate the bounding box here to get
2092 * 64b floating point precision. The serialized bbox has 32b float is not
2093 * precise enough with big numbers such as the ones used in the default
2094 * parameters, e.g: -20037508.3427892 is transformed into -20037510
2095 */
2096 g = lwgeom_from_gserialized(bounds);
2097 if (lwgeom_calculate_gbox(g, &bbox) != LW_SUCCESS)
2098 elog(ERROR, "%s: Unable to compute bbox", __func__);
2099 srid = g->srid;
2100 lwgeom_free(g);
2101
2102 /* Avoid crashing with old signature (old sql code with 3 args, new C code with 4) */
2103 margin = PG_NARGS() < 4 ? 0 : PG_GETARG_FLOAT8(4);
2104 /* shrinking by more than 50% would eliminate the tile outright */
2105 if (margin < -0.5)
2106 elog(ERROR, "%s: Margin must not be less than -50%%, margin=%f", __func__, margin);
2107
2108 boundsWidth = bbox.xmax - bbox.xmin;
2109 boundsHeight = bbox.ymax - bbox.ymin;
2110 if (boundsWidth <= 0 || boundsHeight <= 0)
2111 elog(ERROR, "%s: Geometric bounds are too small", __func__);
2112
2113 if (zoom < 0 || zoom >= 32)
2114 elog(ERROR, "%s: Invalid tile zoom value, %d", __func__, zoom);
2115
2116 zoomu = (uint32_t)zoom;
2117 worldTileSize = 0x01u << (zoomu > 31 ? 31 : zoomu);
2118
2119 if (x < 0 || (uint32_t)x >= worldTileSize)
2120 elog(ERROR, "%s: Invalid tile x value, %d", __func__, x);
2121 if (y < 0 || (uint32_t)y >= worldTileSize)
2122 elog(ERROR, "%s: Invalid tile y value, %d", __func__, y);
2123
2124 tileGeoSizeX = boundsWidth / worldTileSize;
2125 tileGeoSizeY = boundsHeight / worldTileSize;
2126
2127 /*
2128 * 1 margin (100%) is the same as a single tile width
2129 * if the size of the tile with margins span more than the total number of tiles,
2130 * reset x1/x2 to the bounds
2131 */
2132 if ((1 + margin * 2) > worldTileSize)
2133 {
2134 x1 = bbox.xmin;
2135 x2 = bbox.xmax;
2136 }
2137 else
2138 {
2139 x1 = bbox.xmin + tileGeoSizeX * (x - margin);
2140 x2 = bbox.xmin + tileGeoSizeX * (x + 1 + margin);
2141 }
2142
2143 y1 = bbox.ymax - tileGeoSizeY * (y + 1 + margin);
2144 y2 = bbox.ymax - tileGeoSizeY * (y - margin);
2145
2146 /* Clip the final tile bounds to the bounds of the tile plane */
2147 if (y1 < bbox.ymin) y1 = bbox.ymin;
2148 if (y2 > bbox.ymax) y2 = bbox.ymax;
2149 if (x1 < bbox.xmin) x1 = bbox.xmin;
2150 if (x2 > bbox.xmax) x2 = bbox.xmax;
2151
2152 PG_RETURN_POINTER(
2153 geometry_serialize(
2156 srid, x1, y1, x2, y2))));
2157}
2158
2159
2161Datum ST_IsCollection(PG_FUNCTION_ARGS)
2162{
2163 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_HEADER(0);
2164 uint32_t lwtype = gserialized_get_type(geom);
2165 PG_RETURN_BOOL(!lwtype_is_unitary(lwtype));
2166}
2167
2169Datum LWGEOM_makepoint(PG_FUNCTION_ARGS)
2170{
2171 double x, y, z, m;
2172 LWPOINT *point;
2174
2175 POSTGIS_DEBUG(2, "LWGEOM_makepoint called");
2176
2177 x = PG_GETARG_FLOAT8(0);
2178 y = PG_GETARG_FLOAT8(1);
2179
2180 if (PG_NARGS() == 2)
2181 point = lwpoint_make2d(SRID_UNKNOWN, x, y);
2182 else if (PG_NARGS() == 3)
2183 {
2184 z = PG_GETARG_FLOAT8(2);
2185 point = lwpoint_make3dz(SRID_UNKNOWN, x, y, z);
2186 }
2187 else if (PG_NARGS() == 4)
2188 {
2189 z = PG_GETARG_FLOAT8(2);
2190 m = PG_GETARG_FLOAT8(3);
2191 point = lwpoint_make4d(SRID_UNKNOWN, x, y, z, m);
2192 }
2193 else
2194 {
2195 elog(ERROR, "LWGEOM_makepoint: unsupported number of args: %d", PG_NARGS());
2196 PG_RETURN_NULL();
2197 }
2198
2199 result = geometry_serialize((LWGEOM *)point);
2200
2201 PG_RETURN_POINTER(result);
2202}
2203
2205Datum ST_Point(PG_FUNCTION_ARGS)
2206{
2207 double x = PG_GETARG_FLOAT8(0);
2208 double y = PG_GETARG_FLOAT8(1);
2209 int srid = PG_GETARG_INT32(2);
2210 LWPOINT *point = lwpoint_make2d(srid, x, y);
2211 GSERIALIZED *result = geometry_serialize((LWGEOM *)point);
2212 PG_RETURN_POINTER(result);
2213}
2214
2216Datum ST_PointZ(PG_FUNCTION_ARGS)
2217{
2218 double x = PG_GETARG_FLOAT8(0);
2219 double y = PG_GETARG_FLOAT8(1);
2220 double z = PG_GETARG_FLOAT8(2);
2221 int srid = PG_GETARG_INT32(3);
2222 LWPOINT *point = lwpoint_make3dz(srid, x, y, z);
2223 GSERIALIZED *result = geometry_serialize((LWGEOM *)point);
2224 PG_RETURN_POINTER(result);
2225}
2226
2228Datum ST_PointM(PG_FUNCTION_ARGS)
2229{
2230 double x = PG_GETARG_FLOAT8(0);
2231 double y = PG_GETARG_FLOAT8(1);
2232 double m = PG_GETARG_FLOAT8(2);
2233 int srid = PG_GETARG_INT32(3);
2234 LWPOINT *point = lwpoint_make3dm(srid, x, y, m);
2235 GSERIALIZED *result = geometry_serialize((LWGEOM *)point);
2236 PG_RETURN_POINTER(result);
2237}
2238
2240Datum ST_PointZM(PG_FUNCTION_ARGS)
2241{
2242 double x = PG_GETARG_FLOAT8(0);
2243 double y = PG_GETARG_FLOAT8(1);
2244 double z = PG_GETARG_FLOAT8(2);
2245 double m = PG_GETARG_FLOAT8(3);
2246 int srid = PG_GETARG_INT32(4);
2247 LWPOINT *point = lwpoint_make4d(srid, x, y, z, m);
2248 GSERIALIZED *result = geometry_serialize((LWGEOM *)point);
2249 PG_RETURN_POINTER(result);
2250}
2251
2252
2254Datum LWGEOM_makepoint3dm(PG_FUNCTION_ARGS)
2255{
2256 double x, y, m;
2257 LWPOINT *point;
2259
2260 POSTGIS_DEBUG(2, "LWGEOM_makepoint3dm called.");
2261
2262 x = PG_GETARG_FLOAT8(0);
2263 y = PG_GETARG_FLOAT8(1);
2264 m = PG_GETARG_FLOAT8(2);
2265
2266 point = lwpoint_make3dm(SRID_UNKNOWN, x, y, m);
2267 result = geometry_serialize((LWGEOM *)point);
2268
2269 PG_RETURN_POINTER(result);
2270}
2271
2273Datum LWGEOM_addpoint(PG_FUNCTION_ARGS)
2274{
2275 GSERIALIZED *pglwg1, *pglwg2, *result;
2276 LWPOINT *point;
2277 LWLINE *line, *linecopy;
2278 uint32_t uwhere = 0;
2279
2280 POSTGIS_DEBUGF(2, "%s called.", __func__);
2281
2282 pglwg1 = PG_GETARG_GSERIALIZED_P(0);
2283 pglwg2 = PG_GETARG_GSERIALIZED_P(1);
2284
2285 if (gserialized_get_type(pglwg1) != LINETYPE)
2286 {
2287 elog(ERROR, "First argument must be a LINESTRING");
2288 PG_RETURN_NULL();
2289 }
2290
2291 if (gserialized_get_type(pglwg2) != POINTTYPE)
2292 {
2293 elog(ERROR, "Second argument must be a POINT");
2294 PG_RETURN_NULL();
2295 }
2296
2297 if (gserialized_is_empty(pglwg2))
2298 {
2299 PG_RETURN_POINTER(pglwg1);
2300 }
2301
2303
2304 if (PG_NARGS() <= 2)
2305 {
2306 uwhere = line->points->npoints;
2307 }
2308 else
2309 {
2310 int32 where = PG_GETARG_INT32(2);
2311 if (where == -1)
2312 {
2313 uwhere = line->points->npoints;
2314 }
2315 else if (where < 0 || where > (int32)line->points->npoints)
2316 {
2317 elog(ERROR, "%s: Invalid offset", __func__);
2318 PG_RETURN_NULL();
2319 }
2320 else
2321 {
2322 uwhere = where;
2323 }
2324 }
2325
2328 lwline_free(line);
2329
2330 if (lwline_add_lwpoint(linecopy, point, uwhere) == LW_FAILURE)
2331 {
2332 elog(ERROR, "Point insert failed");
2333 PG_RETURN_NULL();
2334 }
2335
2336 result = geometry_serialize(lwline_as_lwgeom(linecopy));
2337
2338 /* Release memory */
2339 PG_FREE_IF_COPY(pglwg1, 0);
2340 PG_FREE_IF_COPY(pglwg2, 1);
2341 lwpoint_free(point);
2342
2343 PG_RETURN_POINTER(result);
2344}
2345
2347Datum LWGEOM_removepoint(PG_FUNCTION_ARGS)
2348{
2349 GSERIALIZED *pglwg1, *result;
2350 LWLINE *line, *outline;
2351 int32 which;
2352
2353 POSTGIS_DEBUG(2, "LWGEOM_removepoint called.");
2354
2355 pglwg1 = PG_GETARG_GSERIALIZED_P(0);
2356 which = PG_GETARG_INT32(1);
2357
2358 if (gserialized_get_type(pglwg1) != LINETYPE)
2359 {
2360 elog(ERROR, "First argument must be a LINESTRING");
2361 PG_RETURN_NULL();
2362 }
2363
2365
2366 if (which < 0 || (uint32_t)which > line->points->npoints - 1)
2367 {
2368 elog(ERROR, "Point index out of range (%u..%u)", 0, line->points->npoints - 1);
2369 PG_RETURN_NULL();
2370 }
2371
2372 if (line->points->npoints < 3)
2373 {
2374 elog(ERROR, "Can't remove points from a single segment line");
2375 PG_RETURN_NULL();
2376 }
2377
2378 outline = lwline_removepoint(line, (uint32_t)which);
2379 /* Release memory */
2380 lwline_free(line);
2381
2382 result = geometry_serialize((LWGEOM *)outline);
2383 lwline_free(outline);
2384
2385 PG_FREE_IF_COPY(pglwg1, 0);
2386 PG_RETURN_POINTER(result);
2387}
2388
2390Datum LWGEOM_setpoint_linestring(PG_FUNCTION_ARGS)
2391{
2392 GSERIALIZED *pglwg1, *pglwg2, *result;
2393 LWGEOM *lwg;
2394 LWLINE *line;
2395 LWPOINT *lwpoint;
2396 POINT4D newpoint;
2397 int64_t which;
2398
2399 POSTGIS_DEBUG(2, "LWGEOM_setpoint_linestring called.");
2400
2401 /* we copy input as we're going to modify it */
2402 pglwg1 = PG_GETARG_GSERIALIZED_P_COPY(0);
2403
2404 which = PG_GETARG_INT32(1);
2405 pglwg2 = PG_GETARG_GSERIALIZED_P(2);
2406
2407 /* Extract a POINT4D from the point */
2408 lwg = lwgeom_from_gserialized(pglwg2);
2409 lwpoint = lwgeom_as_lwpoint(lwg);
2410 if (!lwpoint)
2411 {
2412 elog(ERROR, "Third argument must be a POINT");
2413 PG_RETURN_NULL();
2414 }
2415 getPoint4d_p(lwpoint->point, 0, &newpoint);
2416 lwpoint_free(lwpoint);
2417 PG_FREE_IF_COPY(pglwg2, 2);
2418
2419 lwg = lwgeom_from_gserialized(pglwg1);
2420 line = lwgeom_as_lwline(lwg);
2421
2422 if (!line)
2423 {
2424 elog(ERROR, "First argument must be a LINESTRING");
2425 PG_RETURN_NULL();
2426 }
2427
2428 if ( line->points->npoints < 1 ) {
2429 elog(ERROR, "Line has no points");
2430 PG_RETURN_NULL();
2431 }
2432
2433 if (which < 0)
2434 {
2435 /* Use backward indexing for negative values */
2436 which += (int64_t)line->points->npoints;
2437 }
2438 if ((uint32_t)which > line->points->npoints - 1)
2439 {
2440 elog(ERROR, "abs(Point index) out of range (-)(%u..%u)", 0, line->points->npoints - 1);
2441 PG_RETURN_NULL();
2442 }
2443
2444 /*
2445 * This will change pointarray of the serialized pglwg1,
2446 */
2447 lwline_setPoint4d(line, (uint32_t)which, &newpoint);
2448 result = geometry_serialize((LWGEOM *)line);
2449
2450 /* Release memory */
2451 lwline_free(line);
2452 pfree(pglwg1); /* we forced copy, POINARRAY is released now */
2453
2454 PG_RETURN_POINTER(result);
2455}
2456
2457/* convert LWGEOM to ewkt (in TEXT format) */
2459Datum LWGEOM_asEWKT(PG_FUNCTION_ARGS)
2460{
2461 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
2462 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
2463
2465 if (PG_NARGS() > 1)
2466 precision = PG_GETARG_INT32(1);
2467
2468 PG_RETURN_TEXT_P(lwgeom_to_wkt_varlena(lwgeom, WKT_EXTENDED, precision));
2469}
2470
2478Datum LWGEOM_azimuth(PG_FUNCTION_ARGS)
2479{
2480 GSERIALIZED *geom;
2481 LWPOINT *lwpoint;
2482 POINT2D p1, p2;
2483 double result;
2484 int32_t srid;
2485
2486 /* Extract first point */
2487 geom = PG_GETARG_GSERIALIZED_P(0);
2489 if (!lwpoint)
2490 {
2491 PG_FREE_IF_COPY(geom, 0);
2492 lwpgerror("Argument must be POINT geometries");
2493 PG_RETURN_NULL();
2494 }
2495 srid = lwpoint->srid;
2496 if (!getPoint2d_p(lwpoint->point, 0, &p1))
2497 {
2498 PG_FREE_IF_COPY(geom, 0);
2499 lwpgerror("Error extracting point");
2500 PG_RETURN_NULL();
2501 }
2502 lwpoint_free(lwpoint);
2503 PG_FREE_IF_COPY(geom, 0);
2504
2505 /* Extract second point */
2506 geom = PG_GETARG_GSERIALIZED_P(1);
2508 if (!lwpoint)
2509 {
2510 PG_FREE_IF_COPY(geom, 1);
2511 lwpgerror("Argument must be POINT geometries");
2512 PG_RETURN_NULL();
2513 }
2514 if (lwpoint->srid != srid)
2515 {
2516 PG_FREE_IF_COPY(geom, 1);
2517 lwpgerror("Operation on mixed SRID geometries");
2518 PG_RETURN_NULL();
2519 }
2520 if (!getPoint2d_p(lwpoint->point, 0, &p2))
2521 {
2522 PG_FREE_IF_COPY(geom, 1);
2523 lwpgerror("Error extracting point");
2524 PG_RETURN_NULL();
2525 }
2526 lwpoint_free(lwpoint);
2527 PG_FREE_IF_COPY(geom, 1);
2528
2529 /* Standard return value for equality case */
2530 if ((p1.x == p2.x) && (p1.y == p2.y))
2531 {
2532 PG_RETURN_NULL();
2533 }
2534
2535 /* Compute azimuth */
2536 if (!azimuth_pt_pt(&p1, &p2, &result))
2537 {
2538 PG_RETURN_NULL();
2539 }
2540
2541 PG_RETURN_FLOAT8(result);
2542}
2543
2544
2553Datum geometry_project_direction(PG_FUNCTION_ARGS)
2554{
2555 GSERIALIZED *geom1, *geom2;
2556 LWPOINT *lwpoint1, *lwpoint2;
2557 LWGEOM *lwgeom1, *lwgeom2;
2558 double distance, azimuth;
2559
2560 geom1 = PG_GETARG_GSERIALIZED_P(0);
2561 distance = PG_GETARG_FLOAT8(1);
2562 azimuth = PG_GETARG_FLOAT8(2);
2563 lwgeom1 = lwgeom_from_gserialized(geom1);
2564 lwpoint1 = lwgeom_as_lwpoint(lwgeom1);
2565
2566 if (!lwpoint1)
2567 lwpgerror("Argument must be POINT geometry");
2568
2569 if (lwgeom_is_empty(lwgeom1))
2570 PG_RETURN_NULL();
2571
2572 lwpoint2 = lwpoint_project(lwpoint1, distance, azimuth);
2573 lwgeom2 = lwpoint_as_lwgeom(lwpoint2);
2574 geom2 = geometry_serialize(lwgeom2);
2575 PG_RETURN_POINTER(geom2);
2576}
2577
2578
2587Datum geometry_project_geometry(PG_FUNCTION_ARGS)
2588{
2589 GSERIALIZED *geom1, *geom2, *geom3;
2590 LWPOINT *lwpoint1, *lwpoint2, *lwpoint3;
2591 LWGEOM *lwgeom1, *lwgeom2, *lwgeom3;
2592 double distance;
2593
2594 geom1 = PG_GETARG_GSERIALIZED_P(0);
2595 geom2 = PG_GETARG_GSERIALIZED_P(1);
2596 distance = PG_GETARG_FLOAT8(2);
2597
2598 lwgeom1 = lwgeom_from_gserialized(geom1);
2599 lwpoint1 = lwgeom_as_lwpoint(lwgeom1);
2600 lwgeom2 = lwgeom_from_gserialized(geom2);
2601 lwpoint2 = lwgeom_as_lwpoint(lwgeom2);
2602
2603 if (!(lwpoint1 && lwpoint2))
2604 lwpgerror("Arguments must be POINT geometries");
2605
2606 if (lwgeom_is_empty(lwgeom1) || lwgeom_is_empty(lwgeom2))
2607 PG_RETURN_NULL();
2608
2609 if (lwpoint_same2d(lwpoint1, lwpoint2))
2610 PG_RETURN_POINTER(geom2);
2611
2612 lwpoint3 = lwpoint_project_lwpoint(lwpoint1, lwpoint2, distance);
2613 lwgeom3 = lwpoint_as_lwgeom(lwpoint3);
2614 geom3 = geometry_serialize(lwgeom3);
2615
2616 PG_RETURN_POINTER(geom3);
2617}
2618
2619
2620
2628Datum geometry_line_extend(PG_FUNCTION_ARGS)
2629{
2630 GSERIALIZED *geom1, *geom2;
2631 LWLINE *lwline1, *lwline2;
2632 LWGEOM *lwgeom1, *lwgeom2;
2633 double distance_forward, distance_backward;
2634
2635 geom1 = PG_GETARG_GSERIALIZED_P(0);
2636 distance_forward = PG_GETARG_FLOAT8(1);
2637 distance_backward = PG_GETARG_FLOAT8(2);
2638
2639 lwgeom1 = lwgeom_from_gserialized(geom1);
2640 lwline1 = lwgeom_as_lwline(lwgeom1);
2641 if (!lwline1)
2642 lwpgerror("Argument must be LINESTRING geometry");
2643
2644 if (lwline_is_empty(lwline1))
2645 PG_RETURN_NULL();
2646
2647 if (lwline_length_2d(lwline1) <= 0.0)
2648 PG_RETURN_POINTER(geom1);
2649
2650 lwline2 = lwline_extend(lwline1, distance_forward, distance_backward);
2651 lwgeom2 = lwline_as_lwgeom(lwline2);
2652 geom2 = geometry_serialize(lwgeom2);
2653
2654 PG_RETURN_POINTER(geom2);
2655}
2656
2657
2658
2667Datum LWGEOM_angle(PG_FUNCTION_ARGS)
2668{
2669 GSERIALIZED *seri_geoms[4];
2670 LWGEOM *geom_unser;
2671 LWPOINT *lwpoint;
2672 POINT2D points[4];
2673 double az1, az2;
2674 double result;
2675 int32_t srids[4];
2676 int i = 0;
2677 int j = 0;
2678 int err_code = 0;
2679 int n_args = PG_NARGS();
2680
2681 /* no deserialize, checking for common error first*/
2682 for (i = 0; i < n_args; i++)
2683 {
2684 seri_geoms[i] = PG_GETARG_GSERIALIZED_P(i);
2685 if (gserialized_is_empty(seri_geoms[i]))
2686 { /* empty geom */
2687 if (i == 3)
2688 {
2689 n_args = 3;
2690 }
2691 else
2692 {
2693 err_code = 1;
2694 break;
2695 }
2696 }
2697 else
2698 {
2699 if (gserialized_get_type(seri_geoms[i]) != POINTTYPE)
2700 { /* geom type */
2701 err_code = 2;
2702 break;
2703 }
2704 else
2705 {
2706 srids[i] = gserialized_get_srid(seri_geoms[i]);
2707 if (srids[0] != srids[i])
2708 { /* error on srid*/
2709 err_code = 3;
2710 break;
2711 }
2712 }
2713 }
2714 }
2715 if (err_code > 0)
2716 switch (err_code)
2717 {
2718 default: /*always executed*/
2719 for (j = 0; j <= i; j++)
2720 PG_FREE_IF_COPY(seri_geoms[j], j);
2721 /*FALLTHROUGH*/
2722 case 1:
2723 lwpgerror("Empty geometry");
2724 PG_RETURN_NULL();
2725 break;
2726
2727 case 2:
2728 lwpgerror("Argument must be POINT geometries");
2729 PG_RETURN_NULL();
2730 break;
2731
2732 case 3:
2733 lwpgerror("Operation on mixed SRID geometries");
2734 PG_RETURN_NULL();
2735 break;
2736 }
2737 /* extract points */
2738 for (i = 0; i < n_args; i++)
2739 {
2740 geom_unser = lwgeom_from_gserialized(seri_geoms[i]);
2741 lwpoint = lwgeom_as_lwpoint(geom_unser);
2742 if (!lwpoint)
2743 {
2744 for (j = 0; j < n_args; j++)
2745 PG_FREE_IF_COPY(seri_geoms[j], j);
2746 lwpgerror("Error unserializing geometry");
2747 PG_RETURN_NULL();
2748 }
2749
2750 if (!getPoint2d_p(lwpoint->point, 0, &points[i]))
2751 {
2752 /* // can't free serialized geom, it might be needed by lw
2753 for (j=0;j<n_args;j++)
2754 PG_FREE_IF_COPY(seri_geoms[j], j); */
2755 lwpgerror("Error extracting point");
2756 PG_RETURN_NULL();
2757 }
2758 /* lwfree(geom_unser);don't do, lw may rely on this memory
2759 lwpoint_free(lwpoint); dont do , this memory is needed ! */
2760 }
2761 /* // can't free serialized geom, it might be needed by lw
2762 for (j=0;j<n_args;j++)
2763 PG_FREE_IF_COPY(seri_geoms[j], j); */
2764
2765 /* compute azimuth for the 2 pairs of points
2766 * note that angle is not defined identically for 3 points or 4 points*/
2767 if (n_args == 3)
2768 { /* we rely on azimuth to complain if points are identical */
2769 if (!azimuth_pt_pt(&points[0], &points[1], &az1))
2770 PG_RETURN_NULL();
2771 if (!azimuth_pt_pt(&points[2], &points[1], &az2))
2772 PG_RETURN_NULL();
2773 }
2774 else
2775 {
2776 if (!azimuth_pt_pt(&points[0], &points[1], &az1))
2777 PG_RETURN_NULL();
2778 if (!azimuth_pt_pt(&points[2], &points[3], &az2))
2779 PG_RETURN_NULL();
2780 }
2781 result = az2 - az1;
2782 result += (result < 0) * 2 * M_PI; /* we dont want negative angle*/
2783 PG_RETURN_FLOAT8(result);
2784}
2785
2786/*
2787 * optimistic_overlap(Polygon P1, Multipolygon MP2, double dist)
2788 * returns true if P1 overlaps MP2
2789 * method: bbox check -
2790 * is separation < dist? no - return false (quick)
2791 * yes - return distance(P1,MP2) < dist
2792 */
2794Datum optimistic_overlap(PG_FUNCTION_ARGS)
2795{
2796 GSERIALIZED *pg_geom1 = PG_GETARG_GSERIALIZED_P(0);
2797 GSERIALIZED *pg_geom2 = PG_GETARG_GSERIALIZED_P(1);
2798 double dist = PG_GETARG_FLOAT8(2);
2799 GBOX g1_bvol;
2800 double calc_dist;
2801 LWGEOM *geom1 = lwgeom_from_gserialized(pg_geom1);
2802 LWGEOM *geom2 = lwgeom_from_gserialized(pg_geom2);
2803 gserialized_error_if_srid_mismatch(pg_geom1, pg_geom2, __func__);
2804
2805 if (geom1->type != POLYGONTYPE)
2806 {
2807 elog(ERROR, "optimistic_overlap: first arg isn't a polygon\n");
2808 PG_RETURN_NULL();
2809 }
2810
2811 if (geom2->type != POLYGONTYPE && geom2->type != MULTIPOLYGONTYPE)
2812 {
2813 elog(ERROR, "optimistic_overlap: 2nd arg isn't a [multi-]polygon\n");
2814 PG_RETURN_NULL();
2815 }
2816
2817 /*bbox check */
2818 gserialized_get_gbox_p(pg_geom1, &g1_bvol);
2819
2820 g1_bvol.xmin = g1_bvol.xmin - dist;
2821 g1_bvol.ymin = g1_bvol.ymin - dist;
2822 g1_bvol.xmax = g1_bvol.xmax + dist;
2823 g1_bvol.ymax = g1_bvol.ymax + dist;
2824
2825 if ((g1_bvol.xmin > geom2->bbox->xmax) || (g1_bvol.xmax < geom2->bbox->xmin) ||
2826 (g1_bvol.ymin > geom2->bbox->ymax) || (g1_bvol.ymax < geom2->bbox->ymin))
2827 {
2828 PG_RETURN_BOOL(false); /*bbox not overlap */
2829 }
2830
2831 /*
2832 * compute distances
2833 * should be a fast calc if they actually do intersect
2834 */
2835 calc_dist =
2836 DatumGetFloat8(DirectFunctionCall2(ST_Distance, PointerGetDatum(pg_geom1), PointerGetDatum(pg_geom2)));
2837
2838 PG_RETURN_BOOL(calc_dist < dist);
2839}
2840
2841/*affine transform geometry */
2843Datum LWGEOM_affine(PG_FUNCTION_ARGS)
2844{
2845 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P_COPY(0);
2846 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
2847 GSERIALIZED *ret;
2848 AFFINE affine;
2849
2850 affine.afac = PG_GETARG_FLOAT8(1);
2851 affine.bfac = PG_GETARG_FLOAT8(2);
2852 affine.cfac = PG_GETARG_FLOAT8(3);
2853 affine.dfac = PG_GETARG_FLOAT8(4);
2854 affine.efac = PG_GETARG_FLOAT8(5);
2855 affine.ffac = PG_GETARG_FLOAT8(6);
2856 affine.gfac = PG_GETARG_FLOAT8(7);
2857 affine.hfac = PG_GETARG_FLOAT8(8);
2858 affine.ifac = PG_GETARG_FLOAT8(9);
2859 affine.xoff = PG_GETARG_FLOAT8(10);
2860 affine.yoff = PG_GETARG_FLOAT8(11);
2861 affine.zoff = PG_GETARG_FLOAT8(12);
2862
2863 POSTGIS_DEBUG(2, "LWGEOM_affine called.");
2864
2865 lwgeom_affine(lwgeom, &affine);
2866
2867 /* COMPUTE_BBOX TAINTING */
2868 if (lwgeom->bbox)
2869 {
2870 lwgeom_refresh_bbox(lwgeom);
2871 }
2872 ret = geometry_serialize(lwgeom);
2873
2874 /* Release memory */
2875 lwgeom_free(lwgeom);
2876 PG_FREE_IF_COPY(geom, 0);
2877
2878 PG_RETURN_POINTER(ret);
2879}
2880
2882Datum ST_GeoHash(PG_FUNCTION_ARGS)
2883{
2884
2885 GSERIALIZED *geom = NULL;
2886 int precision = 0;
2887 lwvarlena_t *geohash = NULL;
2888
2889 if (PG_ARGISNULL(0))
2890 {
2891 PG_RETURN_NULL();
2892 }
2893
2894 geom = PG_GETARG_GSERIALIZED_P(0);
2895
2896 if (!PG_ARGISNULL(1))
2897 {
2898 precision = PG_GETARG_INT32(1);
2899 }
2900
2902 if (geohash)
2903 PG_RETURN_TEXT_P(geohash);
2904 PG_RETURN_NULL();
2905}
2906
2908Datum _ST_SortableHash(PG_FUNCTION_ARGS)
2909{
2910 if (PG_ARGISNULL(0))
2911 PG_RETURN_NULL();
2912 PG_RETURN_INT64(gserialized_get_sortable_hash(PG_GETARG_GSERIALIZED_P(0)));
2913}
2914
2916Datum ST_CollectionExtract(PG_FUNCTION_ARGS)
2917{
2918 GSERIALIZED *gser_in, *gser_out;
2919 LWGEOM *lwg_in = NULL;
2920 LWGEOM *lwg_out = NULL;
2921 int extype = 0;
2922
2923 if (PG_NARGS() > 1)
2924 extype = PG_GETARG_INT32(1);
2925
2926 /* Ensure the right type was input */
2927 if (!(extype == 0 || extype == POINTTYPE || extype == LINETYPE || extype == POLYGONTYPE))
2928 {
2929 elog(ERROR, "ST_CollectionExtract: only point, linestring and polygon may be extracted");
2930 PG_RETURN_NULL();
2931 }
2932
2933 gser_in = PG_GETARG_GSERIALIZED_P(0);
2934 lwg_in = lwgeom_from_gserialized(gser_in);
2935
2936 /* Mirror non-collections right back */
2937 if (!lwgeom_is_collection(lwg_in))
2938 {
2939 /* Non-collections of the matching type go back */
2940 if (lwg_in->type == extype || !extype)
2941 {
2942 lwgeom_free(lwg_in);
2943 PG_RETURN_POINTER(gser_in);
2944 }
2945 /* Others go back as EMPTY */
2946 else
2947 {
2948 lwg_out = lwgeom_construct_empty(extype, lwg_in->srid, lwgeom_has_z(lwg_in), lwgeom_has_m(lwg_in));
2949 PG_RETURN_POINTER(geometry_serialize(lwg_out));
2950 }
2951 }
2952
2953 lwg_out = (LWGEOM*)lwcollection_extract((LWCOLLECTION*)lwg_in, extype);
2954
2955 gser_out = geometry_serialize(lwg_out);
2956 lwgeom_free(lwg_in);
2957 lwgeom_free(lwg_out);
2958 PG_RETURN_POINTER(gser_out);
2959}
2960
2962Datum ST_CollectionHomogenize(PG_FUNCTION_ARGS)
2963{
2964 GSERIALIZED *input = PG_GETARG_GSERIALIZED_P(0);
2965 GSERIALIZED *output;
2966 LWGEOM *lwgeom = lwgeom_from_gserialized(input);
2967 LWGEOM *lwoutput = NULL;
2968
2969 lwoutput = lwgeom_homogenize(lwgeom);
2970 lwgeom_free(lwgeom);
2971
2972 if (!lwoutput)
2973 {
2974 PG_FREE_IF_COPY(input, 0);
2975 PG_RETURN_NULL();
2976 }
2977
2978 output = geometry_serialize(lwoutput);
2979 lwgeom_free(lwoutput);
2980
2981 PG_FREE_IF_COPY(input, 0);
2982 PG_RETURN_POINTER(output);
2983}
2984
2985Datum ST_RemoveRepeatedPoints(PG_FUNCTION_ARGS);
2987Datum ST_RemoveRepeatedPoints(PG_FUNCTION_ARGS)
2988{
2989 GSERIALIZED *g_in = PG_GETARG_GSERIALIZED_P_COPY(0);
2990 uint32_t type = gserialized_get_type(g_in);
2991 GSERIALIZED *g_out;
2992 LWGEOM *lwgeom_in = NULL;
2993 double tolerance = 0.0;
2994 int modified = LW_FALSE;
2995
2996 /* Don't even start to think about points */
2997 if (type == POINTTYPE)
2998 PG_RETURN_POINTER(g_in);
2999
3000 if (PG_NARGS() > 1 && !PG_ARGISNULL(1))
3001 tolerance = PG_GETARG_FLOAT8(1);
3002
3003 lwgeom_in = lwgeom_from_gserialized(g_in);
3004 modified = lwgeom_remove_repeated_points_in_place(lwgeom_in, tolerance);
3005 if (!modified)
3006 {
3007 /* Since there were no changes, we can return the input to avoid the serialization */
3008 PG_RETURN_POINTER(g_in);
3009 }
3010
3011 g_out = geometry_serialize(lwgeom_in);
3012
3013 pfree(g_in);
3014 PG_RETURN_POINTER(g_out);
3015}
3016
3017Datum ST_FlipCoordinates(PG_FUNCTION_ARGS);
3019Datum ST_FlipCoordinates(PG_FUNCTION_ARGS)
3020{
3021 GSERIALIZED *in = PG_GETARG_GSERIALIZED_P_COPY(0);
3022 GSERIALIZED *out;
3023 LWGEOM *lwgeom = lwgeom_from_gserialized(in);
3024
3026 out = geometry_serialize(lwgeom);
3027
3028 lwgeom_free(lwgeom);
3029 PG_FREE_IF_COPY(in, 0);
3030
3031 PG_RETURN_POINTER(out);
3032}
3033
3034static LWORD
3036{
3037 if (n == 'x' || n == 'X')
3038 return LWORD_X;
3039 if (n == 'y' || n == 'Y')
3040 return LWORD_Y;
3041 if (n == 'z' || n == 'Z')
3042 return LWORD_Z;
3043 if (n == 'm' || n == 'M')
3044 return LWORD_M;
3045 lwpgerror("Invalid ordinate name '%c'. Expected x,y,z or m", n);
3046 return (LWORD)-1;
3047}
3048
3049Datum ST_SwapOrdinates(PG_FUNCTION_ARGS);
3051Datum ST_SwapOrdinates(PG_FUNCTION_ARGS)
3052{
3053 GSERIALIZED *in;
3054 GSERIALIZED *out;
3055 LWGEOM *lwgeom;
3056 const char *ospec;
3057 LWORD o1, o2;
3058
3059 ospec = PG_GETARG_CSTRING(1);
3060 if (strlen(ospec) != 2)
3061 {
3062 lwpgerror(
3063 "Invalid ordinate specification. "
3064 "Need two letters from the set (x,y,z,m). "
3065 "Got '%s'",
3066 ospec);
3067 PG_RETURN_NULL();
3068 }
3069 o1 = ordname2ordval(ospec[0]);
3070 o2 = ordname2ordval(ospec[1]);
3071
3072 in = PG_GETARG_GSERIALIZED_P_COPY(0);
3073
3074 /* Check presence of given ordinates */
3075 if ((o1 == LWORD_M || o2 == LWORD_M) && !gserialized_has_m(in))
3076 {
3077 lwpgerror("Geometry does not have an M ordinate");
3078 PG_RETURN_NULL();
3079 }
3080 if ((o1 == LWORD_Z || o2 == LWORD_Z) && !gserialized_has_z(in))
3081 {
3082 lwpgerror("Geometry does not have a Z ordinate");
3083 PG_RETURN_NULL();
3084 }
3085
3086 /* Nothing to do if swapping the same ordinate, pity for the copy... */
3087 if (o1 == o2)
3088 PG_RETURN_POINTER(in);
3089
3090 lwgeom = lwgeom_from_gserialized(in);
3091 lwgeom_swap_ordinates(lwgeom, o1, o2);
3092 out = geometry_serialize(lwgeom);
3093 lwgeom_free(lwgeom);
3094 PG_FREE_IF_COPY(in, 0);
3095 PG_RETURN_POINTER(out);
3096}
3097
3098/*
3099 * ST_BoundingDiagonal(inp geometry, fits boolean)
3100 */
3101Datum ST_BoundingDiagonal(PG_FUNCTION_ARGS);
3103Datum ST_BoundingDiagonal(PG_FUNCTION_ARGS)
3104{
3105 GSERIALIZED *geom_out;
3106 bool fits = PG_GETARG_BOOL(1);
3107 LWGEOM *lwgeom_out = NULL;
3108
3109 GBOX gbox = {0};
3110 int hasz;
3111 int hasm;
3112 int32_t srid;
3113
3114 POINT4D pt;
3115 POINTARRAY *pa;
3116
3117 if (fits)
3118 {
3119 GSERIALIZED *geom_in = PG_GETARG_GSERIALIZED_P(0);
3120 LWGEOM *lwgeom_in = lwgeom_from_gserialized(geom_in);
3121 lwgeom_calculate_gbox(lwgeom_in, &gbox);
3122 hasz = FLAGS_GET_Z(lwgeom_in->flags);
3123 hasm = FLAGS_GET_M(lwgeom_in->flags);
3124 srid = lwgeom_in->srid;
3125 }
3126 else
3127 {
3128 uint8_t type;
3129 lwflags_t flags;
3130 int res = gserialized_datum_get_internals_p(PG_GETARG_DATUM(0), &gbox, &flags, &type, &srid);
3131 hasz = FLAGS_GET_Z(flags);
3132 hasm = FLAGS_GET_M(flags);
3133 if (res == LW_FAILURE)
3134 {
3135 lwgeom_out = lwgeom_construct_empty(LINETYPE, srid, hasz, hasm);
3136 }
3137 }
3138
3139 if (!lwgeom_out)
3140 {
3141 pa = ptarray_construct_empty(hasz, hasm, 2);
3142 pt.x = gbox.xmin;
3143 pt.y = gbox.ymin;
3144 pt.z = gbox.zmin;
3145 pt.m = gbox.mmin;
3146 ptarray_append_point(pa, &pt, LW_TRUE);
3147 pt.x = gbox.xmax;
3148 pt.y = gbox.ymax;
3149 pt.z = gbox.zmax;
3150 pt.m = gbox.mmax;
3151 ptarray_append_point(pa, &pt, LW_TRUE);
3152 lwgeom_out = lwline_as_lwgeom(lwline_construct(srid, NULL, pa));
3153 }
3154
3155 geom_out = geometry_serialize(lwgeom_out);
3156 lwgeom_free(lwgeom_out);
3157
3158 PG_RETURN_POINTER(geom_out);
3159}
3160
3161Datum ST_Scale(PG_FUNCTION_ARGS);
3163Datum ST_Scale(PG_FUNCTION_ARGS)
3164{
3165 GSERIALIZED *geom;
3166 GSERIALIZED *geom_scale = PG_GETARG_GSERIALIZED_P(1);
3167 GSERIALIZED *geom_origin = NULL;
3168 LWGEOM *lwg, *lwg_scale, *lwg_origin;
3169 LWPOINT *lwpt_scale, *lwpt_origin;
3170 POINT4D origin;
3171 POINT4D factors;
3172 bool translate = false;
3173 GSERIALIZED *ret;
3174 AFFINE aff;
3175
3176 /* Make sure we have a valid scale input */
3177 lwg_scale = lwgeom_from_gserialized(geom_scale);
3178 lwpt_scale = lwgeom_as_lwpoint(lwg_scale);
3179 if (!lwpt_scale)
3180 {
3181 lwgeom_free(lwg_scale);
3182 PG_FREE_IF_COPY(geom_scale, 1);
3183 lwpgerror("Scale factor geometry parameter must be a point");
3184 PG_RETURN_NULL();
3185 }
3186
3187 /* Geom Will be modified in place, so take a copy */
3188 geom = PG_GETARG_GSERIALIZED_P_COPY(0);
3189 lwg = lwgeom_from_gserialized(geom);
3190
3191 /* Empty point, return input untouched */
3192 if (lwgeom_is_empty(lwg))
3193 {
3194 lwgeom_free(lwg_scale);
3195 lwgeom_free(lwg);
3196 PG_FREE_IF_COPY(geom_scale, 1);
3197 PG_RETURN_POINTER(geom);
3198 }
3199
3200 /* Once we read the scale data into local static point, we can */
3201 /* free the lwgeom */
3202 lwpoint_getPoint4d_p(lwpt_scale, &factors);
3203 if (!lwgeom_has_z(lwg_scale))
3204 factors.z = 1.0;
3205 if (!lwgeom_has_m(lwg_scale))
3206 factors.m = 1.0;
3207 lwgeom_free(lwg_scale);
3208
3209 /* Do we have the optional false origin? */
3210 if (PG_NARGS() > 2 && !PG_ARGISNULL(2))
3211 {
3212 geom_origin = PG_GETARG_GSERIALIZED_P(2);
3213 lwg_origin = lwgeom_from_gserialized(geom_origin);
3214 lwpt_origin = lwgeom_as_lwpoint(lwg_origin);
3215 if (lwpt_origin)
3216 {
3217 lwpoint_getPoint4d_p(lwpt_origin, &origin);
3218 translate = true;
3219 }
3220 /* Free the false origin inputs */
3221 lwgeom_free(lwg_origin);
3222 PG_FREE_IF_COPY(geom_origin, 2);
3223 }
3224
3225 /* If we have false origin, translate to it before scaling */
3226 if (translate)
3227 {
3228 /* Initialize affine */
3229 memset(&aff, 0, sizeof(AFFINE));
3230 /* Set rotation/scale/sheer matrix to no-op */
3231 aff.afac = aff.efac = aff.ifac = 1.0;
3232 /* Strip false origin from all coordinates */
3233 aff.xoff = -1 * origin.x;
3234 aff.yoff = -1 * origin.y;
3235 aff.zoff = -1 * origin.z;
3236 lwgeom_affine(lwg, &aff);
3237 }
3238
3239 lwgeom_scale(lwg, &factors);
3240
3241 /* Return to original origin after scaling */
3242 if (translate)
3243 {
3244 aff.xoff *= -1;
3245 aff.yoff *= -1;
3246 aff.zoff *= -1;
3247 lwgeom_affine(lwg, &aff);
3248 }
3249
3250 /* Cleanup and return */
3251 ret = geometry_serialize(lwg);
3252 lwgeom_free(lwg);
3253 PG_FREE_IF_COPY(geom, 0);
3254 PG_FREE_IF_COPY(geom_scale, 1);
3255 PG_RETURN_POINTER(ret);
3256}
3257
3258Datum ST_Points(PG_FUNCTION_ARGS);
3260Datum ST_Points(PG_FUNCTION_ARGS)
3261{
3262 if (PG_ARGISNULL(0))
3263 {
3264 PG_RETURN_NULL();
3265 }
3266 else
3267 {
3268 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
3269 GSERIALIZED *ret;
3270 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
3272
3273 lwgeom_free(lwgeom);
3274
3275 ret = geometry_serialize(lwmpoint_as_lwgeom(result));
3277 PG_RETURN_POINTER(ret);
3278 }
3279}
3280
3282Datum ST_QuantizeCoordinates(PG_FUNCTION_ARGS)
3283{
3284 GSERIALIZED *input;
3286 LWGEOM *g;
3287 int32_t prec_x;
3288 int32_t prec_y;
3289 int32_t prec_z;
3290 int32_t prec_m;
3291
3292 if (PG_ARGISNULL(0))
3293 PG_RETURN_NULL();
3294 if (PG_ARGISNULL(1))
3295 {
3296 lwpgerror("Must specify precision");
3297 PG_RETURN_NULL();
3298 }
3299 else
3300 {
3301 prec_x = PG_GETARG_INT32(1);
3302 }
3303 prec_y = PG_ARGISNULL(2) ? prec_x : PG_GETARG_INT32(2);
3304 prec_z = PG_ARGISNULL(3) ? prec_x : PG_GETARG_INT32(3);
3305 prec_m = PG_ARGISNULL(4) ? prec_x : PG_GETARG_INT32(4);
3306
3307 input = PG_GETARG_GSERIALIZED_P_COPY(0);
3308
3309 g = lwgeom_from_gserialized(input);
3310
3311 lwgeom_trim_bits_in_place(g, prec_x, prec_y, prec_z, prec_m);
3312
3313 result = geometry_serialize(g);
3314 lwgeom_free(g);
3315 PG_FREE_IF_COPY(input, 0);
3316 PG_RETURN_POINTER(result);
3317}
3318
3319/*
3320 * ST_FilterByM(in geometry, val double precision)
3321 */
3323Datum LWGEOM_FilterByM(PG_FUNCTION_ARGS)
3324{
3325 GSERIALIZED *geom_in;
3326 GSERIALIZED *geom_out;
3327 LWGEOM *lwgeom_in;
3328 LWGEOM *lwgeom_out;
3329 double min, max;
3330 int returnm;
3331 int hasm;
3332
3333 if (PG_NARGS() > 0 && !PG_ARGISNULL(0))
3334 {
3335 geom_in = PG_GETARG_GSERIALIZED_P(0);
3336 }
3337 else
3338 {
3339 PG_RETURN_NULL();
3340 }
3341
3342 if (PG_NARGS() > 1 && !PG_ARGISNULL(1))
3343 min = PG_GETARG_FLOAT8(1);
3344 else
3345 {
3346 min = DBL_MIN;
3347 }
3348 if (PG_NARGS() > 2 && !PG_ARGISNULL(2))
3349 max = PG_GETARG_FLOAT8(2);
3350 else
3351 {
3352 max = DBL_MAX;
3353 }
3354 if (PG_NARGS() > 3 && !PG_ARGISNULL(3) && PG_GETARG_BOOL(3))
3355 returnm = 1;
3356 else
3357 {
3358 returnm = 0;
3359 }
3360
3361 if (min > max)
3362 {
3363 elog(ERROR, "Min-value cannot be larger than Max value\n");
3364 PG_RETURN_NULL();
3365 }
3366
3367 lwgeom_in = lwgeom_from_gserialized(geom_in);
3368
3369 hasm = lwgeom_has_m(lwgeom_in);
3370
3371 if (!hasm)
3372 {
3373 elog(NOTICE, "No M-value, No vertex removed\n");
3374 PG_RETURN_POINTER(geom_in);
3375 }
3376
3377 lwgeom_out = lwgeom_filter_m(lwgeom_in, min, max, returnm);
3378
3379 geom_out = geometry_serialize(lwgeom_out);
3380 lwgeom_free(lwgeom_out);
3381 PG_RETURN_POINTER(geom_out);
3382}
3383
3385Datum boundary(PG_FUNCTION_ARGS)
3386{
3387 GSERIALIZED *geom1;
3389 LWGEOM *lwgeom, *lwresult;
3390
3391 geom1 = PG_GETARG_GSERIALIZED_P(0);
3392
3393 /* Empty.Boundary() == Empty, but of other dimension, so can't shortcut */
3394
3395 lwgeom = lwgeom_from_gserialized(geom1);
3396 lwresult = lwgeom_boundary(lwgeom);
3397 if (!lwresult)
3398 {
3399 lwgeom_free(lwgeom);
3400 PG_RETURN_NULL();
3401 }
3402
3403 result = geometry_serialize(lwresult);
3404
3405 lwgeom_free(lwgeom);
3406 lwgeom_free(lwresult);
3407
3408 PG_RETURN_POINTER(result);
3409}
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:347
LWGEOM * lwmpoint_as_lwgeom(const LWMPOINT *obj)
Definition lwgeom.c:304
void lwgeom_refresh_bbox(LWGEOM *lwgeom)
Drop current bbox and calculate a fresh one.
Definition lwgeom.c:707
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:344
#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:1194
@ 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:927
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:1610
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:2665
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:1008
#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:1218
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:380
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:2686
LWPOLY * lwpoly_from_lwlines(const LWLINE *shell, uint32_t nholes, const LWLINE **holes)
Definition lwpoly.c:360
double lwgeom_perimeter_2d(const LWGEOM *geom)
Definition lwgeom.c:2016
int lwpoint_inside_circle(const LWPOINT *p, double cx, double cy, double rad)
Definition lwgeom.c:662
#define MULTISURFACETYPE
Definition liblwgeom.h:113
#define LINETYPE
Definition liblwgeom.h:103
#define WKT_EXTENDED
Definition liblwgeom.h:2218
#define LW_SUCCESS
Definition liblwgeom.h:97
LWGEOM * lwgeom_force_3dz(const LWGEOM *geom, double zval)
Definition lwgeom.c:799
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:420
int lwgeom_remove_repeated_points_in_place(LWGEOM *in, double tolerance)
Definition lwgeom.c:1667
LWGEOM * lwgeom_force_sfs(LWGEOM *geom, int version)
Definition lwgeom.c:849
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:793
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:2038
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:934
#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:682
#define FLAGS_GET_Z(flags)
Definition liblwgeom.h:165
void lwgeom_scale(LWGEOM *geom, const POINT4D *factors)
Definition lwgeom.c:2137
void * lwalloc(size_t size)
Definition lwutil.c:227
double lwgeom_area(const LWGEOM *geom)
Definition lwgeom.c:1971
#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:1309
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:1097
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:672
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:1541
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition lwgeom.c:339
void lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
Definition lwgeom.c:2083
#define POLYHEDRALSURFACETYPE
Definition liblwgeom.h:114
double lwgeom_length_2d(const LWGEOM *geom)
Definition lwgeom.c:2060
uint32_t lwgeom_count_rings(const LWGEOM *geom)
Count the total number of rings in any LWGEOM.
Definition lwgeom.c:1419
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)
Force Right-hand-rule on LWGEOM polygons.
Definition lwgeom.c:38
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:1104
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:755
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition lwgeom.c:179
void lwline_setPoint4d(LWLINE *line, uint32_t which, POINT4D *newpoint)
Definition lwline.c:364
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:2191
#define MULTICURVETYPE
Definition liblwgeom.h:112
#define TRIANGLETYPE
Definition liblwgeom.h:115
LWMPOINT * lwgeom_as_lwmpoint(const LWGEOM *lwgeom)
Definition lwgeom.c:242
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:1994
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition lwgeom.c:941
LWGEOM * lwgeom_force_4d(const LWGEOM *geom, double zval, double mval)
Definition lwgeom.c:811
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition lwgeom.c:329
LWGEOM * lwgeom_force_3dm(const LWGEOM *geom, double mval)
Definition lwgeom.c:805
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:695
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:275
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:771
int lwline_add_lwpoint(LWLINE *line, LWPOINT *point, uint32_t where)
Add a LWPOINT to an LWLINE.
Definition lwline.c:327
void lwgeom_drop_srid(LWGEOM *lwgeom)
Definition lwgeom.c:765
void lwgeom_reverse_in_place(LWGEOM *lwgeom)
Reverse vertex order of LWGEOM.
Definition lwgeom.c:103
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:529
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:520
#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:2325
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_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