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