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