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