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 &&
1472  gserialized_get_type(geom) != LINETYPE &&
1474  {
1475  continue;
1476  }
1477 
1478  geoms[ngeoms++] = lwgeom_from_gserialized(geom);
1479 
1480  /* Check SRID homogeneity */
1481  if (ngeoms == 1)
1482  {
1483  /* Get first geometry SRID */
1484  srid = geoms[ngeoms - 1]->srid;
1485  /* TODO: also get ZMflags */
1486  }
1487  else
1488  gserialized_error_if_srid_mismatch_reference(geom, srid, __func__);
1489 
1490  POSTGIS_DEBUGF(3, "%s: element %d deserialized", __func__, ngeoms);
1491  }
1492  array_free_iterator(iterator);
1493 
1494  /* Return null on 0-points input array */
1495  if (ngeoms == 0)
1496  {
1497  /* TODO: should we return LINESTRING EMPTY here ? */
1498  elog(NOTICE, "No points or linestrings in input array");
1499  PG_RETURN_NULL();
1500  }
1501 
1502  POSTGIS_DEBUGF(3, "LWGEOM_makeline_garray: elements: %d", ngeoms);
1503 
1504  outlwg = (LWGEOM *)lwline_from_lwgeom_array(srid, ngeoms, geoms);
1505 
1506  result = geometry_serialize(outlwg);
1507 
1508  PG_RETURN_POINTER(result);
1509 }
1510 
1516 Datum LWGEOM_makeline(PG_FUNCTION_ARGS)
1517 {
1518  GSERIALIZED *pglwg1, *pglwg2;
1519  GSERIALIZED *result = NULL;
1520  LWGEOM *lwgeoms[2];
1521  LWLINE *outline;
1522 
1523  POSTGIS_DEBUG(2, "LWGEOM_makeline called.");
1524 
1525  /* Get input datum */
1526  pglwg1 = PG_GETARG_GSERIALIZED_P(0);
1527  pglwg2 = PG_GETARG_GSERIALIZED_P(1);
1528 
1529  if ((gserialized_get_type(pglwg1) != POINTTYPE && gserialized_get_type(pglwg1) != LINETYPE) ||
1530  (gserialized_get_type(pglwg2) != POINTTYPE && gserialized_get_type(pglwg2) != LINETYPE))
1531  {
1532  elog(ERROR, "Input geometries must be points or lines");
1533  PG_RETURN_NULL();
1534  }
1535 
1536  gserialized_error_if_srid_mismatch(pglwg1, pglwg2, __func__);
1537 
1538  lwgeoms[0] = lwgeom_from_gserialized(pglwg1);
1539  lwgeoms[1] = lwgeom_from_gserialized(pglwg2);
1540 
1541  outline = lwline_from_lwgeom_array(lwgeoms[0]->srid, 2, lwgeoms);
1542 
1543  result = geometry_serialize((LWGEOM *)outline);
1544 
1545  PG_FREE_IF_COPY(pglwg1, 0);
1546  PG_FREE_IF_COPY(pglwg2, 1);
1547  lwgeom_free(lwgeoms[0]);
1548  lwgeom_free(lwgeoms[1]);
1549 
1550  PG_RETURN_POINTER(result);
1551 }
1552 
1558 Datum LWGEOM_makepoly(PG_FUNCTION_ARGS)
1559 {
1560  GSERIALIZED *pglwg1;
1561  ArrayType *array = NULL;
1562  GSERIALIZED *result = NULL;
1563  const LWLINE *shell = NULL;
1564  const LWLINE **holes = NULL;
1565  LWPOLY *outpoly;
1566  uint32 nholes = 0;
1567  uint32 i;
1568  size_t offset = 0;
1569 
1570  POSTGIS_DEBUG(2, "LWGEOM_makepoly called.");
1571 
1572  /* Get input shell */
1573  pglwg1 = PG_GETARG_GSERIALIZED_P(0);
1574  if (gserialized_get_type(pglwg1) != LINETYPE)
1575  {
1576  lwpgerror("Shell is not a line");
1577  }
1578  shell = lwgeom_as_lwline(lwgeom_from_gserialized(pglwg1));
1579 
1580  /* Get input holes if any */
1581  if (PG_NARGS() > 1)
1582  {
1583  array = PG_GETARG_ARRAYTYPE_P(1);
1584  nholes = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
1585  holes = lwalloc(sizeof(LWLINE *) * nholes);
1586  for (i = 0; i < nholes; i++)
1587  {
1588 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
1589 #pragma GCC diagnostic push
1590 #pragma GCC diagnostic ignored "-Wsign-compare"
1591 #endif
1592  GSERIALIZED *g = (GSERIALIZED *)(ARR_DATA_PTR(array) + offset);
1593 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
1594 #pragma GCC diagnostic pop
1595 #endif
1596  LWLINE *hole;
1597  offset += INTALIGN(VARSIZE(g));
1598  if (gserialized_get_type(g) != LINETYPE)
1599  {
1600  lwpgerror("Hole %d is not a line", i);
1601  }
1603  holes[i] = hole;
1604  }
1605  }
1606 
1607  outpoly = lwpoly_from_lwlines(shell, nholes, holes);
1608  POSTGIS_DEBUGF(3, "%s", lwgeom_summary((LWGEOM *)outpoly, 0));
1609  result = geometry_serialize((LWGEOM *)outpoly);
1610 
1611  lwline_free((LWLINE *)shell);
1612  PG_FREE_IF_COPY(pglwg1, 0);
1613 
1614  for (i = 0; i < nholes; i++)
1615  {
1616  lwline_free((LWLINE *)holes[i]);
1617  }
1618 
1619  PG_RETURN_POINTER(result);
1620 }
1621 
1628 Datum LWGEOM_expand(PG_FUNCTION_ARGS)
1629 {
1630  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
1631  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
1632  int32_t srid = lwgeom_get_srid(lwgeom);
1633  LWPOLY *poly;
1635  GBOX gbox;
1636 
1637  POSTGIS_DEBUG(2, "LWGEOM_expand called.");
1638 
1639  /* Can't expand an empty */
1640  if (lwgeom_is_empty(lwgeom))
1641  {
1642  lwgeom_free(lwgeom);
1643  PG_RETURN_POINTER(geom);
1644  }
1645 
1646  /* Can't expand something with no gbox! */
1647  if (LW_FAILURE == lwgeom_calculate_gbox(lwgeom, &gbox))
1648  {
1649  lwgeom_free(lwgeom);
1650  PG_RETURN_POINTER(geom);
1651  }
1652 
1653  if (PG_NARGS() == 2)
1654  {
1655  /* Expand the box the same amount in all directions */
1656  double d = PG_GETARG_FLOAT8(1);
1657  gbox_expand(&gbox, d);
1658  }
1659  else
1660  {
1661  double dx = PG_GETARG_FLOAT8(1);
1662  double dy = PG_GETARG_FLOAT8(2);
1663  double dz = PG_GETARG_FLOAT8(3);
1664  double dm = PG_GETARG_FLOAT8(4);
1665 
1666  gbox_expand_xyzm(&gbox, dx, dy, dz, dm);
1667  }
1668 
1669  {
1670  POINT4D p1 = {gbox.xmin, gbox.ymin, gbox.zmin, gbox.mmin};
1671  POINT4D p2 = {gbox.xmin, gbox.ymax, gbox.zmin, gbox.mmin};
1672  POINT4D p3 = {gbox.xmax, gbox.ymax, gbox.zmax, gbox.mmax};
1673  POINT4D p4 = {gbox.xmax, gbox.ymin, gbox.zmax, gbox.mmax};
1674 
1675  poly = lwpoly_construct_rectangle(lwgeom_has_z(lwgeom), lwgeom_has_m(lwgeom), &p1, &p2, &p3, &p4);
1676  }
1677 
1679  lwgeom_set_srid(lwpoly_as_lwgeom(poly), srid);
1680 
1681  /* Construct GSERIALIZED */
1682  result = geometry_serialize(lwpoly_as_lwgeom(poly));
1683 
1685  lwgeom_free(lwgeom);
1686  PG_FREE_IF_COPY(geom, 0);
1687 
1688  PG_RETURN_POINTER(result);
1689 }
1690 
1693 Datum LWGEOM_to_BOX(PG_FUNCTION_ARGS)
1694 {
1695  GSERIALIZED *pg_lwgeom = PG_GETARG_GSERIALIZED_P(0);
1696  LWGEOM *lwgeom = lwgeom_from_gserialized(pg_lwgeom);
1697  GBOX gbox;
1698  int result;
1699  BOX *out = NULL;
1700 
1701  /* Zero out flags */
1702  gbox_init(&gbox);
1703 
1704  /* Calculate the GBOX of the geometry */
1705  result = lwgeom_calculate_gbox(lwgeom, &gbox);
1706 
1707  /* Clean up memory */
1708  lwfree(lwgeom);
1709  PG_FREE_IF_COPY(pg_lwgeom, 0);
1710 
1711  /* Null on failure */
1712  if (!result)
1713  PG_RETURN_NULL();
1714 
1715  out = lwalloc(sizeof(BOX));
1716  out->low.x = gbox.xmin;
1717  out->low.y = gbox.ymin;
1718  out->high.x = gbox.xmax;
1719  out->high.y = gbox.ymax;
1720  PG_RETURN_POINTER(out);
1721 }
1722 
1729 Datum LWGEOM_envelope(PG_FUNCTION_ARGS)
1730 {
1731  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
1732  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
1733  int32_t srid = lwgeom->srid;
1734  POINT4D pt;
1735  GBOX box;
1736  POINTARRAY *pa;
1738 
1739  if (lwgeom_is_empty(lwgeom))
1740  {
1741  /* must be the EMPTY geometry */
1742  PG_RETURN_POINTER(geom);
1743  }
1744 
1745  if (lwgeom_calculate_gbox(lwgeom, &box) == LW_FAILURE)
1746  {
1747  /* must be the EMPTY geometry */
1748  PG_RETURN_POINTER(geom);
1749  }
1750 
1751  /*
1752  * Alter envelope type so that a valid geometry is always
1753  * returned depending upon the size of the geometry. The
1754  * code makes the following assumptions:
1755  * - If the bounding box is a single point then return a
1756  * POINT geometry
1757  * - If the bounding box represents either a horizontal or
1758  * vertical line, return a LINESTRING geometry
1759  * - Otherwise return a POLYGON
1760  */
1761 
1762  if ((box.xmin == box.xmax) && (box.ymin == box.ymax))
1763  {
1764  /* Construct and serialize point */
1765  LWPOINT *point = lwpoint_make2d(srid, box.xmin, box.ymin);
1766  result = geometry_serialize(lwpoint_as_lwgeom(point));
1767  lwpoint_free(point);
1768  }
1769  else if ((box.xmin == box.xmax) || (box.ymin == box.ymax))
1770  {
1771  LWLINE *line;
1772  /* Construct point array */
1773  pa = ptarray_construct_empty(0, 0, 2);
1774 
1775  /* Assign coordinates to POINT2D array */
1776  pt.x = box.xmin;
1777  pt.y = box.ymin;
1778  ptarray_append_point(pa, &pt, LW_TRUE);
1779  pt.x = box.xmax;
1780  pt.y = box.ymax;
1781  ptarray_append_point(pa, &pt, LW_TRUE);
1782 
1783  /* Construct and serialize linestring */
1784  line = lwline_construct(srid, NULL, pa);
1785  result = geometry_serialize(lwline_as_lwgeom(line));
1786  lwline_free(line);
1787  }
1788  else
1789  {
1790  LWPOLY *poly;
1791  POINTARRAY **ppa = lwalloc(sizeof(POINTARRAY *));
1792  pa = ptarray_construct_empty(0, 0, 5);
1793  ppa[0] = pa;
1794 
1795  /* Assign coordinates to POINT2D array */
1796  pt.x = box.xmin;
1797  pt.y = box.ymin;
1798  ptarray_append_point(pa, &pt, LW_TRUE);
1799  pt.x = box.xmin;
1800  pt.y = box.ymax;
1801  ptarray_append_point(pa, &pt, LW_TRUE);
1802  pt.x = box.xmax;
1803  pt.y = box.ymax;
1804  ptarray_append_point(pa, &pt, LW_TRUE);
1805  pt.x = box.xmax;
1806  pt.y = box.ymin;
1807  ptarray_append_point(pa, &pt, LW_TRUE);
1808  pt.x = box.xmin;
1809  pt.y = box.ymin;
1810  ptarray_append_point(pa, &pt, LW_TRUE);
1811 
1812  /* Construct polygon */
1813  poly = lwpoly_construct(srid, NULL, 1, ppa);
1814  result = geometry_serialize(lwpoly_as_lwgeom(poly));
1815  lwpoly_free(poly);
1816  }
1817 
1818  PG_FREE_IF_COPY(geom, 0);
1819 
1820  PG_RETURN_POINTER(result);
1821 }
1822 
1824 Datum LWGEOM_isempty(PG_FUNCTION_ARGS)
1825 {
1826  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
1827  PG_RETURN_BOOL(gserialized_is_empty(geom));
1828 }
1829 
1837 Datum LWGEOM_segmentize2d(PG_FUNCTION_ARGS)
1838 {
1839  GSERIALIZED *outgeom, *ingeom;
1840  double dist;
1841  LWGEOM *inlwgeom, *outlwgeom;
1842  int type;
1843 
1844  POSTGIS_DEBUG(2, "LWGEOM_segmentize2d called");
1845 
1846  ingeom = PG_GETARG_GSERIALIZED_P(0);
1847  dist = PG_GETARG_FLOAT8(1);
1848  type = gserialized_get_type(ingeom);
1849 
1850  /* Avoid types we cannot segmentize. */
1851  if ((type == POINTTYPE) || (type == MULTIPOINTTYPE) || (type == TRIANGLETYPE) || (type == TINTYPE) ||
1853  {
1854  PG_RETURN_POINTER(ingeom);
1855  }
1856 
1857  if (dist <= 0)
1858  {
1859  /* Protect from knowingly infinite loops, see #1799 */
1860  /* Note that we'll end out of memory anyway for other small distances */
1861  elog(ERROR, "ST_Segmentize: invalid max_distance %g (must be >= 0)", dist);
1862  PG_RETURN_NULL();
1863  }
1864 
1865  LWGEOM_INIT();
1866 
1867  inlwgeom = lwgeom_from_gserialized(ingeom);
1868  if (lwgeom_is_empty(inlwgeom))
1869  {
1870  /* Should only happen on interruption */
1871  lwgeom_free(inlwgeom);
1872  PG_RETURN_POINTER(ingeom);
1873  }
1874 
1875  outlwgeom = lwgeom_segmentize2d(inlwgeom, dist);
1876  if (!outlwgeom)
1877  {
1878  /* Should only happen on interruption */
1879  PG_FREE_IF_COPY(ingeom, 0);
1880  PG_RETURN_NULL();
1881  }
1882 
1883  /* Copy input bounding box if any */
1884  if (inlwgeom->bbox)
1885  outlwgeom->bbox = gbox_copy(inlwgeom->bbox);
1886 
1887  outgeom = geometry_serialize(outlwgeom);
1888 
1889  // lwgeom_free(outlwgeom); /* TODO fix lwgeom_clone / ptarray_clone_deep for consistent semantics */
1890  lwgeom_free(inlwgeom);
1891 
1892  PG_FREE_IF_COPY(ingeom, 0);
1893 
1894  PG_RETURN_POINTER(outgeom);
1895 }
1896 
1899 Datum LWGEOM_reverse(PG_FUNCTION_ARGS)
1900 {
1901  GSERIALIZED *geom;
1902  LWGEOM *lwgeom;
1903 
1904  POSTGIS_DEBUG(2, "LWGEOM_reverse called");
1905 
1906  geom = PG_GETARG_GSERIALIZED_P_COPY(0);
1907 
1908  lwgeom = lwgeom_from_gserialized(geom);
1909  lwgeom_reverse_in_place(lwgeom);
1910 
1911  geom = geometry_serialize(lwgeom);
1912 
1913  PG_RETURN_POINTER(geom);
1914 }
1915 
1918 Datum LWGEOM_force_clockwise_poly(PG_FUNCTION_ARGS)
1919 {
1920  GSERIALIZED *ingeom, *outgeom;
1921  LWGEOM *lwgeom;
1922 
1923  POSTGIS_DEBUG(2, "LWGEOM_force_clockwise_poly called");
1924 
1925  ingeom = PG_GETARG_GSERIALIZED_P_COPY(0);
1926 
1927  lwgeom = lwgeom_from_gserialized(ingeom);
1928  lwgeom_force_clockwise(lwgeom);
1929 
1930  outgeom = geometry_serialize(lwgeom);
1931 
1932  lwgeom_free(lwgeom);
1933  PG_FREE_IF_COPY(ingeom, 0);
1934  PG_RETURN_POINTER(outgeom);
1935 }
1936 
1937 
1943 Datum ST_ForcePolygonCCW(PG_FUNCTION_ARGS)
1944 {
1945  GSERIALIZED *ingeom, *outgeom;
1946  LWGEOM *lwgeom;
1947 
1948  POSTGIS_DEBUG(2, "ST_ForcePolygonCCW called");
1949 
1950  ingeom = PG_GETARG_GSERIALIZED_P_COPY(0);
1951 
1952  lwgeom = lwgeom_from_gserialized(ingeom);
1954 
1955  outgeom = geometry_serialize(lwgeom);
1956 
1957  lwgeom_free(lwgeom);
1958  PG_FREE_IF_COPY(ingeom, 0);
1959  PG_RETURN_POINTER(outgeom);
1960 }
1961 
1964 Datum LWGEOM_noop(PG_FUNCTION_ARGS)
1965 {
1966  GSERIALIZED *in = PG_GETARG_GSERIALIZED_P(0);
1967  LWGEOM *lwgeom = lwgeom_from_gserialized(in);
1968  GSERIALIZED *out = geometry_serialize(lwgeom);
1969  PG_RETURN_POINTER(out);
1970 }
1971 
1972 Datum ST_Normalize(PG_FUNCTION_ARGS);
1974 Datum ST_Normalize(PG_FUNCTION_ARGS)
1975 {
1976  GSERIALIZED *in, *out;
1977  LWGEOM *lwgeom_in, *lwgeom_out;
1978 
1979  POSTGIS_DEBUG(2, "ST_Normalize called");
1980 
1981  in = PG_GETARG_GSERIALIZED_P_COPY(0);
1982 
1983  lwgeom_in = lwgeom_from_gserialized(in);
1984  POSTGIS_DEBUGF(3, "Deserialized: %s", lwgeom_summary(lwgeom_in, 0));
1985 
1986  lwgeom_out = lwgeom_normalize(lwgeom_in);
1987  POSTGIS_DEBUGF(3, "Normalized: %s", lwgeom_summary(lwgeom_out, 0));
1988 
1989  out = geometry_serialize(lwgeom_out);
1990  lwgeom_free(lwgeom_in);
1991  lwgeom_free(lwgeom_out);
1992 
1993  PG_FREE_IF_COPY(in, 0);
1994 
1995  PG_RETURN_POINTER(out);
1996 }
1997 
2006 Datum LWGEOM_zmflag(PG_FUNCTION_ARGS)
2007 {
2008  GSERIALIZED *in = PG_GETARG_GSERIALIZED_HEADER(0);
2009  int ret = 0;
2010 
2011  if (gserialized_has_z(in))
2012  ret += 2;
2013  if (gserialized_has_m(in))
2014  ret += 1;
2015  PG_FREE_IF_COPY(in, 0);
2016  PG_RETURN_INT16(ret);
2017 }
2018 
2020 Datum LWGEOM_hasz(PG_FUNCTION_ARGS)
2021 {
2022  GSERIALIZED *in = PG_GETARG_GSERIALIZED_HEADER(0);
2023  PG_RETURN_BOOL(gserialized_has_z(in));
2024 }
2025 
2027 Datum LWGEOM_hasm(PG_FUNCTION_ARGS)
2028 {
2029  GSERIALIZED *in = PG_GETARG_GSERIALIZED_HEADER(0);
2030  PG_RETURN_BOOL(gserialized_has_m(in));
2031 }
2032 
2034 Datum LWGEOM_hasBBOX(PG_FUNCTION_ARGS)
2035 {
2036  GSERIALIZED *in = PG_GETARG_GSERIALIZED_HEADER(0);
2037  char res = gserialized_has_bbox(in);
2038  PG_FREE_IF_COPY(in, 0);
2039  PG_RETURN_BOOL(res);
2040 }
2041 
2044 Datum LWGEOM_ndims(PG_FUNCTION_ARGS)
2045 {
2046  GSERIALIZED *in = PG_GETARG_GSERIALIZED_HEADER(0);
2047  int ret = gserialized_ndims(in);
2048  PG_FREE_IF_COPY(in, 0);
2049  PG_RETURN_INT16(ret);
2050 }
2051 
2054 Datum LWGEOM_same(PG_FUNCTION_ARGS)
2055 {
2056  GSERIALIZED *g1 = PG_GETARG_GSERIALIZED_P(0);
2057  GSERIALIZED *g2 = PG_GETARG_GSERIALIZED_P(1);
2058 
2059  PG_RETURN_BOOL(gserialized_cmp(g1, g2) == 0);
2060 }
2061 
2063 Datum ST_MakeEnvelope(PG_FUNCTION_ARGS)
2064 {
2065  LWPOLY *poly;
2067  double x1, y1, x2, y2;
2068  int32_t srid = SRID_UNKNOWN;
2069 
2070  POSTGIS_DEBUG(2, "ST_MakeEnvelope called");
2071 
2072  x1 = PG_GETARG_FLOAT8(0);
2073  y1 = PG_GETARG_FLOAT8(1);
2074  x2 = PG_GETARG_FLOAT8(2);
2075  y2 = PG_GETARG_FLOAT8(3);
2076  if (PG_NARGS() > 4)
2077  {
2078  srid = PG_GETARG_INT32(4);
2079  }
2080 
2081  poly = lwpoly_construct_envelope(srid, x1, y1, x2, y2);
2082 
2083  result = geometry_serialize(lwpoly_as_lwgeom(poly));
2084  lwpoly_free(poly);
2085 
2086  PG_RETURN_POINTER(result);
2087 }
2088 
2089 
2091 Datum ST_TileEnvelope(PG_FUNCTION_ARGS)
2092 {
2093  GSERIALIZED *bounds;
2094  uint32_t zoomu;
2095  int32_t x, y, zoom;
2096  uint32_t worldTileSize;
2097  double tileGeoSizeX, tileGeoSizeY;
2098  double boundsWidth, boundsHeight;
2099  double x1, y1, x2, y2;
2100  double margin;
2101  /* This is broken, since 3857 doesn't mean "web mercator", it means
2102  the contents of the row in spatial_ref_sys with srid = 3857.
2103  For practical purposes this will work, but in good implementation
2104  we should de-reference in spatial ref sys to confirm that the
2105  srid of the object is EPSG:3857. */
2106  int32_t srid;
2107  GBOX bbox;
2108  LWGEOM *g = NULL;
2109 
2110  POSTGIS_DEBUG(2, "ST_TileEnvelope called");
2111 
2112  zoom = PG_GETARG_INT32(0);
2113  x = PG_GETARG_INT32(1);
2114  y = PG_GETARG_INT32(2);
2115 
2116  bounds = PG_GETARG_GSERIALIZED_P(3);
2117  /*
2118  * We deserialize the geometry and recalculate the bounding box here to get
2119  * 64b floating point precision. The serialized bbox has 32b float is not
2120  * precise enough with big numbers such as the ones used in the default
2121  * parameters, e.g: -20037508.3427892 is transformed into -20037510
2122  */
2123  g = lwgeom_from_gserialized(bounds);
2124  if (lwgeom_calculate_gbox(g, &bbox) != LW_SUCCESS)
2125  elog(ERROR, "%s: Unable to compute bbox", __func__);
2126  srid = g->srid;
2127  lwgeom_free(g);
2128 
2129  /* Avoid crashing with old signature (old sql code with 3 args, new C code with 4) */
2130  margin = PG_NARGS() < 4 ? 0 : PG_GETARG_FLOAT8(4);
2131  /* shrinking by more than 50% would eliminate the tile outright */
2132  if (margin < -0.5)
2133  elog(ERROR, "%s: Margin must not be less than -50%%, margin=%f", __func__, margin);
2134 
2135  boundsWidth = bbox.xmax - bbox.xmin;
2136  boundsHeight = bbox.ymax - bbox.ymin;
2137  if (boundsWidth <= 0 || boundsHeight <= 0)
2138  elog(ERROR, "%s: Geometric bounds are too small", __func__);
2139 
2140  if (zoom < 0 || zoom >= 32)
2141  elog(ERROR, "%s: Invalid tile zoom value, %d", __func__, zoom);
2142 
2143  zoomu = (uint32_t)zoom;
2144  worldTileSize = 0x01u << (zoomu > 31 ? 31 : zoomu);
2145 
2146  if (x < 0 || (uint32_t)x >= worldTileSize)
2147  elog(ERROR, "%s: Invalid tile x value, %d", __func__, x);
2148  if (y < 0 || (uint32_t)y >= worldTileSize)
2149  elog(ERROR, "%s: Invalid tile y value, %d", __func__, y);
2150 
2151  tileGeoSizeX = boundsWidth / worldTileSize;
2152  tileGeoSizeY = boundsHeight / worldTileSize;
2153 
2154  /*
2155  * 1 margin (100%) is the same as a single tile width
2156  * if the size of the tile with margins span more than the total number of tiles,
2157  * reset x1/x2 to the bounds
2158  */
2159  if ((1 + margin * 2) > worldTileSize)
2160  {
2161  x1 = bbox.xmin;
2162  x2 = bbox.xmax;
2163  }
2164  else
2165  {
2166  x1 = bbox.xmin + tileGeoSizeX * (x - margin);
2167  x2 = bbox.xmin + tileGeoSizeX * (x + 1 + margin);
2168  }
2169 
2170  y1 = bbox.ymax - tileGeoSizeY * (y + 1 + margin);
2171  y2 = bbox.ymax - tileGeoSizeY * (y - margin);
2172 
2173  /* Clip the final tile bounds to the bounds of the tile plane */
2174  if (y1 < bbox.ymin) y1 = bbox.ymin;
2175  if (y2 > bbox.ymax) y2 = bbox.ymax;
2176  if (x1 < bbox.xmin) x1 = bbox.xmin;
2177  if (x2 > bbox.xmax) x2 = bbox.xmax;
2178 
2179  PG_RETURN_POINTER(
2180  geometry_serialize(
2183  srid, x1, y1, x2, y2))));
2184 }
2185 
2186 
2188 Datum ST_IsCollection(PG_FUNCTION_ARGS)
2189 {
2190  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_HEADER(0);
2191  uint32_t lwtype = gserialized_get_type(geom);
2192  PG_RETURN_BOOL(!lwtype_is_unitary(lwtype));
2193 }
2194 
2196 Datum LWGEOM_makepoint(PG_FUNCTION_ARGS)
2197 {
2198  double x, y, z, m;
2199  LWPOINT *point;
2201 
2202  POSTGIS_DEBUG(2, "LWGEOM_makepoint called");
2203 
2204  x = PG_GETARG_FLOAT8(0);
2205  y = PG_GETARG_FLOAT8(1);
2206 
2207  if (PG_NARGS() == 2)
2208  point = lwpoint_make2d(SRID_UNKNOWN, x, y);
2209  else if (PG_NARGS() == 3)
2210  {
2211  z = PG_GETARG_FLOAT8(2);
2212  point = lwpoint_make3dz(SRID_UNKNOWN, x, y, z);
2213  }
2214  else if (PG_NARGS() == 4)
2215  {
2216  z = PG_GETARG_FLOAT8(2);
2217  m = PG_GETARG_FLOAT8(3);
2218  point = lwpoint_make4d(SRID_UNKNOWN, x, y, z, m);
2219  }
2220  else
2221  {
2222  elog(ERROR, "LWGEOM_makepoint: unsupported number of args: %d", PG_NARGS());
2223  PG_RETURN_NULL();
2224  }
2225 
2226  result = geometry_serialize((LWGEOM *)point);
2227 
2228  PG_RETURN_POINTER(result);
2229 }
2230 
2232 Datum ST_Point(PG_FUNCTION_ARGS)
2233 {
2234  double x = PG_GETARG_FLOAT8(0);
2235  double y = PG_GETARG_FLOAT8(1);
2236  int srid = PG_GETARG_INT32(2);
2237  LWPOINT *point = lwpoint_make2d(srid, x, y);
2238  GSERIALIZED *result = geometry_serialize((LWGEOM *)point);
2239  PG_RETURN_POINTER(result);
2240 }
2241 
2243 Datum ST_PointZ(PG_FUNCTION_ARGS)
2244 {
2245  double x = PG_GETARG_FLOAT8(0);
2246  double y = PG_GETARG_FLOAT8(1);
2247  double z = PG_GETARG_FLOAT8(2);
2248  int srid = PG_GETARG_INT32(3);
2249  LWPOINT *point = lwpoint_make3dz(srid, x, y, z);
2250  GSERIALIZED *result = geometry_serialize((LWGEOM *)point);
2251  PG_RETURN_POINTER(result);
2252 }
2253 
2255 Datum ST_PointM(PG_FUNCTION_ARGS)
2256 {
2257  double x = PG_GETARG_FLOAT8(0);
2258  double y = PG_GETARG_FLOAT8(1);
2259  double m = PG_GETARG_FLOAT8(2);
2260  int srid = PG_GETARG_INT32(3);
2261  LWPOINT *point = lwpoint_make3dm(srid, x, y, m);
2262  GSERIALIZED *result = geometry_serialize((LWGEOM *)point);
2263  PG_RETURN_POINTER(result);
2264 }
2265 
2267 Datum ST_PointZM(PG_FUNCTION_ARGS)
2268 {
2269  double x = PG_GETARG_FLOAT8(0);
2270  double y = PG_GETARG_FLOAT8(1);
2271  double z = PG_GETARG_FLOAT8(2);
2272  double m = PG_GETARG_FLOAT8(3);
2273  int srid = PG_GETARG_INT32(4);
2274  LWPOINT *point = lwpoint_make4d(srid, x, y, z, m);
2275  GSERIALIZED *result = geometry_serialize((LWGEOM *)point);
2276  PG_RETURN_POINTER(result);
2277 }
2278 
2279 
2281 Datum LWGEOM_makepoint3dm(PG_FUNCTION_ARGS)
2282 {
2283  double x, y, m;
2284  LWPOINT *point;
2286 
2287  POSTGIS_DEBUG(2, "LWGEOM_makepoint3dm called.");
2288 
2289  x = PG_GETARG_FLOAT8(0);
2290  y = PG_GETARG_FLOAT8(1);
2291  m = PG_GETARG_FLOAT8(2);
2292 
2293  point = lwpoint_make3dm(SRID_UNKNOWN, x, y, m);
2294  result = geometry_serialize((LWGEOM *)point);
2295 
2296  PG_RETURN_POINTER(result);
2297 }
2298 
2300 Datum LWGEOM_addpoint(PG_FUNCTION_ARGS)
2301 {
2302  GSERIALIZED *pglwg1, *pglwg2, *result;
2303  LWPOINT *point;
2304  LWLINE *line, *linecopy;
2305  uint32_t uwhere = 0;
2306 
2307  POSTGIS_DEBUGF(2, "%s called.", __func__);
2308 
2309  pglwg1 = PG_GETARG_GSERIALIZED_P(0);
2310  pglwg2 = PG_GETARG_GSERIALIZED_P(1);
2311 
2312  if (gserialized_get_type(pglwg1) != LINETYPE)
2313  {
2314  elog(ERROR, "First argument must be a LINESTRING");
2315  PG_RETURN_NULL();
2316  }
2317 
2318  if (gserialized_get_type(pglwg2) != POINTTYPE)
2319  {
2320  elog(ERROR, "Second argument must be a POINT");
2321  PG_RETURN_NULL();
2322  }
2323 
2324  if (gserialized_is_empty(pglwg2))
2325  {
2326  PG_RETURN_POINTER(pglwg1);
2327  }
2328 
2329  line = lwgeom_as_lwline(lwgeom_from_gserialized(pglwg1));
2330 
2331  if (PG_NARGS() <= 2)
2332  {
2333  uwhere = line->points->npoints;
2334  }
2335  else
2336  {
2337  int32 where = PG_GETARG_INT32(2);
2338  if (where == -1)
2339  {
2340  uwhere = line->points->npoints;
2341  }
2342  else if (where < 0 || where > (int32)line->points->npoints)
2343  {
2344  elog(ERROR, "%s: Invalid offset", __func__);
2345  PG_RETURN_NULL();
2346  }
2347  else
2348  {
2349  uwhere = where;
2350  }
2351  }
2352 
2353  point = lwgeom_as_lwpoint(lwgeom_from_gserialized(pglwg2));
2355  lwline_free(line);
2356 
2357  if (lwline_add_lwpoint(linecopy, point, uwhere) == LW_FAILURE)
2358  {
2359  elog(ERROR, "Point insert failed");
2360  PG_RETURN_NULL();
2361  }
2362 
2363  result = geometry_serialize(lwline_as_lwgeom(linecopy));
2364 
2365  /* Release memory */
2366  PG_FREE_IF_COPY(pglwg1, 0);
2367  PG_FREE_IF_COPY(pglwg2, 1);
2368  lwpoint_free(point);
2369 
2370  PG_RETURN_POINTER(result);
2371 }
2372 
2374 Datum LWGEOM_removepoint(PG_FUNCTION_ARGS)
2375 {
2376  GSERIALIZED *pglwg1, *result;
2377  LWLINE *line, *outline;
2378  int32 which;
2379 
2380  POSTGIS_DEBUG(2, "LWGEOM_removepoint called.");
2381 
2382  pglwg1 = PG_GETARG_GSERIALIZED_P(0);
2383  which = PG_GETARG_INT32(1);
2384 
2385  if (gserialized_get_type(pglwg1) != LINETYPE)
2386  {
2387  elog(ERROR, "First argument must be a LINESTRING");
2388  PG_RETURN_NULL();
2389  }
2390 
2391  line = lwgeom_as_lwline(lwgeom_from_gserialized(pglwg1));
2392 
2393  if (which < 0 || (uint32_t)which > line->points->npoints - 1)
2394  {
2395  elog(ERROR, "Point index out of range (%u..%u)", 0, line->points->npoints - 1);
2396  PG_RETURN_NULL();
2397  }
2398 
2399  if (line->points->npoints < 3)
2400  {
2401  elog(ERROR, "Can't remove points from a single segment line");
2402  PG_RETURN_NULL();
2403  }
2404 
2405  outline = lwline_removepoint(line, (uint32_t)which);
2406  /* Release memory */
2407  lwline_free(line);
2408 
2409  result = geometry_serialize((LWGEOM *)outline);
2411 
2412  PG_FREE_IF_COPY(pglwg1, 0);
2413  PG_RETURN_POINTER(result);
2414 }
2415 
2417 Datum LWGEOM_setpoint_linestring(PG_FUNCTION_ARGS)
2418 {
2419  GSERIALIZED *pglwg1, *pglwg2, *result;
2420  LWGEOM *lwg;
2421  LWLINE *line;
2422  LWPOINT *lwpoint;
2423  POINT4D newpoint;
2424  int64_t which;
2425 
2426  POSTGIS_DEBUG(2, "LWGEOM_setpoint_linestring called.");
2427 
2428  /* we copy input as we're going to modify it */
2429  pglwg1 = PG_GETARG_GSERIALIZED_P_COPY(0);
2430 
2431  which = PG_GETARG_INT32(1);
2432  pglwg2 = PG_GETARG_GSERIALIZED_P(2);
2433 
2434  /* Extract a POINT4D from the point */
2435  lwg = lwgeom_from_gserialized(pglwg2);
2436  lwpoint = lwgeom_as_lwpoint(lwg);
2437  if (!lwpoint)
2438  {
2439  elog(ERROR, "Third argument must be a POINT");
2440  PG_RETURN_NULL();
2441  }
2442  getPoint4d_p(lwpoint->point, 0, &newpoint);
2443  lwpoint_free(lwpoint);
2444  PG_FREE_IF_COPY(pglwg2, 2);
2445 
2446  lwg = lwgeom_from_gserialized(pglwg1);
2447  line = lwgeom_as_lwline(lwg);
2448 
2449  if (!line)
2450  {
2451  elog(ERROR, "First argument must be a LINESTRING");
2452  PG_RETURN_NULL();
2453  }
2454 
2455  if ( line->points->npoints < 1 ) {
2456  elog(ERROR, "Line has no points");
2457  PG_RETURN_NULL();
2458  }
2459 
2460  if (which < 0)
2461  {
2462  /* Use backward indexing for negative values */
2463  which += (int64_t)line->points->npoints;
2464  }
2465  if ((uint32_t)which > line->points->npoints - 1)
2466  {
2467  elog(ERROR, "abs(Point index) out of range (-)(%u..%u)", 0, line->points->npoints - 1);
2468  PG_RETURN_NULL();
2469  }
2470 
2471  /*
2472  * This will change pointarray of the serialized pglwg1,
2473  */
2474  lwline_setPoint4d(line, (uint32_t)which, &newpoint);
2475  result = geometry_serialize((LWGEOM *)line);
2476 
2477  /* Release memory */
2478  lwline_free(line);
2479  pfree(pglwg1); /* we forced copy, POINARRAY is released now */
2480 
2481  PG_RETURN_POINTER(result);
2482 }
2483 
2484 /* convert LWGEOM to ewkt (in TEXT format) */
2486 Datum LWGEOM_asEWKT(PG_FUNCTION_ARGS)
2487 {
2488  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
2489  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
2490 
2492  if (PG_NARGS() > 1)
2493  precision = PG_GETARG_INT32(1);
2494 
2495  PG_RETURN_TEXT_P(lwgeom_to_wkt_varlena(lwgeom, WKT_EXTENDED, precision));
2496 }
2497 
2505 Datum LWGEOM_azimuth(PG_FUNCTION_ARGS)
2506 {
2507  GSERIALIZED *geom;
2508  LWPOINT *lwpoint;
2509  POINT2D p1, p2;
2510  double result;
2511  int32_t srid;
2512 
2513  /* Extract first point */
2514  geom = PG_GETARG_GSERIALIZED_P(0);
2515  lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom));
2516  if (!lwpoint)
2517  {
2518  PG_FREE_IF_COPY(geom, 0);
2519  lwpgerror("Argument must be POINT geometries");
2520  PG_RETURN_NULL();
2521  }
2522  srid = lwpoint->srid;
2523  if (!getPoint2d_p(lwpoint->point, 0, &p1))
2524  {
2525  PG_FREE_IF_COPY(geom, 0);
2526  lwpgerror("Error extracting point");
2527  PG_RETURN_NULL();
2528  }
2529  lwpoint_free(lwpoint);
2530  PG_FREE_IF_COPY(geom, 0);
2531 
2532  /* Extract second point */
2533  geom = PG_GETARG_GSERIALIZED_P(1);
2534  lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom));
2535  if (!lwpoint)
2536  {
2537  PG_FREE_IF_COPY(geom, 1);
2538  lwpgerror("Argument must be POINT geometries");
2539  PG_RETURN_NULL();
2540  }
2541  if (lwpoint->srid != srid)
2542  {
2543  PG_FREE_IF_COPY(geom, 1);
2544  lwpgerror("Operation on mixed SRID geometries");
2545  PG_RETURN_NULL();
2546  }
2547  if (!getPoint2d_p(lwpoint->point, 0, &p2))
2548  {
2549  PG_FREE_IF_COPY(geom, 1);
2550  lwpgerror("Error extracting point");
2551  PG_RETURN_NULL();
2552  }
2553  lwpoint_free(lwpoint);
2554  PG_FREE_IF_COPY(geom, 1);
2555 
2556  /* Standard return value for equality case */
2557  if ((p1.x == p2.x) && (p1.y == p2.y))
2558  {
2559  PG_RETURN_NULL();
2560  }
2561 
2562  /* Compute azimuth */
2563  if (!azimuth_pt_pt(&p1, &p2, &result))
2564  {
2565  PG_RETURN_NULL();
2566  }
2567 
2568  PG_RETURN_FLOAT8(result);
2569 }
2570 
2571 
2580 Datum geometry_project_direction(PG_FUNCTION_ARGS)
2581 {
2582  GSERIALIZED *geom1, *geom2;
2583  LWPOINT *lwpoint1, *lwpoint2;
2584  LWGEOM *lwgeom1, *lwgeom2;
2585  double distance, azimuth;
2586 
2587  geom1 = PG_GETARG_GSERIALIZED_P(0);
2588  distance = PG_GETARG_FLOAT8(1);
2589  azimuth = PG_GETARG_FLOAT8(2);
2590  lwgeom1 = lwgeom_from_gserialized(geom1);
2591  lwpoint1 = lwgeom_as_lwpoint(lwgeom1);
2592 
2593  if (!lwpoint1)
2594  lwpgerror("Argument must be POINT geometry");
2595 
2596  if (lwgeom_is_empty(lwgeom1))
2597  PG_RETURN_NULL();
2598 
2599  lwpoint2 = lwpoint_project(lwpoint1, distance, azimuth);
2600  lwgeom2 = lwpoint_as_lwgeom(lwpoint2);
2601  geom2 = geometry_serialize(lwgeom2);
2602  PG_RETURN_POINTER(geom2);
2603 }
2604 
2605 
2614 Datum geometry_project_geometry(PG_FUNCTION_ARGS)
2615 {
2616  GSERIALIZED *geom1, *geom2, *geom3;
2617  LWPOINT *lwpoint1, *lwpoint2, *lwpoint3;
2618  LWGEOM *lwgeom1, *lwgeom2, *lwgeom3;
2619  double distance;
2620 
2621  geom1 = PG_GETARG_GSERIALIZED_P(0);
2622  geom2 = PG_GETARG_GSERIALIZED_P(1);
2623  distance = PG_GETARG_FLOAT8(2);
2624 
2625  lwgeom1 = lwgeom_from_gserialized(geom1);
2626  lwpoint1 = lwgeom_as_lwpoint(lwgeom1);
2627  lwgeom2 = lwgeom_from_gserialized(geom2);
2628  lwpoint2 = lwgeom_as_lwpoint(lwgeom2);
2629 
2630  if (!(lwpoint1 && lwpoint2))
2631  lwpgerror("Arguments must be POINT geometries");
2632 
2633  if (lwgeom_is_empty(lwgeom1) || lwgeom_is_empty(lwgeom2))
2634  PG_RETURN_NULL();
2635 
2636  if (lwpoint_same2d(lwpoint1, lwpoint2))
2637  PG_RETURN_POINTER(geom2);
2638 
2639  lwpoint3 = lwpoint_project_lwpoint(lwpoint1, lwpoint2, distance);
2640  lwgeom3 = lwpoint_as_lwgeom(lwpoint3);
2641  geom3 = geometry_serialize(lwgeom3);
2642 
2643  PG_RETURN_POINTER(geom3);
2644 }
2645 
2646 
2647 
2655 Datum geometry_line_extend(PG_FUNCTION_ARGS)
2656 {
2657  GSERIALIZED *geom1, *geom2;
2658  LWLINE *lwline1, *lwline2;
2659  LWGEOM *lwgeom1, *lwgeom2;
2660  double distance_forward, distance_backward;
2661 
2662  geom1 = PG_GETARG_GSERIALIZED_P(0);
2663  distance_forward = PG_GETARG_FLOAT8(1);
2664  distance_backward = PG_GETARG_FLOAT8(2);
2665 
2666  lwgeom1 = lwgeom_from_gserialized(geom1);
2667  lwline1 = lwgeom_as_lwline(lwgeom1);
2668  if (!lwline1)
2669  lwpgerror("Argument must be LINESTRING geometry");
2670 
2671  if (lwline_is_empty(lwline1))
2672  PG_RETURN_NULL();
2673 
2674  if (lwline_length_2d(lwline1) <= 0.0)
2675  PG_RETURN_POINTER(geom1);
2676 
2677  lwline2 = lwline_extend(lwline1, distance_forward, distance_backward);
2678  lwgeom2 = lwline_as_lwgeom(lwline2);
2679  geom2 = geometry_serialize(lwgeom2);
2680 
2681  PG_RETURN_POINTER(geom2);
2682 }
2683 
2684 
2685 
2694 Datum LWGEOM_angle(PG_FUNCTION_ARGS)
2695 {
2696  GSERIALIZED *seri_geoms[4];
2697  LWGEOM *geom_unser;
2698  LWPOINT *lwpoint;
2699  POINT2D points[4];
2700  double az1, az2;
2701  double result;
2702  int32_t srids[4];
2703  int i = 0;
2704  int j = 0;
2705  int err_code = 0;
2706  int n_args = PG_NARGS();
2707 
2708  /* no deserialize, checking for common error first*/
2709  for (i = 0; i < n_args; i++)
2710  {
2711  seri_geoms[i] = PG_GETARG_GSERIALIZED_P(i);
2712  if (gserialized_is_empty(seri_geoms[i]))
2713  { /* empty geom */
2714  if (i == 3)
2715  {
2716  n_args = 3;
2717  }
2718  else
2719  {
2720  err_code = 1;
2721  break;
2722  }
2723  }
2724  else
2725  {
2726  if (gserialized_get_type(seri_geoms[i]) != POINTTYPE)
2727  { /* geom type */
2728  err_code = 2;
2729  break;
2730  }
2731  else
2732  {
2733  srids[i] = gserialized_get_srid(seri_geoms[i]);
2734  if (srids[0] != srids[i])
2735  { /* error on srid*/
2736  err_code = 3;
2737  break;
2738  }
2739  }
2740  }
2741  }
2742  if (err_code > 0)
2743  switch (err_code)
2744  {
2745  default: /*always executed*/
2746  for (j = 0; j <= i; j++)
2747  PG_FREE_IF_COPY(seri_geoms[j], j);
2748  /*FALLTHROUGH*/
2749  case 1:
2750  lwpgerror("Empty geometry");
2751  PG_RETURN_NULL();
2752  break;
2753 
2754  case 2:
2755  lwpgerror("Argument must be POINT geometries");
2756  PG_RETURN_NULL();
2757  break;
2758 
2759  case 3:
2760  lwpgerror("Operation on mixed SRID geometries");
2761  PG_RETURN_NULL();
2762  break;
2763  }
2764  /* extract points */
2765  for (i = 0; i < n_args; i++)
2766  {
2767  geom_unser = lwgeom_from_gserialized(seri_geoms[i]);
2768  lwpoint = lwgeom_as_lwpoint(geom_unser);
2769  if (!lwpoint)
2770  {
2771  for (j = 0; j < n_args; j++)
2772  PG_FREE_IF_COPY(seri_geoms[j], j);
2773  lwpgerror("Error unserializing geometry");
2774  PG_RETURN_NULL();
2775  }
2776 
2777  if (!getPoint2d_p(lwpoint->point, 0, &points[i]))
2778  {
2779  /* // can't free serialized geom, it might be needed by lw
2780  for (j=0;j<n_args;j++)
2781  PG_FREE_IF_COPY(seri_geoms[j], j); */
2782  lwpgerror("Error extracting point");
2783  PG_RETURN_NULL();
2784  }
2785  /* lwfree(geom_unser);don't do, lw may rely on this memory
2786  lwpoint_free(lwpoint); dont do , this memory is needed ! */
2787  }
2788  /* // can't free serialized geom, it might be needed by lw
2789  for (j=0;j<n_args;j++)
2790  PG_FREE_IF_COPY(seri_geoms[j], j); */
2791 
2792  /* compute azimuth for the 2 pairs of points
2793  * note that angle is not defined identically for 3 points or 4 points*/
2794  if (n_args == 3)
2795  { /* we rely on azimuth to complain if points are identical */
2796  if (!azimuth_pt_pt(&points[0], &points[1], &az1))
2797  PG_RETURN_NULL();
2798  if (!azimuth_pt_pt(&points[2], &points[1], &az2))
2799  PG_RETURN_NULL();
2800  }
2801  else
2802  {
2803  if (!azimuth_pt_pt(&points[0], &points[1], &az1))
2804  PG_RETURN_NULL();
2805  if (!azimuth_pt_pt(&points[2], &points[3], &az2))
2806  PG_RETURN_NULL();
2807  }
2808  result = az2 - az1;
2809  result += (result < 0) * 2 * M_PI; /* we dont want negative angle*/
2810  PG_RETURN_FLOAT8(result);
2811 }
2812 
2813 /*
2814  * optimistic_overlap(Polygon P1, Multipolygon MP2, double dist)
2815  * returns true if P1 overlaps MP2
2816  * method: bbox check -
2817  * is separation < dist? no - return false (quick)
2818  * yes - return distance(P1,MP2) < dist
2819  */
2821 Datum optimistic_overlap(PG_FUNCTION_ARGS)
2822 {
2823  GSERIALIZED *pg_geom1 = PG_GETARG_GSERIALIZED_P(0);
2824  GSERIALIZED *pg_geom2 = PG_GETARG_GSERIALIZED_P(1);
2825  double dist = PG_GETARG_FLOAT8(2);
2826  GBOX g1_bvol;
2827  double calc_dist;
2828  LWGEOM *geom1 = lwgeom_from_gserialized(pg_geom1);
2829  LWGEOM *geom2 = lwgeom_from_gserialized(pg_geom2);
2830  gserialized_error_if_srid_mismatch(pg_geom1, pg_geom2, __func__);
2831 
2832  if (geom1->type != POLYGONTYPE)
2833  {
2834  elog(ERROR, "optimistic_overlap: first arg isn't a polygon\n");
2835  PG_RETURN_NULL();
2836  }
2837 
2838  if (geom2->type != POLYGONTYPE && geom2->type != MULTIPOLYGONTYPE)
2839  {
2840  elog(ERROR, "optimistic_overlap: 2nd arg isn't a [multi-]polygon\n");
2841  PG_RETURN_NULL();
2842  }
2843 
2844  /*bbox check */
2845  gserialized_get_gbox_p(pg_geom1, &g1_bvol);
2846 
2847  g1_bvol.xmin = g1_bvol.xmin - dist;
2848  g1_bvol.ymin = g1_bvol.ymin - dist;
2849  g1_bvol.xmax = g1_bvol.xmax + dist;
2850  g1_bvol.ymax = g1_bvol.ymax + dist;
2851 
2852  if ((g1_bvol.xmin > geom2->bbox->xmax) || (g1_bvol.xmax < geom2->bbox->xmin) ||
2853  (g1_bvol.ymin > geom2->bbox->ymax) || (g1_bvol.ymax < geom2->bbox->ymin))
2854  {
2855  PG_RETURN_BOOL(false); /*bbox not overlap */
2856  }
2857 
2858  /*
2859  * compute distances
2860  * should be a fast calc if they actually do intersect
2861  */
2862  calc_dist =
2863  DatumGetFloat8(DirectFunctionCall2(ST_Distance, PointerGetDatum(pg_geom1), PointerGetDatum(pg_geom2)));
2864 
2865  PG_RETURN_BOOL(calc_dist < dist);
2866 }
2867 
2868 /*affine transform geometry */
2870 Datum LWGEOM_affine(PG_FUNCTION_ARGS)
2871 {
2872  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P_COPY(0);
2873  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
2874  GSERIALIZED *ret;
2875  AFFINE affine;
2876 
2877  affine.afac = PG_GETARG_FLOAT8(1);
2878  affine.bfac = PG_GETARG_FLOAT8(2);
2879  affine.cfac = PG_GETARG_FLOAT8(3);
2880  affine.dfac = PG_GETARG_FLOAT8(4);
2881  affine.efac = PG_GETARG_FLOAT8(5);
2882  affine.ffac = PG_GETARG_FLOAT8(6);
2883  affine.gfac = PG_GETARG_FLOAT8(7);
2884  affine.hfac = PG_GETARG_FLOAT8(8);
2885  affine.ifac = PG_GETARG_FLOAT8(9);
2886  affine.xoff = PG_GETARG_FLOAT8(10);
2887  affine.yoff = PG_GETARG_FLOAT8(11);
2888  affine.zoff = PG_GETARG_FLOAT8(12);
2889 
2890  POSTGIS_DEBUG(2, "LWGEOM_affine called.");
2891 
2892  lwgeom_affine(lwgeom, &affine);
2893 
2894  /* COMPUTE_BBOX TAINTING */
2895  if (lwgeom->bbox)
2896  {
2897  lwgeom_refresh_bbox(lwgeom);
2898  }
2899  ret = geometry_serialize(lwgeom);
2900 
2901  /* Release memory */
2902  lwgeom_free(lwgeom);
2903  PG_FREE_IF_COPY(geom, 0);
2904 
2905  PG_RETURN_POINTER(ret);
2906 }
2907 
2909 Datum ST_GeoHash(PG_FUNCTION_ARGS)
2910 {
2911 
2912  GSERIALIZED *geom = NULL;
2913  int precision = 0;
2914  lwvarlena_t *geohash = NULL;
2915 
2916  if (PG_ARGISNULL(0))
2917  {
2918  PG_RETURN_NULL();
2919  }
2920 
2921  geom = PG_GETARG_GSERIALIZED_P(0);
2922 
2923  if (!PG_ARGISNULL(1))
2924  {
2925  precision = PG_GETARG_INT32(1);
2926  }
2927 
2928  geohash = lwgeom_geohash((LWGEOM *)(lwgeom_from_gserialized(geom)), precision);
2929  if (geohash)
2930  PG_RETURN_TEXT_P(geohash);
2931  PG_RETURN_NULL();
2932 }
2933 
2935 Datum _ST_SortableHash(PG_FUNCTION_ARGS)
2936 {
2937  if (PG_ARGISNULL(0))
2938  PG_RETURN_NULL();
2939  PG_RETURN_INT64(gserialized_get_sortable_hash(PG_GETARG_GSERIALIZED_P(0)));
2940 }
2941 
2943 Datum ST_CollectionExtract(PG_FUNCTION_ARGS)
2944 {
2945  GSERIALIZED *gser_in, *gser_out;
2946  LWGEOM *lwg_in = NULL;
2947  LWGEOM *lwg_out = NULL;
2948  int extype = 0;
2949 
2950  if (PG_NARGS() > 1)
2951  extype = PG_GETARG_INT32(1);
2952 
2953  /* Ensure the right type was input */
2954  if (!(extype == 0 || extype == POINTTYPE || extype == LINETYPE || extype == POLYGONTYPE))
2955  {
2956  elog(ERROR, "ST_CollectionExtract: only point, linestring and polygon may be extracted");
2957  PG_RETURN_NULL();
2958  }
2959 
2960  gser_in = PG_GETARG_GSERIALIZED_P(0);
2961  lwg_in = lwgeom_from_gserialized(gser_in);
2962 
2963  /* Mirror non-collections right back */
2964  if (!lwgeom_is_collection(lwg_in))
2965  {
2966  /* Non-collections of the matching type go back */
2967  if (lwg_in->type == extype || !extype)
2968  {
2969  lwgeom_free(lwg_in);
2970  PG_RETURN_POINTER(gser_in);
2971  }
2972  /* Others go back as EMPTY */
2973  else
2974  {
2975  lwg_out = lwgeom_construct_empty(extype, lwg_in->srid, lwgeom_has_z(lwg_in), lwgeom_has_m(lwg_in));
2976  PG_RETURN_POINTER(geometry_serialize(lwg_out));
2977  }
2978  }
2979 
2980  lwg_out = (LWGEOM*)lwcollection_extract((LWCOLLECTION*)lwg_in, extype);
2981 
2982  gser_out = geometry_serialize(lwg_out);
2983  lwgeom_free(lwg_in);
2984  lwgeom_free(lwg_out);
2985  PG_RETURN_POINTER(gser_out);
2986 }
2987 
2989 Datum ST_CollectionHomogenize(PG_FUNCTION_ARGS)
2990 {
2991  GSERIALIZED *input = PG_GETARG_GSERIALIZED_P(0);
2992  GSERIALIZED *output;
2993  LWGEOM *lwgeom = lwgeom_from_gserialized(input);
2994  LWGEOM *lwoutput = NULL;
2995 
2996  lwoutput = lwgeom_homogenize(lwgeom);
2997  lwgeom_free(lwgeom);
2998 
2999  if (!lwoutput)
3000  {
3001  PG_FREE_IF_COPY(input, 0);
3002  PG_RETURN_NULL();
3003  }
3004 
3005  output = geometry_serialize(lwoutput);
3006  lwgeom_free(lwoutput);
3007 
3008  PG_FREE_IF_COPY(input, 0);
3009  PG_RETURN_POINTER(output);
3010 }
3011 
3012 Datum ST_RemoveRepeatedPoints(PG_FUNCTION_ARGS);
3014 Datum ST_RemoveRepeatedPoints(PG_FUNCTION_ARGS)
3015 {
3016  GSERIALIZED *g_in = PG_GETARG_GSERIALIZED_P_COPY(0);
3017  uint32_t type = gserialized_get_type(g_in);
3018  GSERIALIZED *g_out;
3019  LWGEOM *lwgeom_in = NULL;
3020  double tolerance = 0.0;
3021  int modified = LW_FALSE;
3022 
3023  /* Don't even start to think about points */
3024  if (type == POINTTYPE)
3025  PG_RETURN_POINTER(g_in);
3026 
3027  if (PG_NARGS() > 1 && !PG_ARGISNULL(1))
3028  tolerance = PG_GETARG_FLOAT8(1);
3029 
3030  lwgeom_in = lwgeom_from_gserialized(g_in);
3031  modified = lwgeom_remove_repeated_points_in_place(lwgeom_in, tolerance);
3032  if (!modified)
3033  {
3034  /* Since there were no changes, we can return the input to avoid the serialization */
3035  PG_RETURN_POINTER(g_in);
3036  }
3037 
3038  g_out = geometry_serialize(lwgeom_in);
3039 
3040  pfree(g_in);
3041  PG_RETURN_POINTER(g_out);
3042 }
3043 
3044 Datum ST_FlipCoordinates(PG_FUNCTION_ARGS);
3046 Datum ST_FlipCoordinates(PG_FUNCTION_ARGS)
3047 {
3048  GSERIALIZED *in = PG_GETARG_GSERIALIZED_P_COPY(0);
3049  GSERIALIZED *out;
3050  LWGEOM *lwgeom = lwgeom_from_gserialized(in);
3051 
3053  out = geometry_serialize(lwgeom);
3054 
3055  lwgeom_free(lwgeom);
3056  PG_FREE_IF_COPY(in, 0);
3057 
3058  PG_RETURN_POINTER(out);
3059 }
3060 
3061 static LWORD
3063 {
3064  if (n == 'x' || n == 'X')
3065  return LWORD_X;
3066  if (n == 'y' || n == 'Y')
3067  return LWORD_Y;
3068  if (n == 'z' || n == 'Z')
3069  return LWORD_Z;
3070  if (n == 'm' || n == 'M')
3071  return LWORD_M;
3072  lwpgerror("Invalid ordinate name '%c'. Expected x,y,z or m", n);
3073  return (LWORD)-1;
3074 }
3075 
3076 Datum ST_SwapOrdinates(PG_FUNCTION_ARGS);
3078 Datum ST_SwapOrdinates(PG_FUNCTION_ARGS)
3079 {
3080  GSERIALIZED *in;
3081  GSERIALIZED *out;
3082  LWGEOM *lwgeom;
3083  const char *ospec;
3084  LWORD o1, o2;
3085 
3086  ospec = PG_GETARG_CSTRING(1);
3087  if (strlen(ospec) != 2)
3088  {
3089  lwpgerror(
3090  "Invalid ordinate specification. "
3091  "Need two letters from the set (x,y,z,m). "
3092  "Got '%s'",
3093  ospec);
3094  PG_RETURN_NULL();
3095  }
3096  o1 = ordname2ordval(ospec[0]);
3097  o2 = ordname2ordval(ospec[1]);
3098 
3099  in = PG_GETARG_GSERIALIZED_P_COPY(0);
3100 
3101  /* Check presence of given ordinates */
3102  if ((o1 == LWORD_M || o2 == LWORD_M) && !gserialized_has_m(in))
3103  {
3104  lwpgerror("Geometry does not have an M ordinate");
3105  PG_RETURN_NULL();
3106  }
3107  if ((o1 == LWORD_Z || o2 == LWORD_Z) && !gserialized_has_z(in))
3108  {
3109  lwpgerror("Geometry does not have a Z ordinate");
3110  PG_RETURN_NULL();
3111  }
3112 
3113  /* Nothing to do if swapping the same ordinate, pity for the copy... */
3114  if (o1 == o2)
3115  PG_RETURN_POINTER(in);
3116 
3117  lwgeom = lwgeom_from_gserialized(in);
3118  lwgeom_swap_ordinates(lwgeom, o1, o2);
3119  out = geometry_serialize(lwgeom);
3120  lwgeom_free(lwgeom);
3121  PG_FREE_IF_COPY(in, 0);
3122  PG_RETURN_POINTER(out);
3123 }
3124 
3125 /*
3126  * ST_BoundingDiagonal(inp geometry, fits boolean)
3127  */
3128 Datum ST_BoundingDiagonal(PG_FUNCTION_ARGS);
3130 Datum ST_BoundingDiagonal(PG_FUNCTION_ARGS)
3131 {
3132  GSERIALIZED *geom_out;
3133  bool fits = PG_GETARG_BOOL(1);
3134  LWGEOM *lwgeom_out = NULL;
3135 
3136  GBOX gbox = {0};
3137  int hasz;
3138  int hasm;
3139  int32_t srid;
3140 
3141  POINT4D pt;
3142  POINTARRAY *pa;
3143 
3144  if (fits)
3145  {
3146  GSERIALIZED *geom_in = PG_GETARG_GSERIALIZED_P(0);
3147  LWGEOM *lwgeom_in = lwgeom_from_gserialized(geom_in);
3148  lwgeom_calculate_gbox(lwgeom_in, &gbox);
3149  hasz = FLAGS_GET_Z(lwgeom_in->flags);
3150  hasm = FLAGS_GET_M(lwgeom_in->flags);
3151  srid = lwgeom_in->srid;
3152  }
3153  else
3154  {
3155  uint8_t type;
3156  lwflags_t flags;
3157  int res = gserialized_datum_get_internals_p(PG_GETARG_DATUM(0), &gbox, &flags, &type, &srid);
3158  hasz = FLAGS_GET_Z(flags);
3159  hasm = FLAGS_GET_M(flags);
3160  if (res == LW_FAILURE)
3161  {
3162  lwgeom_out = lwgeom_construct_empty(LINETYPE, srid, hasz, hasm);
3163  }
3164  }
3165 
3166  if (!lwgeom_out)
3167  {
3168  pa = ptarray_construct_empty(hasz, hasm, 2);
3169  pt.x = gbox.xmin;
3170  pt.y = gbox.ymin;
3171  pt.z = gbox.zmin;
3172  pt.m = gbox.mmin;
3173  ptarray_append_point(pa, &pt, LW_TRUE);
3174  pt.x = gbox.xmax;
3175  pt.y = gbox.ymax;
3176  pt.z = gbox.zmax;
3177  pt.m = gbox.mmax;
3178  ptarray_append_point(pa, &pt, LW_TRUE);
3179  lwgeom_out = lwline_as_lwgeom(lwline_construct(srid, NULL, pa));
3180  }
3181 
3182  geom_out = geometry_serialize(lwgeom_out);
3183  lwgeom_free(lwgeom_out);
3184 
3185  PG_RETURN_POINTER(geom_out);
3186 }
3187 
3188 Datum ST_Scale(PG_FUNCTION_ARGS);
3190 Datum ST_Scale(PG_FUNCTION_ARGS)
3191 {
3192  GSERIALIZED *geom;
3193  GSERIALIZED *geom_scale = PG_GETARG_GSERIALIZED_P(1);
3194  GSERIALIZED *geom_origin = NULL;
3195  LWGEOM *lwg, *lwg_scale, *lwg_origin;
3196  LWPOINT *lwpt_scale, *lwpt_origin;
3197  POINT4D origin;
3198  POINT4D factors;
3199  bool translate = false;
3200  GSERIALIZED *ret;
3201  AFFINE aff;
3202 
3203  /* Make sure we have a valid scale input */
3204  lwg_scale = lwgeom_from_gserialized(geom_scale);
3205  lwpt_scale = lwgeom_as_lwpoint(lwg_scale);
3206  if (!lwpt_scale)
3207  {
3208  lwgeom_free(lwg_scale);
3209  PG_FREE_IF_COPY(geom_scale, 1);
3210  lwpgerror("Scale factor geometry parameter must be a point");
3211  PG_RETURN_NULL();
3212  }
3213 
3214  /* Geom Will be modified in place, so take a copy */
3215  geom = PG_GETARG_GSERIALIZED_P_COPY(0);
3216  lwg = lwgeom_from_gserialized(geom);
3217 
3218  /* Empty point, return input untouched */
3219  if (lwgeom_is_empty(lwg))
3220  {
3221  lwgeom_free(lwg_scale);
3222  lwgeom_free(lwg);
3223  PG_FREE_IF_COPY(geom_scale, 1);
3224  PG_RETURN_POINTER(geom);
3225  }
3226 
3227  /* Once we read the scale data into local static point, we can */
3228  /* free the lwgeom */
3229  lwpoint_getPoint4d_p(lwpt_scale, &factors);
3230  if (!lwgeom_has_z(lwg_scale))
3231  factors.z = 1.0;
3232  if (!lwgeom_has_m(lwg_scale))
3233  factors.m = 1.0;
3234  lwgeom_free(lwg_scale);
3235 
3236  /* Do we have the optional false origin? */
3237  if (PG_NARGS() > 2 && !PG_ARGISNULL(2))
3238  {
3239  geom_origin = PG_GETARG_GSERIALIZED_P(2);
3240  lwg_origin = lwgeom_from_gserialized(geom_origin);
3241  lwpt_origin = lwgeom_as_lwpoint(lwg_origin);
3242  if (lwpt_origin)
3243  {
3244  lwpoint_getPoint4d_p(lwpt_origin, &origin);
3245  translate = true;
3246  }
3247  /* Free the false origin inputs */
3248  lwgeom_free(lwg_origin);
3249  PG_FREE_IF_COPY(geom_origin, 2);
3250  }
3251 
3252  /* If we have false origin, translate to it before scaling */
3253  if (translate)
3254  {
3255  /* Initialize affine */
3256  memset(&aff, 0, sizeof(AFFINE));
3257  /* Set rotation/scale/sheer matrix to no-op */
3258  aff.afac = aff.efac = aff.ifac = 1.0;
3259  /* Strip false origin from all coordinates */
3260  aff.xoff = -1 * origin.x;
3261  aff.yoff = -1 * origin.y;
3262  aff.zoff = -1 * origin.z;
3263  lwgeom_affine(lwg, &aff);
3264  }
3265 
3266  lwgeom_scale(lwg, &factors);
3267 
3268  /* Return to original origin after scaling */
3269  if (translate)
3270  {
3271  aff.xoff *= -1;
3272  aff.yoff *= -1;
3273  aff.zoff *= -1;
3274  lwgeom_affine(lwg, &aff);
3275  }
3276 
3277  /* Cleanup and return */
3278  ret = geometry_serialize(lwg);
3279  lwgeom_free(lwg);
3280  PG_FREE_IF_COPY(geom, 0);
3281  PG_FREE_IF_COPY(geom_scale, 1);
3282  PG_RETURN_POINTER(ret);
3283 }
3284 
3285 Datum ST_Points(PG_FUNCTION_ARGS);
3287 Datum ST_Points(PG_FUNCTION_ARGS)
3288 {
3289  if (PG_ARGISNULL(0))
3290  {
3291  PG_RETURN_NULL();
3292  }
3293  else
3294  {
3295  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P(0);
3296  GSERIALIZED *ret;
3297  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
3299 
3300  lwgeom_free(lwgeom);
3301 
3302  ret = geometry_serialize(lwmpoint_as_lwgeom(result));
3304  PG_RETURN_POINTER(ret);
3305  }
3306 }
3307 
3309 Datum ST_QuantizeCoordinates(PG_FUNCTION_ARGS)
3310 {
3311  GSERIALIZED *input;
3313  LWGEOM *g;
3314  int32_t prec_x;
3315  int32_t prec_y;
3316  int32_t prec_z;
3317  int32_t prec_m;
3318 
3319  if (PG_ARGISNULL(0))
3320  PG_RETURN_NULL();
3321  if (PG_ARGISNULL(1))
3322  {
3323  lwpgerror("Must specify precision");
3324  PG_RETURN_NULL();
3325  }
3326  else
3327  {
3328  prec_x = PG_GETARG_INT32(1);
3329  }
3330  prec_y = PG_ARGISNULL(2) ? prec_x : PG_GETARG_INT32(2);
3331  prec_z = PG_ARGISNULL(3) ? prec_x : PG_GETARG_INT32(3);
3332  prec_m = PG_ARGISNULL(4) ? prec_x : PG_GETARG_INT32(4);
3333 
3334  input = PG_GETARG_GSERIALIZED_P_COPY(0);
3335 
3336  g = lwgeom_from_gserialized(input);
3337 
3338  lwgeom_trim_bits_in_place(g, prec_x, prec_y, prec_z, prec_m);
3339 
3340  result = geometry_serialize(g);
3341  lwgeom_free(g);
3342  PG_FREE_IF_COPY(input, 0);
3343  PG_RETURN_POINTER(result);
3344 }
3345 
3346 /*
3347  * ST_FilterByM(in geometry, val double precision)
3348  */
3350 Datum LWGEOM_FilterByM(PG_FUNCTION_ARGS)
3351 {
3352  GSERIALIZED *geom_in;
3353  GSERIALIZED *geom_out;
3354  LWGEOM *lwgeom_in;
3355  LWGEOM *lwgeom_out;
3356  double min, max;
3357  int returnm;
3358  int hasm;
3359 
3360  if (PG_NARGS() > 0 && !PG_ARGISNULL(0))
3361  {
3362  geom_in = PG_GETARG_GSERIALIZED_P(0);
3363  }
3364  else
3365  {
3366  PG_RETURN_NULL();
3367  }
3368 
3369  if (PG_NARGS() > 1 && !PG_ARGISNULL(1))
3370  min = PG_GETARG_FLOAT8(1);
3371  else
3372  {
3373  min = DBL_MIN;
3374  }
3375  if (PG_NARGS() > 2 && !PG_ARGISNULL(2))
3376  max = PG_GETARG_FLOAT8(2);
3377  else
3378  {
3379  max = DBL_MAX;
3380  }
3381  if (PG_NARGS() > 3 && !PG_ARGISNULL(3) && PG_GETARG_BOOL(3))
3382  returnm = 1;
3383  else
3384  {
3385  returnm = 0;
3386  }
3387 
3388  if (min > max)
3389  {
3390  elog(ERROR, "Min-value cannot be larger than Max value\n");
3391  PG_RETURN_NULL();
3392  }
3393 
3394  lwgeom_in = lwgeom_from_gserialized(geom_in);
3395 
3396  hasm = lwgeom_has_m(lwgeom_in);
3397 
3398  if (!hasm)
3399  {
3400  elog(NOTICE, "No M-value, No vertex removed\n");
3401  PG_RETURN_POINTER(geom_in);
3402  }
3403 
3404  lwgeom_out = lwgeom_filter_m(lwgeom_in, min, max, returnm);
3405 
3406  geom_out = geometry_serialize(lwgeom_out);
3407  lwgeom_free(lwgeom_out);
3408  PG_RETURN_POINTER(geom_out);
3409 }
3410 
3412 Datum boundary(PG_FUNCTION_ARGS)
3413 {
3414  GSERIALIZED *geom1;
3416  LWGEOM *lwgeom, *lwresult;
3417 
3418  geom1 = PG_GETARG_GSERIALIZED_P(0);
3419 
3420  /* Empty.Boundary() == Empty, but of other dimension, so can't shortcut */
3421 
3422  lwgeom = lwgeom_from_gserialized(geom1);
3423  lwresult = lwgeom_boundary(lwgeom);
3424  if (!lwresult)
3425  {
3426  lwgeom_free(lwgeom);
3427  PG_RETURN_NULL();
3428  }
3429 
3430  result = geometry_serialize(lwresult);
3431 
3432  lwgeom_free(lwgeom);
3433  lwgeom_free(lwresult);
3434 
3435  PG_RETURN_POINTER(result);
3436 }
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:735
int lwpoint_getPoint4d_p(const LWPOINT *point, POINT4D *out)
Definition: lwpoint.c:57
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition: lwgeom.c:207
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:367
#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:1222
@ 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:955
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:180
int azimuth_pt_pt(const POINT2D *p1, const POINT2D *p2, double *ret)
Compute the azimuth of segment AB in radians.
Definition: measures.c:2408
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:270
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:1638
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:2693
void lwpoint_free(LWPOINT *pt)
Definition: lwpoint.c:213
void lwgeom_longitude_shift(LWGEOM *lwgeom)
Definition: lwgeom.c:1036
#define LW_FAILURE
Definition: liblwgeom.h:96
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1246
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:408
double lwgeom_perimeter_2d(const LWGEOM *geom)
Definition: lwgeom.c:2044
lwvarlena_t * lwgeom_geohash(const LWGEOM *lwgeom, int precision)
Calculate the GeoHash (http://geohash.org) string for a geometry.
Definition: lwalgorithm.c:878
int lwpoint_inside_circle(const LWPOINT *p, double cx, double cy, double rad)
Definition: lwgeom.c:690
#define MULTISURFACETYPE
Definition: liblwgeom.h:113
#define LINETYPE
Definition: liblwgeom.h:103
LWGEOM * lwgeom_segmentize2d(const LWGEOM *line, double dist)
Definition: lwgeom.c:799
#define WKT_EXTENDED
Definition: liblwgeom.h:2221
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:332
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:357
LWGEOM * lwgeom_force_sfs(LWGEOM *geom, int version)
Definition: lwgeom.c:877
#define MULTIPOINTTYPE
Definition: liblwgeom.h:105
LWGEOM * lwgeom_clone_deep(const LWGEOM *lwgeom)
Deep clone an LWGEOM, everything is copied.
Definition: lwgeom.c:557
int lwgeom_remove_repeated_points_in_place(LWGEOM *in, double tolerance)
Definition: lwgeom.c:1695
LWGEOM * lwgeom_force_3dm(const LWGEOM *geom, double mval)
Definition: lwgeom.c:833
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:839
double lwgeom_length(const LWGEOM *geom)
Definition: lwgeom.c:2066
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:827
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition: lwgeom.c:962
#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:710
#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:2165
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:1999
#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:1337
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:372
double lwgeom_mindistance2d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling min distance calculations and dwithin calculations.
Definition: measures.c:222
LWGEOM * lwgeom_as_curve(const LWGEOM *lwgeom)
Create a new LWGEOM of the appropriate CURVE* type.
Definition: lwgeom.c:448
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:1125
#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:1569
void lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
Definition: lwgeom.c:2111
LWGEOM * lwgeom_closest_line(const LWGEOM *lw1, const LWGEOM *lw2)
Definition: measures.c:43
LWGEOM * lwgeom_boundary(LWGEOM *lwgeom)
Definition: lwgeom.c:2714
#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:2088
uint32_t lwgeom_count_rings(const LWGEOM *geom)
Count the total number of rings in any LWGEOM.
Definition: lwgeom.c:1447
double lwgeom_mindistance2d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing min distance calculation.
Definition: measures.c:212
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)
Definition: lwgeom.c:73
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:1132
LWLINE * lwline_from_lwmpoint(int32_t srid, const LWMPOINT *mpoint)
Definition: lwline.c:285
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:783
void lwline_setPoint4d(LWLINE *line, uint32_t which, POINT4D *newpoint)
Definition: lwline.c:374
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:2022
LWPOLY * lwpoly_from_lwlines(const LWLINE *shell, uint32_t nholes, const LWLINE **holes)
Definition: lwpoly.c:359
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition: lwgeom.c:969
LWLINE * lwline_extend(const LWLINE *line, double distance_forward, double distance_backward)
Extend the ends of a line.
Definition: lwline.c:682
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:2219
LWLINE * lwline_removepoint(LWLINE *line, uint32_t which)
Definition: lwline.c:357
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition: lwgeom.c:723
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
void lwgeom_force_counterclockwise(LWGEOM *lwgeom)
Definition: lwgeom.c:79
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:821
int lwline_add_lwpoint(LWLINE *line, LWPOINT *point, uint32_t where)
Add a LWPOINT to an LWLINE.
Definition: lwline.c:337
void lwgeom_drop_srid(LWGEOM *lwgeom)
Definition: lwgeom.c:793
void lwgeom_reverse_in_place(LWGEOM *lwgeom)
Reverse vertex order of LWGEOM.
Definition: lwgeom.c:131
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:530
#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:2337
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_ForcePolygonCCW(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