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