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