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