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