PostGIS  2.1.10dev-r@@SVN_REVISION@@
lwgeom_functions_basic.c
Go to the documentation of this file.
1 /**********************************************************************
2  * $Id: lwgeom_functions_basic.c 14919 2016-05-25 17:28:25Z pramsey $
3  *
4  * PostGIS - Spatial Types for PostgreSQL
5  * http://postgis.net
6  * Copyright 2001-2006 Refractions Research Inc.
7  *
8  * This is free software; you can redistribute and/or modify it under
9  * the terms of the GNU General Public Licence. See the COPYING file.
10  *
11  **********************************************************************/
12 
13 #include "postgres.h"
14 #include "fmgr.h"
15 #include "utils/elog.h"
16 #include "utils/array.h"
17 #include "utils/geo_decls.h"
18 
19 #include "liblwgeom_internal.h"
20 #include "lwgeom_pg.h"
21 
22 #include <math.h>
23 #include <float.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <errno.h>
27 
28 Datum LWGEOM_mem_size(PG_FUNCTION_ARGS);
29 Datum LWGEOM_summary(PG_FUNCTION_ARGS);
30 Datum LWGEOM_npoints(PG_FUNCTION_ARGS);
31 Datum LWGEOM_nrings(PG_FUNCTION_ARGS);
32 Datum LWGEOM_area_polygon(PG_FUNCTION_ARGS);
33 Datum postgis_uses_stats(PG_FUNCTION_ARGS);
34 Datum postgis_autocache_bbox(PG_FUNCTION_ARGS);
35 Datum postgis_scripts_released(PG_FUNCTION_ARGS);
36 Datum postgis_version(PG_FUNCTION_ARGS);
37 Datum postgis_lib_version(PG_FUNCTION_ARGS);
38 Datum postgis_svn_version(PG_FUNCTION_ARGS);
39 Datum postgis_libxml_version(PG_FUNCTION_ARGS);
40 Datum postgis_lib_build_date(PG_FUNCTION_ARGS);
41 Datum LWGEOM_length2d_linestring(PG_FUNCTION_ARGS);
42 Datum LWGEOM_length_linestring(PG_FUNCTION_ARGS);
43 Datum LWGEOM_perimeter2d_poly(PG_FUNCTION_ARGS);
44 Datum LWGEOM_perimeter_poly(PG_FUNCTION_ARGS);
45 
46 Datum LWGEOM_maxdistance2d_linestring(PG_FUNCTION_ARGS);
47 Datum LWGEOM_mindistance2d(PG_FUNCTION_ARGS);
48 Datum LWGEOM_closestpoint(PG_FUNCTION_ARGS);
49 Datum LWGEOM_shortestline2d(PG_FUNCTION_ARGS);
50 Datum LWGEOM_longestline2d(PG_FUNCTION_ARGS);
51 Datum LWGEOM_dwithin(PG_FUNCTION_ARGS);
52 Datum LWGEOM_dfullywithin(PG_FUNCTION_ARGS);
53 
54 Datum LWGEOM_maxdistance3d(PG_FUNCTION_ARGS);
55 Datum LWGEOM_mindistance3d(PG_FUNCTION_ARGS);
56 Datum LWGEOM_closestpoint3d(PG_FUNCTION_ARGS);
57 Datum LWGEOM_shortestline3d(PG_FUNCTION_ARGS);
58 Datum LWGEOM_longestline3d(PG_FUNCTION_ARGS);
59 Datum LWGEOM_dwithin3d(PG_FUNCTION_ARGS);
60 Datum LWGEOM_dfullywithin3d(PG_FUNCTION_ARGS);
61 
62 Datum LWGEOM_inside_circle_point(PG_FUNCTION_ARGS);
63 Datum LWGEOM_collect(PG_FUNCTION_ARGS);
64 Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS);
65 Datum LWGEOM_expand(PG_FUNCTION_ARGS);
66 Datum LWGEOM_to_BOX(PG_FUNCTION_ARGS);
67 Datum LWGEOM_envelope(PG_FUNCTION_ARGS);
68 Datum LWGEOM_isempty(PG_FUNCTION_ARGS);
69 Datum LWGEOM_segmentize2d(PG_FUNCTION_ARGS);
70 Datum LWGEOM_reverse(PG_FUNCTION_ARGS);
71 Datum LWGEOM_force_clockwise_poly(PG_FUNCTION_ARGS);
72 Datum LWGEOM_force_sfs(PG_FUNCTION_ARGS);
73 Datum LWGEOM_noop(PG_FUNCTION_ARGS);
74 Datum LWGEOM_zmflag(PG_FUNCTION_ARGS);
75 Datum LWGEOM_hasz(PG_FUNCTION_ARGS);
76 Datum LWGEOM_hasm(PG_FUNCTION_ARGS);
77 Datum LWGEOM_ndims(PG_FUNCTION_ARGS);
78 Datum LWGEOM_makepoint(PG_FUNCTION_ARGS);
79 Datum LWGEOM_makepoint3dm(PG_FUNCTION_ARGS);
80 Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS);
81 Datum LWGEOM_makeline(PG_FUNCTION_ARGS);
82 Datum LWGEOM_makepoly(PG_FUNCTION_ARGS);
83 Datum LWGEOM_line_from_mpoint(PG_FUNCTION_ARGS);
84 Datum LWGEOM_addpoint(PG_FUNCTION_ARGS);
85 Datum LWGEOM_removepoint(PG_FUNCTION_ARGS);
86 Datum LWGEOM_setpoint_linestring(PG_FUNCTION_ARGS);
87 Datum LWGEOM_asEWKT(PG_FUNCTION_ARGS);
88 Datum LWGEOM_hasBBOX(PG_FUNCTION_ARGS);
89 Datum LWGEOM_azimuth(PG_FUNCTION_ARGS);
90 Datum LWGEOM_affine(PG_FUNCTION_ARGS);
91 Datum LWGEOM_longitude_shift(PG_FUNCTION_ARGS);
92 Datum optimistic_overlap(PG_FUNCTION_ARGS);
93 Datum ST_GeoHash(PG_FUNCTION_ARGS);
94 Datum ST_MakeEnvelope(PG_FUNCTION_ARGS);
95 Datum ST_CollectionExtract(PG_FUNCTION_ARGS);
96 Datum ST_CollectionHomogenize(PG_FUNCTION_ARGS);
97 Datum ST_IsCollection(PG_FUNCTION_ARGS);
98 
99 
100 /*------------------------------------------------------------------*/
101 
104 Datum LWGEOM_mem_size(PG_FUNCTION_ARGS)
105 {
106  GSERIALIZED *geom = (GSERIALIZED *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
107  size_t size = VARSIZE(geom);
108  PG_FREE_IF_COPY(geom,0);
109  PG_RETURN_INT32(size);
110 }
111 
114 Datum LWGEOM_summary(PG_FUNCTION_ARGS)
115 {
116  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
117  char *result;
118  text *mytext;
119  LWGEOM *lwgeom;
120 
121  lwgeom = lwgeom_from_gserialized(geom);
122  result = lwgeom_summary(lwgeom, 0);
123  lwgeom_free(lwgeom);
124 
125  /* create a text obj to return */
126  mytext = cstring2text(result);
127  pfree(result);
128 
129  PG_FREE_IF_COPY(geom,0);
130  PG_RETURN_TEXT_P(mytext);
131 }
132 
134 Datum postgis_version(PG_FUNCTION_ARGS)
135 {
136  char *ver = POSTGIS_VERSION;
137  text *result = cstring2text(ver);
138  PG_RETURN_TEXT_P(result);
139 }
140 
142 Datum postgis_lib_version(PG_FUNCTION_ARGS)
143 {
144  char *ver = POSTGIS_LIB_VERSION;
145  text *result = cstring2text(ver);
146  PG_RETURN_TEXT_P(result);
147 }
148 
150 Datum postgis_svn_version(PG_FUNCTION_ARGS)
151 {
152  static int rev = POSTGIS_SVN_REVISION;
153  char ver[32];
154  if ( rev > 0 )
155  {
156  snprintf(ver, 32, "%d", rev);
157  PG_RETURN_TEXT_P(cstring2text(ver));
158  }
159  else
160  PG_RETURN_NULL();
161 }
162 
164 Datum postgis_lib_build_date(PG_FUNCTION_ARGS)
165 {
166  char *ver = POSTGIS_BUILD_DATE;
167  text *result = cstring2text(ver);
168  PG_RETURN_TEXT_P(result);
169 }
170 
172 Datum postgis_scripts_released(PG_FUNCTION_ARGS)
173 {
174  char ver[64];
175  text *result;
176 
177  snprintf(ver, 64, "%s r%d", POSTGIS_LIB_VERSION, POSTGIS_SVN_REVISION);
178  ver[63] = '\0';
179 
180  result = cstring2text(ver);
181  PG_RETURN_TEXT_P(result);
182 }
183 
185 Datum postgis_uses_stats(PG_FUNCTION_ARGS)
186 {
187  PG_RETURN_BOOL(TRUE);
188 }
189 
191 Datum postgis_autocache_bbox(PG_FUNCTION_ARGS)
192 {
193 #ifdef POSTGIS_AUTOCACHE_BBOX
194  PG_RETURN_BOOL(TRUE);
195 #else
196  PG_RETURN_BOOL(FALSE);
197 #endif
198 }
199 
200 
202 Datum postgis_libxml_version(PG_FUNCTION_ARGS)
203 {
204  char *ver = POSTGIS_LIBXML2_VERSION;
205  text *result = cstring2text(ver);
206  PG_RETURN_TEXT_P(result);
207 }
208 
211 Datum LWGEOM_npoints(PG_FUNCTION_ARGS)
212 {
213  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
214  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
215  int npoints = 0;
216 
217  npoints = lwgeom_count_vertices(lwgeom);
218  lwgeom_free(lwgeom);
219 
220  PG_FREE_IF_COPY(geom, 0);
221  PG_RETURN_INT32(npoints);
222 }
223 
226 Datum LWGEOM_nrings(PG_FUNCTION_ARGS)
227 {
228  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
229  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
230  int nrings = 0;
231 
232  nrings = lwgeom_count_rings(lwgeom);
233  lwgeom_free(lwgeom);
234 
235  PG_FREE_IF_COPY(geom, 0);
236  PG_RETURN_INT32(nrings);
237 }
238 
246 Datum LWGEOM_area_polygon(PG_FUNCTION_ARGS)
247 {
248  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
249  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
250  double area = 0.0;
251 
252  POSTGIS_DEBUG(2, "in LWGEOM_area_polygon");
253 
254  area = lwgeom_area(lwgeom);
255 
256  lwgeom_free(lwgeom);
257  PG_FREE_IF_COPY(geom, 0);
258 
259  PG_RETURN_FLOAT8(area);
260 }
261 
270 Datum LWGEOM_length2d_linestring(PG_FUNCTION_ARGS)
271 {
272  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
273  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
274  double dist = lwgeom_length_2d(lwgeom);
275  lwgeom_free(lwgeom);
276  PG_FREE_IF_COPY(geom, 0);
277  PG_RETURN_FLOAT8(dist);
278 }
279 
288 Datum LWGEOM_length_linestring(PG_FUNCTION_ARGS)
289 {
290  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
291  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
292  double dist = lwgeom_length(lwgeom);
293  lwgeom_free(lwgeom);
294  PG_FREE_IF_COPY(geom, 0);
295  PG_RETURN_FLOAT8(dist);
296 }
297 
306 Datum LWGEOM_perimeter_poly(PG_FUNCTION_ARGS)
307 {
308  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
309  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
310  double perimeter = 0.0;
311 
312  perimeter = lwgeom_perimeter(lwgeom);
313  PG_FREE_IF_COPY(geom, 0);
314  PG_RETURN_FLOAT8(perimeter);
315 }
316 
325 Datum LWGEOM_perimeter2d_poly(PG_FUNCTION_ARGS)
326 {
327  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
328  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
329  double perimeter = 0.0;
330 
331  perimeter = lwgeom_perimeter_2d(lwgeom);
332  PG_FREE_IF_COPY(geom, 0);
333  PG_RETURN_FLOAT8(perimeter);
334 }
335 
336 
337 /* transform input geometry to 2d if not 2d already */
339 Datum LWGEOM_force_2d(PG_FUNCTION_ARGS)
340 {
341  GSERIALIZED *pg_geom_in = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
342  GSERIALIZED *pg_geom_out;
343  LWGEOM *lwg_in, *lwg_out;
344 
345  /* already 2d */
346  if ( gserialized_ndims(pg_geom_in) == 2 ) PG_RETURN_POINTER(pg_geom_in);
347 
348  lwg_in = lwgeom_from_gserialized(pg_geom_in);
349  lwg_out = lwgeom_force_2d(lwg_in);
350  pg_geom_out = geometry_serialize(lwg_out);
351  lwgeom_free(lwg_out);
352  lwgeom_free(lwg_in);
353 
354  PG_FREE_IF_COPY(pg_geom_in, 0);
355  PG_RETURN_POINTER(pg_geom_out);
356 }
357 
358 /* transform input geometry to 3dz if not 3dz already */
360 Datum LWGEOM_force_3dz(PG_FUNCTION_ARGS)
361 {
362  GSERIALIZED *pg_geom_in = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
363  GSERIALIZED *pg_geom_out;
364  LWGEOM *lwg_in, *lwg_out;
365 
366  /* already 3d */
367  if ( gserialized_ndims(pg_geom_in) == 3 && gserialized_has_z(pg_geom_in) )
368  PG_RETURN_POINTER(pg_geom_in);
369 
370  lwg_in = lwgeom_from_gserialized(pg_geom_in);
371  lwg_out = lwgeom_force_3dz(lwg_in);
372  pg_geom_out = geometry_serialize(lwg_out);
373  lwgeom_free(lwg_out);
374  lwgeom_free(lwg_in);
375 
376  PG_FREE_IF_COPY(pg_geom_in, 0);
377  PG_RETURN_POINTER(pg_geom_out);
378 }
379 
382 Datum LWGEOM_force_3dm(PG_FUNCTION_ARGS)
383 {
384  GSERIALIZED *pg_geom_in = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
385  GSERIALIZED *pg_geom_out;
386  LWGEOM *lwg_in, *lwg_out;
387 
388  /* already 3d */
389  if ( gserialized_ndims(pg_geom_in) == 3 && gserialized_has_m(pg_geom_in) )
390  PG_RETURN_POINTER(pg_geom_in);
391 
392  lwg_in = lwgeom_from_gserialized(pg_geom_in);
393  lwg_out = lwgeom_force_3dm(lwg_in);
394  pg_geom_out = geometry_serialize(lwg_out);
395  lwgeom_free(lwg_out);
396  lwgeom_free(lwg_in);
397 
398  PG_FREE_IF_COPY(pg_geom_in, 0);
399  PG_RETURN_POINTER(pg_geom_out);
400 }
401 
402 /* transform input geometry to 4d if not 4d already */
404 Datum LWGEOM_force_4d(PG_FUNCTION_ARGS)
405 {
406  GSERIALIZED *pg_geom_in = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
407  GSERIALIZED *pg_geom_out;
408  LWGEOM *lwg_in, *lwg_out;
409 
410  /* already 4d */
411  if ( gserialized_ndims(pg_geom_in) == 4 )
412  PG_RETURN_POINTER(pg_geom_in);
413 
414  lwg_in = lwgeom_from_gserialized(pg_geom_in);
415  lwg_out = lwgeom_force_4d(lwg_in);
416  pg_geom_out = geometry_serialize(lwg_out);
417  lwgeom_free(lwg_out);
418  lwgeom_free(lwg_in);
419 
420  PG_FREE_IF_COPY(pg_geom_in, 0);
421  PG_RETURN_POINTER(pg_geom_out);
422 }
423 
426 Datum LWGEOM_force_collection(PG_FUNCTION_ARGS)
427 {
428  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
430  LWGEOM **lwgeoms;
431  LWGEOM *lwgeom;
432  int srid;
433  GBOX *bbox;
434 
435  POSTGIS_DEBUG(2, "LWGEOM_force_collection called");
436 
437  /*
438  * This funx is a no-op only if a bbox cache is already present
439  * in input. If bbox cache is not there we'll need to handle
440  * automatic bbox addition FOR_COMPLEX_GEOMS.
441  */
442  if ( gserialized_get_type(geom) == COLLECTIONTYPE &&
443  gserialized_has_bbox(geom) )
444  {
445  PG_RETURN_POINTER(geom);
446  }
447 
448  /* deserialize into lwgeoms[0] */
449  lwgeom = lwgeom_from_gserialized(geom);
450 
451  /* alread a multi*, just make it a collection */
452  if ( lwgeom_is_collection(lwgeom) )
453  {
454  lwgeom->type = COLLECTIONTYPE;
455  }
456 
457  /* single geom, make it a collection */
458  else
459  {
460  srid = lwgeom->srid;
461  /* We transfer bbox ownership from input to output */
462  bbox = lwgeom->bbox;
463  lwgeom->srid = SRID_UNKNOWN;
464  lwgeom->bbox = NULL;
465  lwgeoms = palloc(sizeof(LWGEOM*));
466  lwgeoms[0] = lwgeom;
468  srid, bbox, 1,
469  lwgeoms);
470  }
471 
472  result = geometry_serialize(lwgeom);
473  lwgeom_free(lwgeom);
474 
475  PG_FREE_IF_COPY(geom, 0);
476  PG_RETURN_POINTER(result);
477 }
478 
481 Datum LWGEOM_force_multi(PG_FUNCTION_ARGS)
482 {
483  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
485  LWGEOM *lwgeom;
486  LWGEOM *ogeom;
487 
488  POSTGIS_DEBUG(2, "LWGEOM_force_multi called");
489 
490  /*
491  ** This funx is a no-op only if a bbox cache is already present
492  ** in input. If bbox cache is not there we'll need to handle
493  ** automatic bbox addition FOR_COMPLEX_GEOMS.
494  */
495  if ( gserialized_has_bbox(geom) ) {
496  switch (gserialized_get_type(geom))
497  {
498  case MULTIPOINTTYPE:
499  case MULTILINETYPE:
500  case MULTIPOLYGONTYPE:
501  case COLLECTIONTYPE:
502  case MULTICURVETYPE:
503  case MULTISURFACETYPE:
504  case TINTYPE:
505  PG_RETURN_POINTER(geom);
506  default:
507  break;
508  }
509  }
510 
511  /* deserialize into lwgeoms[0] */
512  lwgeom = lwgeom_from_gserialized(geom);
513  ogeom = lwgeom_as_multi(lwgeom);
514 
515  result = geometry_serialize(ogeom);
516 
517  PG_FREE_IF_COPY(geom, 0);
518 
519  PG_RETURN_POINTER(result);
520 }
521 
524 Datum LWGEOM_force_sfs(PG_FUNCTION_ARGS)
525 {
526  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
528  LWGEOM *lwgeom;
529  LWGEOM *ogeom;
530  text * ver;
531  int version = 110; /* default version is SFS 1.1 */
532 
533  POSTGIS_DEBUG(2, "LWGEOM_force_sfs called");
534 
535  /* If user specified version, respect it */
536  if ( (PG_NARGS()>1) && (!PG_ARGISNULL(1)) )
537  {
538  ver = PG_GETARG_TEXT_P(1);
539 
540  if ( ! strncmp(VARDATA(ver), "1.2", 3))
541  {
542  version = 120;
543  }
544  }
545 
546  lwgeom = lwgeom_from_gserialized(geom);
547  ogeom = lwgeom_force_sfs(lwgeom, version);
548 
549  result = geometry_serialize(ogeom);
550 
551  PG_FREE_IF_COPY(geom, 0);
552 
553  PG_RETURN_POINTER(result);
554 }
555 
561 Datum LWGEOM_closestpoint(PG_FUNCTION_ARGS)
562 {
564  GSERIALIZED *geom1 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
565  GSERIALIZED *geom2 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
566  LWGEOM *point;
567  LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
568  LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
569 
570  if (lwgeom1->srid != lwgeom2->srid)
571  {
572  elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n");
573  PG_RETURN_NULL();
574  }
575 
576  point = lw_dist2d_distancepoint(lwgeom1, lwgeom2, lwgeom1->srid, DIST_MIN);
577 
578  if (lwgeom_is_empty(point))
579  PG_RETURN_NULL();
580 
581  result = geometry_serialize(point);
582  lwgeom_free(point);
583  lwgeom_free(lwgeom1);
584  lwgeom_free(lwgeom2);
585 
586  PG_FREE_IF_COPY(geom1, 0);
587  PG_FREE_IF_COPY(geom2, 1);
588  PG_RETURN_POINTER(result);
589 }
590 
595 Datum LWGEOM_shortestline2d(PG_FUNCTION_ARGS)
596 {
598  GSERIALIZED *geom1 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
599  GSERIALIZED *geom2 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
600  LWGEOM *theline;
601  LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
602  LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
603 
604  if (lwgeom1->srid != lwgeom2->srid)
605  {
606  elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n");
607  PG_RETURN_NULL();
608  }
609 
610  theline = lw_dist2d_distanceline(lwgeom1, lwgeom2, lwgeom1->srid, DIST_MIN);
611 
612  if (lwgeom_is_empty(theline))
613  PG_RETURN_NULL();
614 
615  result = geometry_serialize(theline);
616  lwgeom_free(theline);
617  lwgeom_free(lwgeom1);
618  lwgeom_free(lwgeom2);
619 
620  PG_FREE_IF_COPY(geom1, 0);
621  PG_FREE_IF_COPY(geom2, 1);
622  PG_RETURN_POINTER(result);
623 }
624 
629 Datum LWGEOM_longestline2d(PG_FUNCTION_ARGS)
630 {
632  GSERIALIZED *geom1 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
633  GSERIALIZED *geom2 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
634  LWGEOM *theline;
635  LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
636  LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
637 
638  if (lwgeom1->srid != lwgeom2->srid)
639  {
640  elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n");
641  PG_RETURN_NULL();
642  }
643 
644  theline = lw_dist2d_distanceline(lwgeom1, lwgeom2, lwgeom1->srid, DIST_MAX);
645 
646  if (lwgeom_is_empty(theline))
647  PG_RETURN_NULL();
648 
649  result = geometry_serialize(theline);
650  lwgeom_free(theline);
651  lwgeom_free(lwgeom1);
652  lwgeom_free(lwgeom2);
653 
654  PG_FREE_IF_COPY(geom1, 0);
655  PG_FREE_IF_COPY(geom2, 1);
656  PG_RETURN_POINTER(result);
657 }
662 Datum LWGEOM_mindistance2d(PG_FUNCTION_ARGS)
663 {
664  double mindist;
665  GSERIALIZED *geom1 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
666  GSERIALIZED *geom2 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
667  LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
668  LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
669 
670  if (lwgeom1->srid != lwgeom2->srid)
671  {
672  elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n");
673  PG_RETURN_NULL();
674  }
675 
676  mindist = lwgeom_mindistance2d(lwgeom1, lwgeom2);
677 
678  lwgeom_free(lwgeom1);
679  lwgeom_free(lwgeom2);
680 
681  PG_FREE_IF_COPY(geom1, 0);
682  PG_FREE_IF_COPY(geom2, 1);
683 
684  /*if called with empty geometries the ingoing mindistance is untouched, and makes us return NULL*/
685  if (mindist<MAXFLOAT)
686  PG_RETURN_FLOAT8(mindist);
687 
688  PG_RETURN_NULL();
689 }
690 
697 Datum LWGEOM_dwithin(PG_FUNCTION_ARGS)
698 {
699  double mindist;
700  GSERIALIZED *geom1 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
701  GSERIALIZED *geom2 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
702  double tolerance = PG_GETARG_FLOAT8(2);
703  LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
704  LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
705 
706  if ( tolerance < 0 )
707  {
708  elog(ERROR,"Tolerance cannot be less than zero\n");
709  PG_RETURN_NULL();
710  }
711 
712  if (lwgeom1->srid != lwgeom2->srid)
713  {
714  elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n");
715  PG_RETURN_NULL();
716  }
717 
718  mindist = lwgeom_mindistance2d_tolerance(lwgeom1,lwgeom2,tolerance);
719 
720  PG_FREE_IF_COPY(geom1, 0);
721  PG_FREE_IF_COPY(geom2, 1);
722  /*empty geometries cases should be right handled since return from underlying
723  functions should be MAXFLOAT which causes false as answer*/
724  PG_RETURN_BOOL(tolerance >= mindist);
725 }
726 
733 Datum LWGEOM_dfullywithin(PG_FUNCTION_ARGS)
734 {
735  double maxdist;
736  GSERIALIZED *geom1 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
737  GSERIALIZED *geom2 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
738  double tolerance = PG_GETARG_FLOAT8(2);
739  LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
740  LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
741 
742  if ( tolerance < 0 )
743  {
744  elog(ERROR,"Tolerance cannot be less than zero\n");
745  PG_RETURN_NULL();
746  }
747 
748  if (lwgeom1->srid != lwgeom2->srid)
749  {
750  elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n");
751  PG_RETURN_NULL();
752  }
753 
754  maxdist = lwgeom_maxdistance2d_tolerance(lwgeom1, lwgeom2, tolerance);
755 
756  PG_FREE_IF_COPY(geom1, 0);
757  PG_FREE_IF_COPY(geom2, 1);
758 
759  /*If function is feed with empty geometries we should return false*/
760  if (maxdist>-1)
761  PG_RETURN_BOOL(tolerance >= maxdist);
762 
763  PG_RETURN_BOOL(LW_FALSE);
764 }
765 
770 Datum LWGEOM_maxdistance2d_linestring(PG_FUNCTION_ARGS)
771 {
772  double maxdist;
773  GSERIALIZED *geom1 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
774  GSERIALIZED *geom2 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
775  LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
776  LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
777 
778  if (lwgeom1->srid != lwgeom2->srid)
779  {
780  elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n");
781  PG_RETURN_NULL();
782  }
783 
784  maxdist = lwgeom_maxdistance2d(lwgeom1, lwgeom2);
785 
786  PG_FREE_IF_COPY(geom1, 0);
787  PG_FREE_IF_COPY(geom2, 1);
788 
789  /*if called with empty geometries the ingoing mindistance is untouched, and makes us return NULL*/
790  if (maxdist>-1)
791  PG_RETURN_FLOAT8(maxdist);
792 
793  PG_RETURN_NULL();
794 }
795 
801 Datum LWGEOM_closestpoint3d(PG_FUNCTION_ARGS)
802 {
804  GSERIALIZED *geom1 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
805  GSERIALIZED *geom2 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
806  LWGEOM *point;
807  LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
808  LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
809 
810  if (lwgeom1->srid != lwgeom2->srid)
811  {
812  elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n");
813  PG_RETURN_NULL();
814  }
815 
816  point = lw_dist3d_distancepoint(lwgeom1, lwgeom2, lwgeom1->srid, DIST_MIN);
817 
818  if (lwgeom_is_empty(point))
819  PG_RETURN_NULL();
820 
821  result = geometry_serialize(point);
822 
823  lwgeom_free(point);
824  lwgeom_free(lwgeom1);
825  lwgeom_free(lwgeom2);
826 
827  PG_FREE_IF_COPY(geom1, 0);
828  PG_FREE_IF_COPY(geom2, 1);
829  PG_RETURN_POINTER(result);
830 }
831 
836 Datum LWGEOM_shortestline3d(PG_FUNCTION_ARGS)
837 {
839  GSERIALIZED *geom1 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
840  GSERIALIZED *geom2 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
841  LWGEOM *theline;
842  LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
843  LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
844 
845  if (lwgeom1->srid != lwgeom2->srid)
846  {
847  elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n");
848  PG_RETURN_NULL();
849  }
850 
851  theline = lw_dist3d_distanceline(lwgeom1, lwgeom2, lwgeom1->srid, DIST_MIN);
852 
853  if (lwgeom_is_empty(theline))
854  PG_RETURN_NULL();
855 
856  result = geometry_serialize(theline);
857 
858  lwgeom_free(theline);
859  lwgeom_free(lwgeom1);
860  lwgeom_free(lwgeom2);
861 
862  PG_FREE_IF_COPY(geom1, 0);
863  PG_FREE_IF_COPY(geom2, 1);
864  PG_RETURN_POINTER(result);
865 }
866 
871 Datum LWGEOM_longestline3d(PG_FUNCTION_ARGS)
872 {
874  GSERIALIZED *geom1 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
875  GSERIALIZED *geom2 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
876  LWGEOM *theline;
877  LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
878  LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
879 
880  if (lwgeom1->srid != lwgeom2->srid)
881  {
882  elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n");
883  PG_RETURN_NULL();
884  }
885 
886  theline = lw_dist3d_distanceline(lwgeom1, lwgeom2, lwgeom1->srid, DIST_MAX);
887 
888  if (lwgeom_is_empty(theline))
889  PG_RETURN_NULL();
890 
891  result = geometry_serialize(theline);
892 
893  lwgeom_free(theline);
894  lwgeom_free(lwgeom1);
895  lwgeom_free(lwgeom2);
896 
897  PG_FREE_IF_COPY(geom1, 0);
898  PG_FREE_IF_COPY(geom2, 1);
899  PG_RETURN_POINTER(result);
900 }
905 Datum LWGEOM_mindistance3d(PG_FUNCTION_ARGS)
906 {
907  double mindist;
908  GSERIALIZED *geom1 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
909  GSERIALIZED *geom2 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
910  LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
911  LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
912 
913  if (lwgeom1->srid != lwgeom2->srid)
914  {
915  elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n");
916  PG_RETURN_NULL();
917  }
918 
919  mindist = lwgeom_mindistance3d(lwgeom1, lwgeom2);
920 
921  PG_FREE_IF_COPY(geom1, 0);
922  PG_FREE_IF_COPY(geom2, 1);
923 
924  /*if called with empty geometries the ingoing mindistance is untouched, and makes us return NULL*/
925  if (mindist<MAXFLOAT)
926  PG_RETURN_FLOAT8(mindist);
927 
928  PG_RETURN_NULL();
929 }
930 
937 Datum LWGEOM_dwithin3d(PG_FUNCTION_ARGS)
938 {
939  double mindist;
940  GSERIALIZED *geom1 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
941  GSERIALIZED *geom2 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
942  double tolerance = PG_GETARG_FLOAT8(2);
943  LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
944  LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
945 
946  if ( tolerance < 0 )
947  {
948  elog(ERROR,"Tolerance cannot be less than zero\n");
949  PG_RETURN_NULL();
950  }
951 
952  if (lwgeom1->srid != lwgeom2->srid)
953  {
954  elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n");
955  PG_RETURN_NULL();
956  }
957 
958  mindist = lwgeom_mindistance3d_tolerance(lwgeom1,lwgeom2,tolerance);
959 
960  PG_FREE_IF_COPY(geom1, 0);
961  PG_FREE_IF_COPY(geom2, 1);
962 
963  /*empty geometries cases should be right handled since return from underlying
964  functions should be MAXFLOAT which causes false as answer*/
965  PG_RETURN_BOOL(tolerance >= mindist);
966 }
967 
974 Datum LWGEOM_dfullywithin3d(PG_FUNCTION_ARGS)
975 {
976  double maxdist;
977  GSERIALIZED *geom1 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
978  GSERIALIZED *geom2 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
979  double tolerance = PG_GETARG_FLOAT8(2);
980  LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
981  LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
982 
983  if ( tolerance < 0 )
984  {
985  elog(ERROR,"Tolerance cannot be less than zero\n");
986  PG_RETURN_NULL();
987  }
988 
989  if (lwgeom1->srid != lwgeom2->srid)
990  {
991  elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n");
992  PG_RETURN_NULL();
993  }
994  maxdist = lwgeom_maxdistance3d_tolerance(lwgeom1, lwgeom2, tolerance);
995 
996  PG_FREE_IF_COPY(geom1, 0);
997  PG_FREE_IF_COPY(geom2, 1);
998 
999  /*If function is feed with empty geometries we should return false*/
1000  if (maxdist>-1)
1001  PG_RETURN_BOOL(tolerance >= maxdist);
1002 
1003  PG_RETURN_BOOL(LW_FALSE);
1004 }
1005 
1010 Datum LWGEOM_maxdistance3d(PG_FUNCTION_ARGS)
1011 {
1012  double maxdist;
1013  GSERIALIZED *geom1 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
1014  GSERIALIZED *geom2 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
1015  LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
1016  LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
1017 
1018  if (lwgeom1->srid != lwgeom2->srid)
1019  {
1020  elog(ERROR,"Operation on two GEOMETRIES with different SRIDs\n");
1021  PG_RETURN_NULL();
1022  }
1023 
1024  maxdist = lwgeom_maxdistance3d(lwgeom1, lwgeom2);
1025 
1026  PG_FREE_IF_COPY(geom1, 0);
1027  PG_FREE_IF_COPY(geom2, 1);
1028 
1029  /*if called with empty geometries the ingoing mindistance is untouched, and makes us return NULL*/
1030  if (maxdist>-1)
1031  PG_RETURN_FLOAT8(maxdist);
1032 
1033  PG_RETURN_NULL();
1034 }
1035 
1036 
1038 Datum LWGEOM_longitude_shift(PG_FUNCTION_ARGS)
1039 {
1040  GSERIALIZED *geom;
1041  LWGEOM *lwgeom;
1042  GSERIALIZED *ret;
1043 
1044  POSTGIS_DEBUG(2, "LWGEOM_longitude_shift called.");
1045 
1046  geom = (GSERIALIZED *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
1047  lwgeom = lwgeom_from_gserialized(geom);
1048 
1049  /* Drop bbox, will be recomputed */
1050  lwgeom_drop_bbox(lwgeom);
1051 
1052  /* Modify geometry */
1053  lwgeom_longitude_shift(lwgeom);
1054 
1055  /* Construct GSERIALIZED */
1056  ret = geometry_serialize(lwgeom);
1057 
1058  /* Release deserialized geometry */
1059  lwgeom_free(lwgeom);
1060 
1061  /* Release detoasted geometry */
1062  pfree(geom);
1063 
1064  PG_RETURN_POINTER(ret);
1065 }
1066 
1068 Datum LWGEOM_inside_circle_point(PG_FUNCTION_ARGS)
1069 {
1070  GSERIALIZED *geom;
1071  double cx = PG_GETARG_FLOAT8(1);
1072  double cy = PG_GETARG_FLOAT8(2);
1073  double rr = PG_GETARG_FLOAT8(3);
1074  LWPOINT *lwpoint;
1075  LWGEOM *lwgeom;
1076  int inside;
1077 
1078  geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
1079  lwgeom = lwgeom_from_gserialized(geom);
1080  lwpoint = lwgeom_as_lwpoint(lwgeom);
1081  if ( lwpoint == NULL || lwgeom_is_empty(lwgeom) )
1082  {
1083  PG_FREE_IF_COPY(geom, 0);
1084  PG_RETURN_NULL(); /* not a point */
1085  }
1086 
1087  inside = lwpoint_inside_circle(lwpoint, cx, cy, rr);
1088  lwpoint_free(lwpoint);
1089 
1090  PG_FREE_IF_COPY(geom, 0);
1091  PG_RETURN_BOOL(inside);
1092 }
1093 
1102 Datum LWGEOM_collect(PG_FUNCTION_ARGS)
1103 {
1104  GSERIALIZED *gser1, *gser2, *result;
1105  LWGEOM *lwgeoms[2], *outlwg;
1106  uint32 type1, type2;
1107  uint8_t outtype;
1108  int srid;
1109 
1110  POSTGIS_DEBUG(2, "LWGEOM_collect called.");
1111 
1112  /* return null if both geoms are null */
1113  if ( PG_ARGISNULL(0) && PG_ARGISNULL(1) )
1114  PG_RETURN_NULL();
1115 
1116  /* Return the second geom if the first geom is null */
1117  if (PG_ARGISNULL(0))
1118  PG_RETURN_DATUM(PG_GETARG_DATUM(1));
1119 
1120  /* Return the first geom if the second geom is null */
1121  if (PG_ARGISNULL(1))
1122  PG_RETURN_DATUM(PG_GETARG_DATUM(0));
1123 
1124  gser1 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
1125  gser2 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
1126 
1127  POSTGIS_DEBUGF(3, "LWGEOM_collect(%s, %s): call", lwtype_name(gserialized_get_type(gser1)), lwtype_name(gserialized_get_type(gser2)));
1128 
1129  if ( FLAGS_GET_ZM(gser1->flags) != FLAGS_GET_ZM(gser2->flags) )
1130  {
1131  elog(ERROR,"Cannot ST_Collect geometries with differing dimensionality.");
1132  PG_RETURN_NULL();
1133  }
1134 
1135  srid = gserialized_get_srid(gser1);
1137 
1138  lwgeoms[0] = lwgeom_from_gserialized(gser1);
1139  lwgeoms[1] = lwgeom_from_gserialized(gser2);
1140 
1141  type1 = lwgeoms[0]->type;
1142  type2 = lwgeoms[1]->type;
1143 
1144  if ( (type1 == type2) && (!lwgeom_is_collection(lwgeoms[0])) )
1145  outtype = lwtype_get_collectiontype(type1);
1146  else
1147  outtype = COLLECTIONTYPE;
1148 
1149  POSTGIS_DEBUGF(3, " outtype = %d", outtype);
1150 
1151  /* Drop input geometries bbox and SRID */
1152  lwgeom_drop_bbox(lwgeoms[0]);
1153  lwgeom_drop_srid(lwgeoms[0]);
1154  lwgeom_drop_bbox(lwgeoms[1]);
1155  lwgeom_drop_srid(lwgeoms[1]);
1156 
1157  outlwg = (LWGEOM *)lwcollection_construct(outtype, srid, NULL, 2, lwgeoms);
1158  result = geometry_serialize(outlwg);
1159 
1160  lwgeom_free(lwgeoms[0]);
1161  lwgeom_free(lwgeoms[1]);
1162 
1163  PG_FREE_IF_COPY(gser1, 0);
1164  PG_FREE_IF_COPY(gser2, 1);
1165 
1166  PG_RETURN_POINTER(result);
1167 }
1168 
1169 
1180 Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS)
1181 {
1182  Datum datum;
1183  ArrayType *array;
1184  int nelems;
1185  /*GSERIALIZED **geoms; */
1186  GSERIALIZED *result=NULL;
1187  LWGEOM **lwgeoms, *outlwg;
1188  uint32 outtype;
1189  int i, count;
1190  int srid=SRID_UNKNOWN;
1191  size_t offset;
1192  GBOX *box=NULL;
1193  bits8 *bitmap;
1194  int bitmask;
1195 
1196  POSTGIS_DEBUG(2, "LWGEOM_collect_garray called.");
1197 
1198  /* Get input datum */
1199  datum = PG_GETARG_DATUM(0);
1200 
1201  /* Return null on null input */
1202  if ( (Pointer *)datum == NULL )
1203  {
1204  elog(NOTICE, "NULL input");
1205  PG_RETURN_NULL();
1206  }
1207 
1208  /* Get actual ArrayType */
1209  array = DatumGetArrayTypeP(datum);
1210 
1211  POSTGIS_DEBUGF(3, " array is %d-bytes in size, %ld w/out header",
1212  ARR_SIZE(array), ARR_SIZE(array)-ARR_OVERHEAD_NONULLS(ARR_NDIM(array)));
1213 
1214 
1215  /* Get number of geometries in array */
1216  nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
1217 
1218  POSTGIS_DEBUGF(3, "LWGEOM_collect_garray: array has %d elements", nelems);
1219 
1220  /* Return null on 0-elements input array */
1221  if ( nelems == 0 )
1222  {
1223  elog(NOTICE, "0 elements input array");
1224  PG_RETURN_NULL();
1225  }
1226 
1227  /*
1228  * Deserialize all geometries in array into the lwgeoms pointers
1229  * array. Check input types to form output type.
1230  */
1231  lwgeoms = palloc(sizeof(LWGEOM *)*nelems);
1232  count = 0;
1233  outtype = 0;
1234  offset = 0;
1235  bitmap = ARR_NULLBITMAP(array);
1236  bitmask = 1;
1237  for (i=0; i<nelems; i++)
1238  {
1239  /* Don't do anything for NULL values */
1240  if ((bitmap && (*bitmap & bitmask) != 0) || !bitmap)
1241  {
1242  GSERIALIZED *geom = (GSERIALIZED *)(ARR_DATA_PTR(array)+offset);
1243  uint8_t intype = gserialized_get_type(geom);
1244 
1245  offset += INTALIGN(VARSIZE(geom));
1246 
1247  lwgeoms[count] = lwgeom_from_gserialized(geom);
1248 
1249  POSTGIS_DEBUGF(3, "LWGEOM_collect_garray: geom %d deserialized", i);
1250 
1251  if ( ! count )
1252  {
1253  /* Get first geometry SRID */
1254  srid = lwgeoms[count]->srid;
1255 
1256  /* COMPUTE_BBOX WHEN_SIMPLE */
1257  if ( lwgeoms[count]->bbox )
1258  {
1259  box = gbox_copy(lwgeoms[count]->bbox);
1260  }
1261  }
1262  else
1263  {
1264  /* Check SRID homogeneity */
1265  if ( lwgeoms[count]->srid != srid )
1266  {
1267  elog(ERROR,
1268  "Operation on mixed SRID geometries");
1269  PG_RETURN_NULL();
1270  }
1271 
1272  /* COMPUTE_BBOX WHEN_SIMPLE */
1273  if ( box )
1274  {
1275  if ( lwgeoms[count]->bbox )
1276  {
1277  box->xmin = Min(box->xmin, lwgeoms[count]->bbox->xmin);
1278  box->ymin = Min(box->ymin, lwgeoms[count]->bbox->ymin);
1279  box->xmax = Max(box->xmax, lwgeoms[count]->bbox->xmax);
1280  box->ymax = Max(box->ymax, lwgeoms[count]->bbox->ymax);
1281  }
1282  else
1283  {
1284  pfree(box);
1285  box = NULL;
1286  }
1287  }
1288  }
1289 
1290  lwgeom_drop_srid(lwgeoms[count]);
1291  lwgeom_drop_bbox(lwgeoms[count]);
1292 
1293  /* Output type not initialized */
1294  if ( ! outtype )
1295  {
1296  /* Input is single, make multi */
1297  if ( ! lwtype_is_collection(intype) )
1298  outtype = lwtype_get_collectiontype(intype);
1299  /* Input is multi, make collection */
1300  else
1301  outtype = COLLECTIONTYPE;
1302  }
1303 
1304  /* Input type not compatible with output */
1305  /* make output type a collection */
1306  else if ( outtype != COLLECTIONTYPE && intype != outtype-3 )
1307  {
1308  outtype = COLLECTIONTYPE;
1309  }
1310 
1311  count++;
1312  }
1313 
1314  /* Advance NULL bitmap */
1315  if (bitmap)
1316  {
1317  bitmask <<= 1;
1318  if (bitmask == 0x100)
1319  {
1320  bitmap++;
1321  bitmask = 1;
1322  }
1323  }
1324 
1325  }
1326 
1327  POSTGIS_DEBUGF(3, "LWGEOM_collect_garray: outtype = %d", outtype);
1328 
1329  /* If we have been passed a complete set of NULLs then return NULL */
1330  if (!outtype)
1331  {
1332  PG_RETURN_NULL();
1333  }
1334  else
1335  {
1336  outlwg = (LWGEOM *)lwcollection_construct(
1337  outtype, srid,
1338  box, count, lwgeoms);
1339 
1340  result = geometry_serialize(outlwg);
1341 
1342  PG_RETURN_POINTER(result);
1343  }
1344 }
1345 
1351 Datum LWGEOM_line_from_mpoint(PG_FUNCTION_ARGS)
1352 {
1353  GSERIALIZED *ingeom, *result;
1354  LWLINE *lwline;
1355  LWMPOINT *mpoint;
1356 
1357  POSTGIS_DEBUG(2, "LWGEOM_line_from_mpoint called");
1358 
1359  /* Get input GSERIALIZED and deserialize it */
1360  ingeom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
1361 
1362  if ( gserialized_get_type(ingeom) != MULTIPOINTTYPE )
1363  {
1364  elog(ERROR, "makeline: input must be a multipoint");
1365  PG_RETURN_NULL(); /* input is not a multipoint */
1366  }
1367 
1368  mpoint = lwgeom_as_lwmpoint(lwgeom_from_gserialized(ingeom));
1369  lwline = lwline_from_lwmpoint(mpoint->srid, mpoint);
1370  if ( ! lwline )
1371  {
1372  PG_FREE_IF_COPY(ingeom, 0);
1373  elog(ERROR, "makeline: lwline_from_lwmpoint returned NULL");
1374  PG_RETURN_NULL();
1375  }
1376 
1377  result = geometry_serialize(lwline_as_lwgeom(lwline));
1378 
1379  PG_FREE_IF_COPY(ingeom, 0);
1380  lwline_free(lwline);
1381 
1382  PG_RETURN_POINTER(result);
1383 }
1384 
1391 Datum LWGEOM_makeline_garray(PG_FUNCTION_ARGS)
1392 {
1393  Datum datum;
1394  ArrayType *array;
1395  int nelems;
1396  GSERIALIZED *result=NULL;
1397  LWGEOM **geoms;
1398  LWGEOM *outlwg;
1399  uint32 ngeoms;
1400  int i;
1401  size_t offset;
1402  int srid=SRID_UNKNOWN;
1403 
1404  bits8 *bitmap;
1405  int bitmask;
1406 
1407  POSTGIS_DEBUG(2, "LWGEOM_makeline_garray called.");
1408 
1409  /* Get input datum */
1410  datum = PG_GETARG_DATUM(0);
1411 
1412  /* Return null on null input */
1413  if ( (Pointer *)datum == NULL )
1414  {
1415  elog(NOTICE, "NULL input");
1416  PG_RETURN_NULL();
1417  }
1418 
1419  /* Get actual ArrayType */
1420  array = DatumGetArrayTypeP(datum);
1421 
1422  POSTGIS_DEBUG(3, "LWGEOM_makeline_garray: array detoasted");
1423 
1424  /* Get number of geometries in array */
1425  nelems = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
1426 
1427  POSTGIS_DEBUGF(3, "LWGEOM_makeline_garray: array has %d elements", nelems);
1428 
1429  /* Return null on 0-elements input array */
1430  if ( nelems == 0 )
1431  {
1432  elog(NOTICE, "0 elements input array");
1433  PG_RETURN_NULL();
1434  }
1435 
1436  /*
1437  * Deserialize all point geometries in array into the
1438  * geoms pointers array.
1439  * Count actual number of points.
1440  */
1441 
1442  /* possibly more then required */
1443  geoms = palloc(sizeof(LWGEOM *)*nelems);
1444  ngeoms = 0;
1445  offset = 0;
1446  bitmap = ARR_NULLBITMAP(array);
1447  bitmask = 1;
1448  for (i=0; i<nelems; i++)
1449  {
1450  /* Don't do anything for NULL values */
1451  if ((bitmap && (*bitmap & bitmask) != 0) || !bitmap)
1452  {
1453  GSERIALIZED *geom = (GSERIALIZED *)(ARR_DATA_PTR(array)+offset);
1454  offset += INTALIGN(VARSIZE(geom));
1455 
1456  if ( gserialized_get_type(geom) != POINTTYPE && gserialized_get_type(geom) != LINETYPE ) continue;
1457 
1458  geoms[ngeoms++] =
1460 
1461  /* Check SRID homogeneity */
1462  if ( ngeoms == 1 )
1463  {
1464  /* Get first geometry SRID */
1465  srid = geoms[ngeoms-1]->srid;
1466  /* TODO: also get ZMflags */
1467  }
1468  else
1469  {
1470  if ( geoms[ngeoms-1]->srid != srid )
1471  {
1472  elog(ERROR,
1473  "Operation on mixed SRID geometries");
1474  PG_RETURN_NULL();
1475  }
1476  }
1477 
1478  POSTGIS_DEBUGF(3, "LWGEOM_makeline_garray: element %d deserialized", i);
1479  }
1480 
1481  /* Advance NULL bitmap */
1482  if (bitmap)
1483  {
1484  bitmask <<= 1;
1485  if (bitmask == 0x100)
1486  {
1487  bitmap++;
1488  bitmask = 1;
1489  }
1490  }
1491  }
1492 
1493  /* Return null on 0-points input array */
1494  if ( ngeoms == 0 )
1495  {
1496  /* TODO: should we return LINESTRING EMPTY here ? */
1497  elog(NOTICE, "No points or linestrings in input array");
1498  PG_RETURN_NULL();
1499  }
1500 
1501  POSTGIS_DEBUGF(3, "LWGEOM_makeline_garray: elements: %d", ngeoms);
1502 
1503  outlwg = (LWGEOM *)lwline_from_lwgeom_array(srid, ngeoms, geoms);
1504 
1505  result = geometry_serialize(outlwg);
1506 
1507  PG_RETURN_POINTER(result);
1508 }
1509 
1515 Datum LWGEOM_makeline(PG_FUNCTION_ARGS)
1516 {
1517  GSERIALIZED *pglwg1, *pglwg2;
1518  GSERIALIZED *result=NULL;
1519  LWGEOM *lwgeoms[2];
1520  LWLINE *outline;
1521 
1522  POSTGIS_DEBUG(2, "LWGEOM_makeline called.");
1523 
1524  /* Get input datum */
1525  pglwg1 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
1526  pglwg2 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
1527 
1528  if ( (gserialized_get_type(pglwg1) != POINTTYPE && gserialized_get_type(pglwg1) != LINETYPE) ||
1529  (gserialized_get_type(pglwg2) != POINTTYPE && gserialized_get_type(pglwg2) != LINETYPE) )
1530  {
1531  elog(ERROR, "Input geometries must be points or lines");
1532  PG_RETURN_NULL();
1533  }
1534 
1536 
1537  lwgeoms[0] = lwgeom_from_gserialized(pglwg1);
1538  lwgeoms[1] = lwgeom_from_gserialized(pglwg2);
1539 
1540  outline = lwline_from_lwgeom_array(lwgeoms[0]->srid, 2, lwgeoms);
1541 
1542  result = geometry_serialize((LWGEOM *)outline);
1543 
1544  PG_FREE_IF_COPY(pglwg1, 0);
1545  PG_FREE_IF_COPY(pglwg2, 1);
1546  lwgeom_free(lwgeoms[0]);
1547  lwgeom_free(lwgeoms[1]);
1548 
1549  PG_RETURN_POINTER(result);
1550 }
1551 
1557 Datum LWGEOM_makepoly(PG_FUNCTION_ARGS)
1558 {
1559  GSERIALIZED *pglwg1;
1560  ArrayType *array=NULL;
1561  GSERIALIZED *result=NULL;
1562  const LWLINE *shell=NULL;
1563  const LWLINE **holes=NULL;
1564  LWPOLY *outpoly;
1565  uint32 nholes=0;
1566  uint32 i;
1567  size_t offset=0;
1568 
1569  POSTGIS_DEBUG(2, "LWGEOM_makepoly called.");
1570 
1571  /* Get input shell */
1572  pglwg1 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
1573  if ( gserialized_get_type(pglwg1) != LINETYPE )
1574  {
1575  lwerror("Shell is not a line");
1576  }
1577  shell = lwgeom_as_lwline(lwgeom_from_gserialized(pglwg1));
1578 
1579  /* Get input holes if any */
1580  if ( PG_NARGS() > 1 )
1581  {
1582  array = PG_GETARG_ARRAYTYPE_P(1);
1583  nholes = ArrayGetNItems(ARR_NDIM(array), ARR_DIMS(array));
1584  holes = lwalloc(sizeof(LWLINE *)*nholes);
1585  for (i=0; i<nholes; i++)
1586  {
1587  GSERIALIZED *g = (GSERIALIZED *)(ARR_DATA_PTR(array)+offset);
1588  LWLINE *hole;
1589  offset += INTALIGN(VARSIZE(g));
1590  if ( gserialized_get_type(g) != LINETYPE )
1591  {
1592  lwerror("Hole %d is not a line", i);
1593  }
1595  holes[i] = hole;
1596  }
1597  }
1598 
1599  outpoly = lwpoly_from_lwlines(shell, nholes, holes);
1600  POSTGIS_DEBUGF(3, "%s", lwgeom_summary((LWGEOM*)outpoly, 0));
1601  result = geometry_serialize((LWGEOM *)outpoly);
1602 
1603  lwline_free((LWLINE*)shell);
1604  PG_FREE_IF_COPY(pglwg1, 0);
1605 
1606  for (i=0; i<nholes; i++)
1607  {
1608  lwline_free((LWLINE*)holes[i]);
1609  }
1610 
1611  PG_RETURN_POINTER(result);
1612 }
1613 
1620 Datum LWGEOM_expand(PG_FUNCTION_ARGS)
1621 {
1622  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
1623  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
1624  double d = PG_GETARG_FLOAT8(1);
1625  POINT4D pt;
1626  POINTARRAY *pa;
1627  POINTARRAY **ppa;
1628  LWPOLY *poly;
1630  GBOX gbox;
1631 
1632  POSTGIS_DEBUG(2, "LWGEOM_expand called.");
1633 
1634  /* Can't expand an empty */
1635  if ( lwgeom_is_empty(lwgeom) )
1636  {
1637  lwgeom_free(lwgeom);
1638  PG_RETURN_POINTER(geom);
1639  }
1640 
1641  /* Can't expand something with no gbox! */
1642  if ( LW_FAILURE == lwgeom_calculate_gbox(lwgeom, &gbox) )
1643  {
1644  lwgeom_free(lwgeom);
1645  PG_RETURN_POINTER(geom);
1646  }
1647 
1648  gbox_expand(&gbox, d);
1649 
1650  pa = ptarray_construct_empty(lwgeom_has_z(lwgeom), lwgeom_has_m(lwgeom), 5);
1651 
1652  /* Assign coordinates to POINT2D array */
1653  pt.x = gbox.xmin;
1654  pt.y = gbox.ymin;
1655  pt.z = gbox.zmin;
1656  pt.m = gbox.mmin;
1657  ptarray_append_point(pa, &pt, LW_TRUE);
1658  pt.x = gbox.xmin;
1659  pt.y = gbox.ymax;
1660  pt.z = gbox.zmin;
1661  pt.m = gbox.mmin;
1662  ptarray_append_point(pa, &pt, LW_TRUE);
1663  pt.x = gbox.xmax;
1664  pt.y = gbox.ymax;
1665  pt.z = gbox.zmax;
1666  pt.m = gbox.mmax;
1667  ptarray_append_point(pa, &pt, LW_TRUE);
1668  pt.x = gbox.xmax;
1669  pt.y = gbox.ymin;
1670  pt.z = gbox.zmax;
1671  pt.m = gbox.mmax;
1672  ptarray_append_point(pa, &pt, LW_TRUE);
1673  pt.x = gbox.xmin;
1674  pt.y = gbox.ymin;
1675  pt.z = gbox.zmin;
1676  pt.m = gbox.mmin;
1677  ptarray_append_point(pa, &pt, LW_TRUE);
1678 
1679  /* Construct point array */
1680  ppa = lwalloc(sizeof(POINTARRAY*));
1681  ppa[0] = pa;
1682 
1683  /* Construct polygon */
1684  poly = lwpoly_construct(lwgeom->srid, NULL, 1, ppa);
1686 
1687  /* Construct GSERIALIZED */
1688  result = geometry_serialize(lwpoly_as_lwgeom(poly));
1689 
1691  lwgeom_free(lwgeom);
1692  PG_FREE_IF_COPY(geom, 0);
1693 
1694  PG_RETURN_POINTER(result);
1695 }
1696 
1699 Datum LWGEOM_to_BOX(PG_FUNCTION_ARGS)
1700 {
1701  GSERIALIZED *pg_lwgeom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
1702  LWGEOM *lwgeom = lwgeom_from_gserialized(pg_lwgeom);
1703  GBOX gbox;
1704  int result;
1705  BOX *out = NULL;
1706 
1707  /* Zero out flags */
1708  gbox_init(&gbox);
1709 
1710  /* Calculate the GBOX of the geometry */
1711  result = lwgeom_calculate_gbox(lwgeom, &gbox);
1712 
1713  /* Clean up memory */
1714  lwfree(lwgeom);
1715  PG_FREE_IF_COPY(pg_lwgeom, 0);
1716 
1717  /* Null on failure */
1718  if ( ! result )
1719  PG_RETURN_NULL();
1720 
1721  out = lwalloc(sizeof(BOX));
1722  out->low.x = gbox.xmin;
1723  out->low.y = gbox.ymin;
1724  out->high.x = gbox.xmax;
1725  out->high.y = gbox.ymax;
1726  PG_RETURN_POINTER(out);
1727 }
1728 
1735 Datum LWGEOM_envelope(PG_FUNCTION_ARGS)
1736 {
1737  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
1738  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
1739  int srid = lwgeom->srid;
1740  POINT4D pt;
1741  GBOX box;
1742  POINTARRAY *pa;
1744 
1745 
1746  if ( lwgeom_is_empty(lwgeom) )
1747  {
1748  /* must be the EMPTY geometry */
1749  PG_RETURN_POINTER(geom);
1750  }
1751 
1752  if ( lwgeom_calculate_gbox(lwgeom, &box) == LW_FAILURE )
1753  {
1754  /* must be the EMPTY geometry */
1755  PG_RETURN_POINTER(geom);
1756  }
1757 
1758  /*
1759  * Alter envelope type so that a valid geometry is always
1760  * returned depending upon the size of the geometry. The
1761  * code makes the following assumptions:
1762  * - If the bounding box is a single point then return a
1763  * POINT geometry
1764  * - If the bounding box represents either a horizontal or
1765  * vertical line, return a LINESTRING geometry
1766  * - Otherwise return a POLYGON
1767  */
1768 
1769  if ( (box.xmin == box.xmax) && (box.ymin == box.ymax) )
1770  {
1771  /* Construct and serialize point */
1772  LWPOINT *point = lwpoint_make2d(srid, box.xmin, box.ymin);
1773  result = geometry_serialize(lwpoint_as_lwgeom(point));
1774  lwpoint_free(point);
1775  }
1776  else if ( (box.xmin == box.xmax) || (box.ymin == box.ymax) )
1777  {
1778  LWLINE *line;
1779  /* Construct point array */
1780  pa = ptarray_construct_empty(0, 0, 2);
1781 
1782  /* Assign coordinates to POINT2D array */
1783  pt.x = box.xmin;
1784  pt.y = box.ymin;
1785  ptarray_append_point(pa, &pt, LW_TRUE);
1786  pt.x = box.xmax;
1787  pt.y = box.ymax;
1788  ptarray_append_point(pa, &pt, LW_TRUE);
1789 
1790  /* Construct and serialize linestring */
1791  line = lwline_construct(srid, NULL, pa);
1792  result = geometry_serialize(lwline_as_lwgeom(line));
1793  lwline_free(line);
1794  }
1795  else
1796  {
1797  LWPOLY *poly;
1798  POINTARRAY **ppa = lwalloc(sizeof(POINTARRAY*));
1799  pa = ptarray_construct_empty(0, 0, 5);
1800  ppa[0] = pa;
1801 
1802  /* Assign coordinates to POINT2D array */
1803  pt.x = box.xmin;
1804  pt.y = box.ymin;
1805  ptarray_append_point(pa, &pt, LW_TRUE);
1806  pt.x = box.xmin;
1807  pt.y = box.ymax;
1808  ptarray_append_point(pa, &pt, LW_TRUE);
1809  pt.x = box.xmax;
1810  pt.y = box.ymax;
1811  ptarray_append_point(pa, &pt, LW_TRUE);
1812  pt.x = box.xmax;
1813  pt.y = box.ymin;
1814  ptarray_append_point(pa, &pt, LW_TRUE);
1815  pt.x = box.xmin;
1816  pt.y = box.ymin;
1817  ptarray_append_point(pa, &pt, LW_TRUE);
1818 
1819  /* Construct polygon */
1820  poly = lwpoly_construct(srid, NULL, 1, ppa);
1821  result = geometry_serialize(lwpoly_as_lwgeom(poly));
1822  lwpoly_free(poly);
1823  }
1824 
1825  PG_FREE_IF_COPY(geom, 0);
1826 
1827  PG_RETURN_POINTER(result);
1828 }
1829 
1831 Datum LWGEOM_isempty(PG_FUNCTION_ARGS)
1832 {
1833  GSERIALIZED *geom = (GSERIALIZED *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
1834  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
1835  bool empty = lwgeom_is_empty(lwgeom);
1836 
1837  lwgeom_free(lwgeom);
1838  PG_FREE_IF_COPY(geom, 0);
1839  PG_RETURN_BOOL(empty);
1840 }
1841 
1842 
1850 Datum LWGEOM_segmentize2d(PG_FUNCTION_ARGS)
1851 {
1852  GSERIALIZED *outgeom, *ingeom;
1853  double dist;
1854  LWGEOM *inlwgeom, *outlwgeom;
1855  int type;
1856 
1857  POSTGIS_DEBUG(2, "LWGEOM_segmentize2d called");
1858 
1859  ingeom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
1860  dist = PG_GETARG_FLOAT8(1);
1861  type = gserialized_get_type(ingeom);
1862 
1863  /* Avoid types we cannot segmentize. */
1864  if ( (type == POINTTYPE) ||
1865  (type == MULTIPOINTTYPE) ||
1866  (type == TRIANGLETYPE) ||
1867  (type == TINTYPE) ||
1868  (type == POLYHEDRALSURFACETYPE) )
1869  {
1870  PG_RETURN_POINTER(ingeom);
1871  }
1872 
1873  if ( dist <= 0 ) {
1874  /* Protect from knowingly infinite loops, see #1799 */
1875  /* Note that we'll end out of memory anyway for other small distances */
1876  elog(ERROR, "ST_Segmentize: invalid max_distance %g (must be >= 0)", dist);
1877  PG_RETURN_NULL();
1878  }
1879 
1880  inlwgeom = lwgeom_from_gserialized(ingeom);
1881 
1882  if ( lwgeom_is_empty(inlwgeom) )
1883  {
1884  lwgeom_free(inlwgeom);
1885  PG_RETURN_POINTER(ingeom);
1886  }
1887 
1888  outlwgeom = lwgeom_segmentize2d(inlwgeom, dist);
1889 
1890  /* Copy input bounding box if any */
1891  if ( inlwgeom->bbox )
1892  outlwgeom->bbox = gbox_copy(inlwgeom->bbox);
1893 
1894  outgeom = geometry_serialize(outlwgeom);
1895 
1896  //lwgeom_free(outlwgeom); /* TODO fix lwgeom_clone / ptarray_clone_deep for consistent semantics */
1897  lwgeom_free(inlwgeom);
1898 
1899  PG_FREE_IF_COPY(ingeom, 0);
1900 
1901  PG_RETURN_POINTER(outgeom);
1902 }
1903 
1906 Datum LWGEOM_reverse(PG_FUNCTION_ARGS)
1907 {
1908  GSERIALIZED *geom;
1909  LWGEOM *lwgeom;
1910 
1911  POSTGIS_DEBUG(2, "LWGEOM_reverse called");
1912 
1913  geom = (GSERIALIZED *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
1914 
1915  lwgeom = lwgeom_from_gserialized(geom);
1916  lwgeom_reverse(lwgeom);
1917 
1918  geom = geometry_serialize(lwgeom);
1919 
1920  PG_RETURN_POINTER(geom);
1921 }
1922 
1925 Datum LWGEOM_force_clockwise_poly(PG_FUNCTION_ARGS)
1926 {
1927  GSERIALIZED *ingeom, *outgeom;
1928  LWGEOM *lwgeom;
1929 
1930  POSTGIS_DEBUG(2, "LWGEOM_force_clockwise_poly called");
1931 
1932  ingeom = (GSERIALIZED *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
1933 
1934  lwgeom = lwgeom_from_gserialized(ingeom);
1935  lwgeom_force_clockwise(lwgeom);
1936 
1937  outgeom = geometry_serialize(lwgeom);
1938 
1939  lwgeom_free(lwgeom);
1940  PG_FREE_IF_COPY(ingeom, 0);
1941  PG_RETURN_POINTER(outgeom);
1942 }
1943 
1946 Datum LWGEOM_noop(PG_FUNCTION_ARGS)
1947 {
1948  GSERIALIZED *in, *out;
1949  LWGEOM *lwgeom;
1950 
1951  POSTGIS_DEBUG(2, "LWGEOM_noop called");
1952 
1953  in = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
1954 
1955  lwgeom = lwgeom_from_gserialized(in);
1956 
1957  POSTGIS_DEBUGF(3, "Deserialized: %s", lwgeom_summary(lwgeom, 0));
1958 
1959  out = geometry_serialize(lwgeom);
1960 
1961  lwgeom_free(lwgeom);
1962  PG_FREE_IF_COPY(in, 0);
1963 
1964  PG_RETURN_POINTER(out);
1965 }
1966 
1975 Datum LWGEOM_zmflag(PG_FUNCTION_ARGS)
1976 {
1977  GSERIALIZED *in;
1978  int ret = 0;
1979 
1980  in = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
1981  if ( gserialized_has_z(in) ) ret += 2;
1982  if ( gserialized_has_m(in) ) ret += 1;
1983  PG_FREE_IF_COPY(in, 0);
1984  PG_RETURN_INT16(ret);
1985 }
1986 
1988 Datum LWGEOM_hasz(PG_FUNCTION_ARGS)
1989 {
1990  GSERIALIZED *in = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
1991  PG_RETURN_BOOL(gserialized_has_z(in));
1992 }
1993 
1995 Datum LWGEOM_hasm(PG_FUNCTION_ARGS)
1996 {
1997  GSERIALIZED *in = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
1998  PG_RETURN_BOOL(gserialized_has_m(in));
1999 }
2000 
2001 
2003 Datum LWGEOM_hasBBOX(PG_FUNCTION_ARGS)
2004 {
2005  GSERIALIZED *in = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
2006  char res = gserialized_has_bbox(in);
2007  PG_FREE_IF_COPY(in, 0);
2008  PG_RETURN_BOOL(res);
2009 }
2010 
2013 Datum LWGEOM_ndims(PG_FUNCTION_ARGS)
2014 {
2015  GSERIALIZED *in;
2016  int ret;
2017 
2018  in = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
2019  ret = (gserialized_ndims(in));
2020  PG_FREE_IF_COPY(in, 0);
2021  PG_RETURN_INT16(ret);
2022 }
2023 
2026 Datum LWGEOM_same(PG_FUNCTION_ARGS)
2027 {
2028  GSERIALIZED *g1 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
2029  GSERIALIZED *g2 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
2030  LWGEOM *lwg1, *lwg2;
2031  bool result;
2032 
2033  if ( gserialized_get_type(g1) != gserialized_get_type(g2) )
2034  {
2035  PG_FREE_IF_COPY(g1, 0);
2036  PG_FREE_IF_COPY(g2, 1);
2037  PG_RETURN_BOOL(FALSE); /* different types */
2038  }
2039 
2040  if ( gserialized_get_zm(g1) != gserialized_get_zm(g2) )
2041  {
2042  PG_FREE_IF_COPY(g1, 0);
2043  PG_FREE_IF_COPY(g2, 1);
2044  PG_RETURN_BOOL(FALSE); /* different dimensions */
2045  }
2046 
2047  /* ok, deserialize. */
2048  lwg1 = lwgeom_from_gserialized(g1);
2049  lwg2 = lwgeom_from_gserialized(g2);
2050 
2051  /* invoke appropriate function */
2052  result = lwgeom_same(lwg1, lwg2);
2053 
2054  /* Relase memory */
2055  lwgeom_free(lwg1);
2056  lwgeom_free(lwg2);
2057  PG_FREE_IF_COPY(g1, 0);
2058  PG_FREE_IF_COPY(g2, 1);
2059 
2060  PG_RETURN_BOOL(result);
2061 }
2062 
2064 Datum ST_MakeEnvelope(PG_FUNCTION_ARGS)
2065 {
2066  LWPOLY *poly;
2068  POINTARRAY **pa;
2069  POINT4D p;
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  pa = (POINTARRAY**)palloc(sizeof(POINTARRAY**));
2084  pa[0] = ptarray_construct_empty(0, 0, 5);
2085 
2086  /* 1st point */
2087  p.x = x1;
2088  p.y = y1;
2089  ptarray_append_point(pa[0], &p, LW_TRUE);
2090 
2091  /* 2nd point */
2092  p.x = x1;
2093  p.y = y2;
2094  ptarray_append_point(pa[0], &p, LW_TRUE);
2095 
2096  /* 3rd point */
2097  p.x = x2;
2098  p.y = y2;
2099  ptarray_append_point(pa[0], &p, LW_TRUE);
2100 
2101  /* 4th point */
2102  p.x = x2;
2103  p.y = y1;
2104  ptarray_append_point(pa[0], &p, LW_TRUE);
2105 
2106  /* 5th point */
2107  p.x = x1;
2108  p.y = y1;
2109  ptarray_append_point(pa[0], &p, LW_TRUE);
2110 
2111  poly = lwpoly_construct(srid, NULL, 1, pa);
2113 
2114  result = geometry_serialize(lwpoly_as_lwgeom(poly));
2115  lwpoly_free(poly);
2116 
2117  PG_RETURN_POINTER(result);
2118 }
2119 
2121 Datum ST_IsCollection(PG_FUNCTION_ARGS)
2122 {
2123  GSERIALIZED *geom;
2124  int type;
2125  size_t size;
2126 
2127  /* Pull only a small amount of the tuple, enough to get the type. */
2128  /* header + srid/flags + bbox? + type number */
2129  size = VARHDRSZ + 8 + 32 + 4;
2130 
2131  geom = (GSERIALIZED*)PG_DETOAST_DATUM_SLICE(PG_GETARG_DATUM(0), 0, size);
2132 
2133  type = gserialized_get_type(geom);
2134  PG_RETURN_BOOL(lwtype_is_collection(type));
2135 }
2136 
2138 Datum LWGEOM_makepoint(PG_FUNCTION_ARGS)
2139 {
2140  double x,y,z,m;
2141  LWPOINT *point;
2143 
2144  POSTGIS_DEBUG(2, "LWGEOM_makepoint called");
2145 
2146  x = PG_GETARG_FLOAT8(0);
2147  y = PG_GETARG_FLOAT8(1);
2148 
2149  if ( PG_NARGS() == 2 ) point = lwpoint_make2d(SRID_UNKNOWN, x, y);
2150  else if ( PG_NARGS() == 3 )
2151  {
2152  z = PG_GETARG_FLOAT8(2);
2153  point = lwpoint_make3dz(SRID_UNKNOWN, x, y, z);
2154  }
2155  else if ( PG_NARGS() == 4 )
2156  {
2157  z = PG_GETARG_FLOAT8(2);
2158  m = PG_GETARG_FLOAT8(3);
2159  point = lwpoint_make4d(SRID_UNKNOWN, x, y, z, m);
2160  }
2161  else
2162  {
2163  elog(ERROR, "LWGEOM_makepoint: unsupported number of args: %d",
2164  PG_NARGS());
2165  PG_RETURN_NULL();
2166  }
2167 
2168  result = geometry_serialize((LWGEOM *)point);
2169 
2170  PG_RETURN_POINTER(result);
2171 }
2172 
2174 Datum LWGEOM_makepoint3dm(PG_FUNCTION_ARGS)
2175 {
2176  double x,y,m;
2177  LWPOINT *point;
2179 
2180  POSTGIS_DEBUG(2, "LWGEOM_makepoint3dm called.");
2181 
2182  x = PG_GETARG_FLOAT8(0);
2183  y = PG_GETARG_FLOAT8(1);
2184  m = PG_GETARG_FLOAT8(2);
2185 
2186  point = lwpoint_make3dm(SRID_UNKNOWN, x, y, m);
2187  result = geometry_serialize((LWGEOM *)point);
2188 
2189  PG_RETURN_POINTER(result);
2190 }
2191 
2193 Datum LWGEOM_addpoint(PG_FUNCTION_ARGS)
2194 {
2195  GSERIALIZED *pglwg1, *pglwg2, *result;
2196  LWPOINT *point;
2197  LWLINE *line, *linecopy;
2198  int where = -1;
2199 
2200  POSTGIS_DEBUG(2, "LWGEOM_addpoint called.");
2201 
2202  pglwg1 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
2203  pglwg2 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
2204 
2205  if ( PG_NARGS() > 2 )
2206  {
2207  where = PG_GETARG_INT32(2);
2208  }
2209 
2210  if ( gserialized_get_type(pglwg1) != LINETYPE )
2211  {
2212  elog(ERROR, "First argument must be a LINESTRING");
2213  PG_RETURN_NULL();
2214  }
2215 
2216  if ( gserialized_get_type(pglwg2) != POINTTYPE )
2217  {
2218  elog(ERROR, "Second argument must be a POINT");
2219  PG_RETURN_NULL();
2220  }
2221 
2222  line = lwgeom_as_lwline(lwgeom_from_gserialized(pglwg1));
2223 
2224  if ( where == -1 ) where = line->points->npoints;
2225  else if ( where < 0 || where > line->points->npoints )
2226  {
2227  elog(ERROR, "Invalid offset");
2228  PG_RETURN_NULL();
2229  }
2230 
2231  point = lwgeom_as_lwpoint(lwgeom_from_gserialized(pglwg2));
2233  lwline_free(line);
2234 
2235  if ( lwline_add_lwpoint(linecopy, point, where) == LW_FAILURE )
2236  {
2237  elog(ERROR, "Point insert failed");
2238  PG_RETURN_NULL();
2239  }
2240 
2241  result = geometry_serialize(lwline_as_lwgeom(linecopy));
2242 
2243  /* Release memory */
2244  PG_FREE_IF_COPY(pglwg1, 0);
2245  PG_FREE_IF_COPY(pglwg2, 1);
2246  lwpoint_free(point);
2247 
2248  PG_RETURN_POINTER(result);
2249 
2250 }
2251 
2253 Datum LWGEOM_removepoint(PG_FUNCTION_ARGS)
2254 {
2255  GSERIALIZED *pglwg1, *result;
2256  LWLINE *line, *outline;
2257  uint32 which;
2258 
2259  POSTGIS_DEBUG(2, "LWGEOM_removepoint called.");
2260 
2261  pglwg1 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
2262  which = PG_GETARG_INT32(1);
2263 
2264  if ( gserialized_get_type(pglwg1) != LINETYPE )
2265  {
2266  elog(ERROR, "First argument must be a LINESTRING");
2267  PG_RETURN_NULL();
2268  }
2269 
2270  line = lwgeom_as_lwline(lwgeom_from_gserialized(pglwg1));
2271 
2272  if ( which > line->points->npoints-1 )
2273  {
2274  elog(ERROR, "Point index out of range (%d..%d)", 0, line->points->npoints-1);
2275  PG_RETURN_NULL();
2276  }
2277 
2278  if ( line->points->npoints < 3 )
2279  {
2280  elog(ERROR, "Can't remove points from a single segment line");
2281  PG_RETURN_NULL();
2282  }
2283 
2284  outline = lwline_removepoint(line, which);
2285  /* Release memory */
2286  lwline_free(line);
2287 
2288  result = geometry_serialize((LWGEOM *)outline);
2289  lwline_free(outline);
2290 
2291  PG_FREE_IF_COPY(pglwg1, 0);
2292  PG_RETURN_POINTER(result);
2293 }
2294 
2296 Datum LWGEOM_setpoint_linestring(PG_FUNCTION_ARGS)
2297 {
2298  GSERIALIZED *pglwg1, *pglwg2, *result;
2299  LWGEOM *lwg;
2300  LWLINE *line;
2301  LWPOINT *lwpoint;
2302  POINT4D newpoint;
2303  uint32 which;
2304 
2305  POSTGIS_DEBUG(2, "LWGEOM_setpoint_linestring called.");
2306 
2307  /* we copy input as we're going to modify it */
2308  pglwg1 = (GSERIALIZED *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
2309 
2310  which = PG_GETARG_INT32(1);
2311  pglwg2 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(2));
2312 
2313 
2314  /* Extract a POINT4D from the point */
2315  lwg = lwgeom_from_gserialized(pglwg2);
2316  lwpoint = lwgeom_as_lwpoint(lwg);
2317  if ( ! lwpoint )
2318  {
2319  elog(ERROR, "Third argument must be a POINT");
2320  PG_RETURN_NULL();
2321  }
2322  getPoint4d_p(lwpoint->point, 0, &newpoint);
2323  lwpoint_free(lwpoint);
2324  PG_FREE_IF_COPY(pglwg2, 2);
2325 
2326  lwg = lwgeom_from_gserialized(pglwg1);
2327  line = lwgeom_as_lwline(lwg);
2328  if ( ! line )
2329  {
2330  elog(ERROR, "First argument must be a LINESTRING");
2331  PG_RETURN_NULL();
2332  }
2333  if ( lwgeom_is_empty(lwg) )
2334  {
2335  elog(ERROR, "Cannot set point values on EMPTY geometry, use ST_AddPoint to add points");
2336  PG_RETURN_NULL();
2337  }
2338  if ( which > line->points->npoints-1 )
2339  {
2340  elog(ERROR, "Point index out of range (%d..%d)", 0, line->points->npoints-1);
2341  PG_RETURN_NULL();
2342  }
2343 
2344  /*
2345  * This will change pointarray of the serialized pglwg1,
2346  */
2347  lwline_setPoint4d(line, which, &newpoint);
2348  result = geometry_serialize((LWGEOM *)line);
2349 
2350  /* Release memory */
2351  lwline_free(line);
2352  pfree(pglwg1); /* we forced copy, POINARRAY is released now */
2353 
2354  PG_RETURN_POINTER(result);
2355 }
2356 
2357 /* convert LWGEOM to ewkt (in TEXT format) */
2359 Datum LWGEOM_asEWKT(PG_FUNCTION_ARGS)
2360 {
2361  GSERIALIZED *geom;
2362  LWGEOM *lwgeom;
2363  char *wkt;
2364  size_t wkt_size;
2365  text *result;
2366 
2367  POSTGIS_DEBUG(2, "LWGEOM_asEWKT called.");
2368 
2369  geom = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
2370  lwgeom = lwgeom_from_gserialized(geom);
2371 
2372  /* Write to WKT and free the geometry */
2373  wkt = lwgeom_to_wkt(lwgeom, WKT_EXTENDED, DBL_DIG, &wkt_size);
2374  lwgeom_free(lwgeom);
2375 
2376  /* Write to text and free the WKT */
2377  result = cstring2text(wkt);
2378  pfree(wkt);
2379 
2380  /* Return the text */
2381  PG_FREE_IF_COPY(geom, 0);
2382  PG_RETURN_TEXT_P(result);
2383 }
2384 
2392 Datum LWGEOM_azimuth(PG_FUNCTION_ARGS)
2393 {
2394  GSERIALIZED *geom;
2395  LWPOINT *lwpoint;
2396  POINT2D p1, p2;
2397  double result;
2398  int srid;
2399 
2400  /* Extract first point */
2401  geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
2402  lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom));
2403  if ( ! lwpoint )
2404  {
2405  PG_FREE_IF_COPY(geom, 0);
2406  lwerror("Argument must be POINT geometries");
2407  PG_RETURN_NULL();
2408  }
2409  srid = lwpoint->srid;
2410  if ( ! getPoint2d_p(lwpoint->point, 0, &p1) )
2411  {
2412  PG_FREE_IF_COPY(geom, 0);
2413  lwerror("Error extracting point");
2414  PG_RETURN_NULL();
2415  }
2416  lwpoint_free(lwpoint);
2417  PG_FREE_IF_COPY(geom, 0);
2418 
2419  /* Extract second point */
2420  geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
2421  lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom));
2422  if ( ! lwpoint )
2423  {
2424  PG_FREE_IF_COPY(geom, 1);
2425  lwerror("Argument must be POINT geometries");
2426  PG_RETURN_NULL();
2427  }
2428  if ( lwpoint->srid != srid )
2429  {
2430  PG_FREE_IF_COPY(geom, 1);
2431  lwerror("Operation on mixed SRID geometries");
2432  PG_RETURN_NULL();
2433  }
2434  if ( ! getPoint2d_p(lwpoint->point, 0, &p2) )
2435  {
2436  PG_FREE_IF_COPY(geom, 1);
2437  lwerror("Error extracting point");
2438  PG_RETURN_NULL();
2439  }
2440  lwpoint_free(lwpoint);
2441  PG_FREE_IF_COPY(geom, 1);
2442 
2443  /* Standard return value for equality case */
2444  if ( (p1.x == p2.x) && (p1.y == p2.y) )
2445  {
2446  PG_RETURN_NULL();
2447  }
2448 
2449  /* Compute azimuth */
2450  if ( ! azimuth_pt_pt(&p1, &p2, &result) )
2451  {
2452  PG_RETURN_NULL();
2453  }
2454 
2455  PG_RETURN_FLOAT8(result);
2456 }
2457 
2458 /*
2459  * optimistic_overlap(Polygon P1, Multipolygon MP2, double dist)
2460  * returns true if P1 overlaps MP2
2461  * method: bbox check -
2462  * is separation < dist? no - return false (quick)
2463  * yes - return distance(P1,MP2) < dist
2464  */
2466 Datum optimistic_overlap(PG_FUNCTION_ARGS)
2467 {
2468  GSERIALIZED *pg_geom1 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
2469  GSERIALIZED *pg_geom2 = (GSERIALIZED*)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
2470  double dist = PG_GETARG_FLOAT8(2);
2471  GBOX g1_bvol;
2472  double calc_dist;
2473 
2474  LWGEOM *geom1 = lwgeom_from_gserialized(pg_geom1);
2475  LWGEOM *geom2 = lwgeom_from_gserialized(pg_geom2);
2476 
2477  if (geom1->srid != geom2->srid)
2478  {
2479  elog(ERROR,"optimistic_overlap:Operation on two GEOMETRIES with different SRIDs\\n");
2480  PG_RETURN_NULL();
2481  }
2482 
2483  if (geom1->type != POLYGONTYPE)
2484  {
2485  elog(ERROR,"optimistic_overlap: first arg isnt a polygon\n");
2486  PG_RETURN_NULL();
2487  }
2488 
2489  if (geom2->type != POLYGONTYPE && geom2->type != MULTIPOLYGONTYPE)
2490  {
2491  elog(ERROR,"optimistic_overlap: 2nd arg isnt a [multi-]polygon\n");
2492  PG_RETURN_NULL();
2493  }
2494 
2495  /*bbox check */
2496  gserialized_get_gbox_p(pg_geom1, &g1_bvol );
2497 
2498  g1_bvol.xmin = g1_bvol.xmin - dist;
2499  g1_bvol.ymin = g1_bvol.ymin - dist;
2500  g1_bvol.xmax = g1_bvol.xmax + dist;
2501  g1_bvol.ymax = g1_bvol.ymax + dist;
2502 
2503  if ( (g1_bvol.xmin > geom2->bbox->xmax) ||
2504  (g1_bvol.xmax < geom2->bbox->xmin) ||
2505  (g1_bvol.ymin > geom2->bbox->ymax) ||
2506  (g1_bvol.ymax < geom2->bbox->ymin) )
2507  {
2508  PG_RETURN_BOOL(FALSE); /*bbox not overlap */
2509  }
2510 
2511  /*
2512  * compute distances
2513  * should be a fast calc if they actually do intersect
2514  */
2515  calc_dist = DatumGetFloat8 ( DirectFunctionCall2(LWGEOM_mindistance2d, PointerGetDatum( pg_geom1 ), PointerGetDatum( pg_geom2 )));
2516 
2517  PG_RETURN_BOOL(calc_dist < dist);
2518 }
2519 
2520 
2521 /*affine transform geometry */
2523 Datum LWGEOM_affine(PG_FUNCTION_ARGS)
2524 {
2525  GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
2526  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
2527  GSERIALIZED *ret;
2528  AFFINE affine;
2529 
2530  affine.afac = PG_GETARG_FLOAT8(1);
2531  affine.bfac = PG_GETARG_FLOAT8(2);
2532  affine.cfac = PG_GETARG_FLOAT8(3);
2533  affine.dfac = PG_GETARG_FLOAT8(4);
2534  affine.efac = PG_GETARG_FLOAT8(5);
2535  affine.ffac = PG_GETARG_FLOAT8(6);
2536  affine.gfac = PG_GETARG_FLOAT8(7);
2537  affine.hfac = PG_GETARG_FLOAT8(8);
2538  affine.ifac = PG_GETARG_FLOAT8(9);
2539  affine.xoff = PG_GETARG_FLOAT8(10);
2540  affine.yoff = PG_GETARG_FLOAT8(11);
2541  affine.zoff = PG_GETARG_FLOAT8(12);
2542 
2543  POSTGIS_DEBUG(2, "LWGEOM_affine called.");
2544 
2545  lwgeom_affine(lwgeom, &affine);
2546 
2547  /* COMPUTE_BBOX TAINTING */
2548  if ( lwgeom->bbox )
2549  {
2550  lwgeom_drop_bbox(lwgeom);
2551  lwgeom_add_bbox(lwgeom);
2552  }
2553  ret = geometry_serialize(lwgeom);
2554 
2555  /* Release memory */
2556  lwgeom_free(lwgeom);
2557  PG_FREE_IF_COPY(geom, 0);
2558 
2559  PG_RETURN_POINTER(ret);
2560 }
2561 
2563 Datum ST_GeoHash(PG_FUNCTION_ARGS)
2564 {
2565 
2566  GSERIALIZED *geom = NULL;
2567  int precision = 0;
2568  char *geohash = NULL;
2569  text *result = NULL;
2570 
2571  if ( PG_ARGISNULL(0) )
2572  {
2573  PG_RETURN_NULL();
2574  }
2575 
2576  geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
2577 
2578  if ( ! PG_ARGISNULL(1) )
2579  {
2580  precision = PG_GETARG_INT32(1);
2581  }
2582 
2583  geohash = lwgeom_geohash((LWGEOM*)(lwgeom_from_gserialized(geom)), precision);
2584 
2585  if ( ! geohash )
2586  PG_RETURN_NULL();
2587 
2588  result = cstring2text(geohash);
2589  pfree(geohash);
2590 
2591  PG_RETURN_TEXT_P(result);
2592 }
2593 
2595 Datum ST_CollectionExtract(PG_FUNCTION_ARGS)
2596 {
2597  GSERIALIZED *input = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
2598  GSERIALIZED *output;
2599  LWGEOM *lwgeom = lwgeom_from_gserialized(input);
2600  LWGEOM *lwcol = NULL;
2601  int type = PG_GETARG_INT32(1);
2602  int lwgeom_type = lwgeom->type;
2603 
2604  /* Ensure the right type was input */
2605  if ( ! ( type == POINTTYPE || type == LINETYPE || type == POLYGONTYPE ) )
2606  {
2607  lwgeom_free(lwgeom);
2608  elog(ERROR, "ST_CollectionExtract: only point, linestring and polygon may be extracted");
2609  PG_RETURN_NULL();
2610  }
2611 
2612  /* Mirror non-collections right back */
2613  if ( ! lwgeom_is_collection(lwgeom) )
2614  {
2615  /* Non-collections of the matching type go back */
2616  if(lwgeom_type == type)
2617  {
2618  lwgeom_free(lwgeom);
2619  PG_RETURN_POINTER(input);
2620  }
2621  /* Others go back as EMPTY */
2622  else
2623  {
2624  lwcol = lwgeom_construct_empty(type, lwgeom->srid, FLAGS_GET_Z(lwgeom->flags), FLAGS_GET_M(lwgeom->flags));
2625  }
2626  }
2627  else
2628  {
2629  lwcol = lwcollection_as_lwgeom(lwcollection_extract((LWCOLLECTION*)lwgeom, type));
2630  }
2631 
2632 #if 0
2634  {
2635  lwgeom_free(lwgeom);
2636  PG_RETURN_NULL();
2637  }
2638 #endif
2639  output = geometry_serialize((LWGEOM*)lwcol);
2640  lwgeom_free(lwgeom);
2641  lwgeom_free(lwcol);
2642 
2643  PG_RETURN_POINTER(output);
2644 }
2645 
2647 Datum ST_CollectionHomogenize(PG_FUNCTION_ARGS)
2648 {
2649  GSERIALIZED *input = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
2650  GSERIALIZED *output;
2651  LWGEOM *lwgeom = lwgeom_from_gserialized(input);
2652  LWGEOM *lwoutput = NULL;
2653 
2654  lwoutput = lwgeom_homogenize(lwgeom);
2655  lwgeom_free(lwgeom);
2656  PG_FREE_IF_COPY(input, 0);
2657 
2658  if ( ! lwoutput )
2659  PG_RETURN_NULL();
2660 
2661  output = geometry_serialize(lwoutput);
2662  lwgeom_free(lwoutput);
2663 
2664  PG_RETURN_POINTER(output);
2665 }
2666 
2667 Datum ST_RemoveRepeatedPoints(PG_FUNCTION_ARGS);
2669 Datum ST_RemoveRepeatedPoints(PG_FUNCTION_ARGS)
2670 {
2671  GSERIALIZED *input = (GSERIALIZED *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
2672  GSERIALIZED *output;
2673  LWGEOM *lwgeom_in = lwgeom_from_gserialized(input);
2674  LWGEOM *lwgeom_out;
2675 
2676  /* lwnotice("ST_RemoveRepeatedPoints got %p", lwgeom_in); */
2677 
2678  lwgeom_out = lwgeom_remove_repeated_points(lwgeom_in);
2679  output = geometry_serialize(lwgeom_out);
2680 
2681  lwgeom_free(lwgeom_in);
2682  PG_FREE_IF_COPY(input, 0);
2683 
2684  PG_RETURN_POINTER(output);
2685 }
2686 
2687 Datum ST_FlipCoordinates(PG_FUNCTION_ARGS);
2689 Datum ST_FlipCoordinates(PG_FUNCTION_ARGS)
2690 {
2691  GSERIALIZED *input = (GSERIALIZED *)PG_DETOAST_DATUM_COPY(PG_GETARG_DATUM(0));
2692  GSERIALIZED *output;
2693  LWGEOM *lwgeom_in = lwgeom_from_gserialized(input);
2694  LWGEOM *lwgeom_out;
2695 
2696  lwgeom_out = lwgeom_flip_coordinates(lwgeom_in);
2697  output = geometry_serialize(lwgeom_out);
2698 
2699  lwgeom_free(lwgeom_in);
2700  PG_FREE_IF_COPY(input, 0);
2701 
2702  PG_RETURN_POINTER(output);
2703 }
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:373
double x
Definition: liblwgeom.h:308
#define LINETYPE
Definition: liblwgeom.h:61
GBOX * gbox_copy(const GBOX *box)
Return a copy of the GBOX, based on dimensionality of flags.
Definition: g_box.c:362
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:56
Datum LWGEOM_mem_size(PG_FUNCTION_ARGS)
Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS)
Datum ST_FlipCoordinates(PG_FUNCTION_ARGS)
Datum LWGEOM_npoints(PG_FUNCTION_ARGS)
double lwgeom_maxdistance3d(LWGEOM *lw1, LWGEOM *lw2)
Function initialazing 3d max distance calculation.
Definition: measures3d.c:120
Datum LWGEOM_force_multi(PG_FUNCTION_ARGS)
Datum LWGEOM_length2d_linestring(PG_FUNCTION_ARGS)
tuple res
Definition: window.py:80
GBOX * bbox
Definition: liblwgeom.h:354
Datum LWGEOM_expand(PG_FUNCTION_ARGS)
int lwtype_get_collectiontype(uint8_t type)
Given an lwtype number, what homogeneous collection can hold it?
Definition: lwgeom.c:982
double m
Definition: liblwgeom.h:308
#define MULTICURVETYPE
Definition: liblwgeom.h:70
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:947
LWCOLLECTION * lwcollection_extract(LWCOLLECTION *col, int type)
Takes a potentially heterogeneous collection and returns a homogeneous collection consisting only of ...
Definition: lwcollection.c:343
double lwgeom_mindistance2d_tolerance(LWGEOM *lw1, LWGEOM *lw2, double tolerance)
Function handling min distance calculations and dwithin calculations.
Definition: measures.c:173
LWCOLLECTION * lwcollection_construct(uint8_t type, int srid, GBOX *bbox, uint32_t ngeoms, LWGEOM **geoms)
Definition: lwcollection.c:30
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:655
Datum LWGEOM_to_BOX(PG_FUNCTION_ARGS)
Datum LWGEOM_force_2d(PG_FUNCTION_ARGS)
LWLINE * lwline_from_lwmpoint(int srid, LWMPOINT *mpoint)
Definition: lwline.c:260
void lwfree(void *mem)
Definition: lwutil.c:190
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
Datum LWGEOM_longestline2d(PG_FUNCTION_ARGS)
int npoints
Definition: liblwgeom.h:327
LWGEOM * lwgeom_force_4d(const LWGEOM *geom)
Definition: lwgeom.c:664
void gbox_expand(GBOX *g, double d)
Move the box minimums down and the maximums up by the distance provided.
Definition: g_box.c:91
void error_if_srid_mismatch(int srid1, int srid2)
Definition: lwutil.c:317
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:30
Datum LWGEOM_maxdistance2d_linestring(PG_FUNCTION_ARGS)
Datum LWGEOM_noop(PG_FUNCTION_ARGS)
#define DIST_MAX
#define POLYGONTYPE
Definition: liblwgeom.h:62
LWPOINT * lwpoint_make2d(int srid, double x, double y)
Definition: lwpoint.c:130
Datum area(PG_FUNCTION_ARGS)
LWGEOM * lwgeom_force_3dz(const LWGEOM *geom)
Definition: lwgeom.c:652
uint8_t flags
Definition: liblwgeom.h:353
double xmax
Definition: liblwgeom.h:249
#define DIST_MIN
Datum LWGEOM_makepoly(PG_FUNCTION_ARGS)
double lwgeom_maxdistance2d_tolerance(LWGEOM *lw1, LWGEOM *lw2, double tolerance)
Function handling max distance calculations and dfyllywithin calculations.
Definition: measures.c:141
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:57
void lwpoint_free(LWPOINT *pt)
Definition: lwpoint.c:180
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1006
#define MULTIPOINTTYPE
Definition: liblwgeom.h:63
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:63
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:40
#define FLAGS_GET_ZM(flags)
Definition: liblwgeom.h:119
double lwgeom_mindistance3d(LWGEOM *lw1, LWGEOM *lw2)
Function initialazing 3d min distance calculation.
Definition: measures3d.c:153
#define TRIANGLETYPE
Definition: liblwgeom.h:73
LWGEOM * lw_dist2d_distanceline(LWGEOM *lw1, LWGEOM *lw2, int srid, int mode)
Function initializing shortestline and longestline calculations.
Definition: measures.c:44
Datum LWGEOM_closestpoint(PG_FUNCTION_ARGS)
Datum ST_RemoveRepeatedPoints(PG_FUNCTION_ARGS)
#define POSTGIS_LIB_VERSION
Definition: sqldefines.h:12
#define POLYHEDRALSURFACETYPE
Definition: liblwgeom.h:72
int lwpoint_inside_circle(const LWPOINT *p, double cx, double cy, double rad)
Definition: lwgeom.c:522
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:389
Datum LWGEOM_length_linestring(PG_FUNCTION_ARGS)
LWGEOM * lwgeom_as_multi(const LWGEOM *lwgeom)
Create a new LWGEOM of the appropriate MULTI* type.
Definition: lwgeom.c:284
LWGEOM * lw_dist3d_distancepoint(LWGEOM *lw1, LWGEOM *lw2, int srid, int mode)
Function initializing 3dclosestpoint calculations.
Definition: measures3d.c:79
Datum ST_CollectionExtract(PG_FUNCTION_ARGS)
double zoff
Definition: liblwgeom.h:226
LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
Definition: lwgeom.c:80
int gserialized_has_bbox(const GSERIALIZED *gser)
Check if a GSERIALIZED has a bounding box without deserializing first.
Definition: g_serialized.c:20
LWGEOM * lwgeom_force_sfs(LWGEOM *geom, int version)
Definition: lwgeom.c:700
POINTARRAY * point
Definition: liblwgeom.h:367
double lwgeom_length_2d(const LWGEOM *geom)
Definition: lwgeom.c:1588
static int input(void)
int gserialized_has_z(const GSERIALIZED *gser)
Check if a GSERIALIZED has a Z ordinate.
Definition: g_serialized.c:25
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition: lwgeom.c:792
char ** result
Definition: liblwgeom.h:218
void lwgeom_drop_bbox(LWGEOM *lwgeom)
Call this function to drop BBOX and SRID from LWGEOM.
Definition: lwgeom.c:542
int32_t srid
Definition: liblwgeom.h:355
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:239
double ifac
Definition: liblwgeom.h:226
Datum LWGEOM_summary(PG_FUNCTION_ARGS)
void lwline_setPoint4d(LWLINE *line, uint32_t which, POINT4D *newpoint)
Definition: lwline.c:350
double ffac
Definition: liblwgeom.h:226
Datum LWGEOM_line_from_mpoint(PG_FUNCTION_ARGS)
double xoff
Definition: liblwgeom.h:226
Datum LWGEOM_affine(PG_FUNCTION_ARGS)
void lwgeom_longitude_shift(LWGEOM *lwgeom)
Definition: lwgeom.c:858
LWGEOM * lwgeom_flip_coordinates(LWGEOM *in)
Reverse the X and Y coordinate order.
Definition: lwgeom.c:1390
double lwgeom_perimeter(const LWGEOM *geom)
Definition: lwgeom.c:1522
Datum LWGEOM_closestpoint3d(PG_FUNCTION_ARGS)
double afac
Definition: liblwgeom.h:226
#define LW_FAILURE
Definition: liblwgeom.h:54
Datum postgis_svn_version(PG_FUNCTION_ARGS)
LWPOINT * lwpoint_make3dm(int srid, double x, double y, double m)
Definition: lwpoint.c:151
Datum ST_IsCollection(PG_FUNCTION_ARGS)
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:67
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:608
double x
Definition: liblwgeom.h:284
Datum postgis_lib_version(PG_FUNCTION_ARGS)
void lwgeom_force_clockwise(LWGEOM *lwgeom)
Ensure the outer ring is clockwise oriented and all inner rings are counter-clockwise.
Definition: lwgeom.c:23
unsigned int uint32
Definition: shpopen.c:274
Datum postgis_version(PG_FUNCTION_ARGS)
double zmax
Definition: liblwgeom.h:253
double ymin
Definition: liblwgeom.h:250
double lwgeom_mindistance2d(LWGEOM *lw1, LWGEOM *lw2)
Function initialazing min distance calculation.
Definition: measures.c:162
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:164
Datum LWGEOM_dwithin(PG_FUNCTION_ARGS)
LWGEOM * lwgeom_homogenize(const LWGEOM *geom)
Definition: lwhomogenize.c:196
Datum ST_MakeEnvelope(PG_FUNCTION_ARGS)
Datum LWGEOM_longestline3d(PG_FUNCTION_ARGS)
LWGEOM * lw_dist2d_distancepoint(LWGEOM *lw1, LWGEOM *lw2, int srid, int mode)
Function initializing closestpoint calculations.
Definition: measures.c:91
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:249
void gbox_init(GBOX *gbox)
Zero out all the entries in the GBOX.
Definition: g_box.c:34
double xmin
Definition: liblwgeom.h:248
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_TRUE, then a duplicate point will not be added.
Definition: ptarray.c:141
#define LW_FALSE
Definition: liblwgeom.h:52
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:29
void lwpoly_free(LWPOLY *poly)
Definition: lwpoly.c:79
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:51
LWLINE * lwline_construct(int srid, GBOX *bbox, POINTARRAY *points)
Definition: lwline.c:29
#define SRID_UNKNOWN
Unknown SRID value.
Definition: liblwgeom.h:154
#define TINTYPE
Definition: liblwgeom.h:74
LWGEOM * lwgeom_force_2d(const LWGEOM *geom)
Strip out the Z/M components of an LWGEOM.
Definition: lwgeom.c:646
int count
Definition: genraster.py:57
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:955
LWPOINT * lwpoint_make3dz(int srid, double x, double y, double z)
Definition: lwpoint.c:140
Datum ST_GeoHash(PG_FUNCTION_ARGS)
double cfac
Definition: liblwgeom.h:226
Datum LWGEOM_reverse(PG_FUNCTION_ARGS)
double ymax
Definition: liblwgeom.h:251
Datum LWGEOM_same(PG_FUNCTION_ARGS)
Datum LWGEOM_force_sfs(PG_FUNCTION_ARGS)
double y
Definition: liblwgeom.h:284
Datum LWGEOM_force_clockwise_poly(PG_FUNCTION_ARGS)
int getPoint2d_p(const POINTARRAY *pa, int n, POINT2D *point)
Definition: lwgeom_api.c:434
Datum LWGEOM_addpoint(PG_FUNCTION_ARGS)
#define FLAGS_GET_Z(flags)
Macros for manipulating the 'flags' byte.
Definition: liblwgeom.h:106
LWGEOM * lwgeom_construct_empty(uint8_t type, int srid, char hasz, char hasm)
Definition: lwgeom.c:1662
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:226
double z
Definition: liblwgeom.h:308
Datum LWGEOM_force_4d(PG_FUNCTION_ARGS)
tuple x
Definition: pixval.py:53
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition: lwgeom.c:89
int32_t srid
Definition: liblwgeom.h:366
#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:451
Datum LWGEOM_collect(PG_FUNCTION_ARGS)
int lwgeom_count_rings(const LWGEOM *geom)
Count the total number of rings in any LWGEOM.
Definition: lwgeom.c:1181
PG_FUNCTION_INFO_V1(LWGEOM_mem_size)
find the size of geometry
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:65
Datum LWGEOM_dfullywithin3d(PG_FUNCTION_ARGS)
Datum LWGEOM_zmflag(PG_FUNCTION_ARGS)
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:35
#define WKT_EXTENDED
Definition: liblwgeom.h:1778
double lwgeom_perimeter_2d(const LWGEOM *geom)
Definition: lwgeom.c:1544
void lwgeom_reverse(LWGEOM *lwgeom)
Reverse vertex order of LWGEOM.
Definition: lwgeom.c:51
double lwgeom_maxdistance3d_tolerance(LWGEOM *lw1, LWGEOM *lw2, double tolerance)
Function handling 3d max distance calculations and dfyllywithin calculations.
Definition: measures3d.c:132
LWPOLY * lwpoly_from_lwlines(const LWLINE *shell, uint32_t nholes, const LWLINE **holes)
Definition: lwpoly.c:250
LWLINE * lwline_from_lwgeom_array(int srid, uint32_t ngeoms, LWGEOM **geoms)
Definition: lwline.c:152
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:828
Datum LWGEOM_hasm(PG_FUNCTION_ARGS)
void lwgeom_drop_srid(LWGEOM *lwgeom)
Definition: lwgeom.c:618
#define MULTISURFACETYPE
Definition: liblwgeom.h:71
LWPOINT * lwpoint_make4d(int srid, double x, double y, double z, double m)
Definition: lwpoint.c:162
#define FALSE
Definition: dbfopen.c:169
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)
Datum LWGEOM_area_polygon(PG_FUNCTION_ARGS)
double lwgeom_area(const LWGEOM *geom)
Definition: lwgeom.c:1499
LWGEOM * lw_dist3d_distanceline(LWGEOM *lw1, LWGEOM *lw2, int srid, int mode)
Function initializing 3dshortestline and 3dlongestline calculations.
Definition: measures3d.c:30
double mmin
Definition: liblwgeom.h:254
double zmin
Definition: liblwgeom.h:252
Datum postgis_libxml_version(PG_FUNCTION_ARGS)
double lwgeom_length(const LWGEOM *geom)
Definition: lwgeom.c:1566
LWGEOM * lwgeom_segmentize2d(LWGEOM *line, double dist)
Definition: lwgeom.c:624
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:60
double efac
Definition: liblwgeom.h:226
LWMPOINT * lwgeom_as_lwmpoint(const LWGEOM *lwgeom)
Definition: lwgeom.c:152
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition: lwgeom.c:555
#define FLAGS_GET_M(flags)
Definition: liblwgeom.h:107
#define MAXFLOAT
Largest float value.
Datum LWGEOM_longitude_shift(PG_FUNCTION_ARGS)
Datum LWGEOM_mindistance2d(PG_FUNCTION_ARGS)
uint8_t type
Definition: liblwgeom.h:352
double mmax
Definition: liblwgeom.h:255
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:254
LWGEOM * lwgeom_force_3dm(const LWGEOM *geom)
Definition: lwgeom.c:658
double yoff
Definition: liblwgeom.h:226
Datum LWGEOM_ndims(PG_FUNCTION_ARGS)
double lwgeom_maxdistance2d(LWGEOM *lw1, LWGEOM *lw2)
Function initialazing max distance calculation.
Definition: measures.c:129
Datum LWGEOM_asEWKT(PG_FUNCTION_ARGS)
void * lwalloc(size_t size)
Definition: lwutil.c:175
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:1229
int lwline_add_lwpoint(LWLINE *line, LWPOINT *point, int where)
Add a LWPOINT to an LWLINE.
Definition: lwline.c:312
int lwgeom_count_vertices(const LWGEOM *geom)
Count the total number of vertices in any LWGEOM.
Definition: lwgeom.c:1072
Datum LWGEOM_nrings(PG_FUNCTION_ARGS)
Datum LWGEOM_makeline(PG_FUNCTION_ARGS)
double y
Definition: liblwgeom.h:308
#define MULTILINETYPE
Definition: liblwgeom.h:64
int azimuth_pt_pt(const POINT2D *p1, const POINT2D *p2, double *ret)
Compute the azimuth of segment AB in radians.
Definition: measures.c:2233
double gfac
Definition: liblwgeom.h:226
double lwgeom_mindistance3d_tolerance(LWGEOM *lw1, LWGEOM *lw2, double tolerance)
Function handling 3d min distance calculations and dwithin calculations.
Definition: measures3d.c:164
LWLINE * lwline_removepoint(LWLINE *line, uint32_t which)
Definition: lwline.c:333
Datum LWGEOM_inside_circle_point(PG_FUNCTION_ARGS)
char * lwgeom_summary(const LWGEOM *lwgeom, int offset)
Definition: lwgeom_debug.c:145
int32_t srid
Definition: liblwgeom.h:423
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition: lwgeom.c:799
#define TRUE
Definition: dbfopen.c:170
Datum LWGEOM_makepoint(PG_FUNCTION_ARGS)
Datum LWGEOM_makepoint3dm(PG_FUNCTION_ARGS)
tuple y
Definition: pixval.py:54
LWGEOM * lwgeom_remove_repeated_points(LWGEOM *in)
Remove repeated points!
Definition: lwgeom.c:1339
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:70
double hfac
Definition: liblwgeom.h:226
Datum postgis_autocache_bbox(PG_FUNCTION_ARGS)
double bfac
Definition: liblwgeom.h:226
int getPoint4d_p(const POINTARRAY *pa, int n, POINT4D *point)
Definition: lwgeom_api.c:217
void lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
Definition: lwgeom.c:1611
#define COLLECTIONTYPE
Definition: liblwgeom.h:66
uint8_t flags
Definition: liblwgeom.h:339
Datum LWGEOM_envelope(PG_FUNCTION_ARGS)
POINTARRAY * points
Definition: liblwgeom.h:378
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition: lwgeom.c:219