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