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