PostGIS 3.0.6dev-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 "lwgeom_pg.h"
36
37#include <math.h>
38#include <float.h>
39#include <string.h>
40#include <stdio.h>
41
42#define xstr(s) str(s)
43#define str(s) #s
44
45Datum LWGEOM_mem_size(PG_FUNCTION_ARGS);
46Datum LWGEOM_summary(PG_FUNCTION_ARGS);
47Datum LWGEOM_npoints(PG_FUNCTION_ARGS);
48Datum LWGEOM_nrings(PG_FUNCTION_ARGS);
49Datum ST_Area(PG_FUNCTION_ARGS);
50Datum postgis_scripts_released(PG_FUNCTION_ARGS);
51Datum postgis_version(PG_FUNCTION_ARGS);
52Datum postgis_liblwgeom_version(PG_FUNCTION_ARGS);
53Datum postgis_lib_version(PG_FUNCTION_ARGS);
54Datum postgis_svn_version(PG_FUNCTION_ARGS);
55Datum postgis_lib_revision(PG_FUNCTION_ARGS);
56Datum postgis_libxml_version(PG_FUNCTION_ARGS);
57Datum postgis_lib_build_date(PG_FUNCTION_ARGS);
58Datum LWGEOM_length2d_linestring(PG_FUNCTION_ARGS);
59Datum LWGEOM_length_linestring(PG_FUNCTION_ARGS);
60Datum LWGEOM_perimeter2d_poly(PG_FUNCTION_ARGS);
61Datum LWGEOM_perimeter_poly(PG_FUNCTION_ARGS);
62
63Datum LWGEOM_maxdistance2d_linestring(PG_FUNCTION_ARGS);
64Datum ST_Distance(PG_FUNCTION_ARGS);
65Datum LWGEOM_closestpoint(PG_FUNCTION_ARGS);
66Datum LWGEOM_shortestline2d(PG_FUNCTION_ARGS);
67Datum LWGEOM_longestline2d(PG_FUNCTION_ARGS);
68Datum LWGEOM_dwithin(PG_FUNCTION_ARGS);
69Datum LWGEOM_dfullywithin(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 LWGEOM_angle(PG_FUNCTION_ARGS);
108Datum LWGEOM_affine(PG_FUNCTION_ARGS);
109Datum LWGEOM_longitude_shift(PG_FUNCTION_ARGS);
110Datum optimistic_overlap(PG_FUNCTION_ARGS);
111Datum ST_GeoHash(PG_FUNCTION_ARGS);
112Datum ST_MakeEnvelope(PG_FUNCTION_ARGS);
113Datum ST_TileEnvelope(PG_FUNCTION_ARGS);
114Datum ST_CollectionExtract(PG_FUNCTION_ARGS);
115Datum ST_CollectionHomogenize(PG_FUNCTION_ARGS);
116Datum ST_IsCollection(PG_FUNCTION_ARGS);
117Datum ST_QuantizeCoordinates(PG_FUNCTION_ARGS);
118Datum ST_WrapX(PG_FUNCTION_ARGS);
119Datum LWGEOM_FilterByM(PG_FUNCTION_ARGS);
120
121/*------------------------------------------------------------------*/
122
125Datum LWGEOM_mem_size(PG_FUNCTION_ARGS)
126{
127 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
128 size_t size = VARSIZE(geom);
129 PG_FREE_IF_COPY(geom, 0);
130 PG_RETURN_INT32(size);
131}
132
135Datum LWGEOM_summary(PG_FUNCTION_ARGS)
136{
137 text *summary;
138 GSERIALIZED *g = PG_GETARG_GSERIALIZED_P(0);
140 char *lwresult = lwgeom_summary(lwg, 0);
141 uint32_t gver = gserialized_get_version(g);
142 size_t result_sz = strlen(lwresult) + 8;
143 char *result;
144 if (gver == 0)
145 {
146 result = lwalloc(result_sz + 2);
147 snprintf(result, result_sz, "0:%s", lwresult);
148 }
149 else
150 {
151 result = lwalloc(result_sz);
152 snprintf(result, result_sz, "%s", lwresult);
153 }
154 lwgeom_free(lwg);
155 lwfree(lwresult);
156
157 /* create a text obj to return */
158 summary = cstring_to_text(result);
159 lwfree(result);
160
161 PG_FREE_IF_COPY(g, 0);
162 PG_RETURN_TEXT_P(summary);
163}
164
166Datum postgis_version(PG_FUNCTION_ARGS)
167{
168 char *ver = POSTGIS_VERSION;
169 text *result = cstring_to_text(ver);
170 PG_RETURN_TEXT_P(result);
171}
172
174Datum postgis_liblwgeom_version(PG_FUNCTION_ARGS)
175{
176 const char *ver = lwgeom_version();
177 text *result = cstring_to_text(ver);
178 PG_RETURN_TEXT_P(result);
179}
180
182Datum postgis_lib_version(PG_FUNCTION_ARGS)
183{
184 char *ver = POSTGIS_LIB_VERSION;
185 text *result = cstring_to_text(ver);
186 PG_RETURN_TEXT_P(result);
187}
188
190Datum postgis_svn_version(PG_FUNCTION_ARGS)
191{
192 return postgis_lib_revision(fcinfo);
193}
194
196Datum postgis_lib_revision(PG_FUNCTION_ARGS)
197{
198 static char *rev = xstr(POSTGIS_REVISION);
199 char ver[32];
200 if (rev && rev[0] != '\0')
201 {
202 snprintf(ver, 32, "%s", rev);
203 ver[31] = '\0';
204 PG_RETURN_TEXT_P(cstring_to_text(ver));
205 }
206 else PG_RETURN_NULL();
207}
208
210Datum postgis_lib_build_date(PG_FUNCTION_ARGS)
211{
212 char *ver = POSTGIS_BUILD_DATE;
213 text *result = cstring_to_text(ver);
214 PG_RETURN_TEXT_P(result);
215}
216
218Datum postgis_scripts_released(PG_FUNCTION_ARGS)
219{
220 char ver[64];
221 text *result;
222
223 snprintf(ver, 64, "%s %s", POSTGIS_LIB_VERSION, xstr(POSTGIS_REVISION));
224 ver[63] = '\0';
225
226 result = cstring_to_text(ver);
227 PG_RETURN_TEXT_P(result);
228}
229
231Datum postgis_libxml_version(PG_FUNCTION_ARGS)
232{
233 char *ver = POSTGIS_LIBXML2_VERSION;
234 text *result = cstring_to_text(ver);
235 PG_RETURN_TEXT_P(result);
236}
237
240Datum LWGEOM_npoints(PG_FUNCTION_ARGS)
241{
242 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
243 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
244 int npoints = 0;
245
246 npoints = lwgeom_count_vertices(lwgeom);
247 lwgeom_free(lwgeom);
248
249 PG_FREE_IF_COPY(geom, 0);
250 PG_RETURN_INT32(npoints);
251}
252
255Datum LWGEOM_nrings(PG_FUNCTION_ARGS)
256{
257 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
258 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
259 int nrings = 0;
260
261 nrings = lwgeom_count_rings(lwgeom);
262 lwgeom_free(lwgeom);
263
264 PG_FREE_IF_COPY(geom, 0);
265 PG_RETURN_INT32(nrings);
266}
267
275Datum ST_Area(PG_FUNCTION_ARGS)
276{
277 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
278 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
279 double area = 0.0;
280
281 area = lwgeom_area(lwgeom);
282
283 lwgeom_free(lwgeom);
284 PG_FREE_IF_COPY(geom, 0);
285
286 PG_RETURN_FLOAT8(area);
287}
288
297Datum LWGEOM_length2d_linestring(PG_FUNCTION_ARGS)
298{
299 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
300 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
301 double dist = lwgeom_length_2d(lwgeom);
302 lwgeom_free(lwgeom);
303 PG_FREE_IF_COPY(geom, 0);
304 PG_RETURN_FLOAT8(dist);
305}
306
315Datum LWGEOM_length_linestring(PG_FUNCTION_ARGS)
316{
317 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
318 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
319 double dist = lwgeom_length(lwgeom);
320 lwgeom_free(lwgeom);
321 PG_FREE_IF_COPY(geom, 0);
322 PG_RETURN_FLOAT8(dist);
323}
324
333Datum LWGEOM_perimeter_poly(PG_FUNCTION_ARGS)
334{
335 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
336 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
337 double perimeter = 0.0;
338
339 perimeter = lwgeom_perimeter(lwgeom);
340 PG_FREE_IF_COPY(geom, 0);
341 PG_RETURN_FLOAT8(perimeter);
342}
343
352Datum LWGEOM_perimeter2d_poly(PG_FUNCTION_ARGS)
353{
354 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
355 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
356 double perimeter = 0.0;
357
358 perimeter = lwgeom_perimeter_2d(lwgeom);
359 PG_FREE_IF_COPY(geom, 0);
360 PG_RETURN_FLOAT8(perimeter);
361}
362
363/* transform input geometry to 2d if not 2d already */
365Datum LWGEOM_force_2d(PG_FUNCTION_ARGS)
366{
367 GSERIALIZED *pg_geom_in = PG_GETARG_GSERIALIZED_P(0);
368 GSERIALIZED *pg_geom_out;
369 LWGEOM *lwg_in, *lwg_out;
370
371 /* already 2d */
372 if (gserialized_ndims(pg_geom_in) == 2)
373 PG_RETURN_POINTER(pg_geom_in);
374
375 lwg_in = lwgeom_from_gserialized(pg_geom_in);
376 lwg_out = lwgeom_force_2d(lwg_in);
377 pg_geom_out = geometry_serialize(lwg_out);
378 lwgeom_free(lwg_out);
379 lwgeom_free(lwg_in);
380
381 PG_FREE_IF_COPY(pg_geom_in, 0);
382 PG_RETURN_POINTER(pg_geom_out);
383}
384
385/* transform input geometry to 3dz if not 3dz already */
387Datum LWGEOM_force_3dz(PG_FUNCTION_ARGS)
388{
389 GSERIALIZED *pg_geom_in = PG_GETARG_GSERIALIZED_P(0);
390 GSERIALIZED *pg_geom_out;
391 LWGEOM *lwg_in, *lwg_out;
392
393 /* already 3d */
394 if (gserialized_ndims(pg_geom_in) == 3 && gserialized_has_z(pg_geom_in))
395 PG_RETURN_POINTER(pg_geom_in);
396
397 lwg_in = lwgeom_from_gserialized(pg_geom_in);
398 lwg_out = lwgeom_force_3dz(lwg_in);
399 pg_geom_out = geometry_serialize(lwg_out);
400 lwgeom_free(lwg_out);
401 lwgeom_free(lwg_in);
402
403 PG_FREE_IF_COPY(pg_geom_in, 0);
404 PG_RETURN_POINTER(pg_geom_out);
405}
406
409Datum LWGEOM_force_3dm(PG_FUNCTION_ARGS)
410{
411 GSERIALIZED *pg_geom_in = PG_GETARG_GSERIALIZED_P(0);
412 GSERIALIZED *pg_geom_out;
413 LWGEOM *lwg_in, *lwg_out;
414
415 /* already 3d */
416 if (gserialized_ndims(pg_geom_in) == 3 && gserialized_has_m(pg_geom_in))
417 PG_RETURN_POINTER(pg_geom_in);
418
419 lwg_in = lwgeom_from_gserialized(pg_geom_in);
420 lwg_out = lwgeom_force_3dm(lwg_in);
421 pg_geom_out = geometry_serialize(lwg_out);
422 lwgeom_free(lwg_out);
423 lwgeom_free(lwg_in);
424
425 PG_FREE_IF_COPY(pg_geom_in, 0);
426 PG_RETURN_POINTER(pg_geom_out);
427}
428
429/* transform input geometry to 4d if not 4d already */
431Datum LWGEOM_force_4d(PG_FUNCTION_ARGS)
432{
433 GSERIALIZED *pg_geom_in = PG_GETARG_GSERIALIZED_P(0);
434 GSERIALIZED *pg_geom_out;
435 LWGEOM *lwg_in, *lwg_out;
436
437 /* already 4d */
438 if (gserialized_ndims(pg_geom_in) == 4)
439 PG_RETURN_POINTER(pg_geom_in);
440
441 lwg_in = lwgeom_from_gserialized(pg_geom_in);
442 lwg_out = lwgeom_force_4d(lwg_in);
443 pg_geom_out = geometry_serialize(lwg_out);
444 lwgeom_free(lwg_out);
445 lwgeom_free(lwg_in);
446
447 PG_FREE_IF_COPY(pg_geom_in, 0);
448 PG_RETURN_POINTER(pg_geom_out);
449}
450
453Datum LWGEOM_force_collection(PG_FUNCTION_ARGS)
454{
455 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
456 GSERIALIZED *result;
457 LWGEOM **lwgeoms;
458 LWGEOM *lwgeom;
459 int32_t srid;
460 GBOX *bbox;
461
462 POSTGIS_DEBUG(2, "LWGEOM_force_collection called");
463
464 /*
465 * This funx is a no-op only if a bbox cache is already present
466 * in input. If bbox cache is not there we'll need to handle
467 * automatic bbox addition FOR_COMPLEX_GEOMS.
468 */
470 {
471 PG_RETURN_POINTER(geom);
472 }
473
474 /* deserialize into lwgeoms[0] */
475 lwgeom = lwgeom_from_gserialized(geom);
476
477 /* alread a multi*, just make it a collection */
478 if (lwgeom_is_collection(lwgeom))
479 {
480 lwgeom->type = COLLECTIONTYPE;
481 }
482
483 /* single geom, make it a collection */
484 else
485 {
486 srid = lwgeom->srid;
487 /* We transfer bbox ownership from input to output */
488 bbox = lwgeom->bbox;
489 lwgeom->srid = SRID_UNKNOWN;
490 lwgeom->bbox = NULL;
491 lwgeoms = palloc(sizeof(LWGEOM *));
492 lwgeoms[0] = lwgeom;
493 lwgeom = (LWGEOM *)lwcollection_construct(COLLECTIONTYPE, srid, bbox, 1, lwgeoms);
494 }
495
496 result = geometry_serialize(lwgeom);
497 lwgeom_free(lwgeom);
498
499 PG_FREE_IF_COPY(geom, 0);
500 PG_RETURN_POINTER(result);
501}
502
505Datum LWGEOM_force_multi(PG_FUNCTION_ARGS)
506{
507 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
508 GSERIALIZED *result;
509 LWGEOM *lwgeom;
510 LWGEOM *ogeom;
511
512 POSTGIS_DEBUG(2, "LWGEOM_force_multi called");
513
514 /*
515 ** This funx is a no-op only if a bbox cache is already present
516 ** in input. If bbox cache is not there we'll need to handle
517 ** automatic bbox addition FOR_COMPLEX_GEOMS.
518 */
519 if (gserialized_has_bbox(geom))
520 {
521 switch (gserialized_get_type(geom))
522 {
523 case MULTIPOINTTYPE:
524 case MULTILINETYPE:
525 case MULTIPOLYGONTYPE:
526 case COLLECTIONTYPE:
527 case MULTICURVETYPE:
528 case MULTISURFACETYPE:
529 case TINTYPE:
530 PG_RETURN_POINTER(geom);
531 default:
532 break;
533 }
534 }
535
536 /* deserialize into lwgeoms[0] */
537 lwgeom = lwgeom_from_gserialized(geom);
538 ogeom = lwgeom_as_multi(lwgeom);
539
540 result = geometry_serialize(ogeom);
541
542 PG_FREE_IF_COPY(geom, 0);
543
544 PG_RETURN_POINTER(result);
545}
546
549Datum LWGEOM_force_curve(PG_FUNCTION_ARGS)
550{
551 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
552 GSERIALIZED *result;
553 LWGEOM *lwgeom;
554 LWGEOM *ogeom;
555
556 POSTGIS_DEBUG(2, "LWGEOM_force_curve called");
557
558 /* TODO: early out if input is already a curve */
559
560 lwgeom = lwgeom_from_gserialized(geom);
561 ogeom = lwgeom_as_curve(lwgeom);
562
563 result = geometry_serialize(ogeom);
564
565 PG_FREE_IF_COPY(geom, 0);
566
567 PG_RETURN_POINTER(result);
568}
569
572Datum LWGEOM_force_sfs(PG_FUNCTION_ARGS)
573{
574 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
575 GSERIALIZED *result;
576 LWGEOM *lwgeom;
577 LWGEOM *ogeom;
578 text *ver;
579 int version = 110; /* default version is SFS 1.1 */
580
581 POSTGIS_DEBUG(2, "LWGEOM_force_sfs called");
582
583 /* If user specified version, respect it */
584 if ((PG_NARGS() > 1) && (!PG_ARGISNULL(1)))
585 {
586 ver = PG_GETARG_TEXT_P(1);
587
588 if (!strncmp(VARDATA(ver), "1.2", 3))
589 {
590 version = 120;
591 }
592 }
593
594 lwgeom = lwgeom_from_gserialized(geom);
595 ogeom = lwgeom_force_sfs(lwgeom, version);
596
597 result = geometry_serialize(ogeom);
598
599 PG_FREE_IF_COPY(geom, 0);
600
601 PG_RETURN_POINTER(result);
602}
603
609Datum LWGEOM_closestpoint(PG_FUNCTION_ARGS)
610{
611 GSERIALIZED *result;
612 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
613 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
614 LWGEOM *point;
615 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
616 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
617 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
618
619 point = lwgeom_closest_point(lwgeom1, lwgeom2);
620
621 if (lwgeom_is_empty(point))
622 PG_RETURN_NULL();
623
624 result = geometry_serialize(point);
625 lwgeom_free(point);
626 lwgeom_free(lwgeom1);
627 lwgeom_free(lwgeom2);
628
629 PG_FREE_IF_COPY(geom1, 0);
630 PG_FREE_IF_COPY(geom2, 1);
631 PG_RETURN_POINTER(result);
632}
633
638Datum LWGEOM_shortestline2d(PG_FUNCTION_ARGS)
639{
640 GSERIALIZED *result;
641 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
642 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
643 LWGEOM *theline;
644 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
645 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
646 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
647
648 theline = lwgeom_closest_line(lwgeom1, lwgeom2);
649
650 if (lwgeom_is_empty(theline))
651 PG_RETURN_NULL();
652
653 result = geometry_serialize(theline);
654 lwgeom_free(theline);
655 lwgeom_free(lwgeom1);
656 lwgeom_free(lwgeom2);
657
658 PG_FREE_IF_COPY(geom1, 0);
659 PG_FREE_IF_COPY(geom2, 1);
660 PG_RETURN_POINTER(result);
661}
662
667Datum LWGEOM_longestline2d(PG_FUNCTION_ARGS)
668{
669 GSERIALIZED *result;
670 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
671 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
672 LWGEOM *theline;
673 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
674 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
675 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
676
677 theline = lwgeom_furthest_line(lwgeom1, lwgeom2);
678
679 if (lwgeom_is_empty(theline))
680 PG_RETURN_NULL();
681
682 result = geometry_serialize(theline);
683 lwgeom_free(theline);
684 lwgeom_free(lwgeom1);
685 lwgeom_free(lwgeom2);
686
687 PG_FREE_IF_COPY(geom1, 0);
688 PG_FREE_IF_COPY(geom2, 1);
689 PG_RETURN_POINTER(result);
690}
695Datum ST_Distance(PG_FUNCTION_ARGS)
696{
697 double mindist;
698 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
699 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
700 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
701 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
702 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
703
704 mindist = lwgeom_mindistance2d(lwgeom1, lwgeom2);
705
706 lwgeom_free(lwgeom1);
707 lwgeom_free(lwgeom2);
708
709 PG_FREE_IF_COPY(geom1, 0);
710 PG_FREE_IF_COPY(geom2, 1);
711
712 /* if called with empty geometries the ingoing mindistance is untouched, and makes us return NULL*/
713 if (mindist < FLT_MAX)
714 PG_RETURN_FLOAT8(mindist);
715
716 PG_RETURN_NULL();
717}
718
725Datum LWGEOM_dwithin(PG_FUNCTION_ARGS)
726{
727 double mindist;
728 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
729 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
730 double tolerance = PG_GETARG_FLOAT8(2);
731 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
732 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
733
734 if (tolerance < 0)
735 {
736 elog(ERROR, "Tolerance cannot be less than zero\n");
737 PG_RETURN_NULL();
738 }
739
740 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
741
742 mindist = lwgeom_mindistance2d_tolerance(lwgeom1, lwgeom2, tolerance);
743
744 PG_FREE_IF_COPY(geom1, 0);
745 PG_FREE_IF_COPY(geom2, 1);
746 /*empty geometries cases should be right handled since return from underlying
747 functions should be FLT_MAX which causes false as answer*/
748 PG_RETURN_BOOL(tolerance >= mindist);
749}
750
757Datum LWGEOM_dfullywithin(PG_FUNCTION_ARGS)
758{
759 double maxdist;
760 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
761 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
762 double tolerance = PG_GETARG_FLOAT8(2);
763 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
764 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
765
766 if (tolerance < 0)
767 {
768 elog(ERROR, "Tolerance cannot be less than zero\n");
769 PG_RETURN_NULL();
770 }
771
772 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
773
774 maxdist = lwgeom_maxdistance2d_tolerance(lwgeom1, lwgeom2, tolerance);
775
776 PG_FREE_IF_COPY(geom1, 0);
777 PG_FREE_IF_COPY(geom2, 1);
778
779 /*If function is feed with empty geometries we should return false*/
780 if (maxdist > -1)
781 PG_RETURN_BOOL(tolerance >= maxdist);
782
783 PG_RETURN_BOOL(LW_FALSE);
784}
785
790Datum LWGEOM_maxdistance2d_linestring(PG_FUNCTION_ARGS)
791{
792 double maxdist;
793 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
794 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
795 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
796 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
797 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
798
799 maxdist = lwgeom_maxdistance2d(lwgeom1, lwgeom2);
800
801 PG_FREE_IF_COPY(geom1, 0);
802 PG_FREE_IF_COPY(geom2, 1);
803
804 /*if called with empty geometries the ingoing mindistance is untouched, and makes us return NULL*/
805 if (maxdist > -1)
806 PG_RETURN_FLOAT8(maxdist);
807
808 PG_RETURN_NULL();
809}
810
816Datum LWGEOM_closestpoint3d(PG_FUNCTION_ARGS)
817{
818 GSERIALIZED *result;
819 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
820 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
821 LWGEOM *point;
822 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
823 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
824 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
825
826 point = lwgeom_closest_point_3d(lwgeom1, lwgeom2);
827 // point = lw_dist3d_distancepoint(lwgeom1, lwgeom2, lwgeom1->srid, DIST_MIN);
828
829 if (lwgeom_is_empty(point))
830 PG_RETURN_NULL();
831
832 result = geometry_serialize(point);
833
834 lwgeom_free(point);
835 lwgeom_free(lwgeom1);
836 lwgeom_free(lwgeom2);
837
838 PG_FREE_IF_COPY(geom1, 0);
839 PG_FREE_IF_COPY(geom2, 1);
840 PG_RETURN_POINTER(result);
841}
842
847Datum LWGEOM_shortestline3d(PG_FUNCTION_ARGS)
848{
849 GSERIALIZED *result;
850 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
851 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
852 LWGEOM *theline;
853 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
854 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
855 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
856
857 theline = lwgeom_closest_line_3d(lwgeom1, lwgeom2);
858 // theline = lw_dist3d_distanceline(lwgeom1, lwgeom2, lwgeom1->srid, DIST_MIN);
859
860 if (lwgeom_is_empty(theline))
861 PG_RETURN_NULL();
862
863 result = geometry_serialize(theline);
864
865 lwgeom_free(theline);
866 lwgeom_free(lwgeom1);
867 lwgeom_free(lwgeom2);
868
869 PG_FREE_IF_COPY(geom1, 0);
870 PG_FREE_IF_COPY(geom2, 1);
871 PG_RETURN_POINTER(result);
872}
873
878Datum LWGEOM_longestline3d(PG_FUNCTION_ARGS)
879{
880 GSERIALIZED *result;
881 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
882 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
883 LWGEOM *theline;
884 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
885 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
886 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
887
888 theline = lwgeom_furthest_line_3d(lwgeom1, lwgeom2);
889 // theline = lw_dist3d_distanceline(lwgeom1, lwgeom2, lwgeom1->srid, DIST_MAX);
890
891 if (lwgeom_is_empty(theline))
892 PG_RETURN_NULL();
893
894 result = geometry_serialize(theline);
895
896 lwgeom_free(theline);
897 lwgeom_free(lwgeom1);
898 lwgeom_free(lwgeom2);
899
900 PG_FREE_IF_COPY(geom1, 0);
901 PG_FREE_IF_COPY(geom2, 1);
902 PG_RETURN_POINTER(result);
903}
908Datum ST_3DDistance(PG_FUNCTION_ARGS)
909{
910 double mindist;
911 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
912 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
913 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
914 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
915 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
916
917 mindist = lwgeom_mindistance3d(lwgeom1, lwgeom2);
918
919 PG_FREE_IF_COPY(geom1, 0);
920 PG_FREE_IF_COPY(geom2, 1);
921
922 /*if called with empty geometries the ingoing mindistance is untouched, and makes us return NULL*/
923 if (mindist < FLT_MAX)
924 PG_RETURN_FLOAT8(mindist);
925
926 PG_RETURN_NULL();
927}
928
929/* intersects3d through dwithin */
931Datum ST_3DIntersects(PG_FUNCTION_ARGS)
932{
933 double mindist;
934 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
935 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
936 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
937 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
938 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
939
940 mindist = lwgeom_mindistance3d_tolerance(lwgeom1, lwgeom2, 0.0);
941
942 PG_FREE_IF_COPY(geom1, 0);
943 PG_FREE_IF_COPY(geom2, 1);
944 /*empty geometries cases should be right handled since return from underlying
945 functions should be FLT_MAX which causes false as answer*/
946 PG_RETURN_BOOL(0.0 == mindist);
947}
948
949
956Datum LWGEOM_dwithin3d(PG_FUNCTION_ARGS)
957{
958 double mindist;
959 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
960 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
961 double tolerance = PG_GETARG_FLOAT8(2);
962 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
963 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
964
965 if (tolerance < 0)
966 {
967 elog(ERROR, "Tolerance cannot be less than zero\n");
968 PG_RETURN_NULL();
969 }
970
971 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
972
973 mindist = lwgeom_mindistance3d_tolerance(lwgeom1, lwgeom2, tolerance);
974
975 PG_FREE_IF_COPY(geom1, 0);
976 PG_FREE_IF_COPY(geom2, 1);
977
978 /*empty geometries cases should be right handled since return from underlying
979 functions should be FLT_MAX which causes false as answer*/
980 PG_RETURN_BOOL(tolerance >= mindist);
981}
982
989Datum LWGEOM_dfullywithin3d(PG_FUNCTION_ARGS)
990{
991 double maxdist;
992 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
993 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
994 double tolerance = PG_GETARG_FLOAT8(2);
995 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
996 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
997
998 if (tolerance < 0)
999 {
1000 elog(ERROR, "Tolerance cannot be less than zero\n");
1001 PG_RETURN_NULL();
1002 }
1003
1004 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
1005 maxdist = lwgeom_maxdistance3d_tolerance(lwgeom1, lwgeom2, tolerance);
1006
1007 PG_FREE_IF_COPY(geom1, 0);
1008 PG_FREE_IF_COPY(geom2, 1);
1009
1010 /*If function is feed with empty geometries we should return false*/
1011 if (maxdist > -1)
1012 PG_RETURN_BOOL(tolerance >= maxdist);
1013
1014 PG_RETURN_BOOL(LW_FALSE);
1015}
1016
1021Datum LWGEOM_maxdistance3d(PG_FUNCTION_ARGS)
1022{
1023 double maxdist;
1024 GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
1025 GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
1026 LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
1027 LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
1028
1029 gserialized_error_if_srid_mismatch(geom1, geom2, __func__);
1030
1031 maxdist = lwgeom_maxdistance3d(lwgeom1, lwgeom2);
1032
1033 PG_FREE_IF_COPY(geom1, 0);
1034 PG_FREE_IF_COPY(geom2, 1);
1035
1036 /*if called with empty geometries the ingoing mindistance is untouched, and makes us return NULL*/
1037 if (maxdist > -1)
1038 PG_RETURN_FLOAT8(maxdist);
1039
1040 PG_RETURN_NULL();
1041}
1042
1044Datum LWGEOM_longitude_shift(PG_FUNCTION_ARGS)
1045{
1046 GSERIALIZED *geom;
1047 LWGEOM *lwgeom;
1048 GSERIALIZED *ret;
1049
1050 POSTGIS_DEBUG(2, "LWGEOM_longitude_shift called.");
1051
1052 geom = PG_GETARG_GSERIALIZED_P_COPY(0);
1053 lwgeom = lwgeom_from_gserialized(geom);
1054
1055 /* Drop bbox, will be recomputed */
1056 lwgeom_drop_bbox(lwgeom);
1057
1058 /* Modify geometry */
1059 lwgeom_longitude_shift(lwgeom);
1060
1061 /* Construct GSERIALIZED */
1062 ret = geometry_serialize(lwgeom);
1063
1064 /* Release deserialized geometry */
1065 lwgeom_free(lwgeom);
1066
1067 /* Release detoasted geometry */
1068 pfree(geom);
1069
1070 PG_RETURN_POINTER(ret);
1071}
1072
1074Datum ST_WrapX(PG_FUNCTION_ARGS)
1075{
1076 Datum gdatum;
1077 GSERIALIZED *geom_in;
1078 LWGEOM *lwgeom_in, *lwgeom_out;
1079 GSERIALIZED *geom_out;
1080 double cutx;
1081 double amount;
1082
1083 POSTGIS_DEBUG(2, "ST_WrapX called.");
1084
1085 gdatum = PG_GETARG_DATUM(0);
1086 cutx = PG_GETARG_FLOAT8(1);
1087 amount = PG_GETARG_FLOAT8(2);
1088
1089 // if ( ! amount ) PG_RETURN_DATUM(gdatum);
1090
1091 geom_in = ((GSERIALIZED *)PG_DETOAST_DATUM(gdatum));
1092 lwgeom_in = lwgeom_from_gserialized(geom_in);
1093
1094 lwgeom_out = lwgeom_wrapx(lwgeom_in, cutx, amount);
1095 geom_out = geometry_serialize(lwgeom_out);
1096
1097 lwgeom_free(lwgeom_in);
1098 lwgeom_free(lwgeom_out);
1099 PG_FREE_IF_COPY(geom_in, 0);
1100
1101 PG_RETURN_POINTER(geom_out);
1102}
1103
1105Datum LWGEOM_inside_circle_point(PG_FUNCTION_ARGS)
1106{
1107 GSERIALIZED *geom;
1108 double cx = PG_GETARG_FLOAT8(1);
1109 double cy = PG_GETARG_FLOAT8(2);
1110 double rr = PG_GETARG_FLOAT8(3);
1111 LWPOINT *lwpoint;
1112 LWGEOM *lwgeom;
1113 int inside;
1114
1115 geom = PG_GETARG_GSERIALIZED_P(0);
1116 lwgeom = lwgeom_from_gserialized(geom);
1117 lwpoint = lwgeom_as_lwpoint(lwgeom);
1118 if (lwpoint == NULL || lwgeom_is_empty(lwgeom))
1119 {
1120 PG_FREE_IF_COPY(geom, 0);
1121 PG_RETURN_NULL(); /* not a point */
1122 }
1123
1124 inside = lwpoint_inside_circle(lwpoint, cx, cy, rr);
1125 lwpoint_free(lwpoint);
1126
1127 PG_FREE_IF_COPY(geom, 0);
1128 PG_RETURN_BOOL(inside);
1129}
1130
1139Datum LWGEOM_collect(PG_FUNCTION_ARGS)
1140{
1141 GSERIALIZED *gser1, *gser2, *result;
1142 LWGEOM *lwgeoms[2], *outlwg;
1143 uint32 type1, type2;
1144 uint8_t outtype;
1145 int32_t srid;
1146
1147 POSTGIS_DEBUG(2, "LWGEOM_collect called.");
1148
1149 /* return null if both geoms are null */
1150 if (PG_ARGISNULL(0) && PG_ARGISNULL(1))
1151 PG_RETURN_NULL();
1152
1153 /* Return the second geom if the first geom is null */
1154 if (PG_ARGISNULL(0))
1155 PG_RETURN_DATUM(PG_GETARG_DATUM(1));
1156
1157 /* Return the first geom if the second geom is null */
1158 if (PG_ARGISNULL(1))
1159 PG_RETURN_DATUM(PG_GETARG_DATUM(0));
1160
1161 gser1 = PG_GETARG_GSERIALIZED_P(0);
1162 gser2 = PG_GETARG_GSERIALIZED_P(1);
1163 gserialized_error_if_srid_mismatch(gser1, gser2, __func__);
1164
1165 POSTGIS_DEBUGF(3,
1166 "LWGEOM_collect(%s, %s): call",
1169
1170 if ((gserialized_has_z(gser1) != gserialized_has_z(gser2)) ||
1171 (gserialized_has_m(gser1) != gserialized_has_m(gser2)))
1172 {
1173 elog(ERROR, "Cannot ST_Collect geometries with differing dimensionality.");
1174 PG_RETURN_NULL();
1175 }
1176
1177 srid = gserialized_get_srid(gser1);
1178
1179 lwgeoms[0] = lwgeom_from_gserialized(gser1);
1180 lwgeoms[1] = lwgeom_from_gserialized(gser2);
1181
1182 type1 = lwgeoms[0]->type;
1183 type2 = lwgeoms[1]->type;
1184
1185 if ((type1 == type2) && (!lwgeom_is_collection(lwgeoms[0])))
1186 outtype = lwtype_get_collectiontype(type1);
1187 else
1188 outtype = COLLECTIONTYPE;
1189
1190 POSTGIS_DEBUGF(3, " outtype = %d", outtype);
1191
1192 /* Drop input geometries bbox and SRID */
1193 lwgeom_drop_bbox(lwgeoms[0]);
1194 lwgeom_drop_srid(lwgeoms[0]);
1195 lwgeom_drop_bbox(lwgeoms[1]);
1196 lwgeom_drop_srid(lwgeoms[1]);
1197
1198 outlwg = (LWGEOM *)lwcollection_construct(outtype, srid, NULL, 2, lwgeoms);
1199 result = geometry_serialize(outlwg);
1200
1201 lwgeom_free(lwgeoms[0]);
1202 lwgeom_free(lwgeoms[1]);
1203
1204 PG_FREE_IF_COPY(gser1, 0);
1205 PG_FREE_IF_COPY(gser2, 1);
1206
1207 PG_RETURN_POINTER(result);
1208}
1209
1220Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS)
1221{
1222 ArrayType *array;
1223 int nelems;
1224 /*GSERIALIZED **geoms; */
1225 GSERIALIZED *result = NULL;
1226 LWGEOM **lwgeoms, *outlwg;
1227 uint32 outtype;
1228 int count;
1229 int32_t srid = SRID_UNKNOWN;
1230 GBOX *box = NULL;
1231
1232 ArrayIterator iterator;
1233 Datum value;
1234 bool isnull;
1235
1236 POSTGIS_DEBUG(2, "LWGEOM_collect_garray called.");
1237
1238 if (PG_ARGISNULL(0))
1239 PG_RETURN_NULL();
1240
1241 /* Get actual ArrayType */
1242 array = PG_GETARG_ARRAYTYPE_P(0);
1243 nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
1244
1245 POSTGIS_DEBUGF(3,
1246 " array is %d-bytes in size, %ld w/out header",
1247 ARR_SIZE(array),
1248 ARR_SIZE(array) - ARR_OVERHEAD_NONULLS(ARR_NDIM(array)));
1249
1250 POSTGIS_DEBUGF(3, "LWGEOM_collect_garray: array has %d elements", nelems);
1251
1252 /* Return null on 0-elements input array */
1253 if (nelems == 0)
1254 PG_RETURN_NULL();
1255
1256 /*
1257 * Deserialize all geometries in array into the lwgeoms pointers
1258 * array. Check input types to form output type.
1259 */
1260 lwgeoms = palloc(sizeof(LWGEOM *) * nelems);
1261 count = 0;
1262 outtype = 0;
1263
1264 iterator = array_create_iterator(array, 0, NULL);
1265
1266 while (array_iterate(iterator, &value, &isnull))
1267 {
1268 GSERIALIZED *geom;
1269 uint8_t intype;
1270
1271 /* Don't do anything for NULL values */
1272 if (isnull)
1273 continue;
1274
1275 geom = (GSERIALIZED *)DatumGetPointer(value);
1276 intype = gserialized_get_type(geom);
1277
1278 lwgeoms[count] = lwgeom_from_gserialized(geom);
1279
1280 POSTGIS_DEBUGF(3, "%s: geom %d deserialized", __func__, count);
1281
1282 if (!count)
1283 {
1284 /* Get first geometry SRID */
1285 srid = lwgeoms[count]->srid;
1286
1287 /* COMPUTE_BBOX WHEN_SIMPLE */
1288 if (lwgeoms[count]->bbox)
1289 box = gbox_copy(lwgeoms[count]->bbox);
1290 }
1291 else
1292 {
1293 /* Check SRID homogeneity */
1295
1296 /* COMPUTE_BBOX WHEN_SIMPLE */
1297 if (box)
1298 {
1299 if (lwgeoms[count]->bbox)
1300 gbox_merge(lwgeoms[count]->bbox, box);
1301 else
1302 {
1303 pfree(box);
1304 box = NULL;
1305 }
1306 }
1307 }
1308
1309 lwgeom_drop_srid(lwgeoms[count]);
1310 lwgeom_drop_bbox(lwgeoms[count]);
1311
1312 /* Output type not initialized */
1313 if (!outtype)
1314 {
1315 outtype = lwtype_get_collectiontype(intype);
1316 }
1317 /* Input type not compatible with output */
1318 /* make output type a collection */
1319 else if (outtype != COLLECTIONTYPE && lwtype_get_collectiontype(intype) != outtype)
1320 {
1321 outtype = COLLECTIONTYPE;
1322 }
1323
1324 count++;
1325 }
1326 array_free_iterator(iterator);
1327
1328 POSTGIS_DEBUGF(3, "LWGEOM_collect_garray: outtype = %d", outtype);
1329
1330 /* If we have been passed a complete set of NULLs then return NULL */
1331 if (!outtype)
1332 {
1333 PG_RETURN_NULL();
1334 }
1335 else
1336 {
1337 outlwg = (LWGEOM *)lwcollection_construct(outtype, srid, box, count, lwgeoms);
1338
1339 result = geometry_serialize(outlwg);
1340
1341 PG_RETURN_POINTER(result);
1342 }
1343}
1344
1350Datum LWGEOM_line_from_mpoint(PG_FUNCTION_ARGS)
1351{
1352 GSERIALIZED *ingeom, *result;
1353 LWLINE *lwline;
1354 LWMPOINT *mpoint;
1355
1356 POSTGIS_DEBUG(2, "LWGEOM_line_from_mpoint called");
1357
1358 /* Get input GSERIALIZED and deserialize it */
1359 ingeom = PG_GETARG_GSERIALIZED_P(0);
1360
1361 if (gserialized_get_type(ingeom) != MULTIPOINTTYPE)
1362 {
1363 elog(ERROR, "makeline: input must be a multipoint");
1364 PG_RETURN_NULL(); /* input is not a multipoint */
1365 }
1366
1368 lwline = lwline_from_lwmpoint(mpoint->srid, mpoint);
1369 if (!lwline)
1370 {
1371 PG_FREE_IF_COPY(ingeom, 0);
1372 elog(ERROR, "makeline: lwline_from_lwmpoint returned NULL");
1373 PG_RETURN_NULL();
1374 }
1375
1376 result = geometry_serialize(lwline_as_lwgeom(lwline));
1377
1378 PG_FREE_IF_COPY(ingeom, 0);
1379 lwline_free(lwline);
1380
1381 PG_RETURN_POINTER(result);
1382}
1383
1390Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS)
1391{
1392 ArrayType *array;
1393 int nelems;
1394 GSERIALIZED *result = NULL;
1395 LWGEOM **geoms;
1396 LWGEOM *outlwg;
1397 uint32 ngeoms;
1398 int32_t srid = SRID_UNKNOWN;
1399
1400 ArrayIterator iterator;
1401 Datum value;
1402 bool isnull;
1403
1404 POSTGIS_DEBUGF(2, "%s called", __func__);
1405
1406 /* Return null on null input */
1407 if (PG_ARGISNULL(0))
1408 PG_RETURN_NULL();
1409
1410 /* Get actual ArrayType */
1411 array = PG_GETARG_ARRAYTYPE_P(0);
1412
1413 /* Get number of geometries in array */
1414 nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
1415
1416 POSTGIS_DEBUGF(3, "%s: array has %d elements", __func__, nelems);
1417
1418 /* Return null on 0-elements input array */
1419 if (nelems == 0)
1420 PG_RETURN_NULL();
1421
1422 /*
1423 * Deserialize all point geometries in array into the
1424 * geoms pointers array.
1425 * Count actual number of points.
1426 */
1427
1428 /* possibly more then required */
1429 geoms = palloc(sizeof(LWGEOM *) * nelems);
1430 ngeoms = 0;
1431
1432 iterator = array_create_iterator(array, 0, NULL);
1433
1434 while (array_iterate(iterator, &value, &isnull))
1435 {
1436 GSERIALIZED *geom;
1437
1438 if (isnull)
1439 continue;
1440
1441 geom = (GSERIALIZED *)DatumGetPointer(value);
1442
1445 {
1446 continue;
1447 }
1448
1449 geoms[ngeoms++] = lwgeom_from_gserialized(geom);
1450
1451 /* Check SRID homogeneity */
1452 if (ngeoms == 1)
1453 {
1454 /* Get first geometry SRID */
1455 srid = geoms[ngeoms - 1]->srid;
1456 /* TODO: also get ZMflags */
1457 }
1458 else
1460
1461 POSTGIS_DEBUGF(3, "%s: element %d deserialized", __func__, ngeoms);
1462 }
1463 array_free_iterator(iterator);
1464
1465 /* Return null on 0-points input array */
1466 if (ngeoms == 0)
1467 {
1468 /* TODO: should we return LINESTRING EMPTY here ? */
1469 elog(NOTICE, "No points or linestrings in input array");
1470 PG_RETURN_NULL();
1471 }
1472
1473 POSTGIS_DEBUGF(3, "LWGEOM_makeline_garray: elements: %d", ngeoms);
1474
1475 outlwg = (LWGEOM *)lwline_from_lwgeom_array(srid, ngeoms, geoms);
1476
1477 result = geometry_serialize(outlwg);
1478
1479 PG_RETURN_POINTER(result);
1480}
1481
1487Datum LWGEOM_makeline(PG_FUNCTION_ARGS)
1488{
1489 GSERIALIZED *pglwg1, *pglwg2;
1490 GSERIALIZED *result = NULL;
1491 LWGEOM *lwgeoms[2];
1492 LWLINE *outline;
1493
1494 POSTGIS_DEBUG(2, "LWGEOM_makeline called.");
1495
1496 /* Get input datum */
1497 pglwg1 = PG_GETARG_GSERIALIZED_P(0);
1498 pglwg2 = PG_GETARG_GSERIALIZED_P(1);
1499
1500 if ((gserialized_get_type(pglwg1) != POINTTYPE && gserialized_get_type(pglwg1) != LINETYPE) ||
1502 {
1503 elog(ERROR, "Input geometries must be points or lines");
1504 PG_RETURN_NULL();
1505 }
1506
1507 gserialized_error_if_srid_mismatch(pglwg1, pglwg2, __func__);
1508
1509 lwgeoms[0] = lwgeom_from_gserialized(pglwg1);
1510 lwgeoms[1] = lwgeom_from_gserialized(pglwg2);
1511
1512 outline = lwline_from_lwgeom_array(lwgeoms[0]->srid, 2, lwgeoms);
1513
1514 result = geometry_serialize((LWGEOM *)outline);
1515
1516 PG_FREE_IF_COPY(pglwg1, 0);
1517 PG_FREE_IF_COPY(pglwg2, 1);
1518 lwgeom_free(lwgeoms[0]);
1519 lwgeom_free(lwgeoms[1]);
1520
1521 PG_RETURN_POINTER(result);
1522}
1523
1529Datum LWGEOM_makepoly(PG_FUNCTION_ARGS)
1530{
1531 GSERIALIZED *pglwg1;
1532 ArrayType *array = NULL;
1533 GSERIALIZED *result = NULL;
1534 const LWLINE *shell = NULL;
1535 const LWLINE **holes = NULL;
1536 LWPOLY *outpoly;
1537 uint32 nholes = 0;
1538 uint32 i;
1539 size_t offset = 0;
1540
1541 POSTGIS_DEBUG(2, "LWGEOM_makepoly called.");
1542
1543 /* Get input shell */
1544 pglwg1 = PG_GETARG_GSERIALIZED_P(0);
1545 if (gserialized_get_type(pglwg1) != LINETYPE)
1546 {
1547 lwpgerror("Shell is not a line");
1548 }
1550
1551 /* Get input holes if any */
1552 if (PG_NARGS() > 1)
1553 {
1554 array = PG_GETARG_ARRAYTYPE_P(1);
1555 nholes = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
1556 holes = lwalloc(sizeof(LWLINE *) * nholes);
1557 for (i = 0; i < nholes; i++)
1558 {
1559#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
1560#pragma GCC diagnostic push
1561#pragma GCC diagnostic ignored "-Wsign-compare"
1562#endif
1563 GSERIALIZED *g = (GSERIALIZED *)(ARR_DATA_PTR(array) + offset);
1564#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
1565#pragma GCC diagnostic pop
1566#endif
1567 LWLINE *hole;
1568 offset += INTALIGN(VARSIZE(g));
1570 {
1571 lwpgerror("Hole %d is not a line", i);
1572 }
1574 holes[i] = hole;
1575 }
1576 }
1577
1578 outpoly = lwpoly_from_lwlines(shell, nholes, holes);
1579 POSTGIS_DEBUGF(3, "%s", lwgeom_summary((LWGEOM *)outpoly, 0));
1580 result = geometry_serialize((LWGEOM *)outpoly);
1581
1582 lwline_free((LWLINE *)shell);
1583 PG_FREE_IF_COPY(pglwg1, 0);
1584
1585 for (i = 0; i < nholes; i++)
1586 {
1587 lwline_free((LWLINE *)holes[i]);
1588 }
1589
1590 PG_RETURN_POINTER(result);
1591}
1592
1599Datum LWGEOM_expand(PG_FUNCTION_ARGS)
1600{
1601 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
1602 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
1603 int32_t srid = lwgeom_get_srid(lwgeom);
1604 LWPOLY *poly;
1605 GSERIALIZED *result;
1606 GBOX gbox;
1607
1608 POSTGIS_DEBUG(2, "LWGEOM_expand called.");
1609
1610 /* Can't expand an empty */
1611 if (lwgeom_is_empty(lwgeom))
1612 {
1613 lwgeom_free(lwgeom);
1614 PG_RETURN_POINTER(geom);
1615 }
1616
1617 /* Can't expand something with no gbox! */
1618 if (LW_FAILURE == lwgeom_calculate_gbox(lwgeom, &gbox))
1619 {
1620 lwgeom_free(lwgeom);
1621 PG_RETURN_POINTER(geom);
1622 }
1623
1624 if (PG_NARGS() == 2)
1625 {
1626 /* Expand the box the same amount in all directions */
1627 double d = PG_GETARG_FLOAT8(1);
1628 gbox_expand(&gbox, d);
1629 }
1630 else
1631 {
1632 double dx = PG_GETARG_FLOAT8(1);
1633 double dy = PG_GETARG_FLOAT8(2);
1634 double dz = PG_GETARG_FLOAT8(3);
1635 double dm = PG_GETARG_FLOAT8(4);
1636
1637 gbox_expand_xyzm(&gbox, dx, dy, dz, dm);
1638 }
1639
1640 {
1641 POINT4D p1 = {gbox.xmin, gbox.ymin, gbox.zmin, gbox.mmin};
1642 POINT4D p2 = {gbox.xmin, gbox.ymax, gbox.zmin, gbox.mmin};
1643 POINT4D p3 = {gbox.xmax, gbox.ymax, gbox.zmax, gbox.mmax};
1644 POINT4D p4 = {gbox.xmax, gbox.ymin, gbox.zmax, gbox.mmax};
1645
1646 poly = lwpoly_construct_rectangle(lwgeom_has_z(lwgeom), lwgeom_has_m(lwgeom), &p1, &p2, &p3, &p4);
1647 }
1648
1650 lwgeom_set_srid(lwpoly_as_lwgeom(poly), srid);
1651
1652 /* Construct GSERIALIZED */
1653 result = geometry_serialize(lwpoly_as_lwgeom(poly));
1654
1656 lwgeom_free(lwgeom);
1657 PG_FREE_IF_COPY(geom, 0);
1658
1659 PG_RETURN_POINTER(result);
1660}
1661
1664Datum LWGEOM_to_BOX(PG_FUNCTION_ARGS)
1665{
1666 GSERIALIZED *pg_lwgeom = PG_GETARG_GSERIALIZED_P(0);
1667 LWGEOM *lwgeom = lwgeom_from_gserialized(pg_lwgeom);
1668 GBOX gbox;
1669 int result;
1670 BOX *out = NULL;
1671
1672 /* Zero out flags */
1673 gbox_init(&gbox);
1674
1675 /* Calculate the GBOX of the geometry */
1676 result = lwgeom_calculate_gbox(lwgeom, &gbox);
1677
1678 /* Clean up memory */
1679 lwfree(lwgeom);
1680 PG_FREE_IF_COPY(pg_lwgeom, 0);
1681
1682 /* Null on failure */
1683 if (!result)
1684 PG_RETURN_NULL();
1685
1686 out = lwalloc(sizeof(BOX));
1687 out->low.x = gbox.xmin;
1688 out->low.y = gbox.ymin;
1689 out->high.x = gbox.xmax;
1690 out->high.y = gbox.ymax;
1691 PG_RETURN_POINTER(out);
1692}
1693
1700Datum LWGEOM_envelope(PG_FUNCTION_ARGS)
1701{
1702 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
1703 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
1704 int32_t srid = lwgeom->srid;
1705 POINT4D pt;
1706 GBOX box;
1707 POINTARRAY *pa;
1708 GSERIALIZED *result;
1709
1710 if (lwgeom_is_empty(lwgeom))
1711 {
1712 /* must be the EMPTY geometry */
1713 PG_RETURN_POINTER(geom);
1714 }
1715
1716 if (lwgeom_calculate_gbox(lwgeom, &box) == LW_FAILURE)
1717 {
1718 /* must be the EMPTY geometry */
1719 PG_RETURN_POINTER(geom);
1720 }
1721
1722 /*
1723 * Alter envelope type so that a valid geometry is always
1724 * returned depending upon the size of the geometry. The
1725 * code makes the following assumptions:
1726 * - If the bounding box is a single point then return a
1727 * POINT geometry
1728 * - If the bounding box represents either a horizontal or
1729 * vertical line, return a LINESTRING geometry
1730 * - Otherwise return a POLYGON
1731 */
1732
1733 if ((box.xmin == box.xmax) && (box.ymin == box.ymax))
1734 {
1735 /* Construct and serialize point */
1736 LWPOINT *point = lwpoint_make2d(srid, box.xmin, box.ymin);
1737 result = geometry_serialize(lwpoint_as_lwgeom(point));
1738 lwpoint_free(point);
1739 }
1740 else if ((box.xmin == box.xmax) || (box.ymin == box.ymax))
1741 {
1742 LWLINE *line;
1743 /* Construct point array */
1744 pa = ptarray_construct_empty(0, 0, 2);
1745
1746 /* Assign coordinates to POINT2D array */
1747 pt.x = box.xmin;
1748 pt.y = box.ymin;
1749 ptarray_append_point(pa, &pt, LW_TRUE);
1750 pt.x = box.xmax;
1751 pt.y = box.ymax;
1752 ptarray_append_point(pa, &pt, LW_TRUE);
1753
1754 /* Construct and serialize linestring */
1755 line = lwline_construct(srid, NULL, pa);
1756 result = geometry_serialize(lwline_as_lwgeom(line));
1757 lwline_free(line);
1758 }
1759 else
1760 {
1761 LWPOLY *poly;
1762 POINTARRAY **ppa = lwalloc(sizeof(POINTARRAY *));
1763 pa = ptarray_construct_empty(0, 0, 5);
1764 ppa[0] = pa;
1765
1766 /* Assign coordinates to POINT2D array */
1767 pt.x = box.xmin;
1768 pt.y = box.ymin;
1769 ptarray_append_point(pa, &pt, LW_TRUE);
1770 pt.x = box.xmin;
1771 pt.y = box.ymax;
1772 ptarray_append_point(pa, &pt, LW_TRUE);
1773 pt.x = box.xmax;
1774 pt.y = box.ymax;
1775 ptarray_append_point(pa, &pt, LW_TRUE);
1776 pt.x = box.xmax;
1777 pt.y = box.ymin;
1778 ptarray_append_point(pa, &pt, LW_TRUE);
1779 pt.x = box.xmin;
1780 pt.y = box.ymin;
1781 ptarray_append_point(pa, &pt, LW_TRUE);
1782
1783 /* Construct polygon */
1784 poly = lwpoly_construct(srid, NULL, 1, ppa);
1785 result = geometry_serialize(lwpoly_as_lwgeom(poly));
1786 lwpoly_free(poly);
1787 }
1788
1789 PG_FREE_IF_COPY(geom, 0);
1790
1791 PG_RETURN_POINTER(result);
1792}
1793
1795Datum LWGEOM_isempty(PG_FUNCTION_ARGS)
1796{
1797 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
1798 PG_RETURN_BOOL(gserialized_is_empty(geom));
1799}
1800
1808Datum LWGEOM_segmentize2d(PG_FUNCTION_ARGS)
1809{
1810 GSERIALIZED *outgeom, *ingeom;
1811 double dist;
1812 LWGEOM *inlwgeom, *outlwgeom;
1813 int type;
1814
1815 POSTGIS_DEBUG(2, "LWGEOM_segmentize2d called");
1816
1817 ingeom = PG_GETARG_GSERIALIZED_P(0);
1818 dist = PG_GETARG_FLOAT8(1);
1819 type = gserialized_get_type(ingeom);
1820
1821 /* Avoid types we cannot segmentize. */
1822 if ((type == POINTTYPE) || (type == MULTIPOINTTYPE) || (type == TRIANGLETYPE) || (type == TINTYPE) ||
1823 (type == POLYHEDRALSURFACETYPE))
1824 {
1825 PG_RETURN_POINTER(ingeom);
1826 }
1827
1828 if (dist <= 0)
1829 {
1830 /* Protect from knowingly infinite loops, see #1799 */
1831 /* Note that we'll end out of memory anyway for other small distances */
1832 elog(ERROR, "ST_Segmentize: invalid max_distance %g (must be >= 0)", dist);
1833 PG_RETURN_NULL();
1834 }
1835
1836 LWGEOM_INIT();
1837
1838 inlwgeom = lwgeom_from_gserialized(ingeom);
1839 if (lwgeom_is_empty(inlwgeom))
1840 {
1841 /* Should only happen on interruption */
1842 lwgeom_free(inlwgeom);
1843 PG_RETURN_POINTER(ingeom);
1844 }
1845
1846 outlwgeom = lwgeom_segmentize2d(inlwgeom, dist);
1847 if (!outlwgeom)
1848 {
1849 /* Should only happen on interruption */
1850 PG_FREE_IF_COPY(ingeom, 0);
1851 PG_RETURN_NULL();
1852 }
1853
1854 /* Copy input bounding box if any */
1855 if (inlwgeom->bbox)
1856 outlwgeom->bbox = gbox_copy(inlwgeom->bbox);
1857
1858 outgeom = geometry_serialize(outlwgeom);
1859
1860 // lwgeom_free(outlwgeom); /* TODO fix lwgeom_clone / ptarray_clone_deep for consistent semantics */
1861 lwgeom_free(inlwgeom);
1862
1863 PG_FREE_IF_COPY(ingeom, 0);
1864
1865 PG_RETURN_POINTER(outgeom);
1866}
1867
1870Datum LWGEOM_reverse(PG_FUNCTION_ARGS)
1871{
1872 GSERIALIZED *geom;
1873 LWGEOM *lwgeom;
1874
1875 POSTGIS_DEBUG(2, "LWGEOM_reverse called");
1876
1877 geom = PG_GETARG_GSERIALIZED_P_COPY(0);
1878
1879 lwgeom = lwgeom_from_gserialized(geom);
1881
1882 geom = geometry_serialize(lwgeom);
1883
1884 PG_RETURN_POINTER(geom);
1885}
1886
1889Datum LWGEOM_force_clockwise_poly(PG_FUNCTION_ARGS)
1890{
1891 GSERIALIZED *ingeom, *outgeom;
1892 LWGEOM *lwgeom;
1893
1894 POSTGIS_DEBUG(2, "LWGEOM_force_clockwise_poly called");
1895
1896 ingeom = PG_GETARG_GSERIALIZED_P_COPY(0);
1897
1898 lwgeom = lwgeom_from_gserialized(ingeom);
1899 lwgeom_force_clockwise(lwgeom);
1900
1901 outgeom = geometry_serialize(lwgeom);
1902
1903 lwgeom_free(lwgeom);
1904 PG_FREE_IF_COPY(ingeom, 0);
1905 PG_RETURN_POINTER(outgeom);
1906}
1907
1910Datum LWGEOM_noop(PG_FUNCTION_ARGS)
1911{
1912 GSERIALIZED *in = PG_GETARG_GSERIALIZED_P(0);
1913 LWGEOM *lwgeom = lwgeom_from_gserialized(in);
1914 GSERIALIZED *out = geometry_serialize(lwgeom);
1915 lwgeom_free(lwgeom);
1916 PG_FREE_IF_COPY(in, 0);
1917 PG_RETURN_POINTER(out);
1918}
1919
1920Datum ST_Normalize(PG_FUNCTION_ARGS);
1922Datum ST_Normalize(PG_FUNCTION_ARGS)
1923{
1924 GSERIALIZED *in, *out;
1925 LWGEOM *lwgeom_in, *lwgeom_out;
1926
1927 POSTGIS_DEBUG(2, "ST_Normalize called");
1928
1929 in = PG_GETARG_GSERIALIZED_P_COPY(0);
1930
1931 lwgeom_in = lwgeom_from_gserialized(in);
1932 POSTGIS_DEBUGF(3, "Deserialized: %s", lwgeom_summary(lwgeom_in, 0));
1933
1934 lwgeom_out = lwgeom_normalize(lwgeom_in);
1935 POSTGIS_DEBUGF(3, "Normalized: %s", lwgeom_summary(lwgeom_out, 0));
1936
1937 out = geometry_serialize(lwgeom_out);
1938 lwgeom_free(lwgeom_in);
1939 lwgeom_free(lwgeom_out);
1940
1941 PG_FREE_IF_COPY(in, 0);
1942
1943 PG_RETURN_POINTER(out);
1944}
1945
1954Datum LWGEOM_zmflag(PG_FUNCTION_ARGS)
1955{
1956 GSERIALIZED *in = PG_GETARG_GSERIALIZED_P(0);
1957 int ret = 0;
1958
1959 if (gserialized_has_z(in))
1960 ret += 2;
1961 if (gserialized_has_m(in))
1962 ret += 1;
1963 PG_FREE_IF_COPY(in, 0);
1964 PG_RETURN_INT16(ret);
1965}
1966
1968Datum LWGEOM_hasz(PG_FUNCTION_ARGS)
1969{
1970 GSERIALIZED *in = PG_GETARG_GSERIALIZED_P(0);
1971 PG_RETURN_BOOL(gserialized_has_z(in));
1972}
1973
1975Datum LWGEOM_hasm(PG_FUNCTION_ARGS)
1976{
1977 GSERIALIZED *in = PG_GETARG_GSERIALIZED_P(0);
1978 PG_RETURN_BOOL(gserialized_has_m(in));
1979}
1980
1982Datum LWGEOM_hasBBOX(PG_FUNCTION_ARGS)
1983{
1984 GSERIALIZED *in = PG_GETARG_GSERIALIZED_P(0);
1985 char res = gserialized_has_bbox(in);
1986 PG_FREE_IF_COPY(in, 0);
1987 PG_RETURN_BOOL(res);
1988}
1989
1992Datum LWGEOM_ndims(PG_FUNCTION_ARGS)
1993{
1994 GSERIALIZED *in = PG_GETARG_GSERIALIZED_P(0);
1995 int ret = gserialized_ndims(in);
1996 PG_FREE_IF_COPY(in, 0);
1997 PG_RETURN_INT16(ret);
1998}
1999
2002Datum LWGEOM_same(PG_FUNCTION_ARGS)
2003{
2004 GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
2005 GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
2006
2007 PG_RETURN_BOOL(gserialized_cmp(g1, g2) == 0);
2008}
2009
2011Datum ST_MakeEnvelope(PG_FUNCTION_ARGS)
2012{
2013 LWPOLY *poly;
2014 GSERIALIZED *result;
2015 double x1, y1, x2, y2;
2016 int32_t srid = SRID_UNKNOWN;
2017
2018 POSTGIS_DEBUG(2, "ST_MakeEnvelope called");
2019
2020 x1 = PG_GETARG_FLOAT8(0);
2021 y1 = PG_GETARG_FLOAT8(1);
2022 x2 = PG_GETARG_FLOAT8(2);
2023 y2 = PG_GETARG_FLOAT8(3);
2024 if (PG_NARGS() > 4)
2025 {
2026 srid = PG_GETARG_INT32(4);
2027 }
2028
2029 poly = lwpoly_construct_envelope(srid, x1, y1, x2, y2);
2030
2031 result = geometry_serialize(lwpoly_as_lwgeom(poly));
2032 lwpoly_free(poly);
2033
2034 PG_RETURN_POINTER(result);
2035}
2036
2037
2039Datum ST_TileEnvelope(PG_FUNCTION_ARGS)
2040{
2041 GSERIALIZED *bounds;
2042 uint32_t zoomu;
2043 int32_t x, y, zoom;
2044 uint32_t worldTileSize;
2045 double tileGeoSizeX, tileGeoSizeY;
2046 double boundsWidth, boundsHeight;
2047 double x1, y1, x2, y2;
2048 /* This is broken, since 3857 doesn't mean "web mercator", it means
2049 the contents of the row in spatial_ref_sys with srid = 3857.
2050 For practical purposes this will work, but in good implementation
2051 we should de-reference in spatial ref sys to confirm that the
2052 srid of the object is EPSG:3857. */
2053 int32_t srid;
2054 GBOX bbox;
2055 LWGEOM *g = NULL;
2056
2057 POSTGIS_DEBUG(2, "ST_TileEnvelope called");
2058
2059 zoom = PG_GETARG_INT32(0);
2060 x = PG_GETARG_INT32(1);
2061 y = PG_GETARG_INT32(2);
2062
2063 bounds = PG_GETARG_GSERIALIZED_P(3);
2064 /*
2065 * We deserialize the geometry and recalculate the bounding box here to get
2066 * 64b floating point precision. The serialized bbox has 32b float is not
2067 * precise enough with big numbers such as the ones used in the default
2068 * parameters, e.g: -20037508.3427892 is transformed into -20037510
2069 */
2070 g = lwgeom_from_gserialized(bounds);
2071 if (lwgeom_calculate_gbox(g, &bbox) != LW_SUCCESS)
2072 elog(ERROR, "%s: Unable to compute bbox", __func__);
2073 srid = g->srid;
2074 lwgeom_free(g);
2075
2076 boundsWidth = bbox.xmax - bbox.xmin;
2077 boundsHeight = bbox.ymax - bbox.ymin;
2078 if (boundsWidth <= 0 || boundsHeight <= 0)
2079 elog(ERROR, "%s: Geometric bounds are too small", __func__);
2080
2081 if (zoom < 0 || zoom >= 32)
2082 elog(ERROR, "%s: Invalid tile zoom value, %d", __func__, zoom);
2083
2084 zoomu = (uint32_t)zoom;
2085 worldTileSize = 0x01u << (zoomu > 31 ? 31 : zoomu);
2086
2087 if (x < 0 || (uint32_t)x >= worldTileSize)
2088 elog(ERROR, "%s: Invalid tile x value, %d", __func__, x);
2089 if (y < 0 || (uint32_t)y >= worldTileSize)
2090 elog(ERROR, "%s: Invalid tile y value, %d", __func__, y);
2091
2092 tileGeoSizeX = boundsWidth / worldTileSize;
2093 tileGeoSizeY = boundsHeight / worldTileSize;
2094 x1 = bbox.xmin + tileGeoSizeX * (x);
2095 x2 = bbox.xmin + tileGeoSizeX * (x+1);
2096 y1 = bbox.ymax - tileGeoSizeY * (y+1);
2097 y2 = bbox.ymax - tileGeoSizeY * (y);
2098
2099 PG_RETURN_POINTER(
2103 srid, x1, y1, x2, y2))));
2104}
2105
2106
2108Datum ST_IsCollection(PG_FUNCTION_ARGS)
2109{
2110 GSERIALIZED *geom;
2111 int type;
2112 size_t size;
2113
2114 /* Pull only a small amount of the tuple, enough to get the type. */
2115 /* header + srid/flags + bbox? + type number */
2116 size = VARHDRSZ + 8 + 32 + 4;
2117
2118 geom = PG_GETARG_GSERIALIZED_P_SLICE(0, 0, size);
2119
2120 type = gserialized_get_type(geom);
2121 PG_RETURN_BOOL(lwtype_is_collection(type));
2122}
2123
2125Datum LWGEOM_makepoint(PG_FUNCTION_ARGS)
2126{
2127 double x, y, z, m;
2128 LWPOINT *point;
2129 GSERIALIZED *result;
2130
2131 POSTGIS_DEBUG(2, "LWGEOM_makepoint called");
2132
2133 x = PG_GETARG_FLOAT8(0);
2134 y = PG_GETARG_FLOAT8(1);
2135
2136 if (PG_NARGS() == 2)
2137 point = lwpoint_make2d(SRID_UNKNOWN, x, y);
2138 else if (PG_NARGS() == 3)
2139 {
2140 z = PG_GETARG_FLOAT8(2);
2141 point = lwpoint_make3dz(SRID_UNKNOWN, x, y, z);
2142 }
2143 else if (PG_NARGS() == 4)
2144 {
2145 z = PG_GETARG_FLOAT8(2);
2146 m = PG_GETARG_FLOAT8(3);
2147 point = lwpoint_make4d(SRID_UNKNOWN, x, y, z, m);
2148 }
2149 else
2150 {
2151 elog(ERROR, "LWGEOM_makepoint: unsupported number of args: %d", PG_NARGS());
2152 PG_RETURN_NULL();
2153 }
2154
2155 result = geometry_serialize((LWGEOM *)point);
2156
2157 PG_RETURN_POINTER(result);
2158}
2159
2161Datum LWGEOM_makepoint3dm(PG_FUNCTION_ARGS)
2162{
2163 double x, y, m;
2164 LWPOINT *point;
2165 GSERIALIZED *result;
2166
2167 POSTGIS_DEBUG(2, "LWGEOM_makepoint3dm called.");
2168
2169 x = PG_GETARG_FLOAT8(0);
2170 y = PG_GETARG_FLOAT8(1);
2171 m = PG_GETARG_FLOAT8(2);
2172
2173 point = lwpoint_make3dm(SRID_UNKNOWN, x, y, m);
2174 result = geometry_serialize((LWGEOM *)point);
2175
2176 PG_RETURN_POINTER(result);
2177}
2178
2180Datum LWGEOM_addpoint(PG_FUNCTION_ARGS)
2181{
2182 GSERIALIZED *pglwg1, *pglwg2, *result;
2183 LWPOINT *point;
2184 LWLINE *line, *linecopy;
2185 uint32_t uwhere = 0;
2186
2187 POSTGIS_DEBUGF(2, "%s called.", __func__);
2188
2189 pglwg1 = PG_GETARG_GSERIALIZED_P(0);
2190 pglwg2 = PG_GETARG_GSERIALIZED_P(1);
2191
2192 if (gserialized_get_type(pglwg1) != LINETYPE)
2193 {
2194 elog(ERROR, "First argument must be a LINESTRING");
2195 PG_RETURN_NULL();
2196 }
2197
2198 if (gserialized_get_type(pglwg2) != POINTTYPE)
2199 {
2200 elog(ERROR, "Second argument must be a POINT");
2201 PG_RETURN_NULL();
2202 }
2203
2205
2206 if (PG_NARGS() <= 2)
2207 {
2208 uwhere = line->points->npoints;
2209 }
2210 else
2211 {
2212 int32 where = PG_GETARG_INT32(2);
2213 if (where == -1)
2214 {
2215 uwhere = line->points->npoints;
2216 }
2217 else if (where < 0 || where > (int32)line->points->npoints)
2218 {
2219 elog(ERROR, "%s: Invalid offset", __func__);
2220 PG_RETURN_NULL();
2221 }
2222 else
2223 {
2224 uwhere = where;
2225 }
2226 }
2227
2230 lwline_free(line);
2231
2232 if (lwline_add_lwpoint(linecopy, point, uwhere) == LW_FAILURE)
2233 {
2234 elog(ERROR, "Point insert failed");
2235 PG_RETURN_NULL();
2236 }
2237
2238 result = geometry_serialize(lwline_as_lwgeom(linecopy));
2239
2240 /* Release memory */
2241 PG_FREE_IF_COPY(pglwg1, 0);
2242 PG_FREE_IF_COPY(pglwg2, 1);
2243 lwpoint_free(point);
2244
2245 PG_RETURN_POINTER(result);
2246}
2247
2249Datum LWGEOM_removepoint(PG_FUNCTION_ARGS)
2250{
2251 GSERIALIZED *pglwg1, *result;
2252 LWLINE *line, *outline;
2253 int32 which;
2254
2255 POSTGIS_DEBUG(2, "LWGEOM_removepoint called.");
2256
2257 pglwg1 = PG_GETARG_GSERIALIZED_P(0);
2258 which = PG_GETARG_INT32(1);
2259
2260 if (gserialized_get_type(pglwg1) != LINETYPE)
2261 {
2262 elog(ERROR, "First argument must be a LINESTRING");
2263 PG_RETURN_NULL();
2264 }
2265
2267
2268 if (which < 0 || (uint32_t)which > line->points->npoints - 1)
2269 {
2270 elog(ERROR, "Point index out of range (%u..%u)", 0, line->points->npoints - 1);
2271 PG_RETURN_NULL();
2272 }
2273
2274 if (line->points->npoints < 3)
2275 {
2276 elog(ERROR, "Can't remove points from a single segment line");
2277 PG_RETURN_NULL();
2278 }
2279
2280 outline = lwline_removepoint(line, (uint32_t)which);
2281 /* Release memory */
2282 lwline_free(line);
2283
2284 result = geometry_serialize((LWGEOM *)outline);
2285 lwline_free(outline);
2286
2287 PG_FREE_IF_COPY(pglwg1, 0);
2288 PG_RETURN_POINTER(result);
2289}
2290
2292Datum LWGEOM_setpoint_linestring(PG_FUNCTION_ARGS)
2293{
2294 GSERIALIZED *pglwg1, *pglwg2, *result;
2295 LWGEOM *lwg;
2296 LWLINE *line;
2297 LWPOINT *lwpoint;
2298 POINT4D newpoint;
2299 int64_t which;
2300
2301 POSTGIS_DEBUG(2, "LWGEOM_setpoint_linestring called.");
2302
2303 /* we copy input as we're going to modify it */
2304 pglwg1 = PG_GETARG_GSERIALIZED_P_COPY(0);
2305
2306 which = PG_GETARG_INT32(1);
2307 pglwg2 = PG_GETARG_GSERIALIZED_P(2);
2308
2309 /* Extract a POINT4D from the point */
2310 lwg = lwgeom_from_gserialized(pglwg2);
2311 lwpoint = lwgeom_as_lwpoint(lwg);
2312 if (!lwpoint)
2313 {
2314 elog(ERROR, "Third argument must be a POINT");
2315 PG_RETURN_NULL();
2316 }
2317 getPoint4d_p(lwpoint->point, 0, &newpoint);
2318 lwpoint_free(lwpoint);
2319 PG_FREE_IF_COPY(pglwg2, 2);
2320
2321 lwg = lwgeom_from_gserialized(pglwg1);
2322 line = lwgeom_as_lwline(lwg);
2323
2324 if (!line)
2325 {
2326 elog(ERROR, "First argument must be a LINESTRING");
2327 PG_RETURN_NULL();
2328 }
2329
2330 if ( line->points->npoints < 1 ) {
2331 elog(ERROR, "Line has no points");
2332 PG_RETURN_NULL();
2333 }
2334
2335 if (which < 0)
2336 {
2337 /* Use backward indexing for negative values */
2338 which += (int64_t)line->points->npoints;
2339 }
2340 if ((uint32_t)which > line->points->npoints - 1)
2341 {
2342 elog(ERROR, "abs(Point index) out of range (-)(%u..%u)", 0, line->points->npoints - 1);
2343 PG_RETURN_NULL();
2344 }
2345
2346 /*
2347 * This will change pointarray of the serialized pglwg1,
2348 */
2349 lwline_setPoint4d(line, (uint32_t)which, &newpoint);
2350 result = geometry_serialize((LWGEOM *)line);
2351
2352 /* Release memory */
2353 lwline_free(line);
2354 pfree(pglwg1); /* we forced copy, POINARRAY is released now */
2355
2356 PG_RETURN_POINTER(result);
2357}
2358
2359/* convert LWGEOM to ewkt (in TEXT format) */
2361Datum LWGEOM_asEWKT(PG_FUNCTION_ARGS)
2362{
2363 GSERIALIZED *geom;
2364 LWGEOM *lwgeom;
2365 char *wkt;
2366 size_t wkt_size;
2367 text *result;
2368
2369 POSTGIS_DEBUG(2, "LWGEOM_asEWKT called.");
2370
2371 geom = PG_GETARG_GSERIALIZED_P(0);
2372 lwgeom = lwgeom_from_gserialized(geom);
2373
2374 /* Write to WKT and free the geometry */
2375 wkt = lwgeom_to_wkt(lwgeom, WKT_EXTENDED, DBL_DIG, &wkt_size);
2376 lwgeom_free(lwgeom);
2377
2378 /* Write to text and free the WKT */
2379 result = cstring_to_text(wkt);
2380 lwfree(wkt);
2381
2382 /* Return the text */
2383 PG_FREE_IF_COPY(geom, 0);
2384 PG_RETURN_TEXT_P(result);
2385}
2386
2394Datum LWGEOM_azimuth(PG_FUNCTION_ARGS)
2395{
2396 GSERIALIZED *geom;
2397 LWPOINT *lwpoint;
2398 POINT2D p1, p2;
2399 double result;
2400 int32_t srid;
2401
2402 /* Extract first point */
2403 geom = PG_GETARG_GSERIALIZED_P(0);
2405 if (!lwpoint)
2406 {
2407 PG_FREE_IF_COPY(geom, 0);
2408 lwpgerror("Argument must be POINT geometries");
2409 PG_RETURN_NULL();
2410 }
2411 srid = lwpoint->srid;
2412 if (!getPoint2d_p(lwpoint->point, 0, &p1))
2413 {
2414 PG_FREE_IF_COPY(geom, 0);
2415 lwpgerror("Error extracting point");
2416 PG_RETURN_NULL();
2417 }
2418 lwpoint_free(lwpoint);
2419 PG_FREE_IF_COPY(geom, 0);
2420
2421 /* Extract second point */
2422 geom = PG_GETARG_GSERIALIZED_P(1);
2424 if (!lwpoint)
2425 {
2426 PG_FREE_IF_COPY(geom, 1);
2427 lwpgerror("Argument must be POINT geometries");
2428 PG_RETURN_NULL();
2429 }
2430 if (lwpoint->srid != srid)
2431 {
2432 PG_FREE_IF_COPY(geom, 1);
2433 lwpgerror("Operation on mixed SRID geometries");
2434 PG_RETURN_NULL();
2435 }
2436 if (!getPoint2d_p(lwpoint->point, 0, &p2))
2437 {
2438 PG_FREE_IF_COPY(geom, 1);
2439 lwpgerror("Error extracting point");
2440 PG_RETURN_NULL();
2441 }
2442 lwpoint_free(lwpoint);
2443 PG_FREE_IF_COPY(geom, 1);
2444
2445 /* Standard return value for equality case */
2446 if ((p1.x == p2.x) && (p1.y == p2.y))
2447 {
2448 PG_RETURN_NULL();
2449 }
2450
2451 /* Compute azimuth */
2452 if (!azimuth_pt_pt(&p1, &p2, &result))
2453 {
2454 PG_RETURN_NULL();
2455 }
2456
2457 PG_RETURN_FLOAT8(result);
2458}
2459
2468Datum LWGEOM_angle(PG_FUNCTION_ARGS)
2469{
2470 GSERIALIZED *seri_geoms[4];
2471 LWGEOM *geom_unser;
2472 LWPOINT *lwpoint;
2473 POINT2D points[4];
2474 double az1, az2;
2475 double result;
2476 int32_t srids[4];
2477 int i = 0;
2478 int j = 0;
2479 int err_code = 0;
2480 int n_args = PG_NARGS();
2481
2482 /* no deserialize, checking for common error first*/
2483 for (i = 0; i < n_args; i++)
2484 {
2485 seri_geoms[i] = PG_GETARG_GSERIALIZED_P(i);
2486 if (gserialized_is_empty(seri_geoms[i]))
2487 { /* empty geom */
2488 if (i == 3)
2489 {
2490 n_args = 3;
2491 }
2492 else
2493 {
2494 err_code = 1;
2495 break;
2496 }
2497 }
2498 else
2499 {
2500 if (gserialized_get_type(seri_geoms[i]) != POINTTYPE)
2501 { /* geom type */
2502 err_code = 2;
2503 break;
2504 }
2505 else
2506 {
2507 srids[i] = gserialized_get_srid(seri_geoms[i]);
2508 if (srids[0] != srids[i])
2509 { /* error on srid*/
2510 err_code = 3;
2511 break;
2512 }
2513 }
2514 }
2515 }
2516 if (err_code > 0)
2517 switch (err_code)
2518 {
2519 default: /*always executed*/
2520 for (j = 0; j <= i; j++)
2521 PG_FREE_IF_COPY(seri_geoms[j], j);
2522 /*FALLTHROUGH*/
2523 case 1:
2524 lwpgerror("Empty geometry");
2525 PG_RETURN_NULL();
2526 break;
2527
2528 case 2:
2529 lwpgerror("Argument must be POINT geometries");
2530 PG_RETURN_NULL();
2531 break;
2532
2533 case 3:
2534 lwpgerror("Operation on mixed SRID geometries");
2535 PG_RETURN_NULL();
2536 break;
2537 }
2538 /* extract points */
2539 for (i = 0; i < n_args; i++)
2540 {
2541 geom_unser = lwgeom_from_gserialized(seri_geoms[i]);
2542 lwpoint = lwgeom_as_lwpoint(geom_unser);
2543 if (!lwpoint)
2544 {
2545 for (j = 0; j < n_args; j++)
2546 PG_FREE_IF_COPY(seri_geoms[j], j);
2547 lwpgerror("Error unserializing geometry");
2548 PG_RETURN_NULL();
2549 }
2550
2551 if (!getPoint2d_p(lwpoint->point, 0, &points[i]))
2552 {
2553 /* // can't free serialized geom, it might be needed by lw
2554 for (j=0;j<n_args;j++)
2555 PG_FREE_IF_COPY(seri_geoms[j], j); */
2556 lwpgerror("Error extracting point");
2557 PG_RETURN_NULL();
2558 }
2559 /* lwfree(geom_unser);don't do, lw may rely on this memory
2560 lwpoint_free(lwpoint); dont do , this memory is needed ! */
2561 }
2562 /* // can't free serialized geom, it might be needed by lw
2563 for (j=0;j<n_args;j++)
2564 PG_FREE_IF_COPY(seri_geoms[j], j); */
2565
2566 /* compute azimuth for the 2 pairs of points
2567 * note that angle is not defined identically for 3 points or 4 points*/
2568 if (n_args == 3)
2569 { /* we rely on azimuth to complain if points are identical */
2570 if (!azimuth_pt_pt(&points[0], &points[1], &az1))
2571 PG_RETURN_NULL();
2572 if (!azimuth_pt_pt(&points[2], &points[1], &az2))
2573 PG_RETURN_NULL();
2574 }
2575 else
2576 {
2577 if (!azimuth_pt_pt(&points[0], &points[1], &az1))
2578 PG_RETURN_NULL();
2579 if (!azimuth_pt_pt(&points[2], &points[3], &az2))
2580 PG_RETURN_NULL();
2581 }
2582 result = az2 - az1;
2583 result += (result < 0) * 2 * M_PI; /* we dont want negative angle*/
2584 PG_RETURN_FLOAT8(result);
2585}
2586
2587/*
2588 * optimistic_overlap(Polygon P1, Multipolygon MP2, double dist)
2589 * returns true if P1 overlaps MP2
2590 * method: bbox check -
2591 * is separation < dist? no - return false (quick)
2592 * yes - return distance(P1,MP2) < dist
2593 */
2595Datum optimistic_overlap(PG_FUNCTION_ARGS)
2596{
2597 GSERIALIZED *pg_geom1 = PG_GETARG_GSERIALIZED_P(0);
2598 GSERIALIZED *pg_geom2 = PG_GETARG_GSERIALIZED_P(1);
2599 double dist = PG_GETARG_FLOAT8(2);
2600 GBOX g1_bvol;
2601 double calc_dist;
2602 LWGEOM *geom1 = lwgeom_from_gserialized(pg_geom1);
2603 LWGEOM *geom2 = lwgeom_from_gserialized(pg_geom2);
2604 gserialized_error_if_srid_mismatch(pg_geom1, pg_geom2, __func__);
2605
2606 if (geom1->type != POLYGONTYPE)
2607 {
2608 elog(ERROR, "optimistic_overlap: first arg isn't a polygon\n");
2609 PG_RETURN_NULL();
2610 }
2611
2612 if (geom2->type != POLYGONTYPE && geom2->type != MULTIPOLYGONTYPE)
2613 {
2614 elog(ERROR, "optimistic_overlap: 2nd arg isn't a [multi-]polygon\n");
2615 PG_RETURN_NULL();
2616 }
2617
2618 /*bbox check */
2619 gserialized_get_gbox_p(pg_geom1, &g1_bvol);
2620
2621 g1_bvol.xmin = g1_bvol.xmin - dist;
2622 g1_bvol.ymin = g1_bvol.ymin - dist;
2623 g1_bvol.xmax = g1_bvol.xmax + dist;
2624 g1_bvol.ymax = g1_bvol.ymax + dist;
2625
2626 if ((g1_bvol.xmin > geom2->bbox->xmax) || (g1_bvol.xmax < geom2->bbox->xmin) ||
2627 (g1_bvol.ymin > geom2->bbox->ymax) || (g1_bvol.ymax < geom2->bbox->ymin))
2628 {
2629 PG_RETURN_BOOL(false); /*bbox not overlap */
2630 }
2631
2632 /*
2633 * compute distances
2634 * should be a fast calc if they actually do intersect
2635 */
2636 calc_dist =
2637 DatumGetFloat8(DirectFunctionCall2(ST_Distance, PointerGetDatum(pg_geom1), PointerGetDatum(pg_geom2)));
2638
2639 PG_RETURN_BOOL(calc_dist < dist);
2640}
2641
2642/*affine transform geometry */
2644Datum LWGEOM_affine(PG_FUNCTION_ARGS)
2645{
2646 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P_COPY(0);
2647 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
2648 GSERIALIZED *ret;
2649 AFFINE affine;
2650
2651 affine.afac = PG_GETARG_FLOAT8(1);
2652 affine.bfac = PG_GETARG_FLOAT8(2);
2653 affine.cfac = PG_GETARG_FLOAT8(3);
2654 affine.dfac = PG_GETARG_FLOAT8(4);
2655 affine.efac = PG_GETARG_FLOAT8(5);
2656 affine.ffac = PG_GETARG_FLOAT8(6);
2657 affine.gfac = PG_GETARG_FLOAT8(7);
2658 affine.hfac = PG_GETARG_FLOAT8(8);
2659 affine.ifac = PG_GETARG_FLOAT8(9);
2660 affine.xoff = PG_GETARG_FLOAT8(10);
2661 affine.yoff = PG_GETARG_FLOAT8(11);
2662 affine.zoff = PG_GETARG_FLOAT8(12);
2663
2664 POSTGIS_DEBUG(2, "LWGEOM_affine called.");
2665
2666 lwgeom_affine(lwgeom, &affine);
2667
2668 /* COMPUTE_BBOX TAINTING */
2669 if (lwgeom->bbox)
2670 {
2671 lwgeom_refresh_bbox(lwgeom);
2672 }
2673 ret = geometry_serialize(lwgeom);
2674
2675 /* Release memory */
2676 lwgeom_free(lwgeom);
2677 PG_FREE_IF_COPY(geom, 0);
2678
2679 PG_RETURN_POINTER(ret);
2680}
2681
2683Datum ST_GeoHash(PG_FUNCTION_ARGS)
2684{
2685
2686 GSERIALIZED *geom = NULL;
2687 int precision = 0;
2688 char *geohash = NULL;
2689 text *result = NULL;
2690
2691 if (PG_ARGISNULL(0))
2692 {
2693 PG_RETURN_NULL();
2694 }
2695
2696 geom = PG_GETARG_GSERIALIZED_P(0);
2697
2698 if (!PG_ARGISNULL(1))
2699 {
2700 precision = PG_GETARG_INT32(1);
2701 }
2702
2704
2705 if (!geohash)
2706 PG_RETURN_NULL();
2707
2708 result = cstring_to_text(geohash);
2709 pfree(geohash);
2710
2711 PG_RETURN_TEXT_P(result);
2712}
2713
2715Datum ST_CollectionExtract(PG_FUNCTION_ARGS)
2716{
2717 GSERIALIZED *input = PG_GETARG_GSERIALIZED_P(0);
2718 GSERIALIZED *output;
2719 LWGEOM *lwgeom = lwgeom_from_gserialized(input);
2720 LWGEOM *lwcol = NULL;
2721 int type = PG_GETARG_INT32(1);
2722 int lwgeom_type = lwgeom->type;
2723
2724 /* Ensure the right type was input */
2725 if (!(type == POINTTYPE || type == LINETYPE || type == POLYGONTYPE))
2726 {
2727 lwgeom_free(lwgeom);
2728 elog(ERROR, "ST_CollectionExtract: only point, linestring and polygon may be extracted");
2729 PG_RETURN_NULL();
2730 }
2731
2732 /* Mirror non-collections right back */
2733 if (!lwgeom_is_collection(lwgeom))
2734 {
2735 /* Non-collections of the matching type go back */
2736 if (lwgeom_type == type)
2737 {
2738 lwgeom_free(lwgeom);
2739 PG_RETURN_POINTER(input);
2740 }
2741 /* Others go back as EMPTY */
2742 else
2743 {
2744 lwcol = lwgeom_construct_empty(
2745 type, lwgeom->srid, lwgeom_has_z(lwgeom), lwgeom_has_m(lwgeom));
2746 }
2747 }
2748 else
2749 {
2751 }
2752
2753 output = geometry_serialize((LWGEOM *)lwcol);
2754 lwgeom_free(lwgeom);
2755 lwgeom_free(lwcol);
2756
2757 PG_RETURN_POINTER(output);
2758}
2759
2761Datum ST_CollectionHomogenize(PG_FUNCTION_ARGS)
2762{
2763 GSERIALIZED *input = PG_GETARG_GSERIALIZED_P(0);
2764 GSERIALIZED *output;
2765 LWGEOM *lwgeom = lwgeom_from_gserialized(input);
2766 LWGEOM *lwoutput = NULL;
2767
2768 lwoutput = lwgeom_homogenize(lwgeom);
2769 lwgeom_free(lwgeom);
2770
2771 if (!lwoutput)
2772 {
2773 PG_FREE_IF_COPY(input, 0);
2774 PG_RETURN_NULL();
2775 }
2776
2777 output = geometry_serialize(lwoutput);
2778 lwgeom_free(lwoutput);
2779
2780 PG_FREE_IF_COPY(input, 0);
2781 PG_RETURN_POINTER(output);
2782}
2783
2784Datum ST_RemoveRepeatedPoints(PG_FUNCTION_ARGS);
2786Datum ST_RemoveRepeatedPoints(PG_FUNCTION_ARGS)
2787{
2788 GSERIALIZED *g_in = PG_GETARG_GSERIALIZED_P_COPY(0);
2789 uint32_t type = gserialized_get_type(g_in);
2790 GSERIALIZED *g_out;
2791 LWGEOM *lwgeom_in = NULL;
2792 double tolerance = 0.0;
2793 int modified = LW_FALSE;
2794
2795 /* Don't even start to think about points */
2796 if (type == POINTTYPE)
2797 PG_RETURN_POINTER(g_in);
2798
2799 if (PG_NARGS() > 1 && !PG_ARGISNULL(1))
2800 tolerance = PG_GETARG_FLOAT8(1);
2801
2802 lwgeom_in = lwgeom_from_gserialized(g_in);
2803 modified = lwgeom_remove_repeated_points_in_place(lwgeom_in, tolerance);
2804 if (!modified)
2805 {
2806 /* Since there were no changes, we can return the input to avoid the serialization */
2807 PG_RETURN_POINTER(g_in);
2808 }
2809
2810 g_out = geometry_serialize(lwgeom_in);
2811
2812 pfree(g_in);
2813 PG_RETURN_POINTER(g_out);
2814}
2815
2816Datum ST_FlipCoordinates(PG_FUNCTION_ARGS);
2818Datum ST_FlipCoordinates(PG_FUNCTION_ARGS)
2819{
2820 GSERIALIZED *in = PG_GETARG_GSERIALIZED_P_COPY(0);
2821 GSERIALIZED *out;
2822 LWGEOM *lwgeom = lwgeom_from_gserialized(in);
2823
2825 out = geometry_serialize(lwgeom);
2826
2827 lwgeom_free(lwgeom);
2828 PG_FREE_IF_COPY(in, 0);
2829
2830 PG_RETURN_POINTER(out);
2831}
2832
2833static LWORD
2835{
2836 if (n == 'x' || n == 'X')
2837 return LWORD_X;
2838 if (n == 'y' || n == 'Y')
2839 return LWORD_Y;
2840 if (n == 'z' || n == 'Z')
2841 return LWORD_Z;
2842 if (n == 'm' || n == 'M')
2843 return LWORD_M;
2844 lwpgerror("Invalid ordinate name '%c'. Expected x,y,z or m", n);
2845 return (LWORD)-1;
2846}
2847
2848Datum ST_SwapOrdinates(PG_FUNCTION_ARGS);
2850Datum ST_SwapOrdinates(PG_FUNCTION_ARGS)
2851{
2852 GSERIALIZED *in;
2853 GSERIALIZED *out;
2854 LWGEOM *lwgeom;
2855 const char *ospec;
2856 LWORD o1, o2;
2857
2858 ospec = PG_GETARG_CSTRING(1);
2859 if (strlen(ospec) != 2)
2860 {
2861 lwpgerror(
2862 "Invalid ordinate specification. "
2863 "Need two letters from the set (x,y,z,m). "
2864 "Got '%s'",
2865 ospec);
2866 PG_RETURN_NULL();
2867 }
2868 o1 = ordname2ordval(ospec[0]);
2869 o2 = ordname2ordval(ospec[1]);
2870
2871 in = PG_GETARG_GSERIALIZED_P_COPY(0);
2872
2873 /* Check presence of given ordinates */
2874 if ((o1 == LWORD_M || o2 == LWORD_M) && !gserialized_has_m(in))
2875 {
2876 lwpgerror("Geometry does not have an M ordinate");
2877 PG_RETURN_NULL();
2878 }
2879 if ((o1 == LWORD_Z || o2 == LWORD_Z) && !gserialized_has_z(in))
2880 {
2881 lwpgerror("Geometry does not have a Z ordinate");
2882 PG_RETURN_NULL();
2883 }
2884
2885 /* Nothing to do if swapping the same ordinate, pity for the copy... */
2886 if (o1 == o2)
2887 PG_RETURN_POINTER(in);
2888
2889 lwgeom = lwgeom_from_gserialized(in);
2890 lwgeom_swap_ordinates(lwgeom, o1, o2);
2891 out = geometry_serialize(lwgeom);
2892 lwgeom_free(lwgeom);
2893 PG_FREE_IF_COPY(in, 0);
2894 PG_RETURN_POINTER(out);
2895}
2896
2897/*
2898 * ST_BoundingDiagonal(inp geometry, fits boolean)
2899 */
2900Datum ST_BoundingDiagonal(PG_FUNCTION_ARGS);
2902Datum ST_BoundingDiagonal(PG_FUNCTION_ARGS)
2903{
2904 GSERIALIZED *geom_in = PG_GETARG_GSERIALIZED_P(0);
2905 GSERIALIZED *geom_out;
2906 bool fits = PG_GETARG_BOOL(1);
2907 LWGEOM *lwgeom_in = lwgeom_from_gserialized(geom_in);
2908 LWGEOM *lwgeom_out;
2909 const GBOX *gbox;
2910 int hasz = FLAGS_GET_Z(lwgeom_in->flags);
2911 int hasm = FLAGS_GET_M(lwgeom_in->flags);
2912 int32_t srid = lwgeom_in->srid;
2913 POINT4D pt;
2914 POINTARRAY *pa;
2915
2916 if (fits)
2917 {
2918 /* unregister any cached bbox to ensure it's recomputed */
2919 lwgeom_in->bbox = NULL;
2920 }
2921
2922 gbox = lwgeom_get_bbox(lwgeom_in);
2923
2924 if (!gbox)
2925 {
2926 lwgeom_out = lwgeom_construct_empty(LINETYPE, srid, hasz, hasm);
2927 }
2928 else
2929 {
2930 pa = ptarray_construct_empty(hasz, hasm, 2);
2931 pt.x = gbox->xmin;
2932 pt.y = gbox->ymin;
2933 pt.z = gbox->zmin;
2934 pt.m = gbox->mmin;
2935 ptarray_append_point(pa, &pt, LW_TRUE);
2936 pt.x = gbox->xmax;
2937 pt.y = gbox->ymax;
2938 pt.z = gbox->zmax;
2939 pt.m = gbox->mmax;
2940 ptarray_append_point(pa, &pt, LW_TRUE);
2941 lwgeom_out = lwline_as_lwgeom(lwline_construct(srid, NULL, pa));
2942 }
2943
2944 lwgeom_free(lwgeom_in);
2945 PG_FREE_IF_COPY(geom_in, 0);
2946
2947 geom_out = geometry_serialize(lwgeom_out);
2948 lwgeom_free(lwgeom_out);
2949
2950 PG_RETURN_POINTER(geom_out);
2951}
2952
2953Datum ST_Scale(PG_FUNCTION_ARGS);
2955Datum ST_Scale(PG_FUNCTION_ARGS)
2956{
2957 GSERIALIZED *geom;
2958 GSERIALIZED *geom_scale = PG_GETARG_GSERIALIZED_P(1);
2959 GSERIALIZED *geom_origin = NULL;
2960 LWGEOM *lwg, *lwg_scale, *lwg_origin;
2961 LWPOINT *lwpt_scale, *lwpt_origin;
2962 POINT4D origin;
2963 POINT4D factors;
2964 bool translate = false;
2965 GSERIALIZED *ret;
2966 AFFINE aff;
2967
2968 /* Make sure we have a valid scale input */
2969 lwg_scale = lwgeom_from_gserialized(geom_scale);
2970 lwpt_scale = lwgeom_as_lwpoint(lwg_scale);
2971 if (!lwpt_scale)
2972 {
2973 lwgeom_free(lwg_scale);
2974 PG_FREE_IF_COPY(geom_scale, 1);
2975 lwpgerror("Scale factor geometry parameter must be a point");
2976 PG_RETURN_NULL();
2977 }
2978
2979 /* Geom Will be modified in place, so take a copy */
2980 geom = PG_GETARG_GSERIALIZED_P_COPY(0);
2981 lwg = lwgeom_from_gserialized(geom);
2982
2983 /* Empty point, return input untouched */
2984 if (lwgeom_is_empty(lwg))
2985 {
2986 lwgeom_free(lwg_scale);
2987 lwgeom_free(lwg);
2988 PG_FREE_IF_COPY(geom_scale, 1);
2989 PG_RETURN_POINTER(geom);
2990 }
2991
2992 /* Once we read the scale data into local static point, we can */
2993 /* free the lwgeom */
2994 lwpoint_getPoint4d_p(lwpt_scale, &factors);
2995 if (!lwgeom_has_z(lwg_scale))
2996 factors.z = 1.0;
2997 if (!lwgeom_has_m(lwg_scale))
2998 factors.m = 1.0;
2999 lwgeom_free(lwg_scale);
3000
3001 /* Do we have the optional false origin? */
3002 if (PG_NARGS() > 2 && !PG_ARGISNULL(2))
3003 {
3004 geom_origin = PG_GETARG_GSERIALIZED_P(2);
3005 lwg_origin = lwgeom_from_gserialized(geom_origin);
3006 lwpt_origin = lwgeom_as_lwpoint(lwg_origin);
3007 if (lwpt_origin)
3008 {
3009 lwpoint_getPoint4d_p(lwpt_origin, &origin);
3010 translate = true;
3011 }
3012 /* Free the false origin inputs */
3013 lwgeom_free(lwg_origin);
3014 PG_FREE_IF_COPY(geom_origin, 2);
3015 }
3016
3017 /* If we have false origin, translate to it before scaling */
3018 if (translate)
3019 {
3020 /* Initialize affine */
3021 memset(&aff, 0, sizeof(AFFINE));
3022 /* Set rotation/scale/sheer matrix to no-op */
3023 aff.afac = aff.efac = aff.ifac = 1.0;
3024 /* Strip false origin from all coordinates */
3025 aff.xoff = -1 * origin.x;
3026 aff.yoff = -1 * origin.y;
3027 aff.zoff = -1 * origin.z;
3028 lwgeom_affine(lwg, &aff);
3029 }
3030
3031 lwgeom_scale(lwg, &factors);
3032
3033 /* Return to original origin after scaling */
3034 if (translate)
3035 {
3036 aff.xoff *= -1;
3037 aff.yoff *= -1;
3038 aff.zoff *= -1;
3039 lwgeom_affine(lwg, &aff);
3040 }
3041
3042 /* Cleanup and return */
3043 ret = geometry_serialize(lwg);
3044 lwgeom_free(lwg);
3045 PG_FREE_IF_COPY(geom, 0);
3046 PG_FREE_IF_COPY(geom_scale, 1);
3047 PG_RETURN_POINTER(ret);
3048}
3049
3050Datum ST_Points(PG_FUNCTION_ARGS);
3052Datum ST_Points(PG_FUNCTION_ARGS)
3053{
3054 if (PG_ARGISNULL(0))
3055 {
3056 PG_RETURN_NULL();
3057 }
3058 else
3059 {
3060 GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
3061 GSERIALIZED *ret;
3062 LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
3063 LWMPOINT *result = lwmpoint_from_lwgeom(lwgeom);
3064
3065 lwgeom_free(lwgeom);
3066
3068 lwmpoint_free(result);
3069 PG_RETURN_POINTER(ret);
3070 }
3071}
3072
3074Datum ST_QuantizeCoordinates(PG_FUNCTION_ARGS)
3075{
3076 GSERIALIZED *input;
3077 GSERIALIZED *result;
3078 LWGEOM *g;
3079 int32_t prec_x;
3080 int32_t prec_y;
3081 int32_t prec_z;
3082 int32_t prec_m;
3083
3084 if (PG_ARGISNULL(0))
3085 PG_RETURN_NULL();
3086 if (PG_ARGISNULL(1))
3087 {
3088 lwpgerror("Must specify precision");
3089 PG_RETURN_NULL();
3090 }
3091 else
3092 {
3093 prec_x = PG_GETARG_INT32(1);
3094 }
3095 prec_y = PG_ARGISNULL(2) ? prec_x : PG_GETARG_INT32(2);
3096 prec_z = PG_ARGISNULL(3) ? prec_x : PG_GETARG_INT32(3);
3097 prec_m = PG_ARGISNULL(4) ? prec_x : PG_GETARG_INT32(4);
3098
3099 input = PG_GETARG_GSERIALIZED_P_COPY(0);
3100
3101 g = lwgeom_from_gserialized(input);
3102
3103 lwgeom_trim_bits_in_place(g, prec_x, prec_y, prec_z, prec_m);
3104
3105 result = geometry_serialize(g);
3106 lwgeom_free(g);
3107 PG_FREE_IF_COPY(input, 0);
3108 PG_RETURN_POINTER(result);
3109}
3110
3111/*
3112 * ST_FilterByM(in geometry, val double precision)
3113 */
3115Datum LWGEOM_FilterByM(PG_FUNCTION_ARGS)
3116{
3117 GSERIALIZED *geom_in;
3118 GSERIALIZED *geom_out;
3119 LWGEOM *lwgeom_in;
3120 LWGEOM *lwgeom_out;
3121 double min, max;
3122 int returnm;
3123 int hasm;
3124
3125 if (PG_NARGS() > 0 && !PG_ARGISNULL(0))
3126 {
3127 geom_in = PG_GETARG_GSERIALIZED_P(0);
3128 }
3129 else
3130 {
3131 PG_RETURN_NULL();
3132 }
3133
3134 if (PG_NARGS() > 1 && !PG_ARGISNULL(1))
3135 min = PG_GETARG_FLOAT8(1);
3136 else
3137 {
3138 min = DBL_MIN;
3139 }
3140 if (PG_NARGS() > 2 && !PG_ARGISNULL(2))
3141 max = PG_GETARG_FLOAT8(2);
3142 else
3143 {
3144 max = DBL_MAX;
3145 }
3146 if (PG_NARGS() > 3 && !PG_ARGISNULL(3) && PG_GETARG_BOOL(3))
3147 returnm = 1;
3148 else
3149 {
3150 returnm = 0;
3151 }
3152
3153 if (min > max)
3154 {
3155 elog(ERROR, "Min-value cannot be larger than Max value\n");
3156 PG_RETURN_NULL();
3157 }
3158
3159 lwgeom_in = lwgeom_from_gserialized(geom_in);
3160
3161 hasm = lwgeom_has_m(lwgeom_in);
3162
3163 if (!hasm)
3164 {
3165 elog(NOTICE, "No M-value, No vertex removed\n");
3166 PG_RETURN_POINTER(geom_in);
3167 }
3168
3169 lwgeom_out = lwgeom_filter_m(lwgeom_in, min, max, returnm);
3170
3171 geom_out = geometry_serialize(lwgeom_out);
3172 lwgeom_free(lwgeom_out);
3173 PG_RETURN_POINTER(geom_out);
3174}
static uint8_t precision
Definition cu_in_twkb.c:25
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:426
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:42
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:65
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.
uint32_t gserialized_get_type(const GSERIALIZED *g)
Extract the geometry type from the serialized form (it hides in the anonymous data area,...
Definition gserialized.c:89
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".
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:286
void lwgeom_refresh_bbox(LWGEOM *lwgeom)
Drop current bbox and calculate a fresh one.
Definition lwgeom.c:689
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 * lwgeom_force_3dm(const LWGEOM *geom)
Definition lwgeom.c:787
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition lwgeom.c:326
#define LW_FALSE
Definition liblwgeom.h:108
uint32_t lwtype_get_collectiontype(uint8_t type)
Given an lwtype number, what homogeneous collection can hold it?
Definition lwgeom.c:1114
@ LWORD_Z
Definition liblwgeom.h:147
@ LWORD_M
Definition liblwgeom.h:148
@ LWORD_Y
Definition liblwgeom.h:146
@ LWORD_X
Definition liblwgeom.h:145
#define COLLECTIONTYPE
Definition liblwgeom.h:122
LWCOLLECTION * lwcollection_extract(LWCOLLECTION *col, int type)
Takes a potentially heterogeneous collection and returns a homogeneous collection consisting only of ...
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:909
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:165
LWGEOM * lwgeom_closest_point(const LWGEOM *lw1, const LWGEOM *lw2)
Definition measures.c:52
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:2461
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:1530
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:2508
void lwpoint_free(LWPOINT *pt)
Definition lwpoint.c:213
void lwgeom_longitude_shift(LWGEOM *lwgeom)
Definition lwgeom.c:990
#define LW_FAILURE
Definition liblwgeom.h:110
const char * lwgeom_version(void)
Return lwgeom version string (not to be freed)
Definition lwgeom_api.c:39
void lwgeom_free(LWGEOM *geom)
Definition lwgeom.c:1138
LWGEOM * lwgeom_closest_line(const LWGEOM *lw1, const LWGEOM *lw2)
Definition measures.c:40
LWGEOM * lwgeom_as_multi(const LWGEOM *lwgeom)
Create a new LWGEOM of the appropriate MULTI* type.
Definition lwgeom.c:362
double lwgeom_maxdistance3d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling 3d max distance calculations and dfullywithin calculations.
Definition measures3d.c:310
char * lwgeom_summary(const LWGEOM *lwgeom, int offset)
#define MULTILINETYPE
Definition liblwgeom.h:120
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:1908
int lwpoint_inside_circle(const LWPOINT *p, double cx, double cy, double rad)
Definition lwgeom.c:644
#define MULTISURFACETYPE
Definition liblwgeom.h:127
#define LINETYPE
Definition liblwgeom.h:117
#define WKT_EXTENDED
Definition liblwgeom.h:2132
#define LW_SUCCESS
Definition liblwgeom.h:111
char * lwgeom_to_wkt(const LWGEOM *geom, uint8_t variant, int precision, size_t *size_out)
WKT emitter function.
Definition lwout_wkt.c:676
LWGEOM * lwgeom_furthest_line_3d(LWGEOM *lw1, LWGEOM *lw2)
Definition measures3d.c:82
#define MULTIPOINTTYPE
Definition liblwgeom.h:119
LWGEOM * lwgeom_as_curve(const LWGEOM *lwgeom)
Create a new LWGEOM of the appropriate CURVE* type.
Definition lwgeom.c:402
int lwgeom_remove_repeated_points_in_place(LWGEOM *in, double tolerance)
Definition lwgeom.c:1554
LWGEOM * lwgeom_force_sfs(LWGEOM *geom, int version)
Definition lwgeom.c:831
int getPoint2d_p(const POINTARRAY *pa, uint32_t n, POINT2D *point)
Definition lwgeom_api.c:349
LWGEOM * lwgeom_closest_point_3d(const LWGEOM *lw1, const LWGEOM *lw2)
Definition measures3d.c:88
LWGEOM * lwgeom_force_2d(const LWGEOM *geom)
Strip out the Z/M components of an LWGEOM.
Definition lwgeom.c:775
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:1930
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:916
int lwtype_is_collection(uint8_t type)
Determine whether a type number is a collection or not.
Definition lwgeom.c:1087
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition liblwgeom.h:116
void lwgeom_drop_bbox(LWGEOM *lwgeom)
Call this function to drop BBOX and SRID from LWGEOM.
Definition lwgeom.c:664
#define FLAGS_GET_Z(flags)
Definition liblwgeom.h:179
void lwgeom_scale(LWGEOM *geom, const POINT4D *factors)
Definition lwgeom.c:2029
void * lwalloc(size_t size)
Definition lwutil.c:227
double lwgeom_area(const LWGEOM *geom)
Definition lwgeom.c:1863
#define TINTYPE
Definition liblwgeom.h:130
LWLINE * lwline_construct(int32_t srid, GBOX *bbox, POINTARRAY *points)
Definition lwline.c:42
#define MULTIPOLYGONTYPE
Definition liblwgeom.h:121
uint32_t lwgeom_count_vertices(const LWGEOM *geom)
Count the total number of vertices in any LWGEOM.
Definition lwgeom.c:1229
void lwfree(void *mem)
Definition lwutil.c:242
double lwgeom_mindistance2d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling min distance calculations and dwithin calculations.
Definition measures.c:207
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 can contain sub-geometries or not.
Definition lwgeom.c:1079
#define POLYGONTYPE
Definition liblwgeom.h:118
LWGEOM * lwgeom_force_3dz(const LWGEOM *geom)
Definition lwgeom.c:781
double lwgeom_mindistance3d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling 3d min distance calculations and dwithin calculations.
Definition measures3d.c:442
void lwgeom_swap_ordinates(LWGEOM *in, LWORD o1, LWORD o2)
Swap ordinate values in every vertex of the geometry.
Definition lwgeom.c:1461
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition lwgeom.c:321
void lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
Definition lwgeom.c:1975
#define POLYHEDRALSURFACETYPE
Definition liblwgeom.h:128
double lwgeom_length_2d(const LWGEOM *geom)
Definition lwgeom.c:1952
uint32_t lwgeom_count_rings(const LWGEOM *geom)
Count the total number of rings in any LWGEOM.
Definition lwgeom.c:1339
double lwgeom_mindistance2d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing min distance calculation.
Definition measures.c:197
#define FLAGS_GET_M(flags)
Definition liblwgeom.h:180
void lwgeom_force_clockwise(LWGEOM *lwgeom)
Force Right-hand-rule on LWGEOM polygons.
Definition lwgeom.c:37
char * lwgeom_geohash(const LWGEOM *lwgeom, int precision)
Calculate the GeoHash (http://geohash.org) string for a geometry.
int getPoint4d_p(const POINTARRAY *pa, uint32_t n, POINT4D *point)
Definition lwgeom_api.c:125
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:737
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition lwgeom.c:161
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:2083
#define MULTICURVETYPE
Definition liblwgeom.h:126
#define TRIANGLETYPE
Definition liblwgeom.h:129
LWMPOINT * lwgeom_as_lwmpoint(const LWGEOM *lwgeom)
Definition lwgeom.c:224
double lwgeom_maxdistance2d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling max distance calculations and dfullywithin calculations.
Definition measures.c:177
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:46
#define LW_TRUE
Return types for functions with status returns.
Definition liblwgeom.h:107
LWMPOINT * lwmpoint_from_lwgeom(const LWGEOM *g)
Definition lwmpoint.c:93
const GBOX * lwgeom_get_bbox(const LWGEOM *lwgeom)
Get a non-empty geometry bounding box, computing and caching it if not already there.
Definition lwgeom.c:725
double lwgeom_maxdistance3d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing 3d max distance calculation.
Definition measures3d.c:300
#define SRID_UNKNOWN
Unknown SRID value.
Definition liblwgeom.h:229
double lwgeom_perimeter(const LWGEOM *geom)
Definition lwgeom.c:1886
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition lwgeom.c:923
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition lwgeom.c:311
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition lwgeom.c:677
void lwline_free(LWLINE *line)
Definition lwline.c:67
LWGEOM * lwgeom_closest_line_3d(const LWGEOM *lw1, const LWGEOM *lw2)
Definition measures3d.c:76
LWGEOM * lwgeom_force_4d(const LWGEOM *geom)
Definition lwgeom.c:793
LWLINE * lwline_from_lwmpoint(int32_t srid, const LWMPOINT *mpoint)
Definition lwline.c:275
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition lwgeom.c:291
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:753
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:747
void lwgeom_reverse_in_place(LWGEOM *lwgeom)
Reverse vertex order of LWGEOM.
Definition lwgeom.c:102
double lwgeom_mindistance3d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing 3d min distance calculation.
Definition measures3d.c:335
LWGEOM * lwgeom_clone_deep(const LWGEOM *lwgeom)
Deep clone an LWGEOM, everything is copied.
Definition lwgeom.c:511
enum LWORD_T LWORD
Ordinate names.
This library is the generic geometry handling section of PostGIS.
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 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 LWGEOM_segmentize2d(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_dfullywithin(PG_FUNCTION_ARGS)
Datum LWGEOM_removepoint(PG_FUNCTION_ARGS)
Datum LWGEOM_noop(PG_FUNCTION_ARGS)
Datum postgis_scripts_released(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_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 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 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)
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:121
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:193
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)
unsigned int int32
Definition shpopen.c:273
#define POSTGIS_LIB_VERSION
Definition sqldefines.h:13
#define POSTGIS_LIBXML2_VERSION
Definition sqldefines.h:14
double gfac
Definition liblwgeom.h:318
double zoff
Definition liblwgeom.h:318
double bfac
Definition liblwgeom.h:318
double ifac
Definition liblwgeom.h:318
double xoff
Definition liblwgeom.h:318
double dfac
Definition liblwgeom.h:318
double afac
Definition liblwgeom.h:318
double ffac
Definition liblwgeom.h:318
double cfac
Definition liblwgeom.h:318
double hfac
Definition liblwgeom.h:318
double efac
Definition liblwgeom.h:318
double yoff
Definition liblwgeom.h:318
double ymax
Definition liblwgeom.h:343
double zmax
Definition liblwgeom.h:345
double xmax
Definition liblwgeom.h:341
double zmin
Definition liblwgeom.h:344
double mmax
Definition liblwgeom.h:347
double ymin
Definition liblwgeom.h:342
double xmin
Definition liblwgeom.h:340
double mmin
Definition liblwgeom.h:346
uint8_t type
Definition liblwgeom.h:448
GBOX * bbox
Definition liblwgeom.h:444
int32_t srid
Definition liblwgeom.h:446
lwflags_t flags
Definition liblwgeom.h:447
POINTARRAY * points
Definition liblwgeom.h:469
int32_t srid
Definition liblwgeom.h:520
POINTARRAY * point
Definition liblwgeom.h:457
int32_t srid
Definition liblwgeom.h:458
double y
Definition liblwgeom.h:376
double x
Definition liblwgeom.h:376
double m
Definition liblwgeom.h:400
double x
Definition liblwgeom.h:400
double z
Definition liblwgeom.h:400
double y
Definition liblwgeom.h:400
uint32_t npoints
Definition liblwgeom.h:413