PostGIS  2.4.9dev-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  double x1, y1, x2, y2;
2064  int srid = SRID_UNKNOWN;
2065 
2066  POSTGIS_DEBUG(2, "ST_MakeEnvelope called");
2067 
2068  x1 = PG_GETARG_FLOAT8(0);
2069  y1 = PG_GETARG_FLOAT8(1);
2070  x2 = PG_GETARG_FLOAT8(2);
2071  y2 = PG_GETARG_FLOAT8(3);
2072  if ( PG_NARGS() > 4 ) {
2073  srid = PG_GETARG_INT32(4);
2074  }
2075 
2076  poly = lwpoly_construct_envelope(srid, x1, y1, x2, y2);
2077 
2078  result = geometry_serialize(lwpoly_as_lwgeom(poly));
2079  lwpoly_free(poly);
2080 
2081  PG_RETURN_POINTER(result);
2082 }
2083 
2085 Datum ST_IsCollection(PG_FUNCTION_ARGS)
2086 {
2087  GSERIALIZED *geom;
2088  int type;
2089  size_t size;
2090 
2091  /* Pull only a small amount of the tuple, enough to get the type. */
2092  /* header + srid/flags + bbox? + type number */
2093  size = VARHDRSZ + 8 + 32 + 4;
2094 
2095  geom = PG_GETARG_GSERIALIZED_P_SLICE(0, 0, size);
2096 
2097  type = gserialized_get_type(geom);
2098  PG_RETURN_BOOL(lwtype_is_collection(type));
2099 }
2100 
2102 Datum LWGEOM_makepoint(PG_FUNCTION_ARGS)
2103 {
2104  double x,y,z,m;
2105  LWPOINT *point;
2106  GSERIALIZED *result;
2107 
2108  POSTGIS_DEBUG(2, "LWGEOM_makepoint called");
2109 
2110  x = PG_GETARG_FLOAT8(0);
2111  y = PG_GETARG_FLOAT8(1);
2112 
2113  if ( PG_NARGS() == 2 ) point = lwpoint_make2d(SRID_UNKNOWN, x, y);
2114  else if ( PG_NARGS() == 3 )
2115  {
2116  z = PG_GETARG_FLOAT8(2);
2117  point = lwpoint_make3dz(SRID_UNKNOWN, x, y, z);
2118  }
2119  else if ( PG_NARGS() == 4 )
2120  {
2121  z = PG_GETARG_FLOAT8(2);
2122  m = PG_GETARG_FLOAT8(3);
2123  point = lwpoint_make4d(SRID_UNKNOWN, x, y, z, m);
2124  }
2125  else
2126  {
2127  elog(ERROR, "LWGEOM_makepoint: unsupported number of args: %d",
2128  PG_NARGS());
2129  PG_RETURN_NULL();
2130  }
2131 
2132  result = geometry_serialize((LWGEOM *)point);
2133 
2134  PG_RETURN_POINTER(result);
2135 }
2136 
2138 Datum LWGEOM_makepoint3dm(PG_FUNCTION_ARGS)
2139 {
2140  double x,y,m;
2141  LWPOINT *point;
2142  GSERIALIZED *result;
2143 
2144  POSTGIS_DEBUG(2, "LWGEOM_makepoint3dm called.");
2145 
2146  x = PG_GETARG_FLOAT8(0);
2147  y = PG_GETARG_FLOAT8(1);
2148  m = PG_GETARG_FLOAT8(2);
2149 
2150  point = lwpoint_make3dm(SRID_UNKNOWN, x, y, m);
2151  result = geometry_serialize((LWGEOM *)point);
2152 
2153  PG_RETURN_POINTER(result);
2154 }
2155 
2157 Datum LWGEOM_addpoint(PG_FUNCTION_ARGS)
2158 {
2159  GSERIALIZED *pglwg1, *pglwg2, *result;
2160  LWPOINT *point;
2161  LWLINE *line, *linecopy;
2162  int where = -1;
2163 
2164  POSTGIS_DEBUGF(2, "%s called.", __func__);
2165 
2166  pglwg1 = PG_GETARG_GSERIALIZED_P(0);
2167  pglwg2 = PG_GETARG_GSERIALIZED_P(1);
2168 
2169  if ( PG_NARGS() > 2 )
2170  {
2171  where = PG_GETARG_INT32(2);
2172  }
2173 
2174  if ( gserialized_get_type(pglwg1) != LINETYPE )
2175  {
2176  elog(ERROR, "First argument must be a LINESTRING");
2177  PG_RETURN_NULL();
2178  }
2179 
2180  if ( gserialized_get_type(pglwg2) != POINTTYPE )
2181  {
2182  elog(ERROR, "Second argument must be a POINT");
2183  PG_RETURN_NULL();
2184  }
2185 
2186  line = lwgeom_as_lwline(lwgeom_from_gserialized(pglwg1));
2187 
2188  if ( where == -1 ) where = line->points->npoints;
2189  else if ( where < 0 || where > line->points->npoints )
2190  {
2191  elog(ERROR, "Invalid offset");
2192  PG_RETURN_NULL();
2193  }
2194 
2195  point = lwgeom_as_lwpoint(lwgeom_from_gserialized(pglwg2));
2197  lwline_free(line);
2198 
2199  if ( lwline_add_lwpoint(linecopy, point, where) == LW_FAILURE )
2200  {
2201  elog(ERROR, "Point insert failed");
2202  PG_RETURN_NULL();
2203  }
2204 
2205  result = geometry_serialize(lwline_as_lwgeom(linecopy));
2206 
2207  /* Release memory */
2208  PG_FREE_IF_COPY(pglwg1, 0);
2209  PG_FREE_IF_COPY(pglwg2, 1);
2210  lwpoint_free(point);
2211 
2212  PG_RETURN_POINTER(result);
2213 
2214 }
2215 
2217 Datum LWGEOM_removepoint(PG_FUNCTION_ARGS)
2218 {
2219  GSERIALIZED *pglwg1, *result;
2220  LWLINE *line, *outline;
2221  uint32 which;
2222 
2223  POSTGIS_DEBUG(2, "LWGEOM_removepoint called.");
2224 
2225  pglwg1 = PG_GETARG_GSERIALIZED_P(0);
2226  which = PG_GETARG_INT32(1);
2227 
2228  if ( gserialized_get_type(pglwg1) != LINETYPE )
2229  {
2230  elog(ERROR, "First argument must be a LINESTRING");
2231  PG_RETURN_NULL();
2232  }
2233 
2234  line = lwgeom_as_lwline(lwgeom_from_gserialized(pglwg1));
2235 
2236  if ( which > line->points->npoints-1 )
2237  {
2238  elog(ERROR, "Point index out of range (%d..%d)", 0, line->points->npoints-1);
2239  PG_RETURN_NULL();
2240  }
2241 
2242  if ( line->points->npoints < 3 )
2243  {
2244  elog(ERROR, "Can't remove points from a single segment line");
2245  PG_RETURN_NULL();
2246  }
2247 
2248  outline = lwline_removepoint(line, which);
2249  /* Release memory */
2250  lwline_free(line);
2251 
2252  result = geometry_serialize((LWGEOM *)outline);
2253  lwline_free(outline);
2254 
2255  PG_FREE_IF_COPY(pglwg1, 0);
2256  PG_RETURN_POINTER(result);
2257 }
2258 
2260 Datum LWGEOM_setpoint_linestring(PG_FUNCTION_ARGS)
2261 {
2262  GSERIALIZED *pglwg1, *pglwg2, *result;
2263  LWGEOM *lwg;
2264  LWLINE *line;
2265  LWPOINT *lwpoint;
2266  POINT4D newpoint;
2267  int32 which;
2268 
2269  POSTGIS_DEBUG(2, "LWGEOM_setpoint_linestring called.");
2270 
2271  /* we copy input as we're going to modify it */
2272  pglwg1 = PG_GETARG_GSERIALIZED_P_COPY(0);
2273 
2274  which = PG_GETARG_INT32(1);
2275  pglwg2 = PG_GETARG_GSERIALIZED_P(2);
2276 
2277 
2278  /* Extract a POINT4D from the point */
2279  lwg = lwgeom_from_gserialized(pglwg2);
2280  lwpoint = lwgeom_as_lwpoint(lwg);
2281  if ( ! lwpoint )
2282  {
2283  elog(ERROR, "Third argument must be a POINT");
2284  PG_RETURN_NULL();
2285  }
2286  getPoint4d_p(lwpoint->point, 0, &newpoint);
2287  lwpoint_free(lwpoint);
2288  PG_FREE_IF_COPY(pglwg2, 2);
2289 
2290  lwg = lwgeom_from_gserialized(pglwg1);
2291  line = lwgeom_as_lwline(lwg);
2292  if ( ! line )
2293  {
2294  elog(ERROR, "First argument must be a LINESTRING");
2295  PG_RETURN_NULL();
2296  }
2297  if(which < 0){
2298  /* Use backward indexing for negative values */
2299  which = which + line->points->npoints ;
2300  }
2301  if ( which > line->points->npoints-1 || which < 0 )
2302  {
2303  elog(ERROR, "abs(Point index) out of range (-)(%d..%d)", 0, line->points->npoints-1);
2304  PG_RETURN_NULL();
2305  }
2306 
2307  /*
2308  * This will change pointarray of the serialized pglwg1,
2309  */
2310  lwline_setPoint4d(line, which, &newpoint);
2311  result = geometry_serialize((LWGEOM *)line);
2312 
2313  /* Release memory */
2314  lwline_free(line);
2315  pfree(pglwg1); /* we forced copy, POINARRAY is released now */
2316 
2317  PG_RETURN_POINTER(result);
2318 }
2319 
2320 /* convert LWGEOM to ewkt (in TEXT format) */
2322 Datum LWGEOM_asEWKT(PG_FUNCTION_ARGS)
2323 {
2324  GSERIALIZED *geom;
2325  LWGEOM *lwgeom;
2326  char *wkt;
2327  size_t wkt_size;
2328  text *result;
2329 
2330  POSTGIS_DEBUG(2, "LWGEOM_asEWKT called.");
2331 
2332  geom = PG_GETARG_GSERIALIZED_P(0);
2333  lwgeom = lwgeom_from_gserialized(geom);
2334 
2335  /* Write to WKT and free the geometry */
2336  wkt = lwgeom_to_wkt(lwgeom, WKT_EXTENDED, DBL_DIG, &wkt_size);
2337  lwgeom_free(lwgeom);
2338 
2339  /* Write to text and free the WKT */
2340  result = cstring2text(wkt);
2341  pfree(wkt);
2342 
2343  /* Return the text */
2344  PG_FREE_IF_COPY(geom, 0);
2345  PG_RETURN_TEXT_P(result);
2346 }
2347 
2355 Datum LWGEOM_azimuth(PG_FUNCTION_ARGS)
2356 {
2357  GSERIALIZED *geom;
2358  LWPOINT *lwpoint;
2359  POINT2D p1, p2;
2360  double result;
2361  int srid;
2362 
2363  /* Extract first point */
2364  geom = PG_GETARG_GSERIALIZED_P(0);
2365  lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom));
2366  if ( ! lwpoint )
2367  {
2368  PG_FREE_IF_COPY(geom, 0);
2369  lwpgerror("Argument must be POINT geometries");
2370  PG_RETURN_NULL();
2371  }
2372  srid = lwpoint->srid;
2373  if ( ! getPoint2d_p(lwpoint->point, 0, &p1) )
2374  {
2375  PG_FREE_IF_COPY(geom, 0);
2376  lwpgerror("Error extracting point");
2377  PG_RETURN_NULL();
2378  }
2379  lwpoint_free(lwpoint);
2380  PG_FREE_IF_COPY(geom, 0);
2381 
2382  /* Extract second point */
2383  geom = PG_GETARG_GSERIALIZED_P(1);
2384  lwpoint = lwgeom_as_lwpoint(lwgeom_from_gserialized(geom));
2385  if ( ! lwpoint )
2386  {
2387  PG_FREE_IF_COPY(geom, 1);
2388  lwpgerror("Argument must be POINT geometries");
2389  PG_RETURN_NULL();
2390  }
2391  if ( lwpoint->srid != srid )
2392  {
2393  PG_FREE_IF_COPY(geom, 1);
2394  lwpgerror("Operation on mixed SRID geometries");
2395  PG_RETURN_NULL();
2396  }
2397  if ( ! getPoint2d_p(lwpoint->point, 0, &p2) )
2398  {
2399  PG_FREE_IF_COPY(geom, 1);
2400  lwpgerror("Error extracting point");
2401  PG_RETURN_NULL();
2402  }
2403  lwpoint_free(lwpoint);
2404  PG_FREE_IF_COPY(geom, 1);
2405 
2406  /* Standard return value for equality case */
2407  if ( (p1.x == p2.x) && (p1.y == p2.y) )
2408  {
2409  PG_RETURN_NULL();
2410  }
2411 
2412  /* Compute azimuth */
2413  if ( ! azimuth_pt_pt(&p1, &p2, &result) )
2414  {
2415  PG_RETURN_NULL();
2416  }
2417 
2418  PG_RETURN_FLOAT8(result);
2419 }
2420 
2421 /*
2422  * optimistic_overlap(Polygon P1, Multipolygon MP2, double dist)
2423  * returns true if P1 overlaps MP2
2424  * method: bbox check -
2425  * is separation < dist? no - return false (quick)
2426  * yes - return distance(P1,MP2) < dist
2427  */
2429 Datum optimistic_overlap(PG_FUNCTION_ARGS)
2430 {
2431  GSERIALIZED *pg_geom1 = PG_GETARG_GSERIALIZED_P(0);
2432  GSERIALIZED *pg_geom2 = PG_GETARG_GSERIALIZED_P(1);
2433  double dist = PG_GETARG_FLOAT8(2);
2434  GBOX g1_bvol;
2435  double calc_dist;
2436 
2437  LWGEOM *geom1 = lwgeom_from_gserialized(pg_geom1);
2438  LWGEOM *geom2 = lwgeom_from_gserialized(pg_geom2);
2439 
2440  error_if_srid_mismatch(geom1->srid, geom2->srid);
2441 
2442  if (geom1->type != POLYGONTYPE)
2443  {
2444  elog(ERROR,"optimistic_overlap: first arg isn't a polygon\n");
2445  PG_RETURN_NULL();
2446  }
2447 
2448  if (geom2->type != POLYGONTYPE && geom2->type != MULTIPOLYGONTYPE)
2449  {
2450  elog(ERROR,"optimistic_overlap: 2nd arg isn't a [multi-]polygon\n");
2451  PG_RETURN_NULL();
2452  }
2453 
2454  /*bbox check */
2455  gserialized_get_gbox_p(pg_geom1, &g1_bvol );
2456 
2457  g1_bvol.xmin = g1_bvol.xmin - dist;
2458  g1_bvol.ymin = g1_bvol.ymin - dist;
2459  g1_bvol.xmax = g1_bvol.xmax + dist;
2460  g1_bvol.ymax = g1_bvol.ymax + dist;
2461 
2462  if ( (g1_bvol.xmin > geom2->bbox->xmax) ||
2463  (g1_bvol.xmax < geom2->bbox->xmin) ||
2464  (g1_bvol.ymin > geom2->bbox->ymax) ||
2465  (g1_bvol.ymax < geom2->bbox->ymin) )
2466  {
2467  PG_RETURN_BOOL(FALSE); /*bbox not overlap */
2468  }
2469 
2470  /*
2471  * compute distances
2472  * should be a fast calc if they actually do intersect
2473  */
2474  calc_dist = DatumGetFloat8 ( DirectFunctionCall2(LWGEOM_mindistance2d, PointerGetDatum( pg_geom1 ), PointerGetDatum( pg_geom2 )));
2475 
2476  PG_RETURN_BOOL(calc_dist < dist);
2477 }
2478 
2479 
2480 /*affine transform geometry */
2482 Datum LWGEOM_affine(PG_FUNCTION_ARGS)
2483 {
2484  GSERIALIZED *geom = PG_GETARG_GSERIALIZED_P_COPY(0);
2485  LWGEOM *lwgeom = lwgeom_from_gserialized(geom);
2486  GSERIALIZED *ret;
2487  AFFINE affine;
2488 
2489  affine.afac = PG_GETARG_FLOAT8(1);
2490  affine.bfac = PG_GETARG_FLOAT8(2);
2491  affine.cfac = PG_GETARG_FLOAT8(3);
2492  affine.dfac = PG_GETARG_FLOAT8(4);
2493  affine.efac = PG_GETARG_FLOAT8(5);
2494  affine.ffac = PG_GETARG_FLOAT8(6);
2495  affine.gfac = PG_GETARG_FLOAT8(7);
2496  affine.hfac = PG_GETARG_FLOAT8(8);
2497  affine.ifac = PG_GETARG_FLOAT8(9);
2498  affine.xoff = PG_GETARG_FLOAT8(10);
2499  affine.yoff = PG_GETARG_FLOAT8(11);
2500  affine.zoff = PG_GETARG_FLOAT8(12);
2501 
2502  POSTGIS_DEBUG(2, "LWGEOM_affine called.");
2503 
2504  lwgeom_affine(lwgeom, &affine);
2505 
2506  /* COMPUTE_BBOX TAINTING */
2507  if ( lwgeom->bbox )
2508  {
2509  lwgeom_drop_bbox(lwgeom);
2510  lwgeom_add_bbox(lwgeom);
2511  }
2512  ret = geometry_serialize(lwgeom);
2513 
2514  /* Release memory */
2515  lwgeom_free(lwgeom);
2516  PG_FREE_IF_COPY(geom, 0);
2517 
2518  PG_RETURN_POINTER(ret);
2519 }
2520 
2522 Datum ST_GeoHash(PG_FUNCTION_ARGS)
2523 {
2524 
2525  GSERIALIZED *geom = NULL;
2526  int precision = 0;
2527  char *geohash = NULL;
2528  text *result = NULL;
2529 
2530  if ( PG_ARGISNULL(0) )
2531  {
2532  PG_RETURN_NULL();
2533  }
2534 
2535  geom = PG_GETARG_GSERIALIZED_P(0);
2536 
2537  if ( ! PG_ARGISNULL(1) )
2538  {
2539  precision = PG_GETARG_INT32(1);
2540  }
2541 
2542  geohash = lwgeom_geohash((LWGEOM*)(lwgeom_from_gserialized(geom)), precision);
2543 
2544  if ( ! geohash )
2545  PG_RETURN_NULL();
2546 
2547  result = cstring2text(geohash);
2548  pfree(geohash);
2549 
2550  PG_RETURN_TEXT_P(result);
2551 }
2552 
2554 Datum ST_CollectionExtract(PG_FUNCTION_ARGS)
2555 {
2556  GSERIALIZED *input = PG_GETARG_GSERIALIZED_P(0);
2557  GSERIALIZED *output;
2558  LWGEOM *lwgeom = lwgeom_from_gserialized(input);
2559  LWGEOM *lwcol = NULL;
2560  int type = PG_GETARG_INT32(1);
2561  int lwgeom_type = lwgeom->type;
2562 
2563  /* Ensure the right type was input */
2564  if ( ! ( type == POINTTYPE || type == LINETYPE || type == POLYGONTYPE ) )
2565  {
2566  lwgeom_free(lwgeom);
2567  elog(ERROR, "ST_CollectionExtract: only point, linestring and polygon may be extracted");
2568  PG_RETURN_NULL();
2569  }
2570 
2571  /* Mirror non-collections right back */
2572  if ( ! lwgeom_is_collection(lwgeom) )
2573  {
2574  /* Non-collections of the matching type go back */
2575  if(lwgeom_type == type)
2576  {
2577  lwgeom_free(lwgeom);
2578  PG_RETURN_POINTER(input);
2579  }
2580  /* Others go back as EMPTY */
2581  else
2582  {
2583  lwcol = lwgeom_construct_empty(type, lwgeom->srid, FLAGS_GET_Z(lwgeom->flags), FLAGS_GET_M(lwgeom->flags));
2584  }
2585  }
2586  else
2587  {
2588  lwcol = lwcollection_as_lwgeom(lwcollection_extract((LWCOLLECTION*)lwgeom, type));
2589  }
2590 
2591 #if 0
2593  {
2594  lwgeom_free(lwgeom);
2595  PG_RETURN_NULL();
2596  }
2597 #endif
2598  output = geometry_serialize((LWGEOM*)lwcol);
2599  lwgeom_free(lwgeom);
2600  lwgeom_free(lwcol);
2601 
2602  PG_RETURN_POINTER(output);
2603 }
2604 
2606 Datum ST_CollectionHomogenize(PG_FUNCTION_ARGS)
2607 {
2608  GSERIALIZED *input = PG_GETARG_GSERIALIZED_P(0);
2609  GSERIALIZED *output;
2610  LWGEOM *lwgeom = lwgeom_from_gserialized(input);
2611  LWGEOM *lwoutput = NULL;
2612 
2613  lwoutput = lwgeom_homogenize(lwgeom);
2614  lwgeom_free(lwgeom);
2615 
2616  if ( ! lwoutput )
2617  {
2618  PG_RETURN_NULL();
2619  PG_FREE_IF_COPY(input, 0);
2620  }
2621 
2622  output = geometry_serialize(lwoutput);
2623  lwgeom_free(lwoutput);
2624 
2625  PG_FREE_IF_COPY(input, 0);
2626  PG_RETURN_POINTER(output);
2627 }
2628 
2629 Datum ST_RemoveRepeatedPoints(PG_FUNCTION_ARGS);
2631 Datum ST_RemoveRepeatedPoints(PG_FUNCTION_ARGS)
2632 {
2633  GSERIALIZED *g_in = PG_GETARG_GSERIALIZED_P(0);
2634  int type = gserialized_get_type(g_in);
2635  GSERIALIZED *g_out;
2636  LWGEOM *lwgeom_in = NULL;
2637  LWGEOM *lwgeom_out = NULL;
2638  double tolerance = 0.0;
2639 
2640  /* Don't even start to think about points */
2641  if ( type == POINTTYPE )
2642  PG_RETURN_POINTER(g_in);
2643 
2644  if ( PG_NARGS() > 1 && ! PG_ARGISNULL(1) )
2645  tolerance = PG_GETARG_FLOAT8(1);
2646 
2647  lwgeom_in = lwgeom_from_gserialized(g_in);
2648  lwgeom_out = lwgeom_remove_repeated_points(lwgeom_in, tolerance);
2649 
2650  /* COMPUTE_BBOX TAINTING */
2651  if (lwgeom_in->bbox)
2652  {
2653  lwgeom_drop_bbox(lwgeom_out);
2654  lwgeom_add_bbox(lwgeom_out);
2655  }
2656 
2657  g_out = geometry_serialize(lwgeom_out);
2658 
2659  if ( lwgeom_out != lwgeom_in )
2660  {
2661  lwgeom_free(lwgeom_out);
2662  }
2663 
2664  lwgeom_free(lwgeom_in);
2665 
2666  PG_FREE_IF_COPY(g_in, 0);
2667  PG_RETURN_POINTER(g_out);
2668 }
2669 
2670 Datum ST_FlipCoordinates(PG_FUNCTION_ARGS);
2672 Datum ST_FlipCoordinates(PG_FUNCTION_ARGS)
2673 {
2674  GSERIALIZED *in = PG_GETARG_GSERIALIZED_P_COPY(0);
2675  GSERIALIZED *out;
2676  LWGEOM *lwgeom = lwgeom_from_gserialized(in);
2677 
2679  out = geometry_serialize(lwgeom);
2680 
2681  lwgeom_free(lwgeom);
2682  PG_FREE_IF_COPY(in, 0);
2683 
2684  PG_RETURN_POINTER(out);
2685 }
2686 
2687 static LWORD ordname2ordval(char n)
2688 {
2689  if ( n == 'x' || n == 'X' ) return LWORD_X;
2690  if ( n == 'y' || n == 'Y' ) return LWORD_Y;
2691  if ( n == 'z' || n == 'Z' ) return LWORD_Z;
2692  if ( n == 'm' || n == 'M' ) return LWORD_M;
2693  lwpgerror("Invalid ordinate name '%c'. Expected x,y,z or m", n);
2694  return (LWORD)-1;
2695 }
2696 
2697 Datum ST_SwapOrdinates(PG_FUNCTION_ARGS);
2699 Datum ST_SwapOrdinates(PG_FUNCTION_ARGS)
2700 {
2701  GSERIALIZED *in;
2702  GSERIALIZED *out;
2703  LWGEOM *lwgeom;
2704  const char *ospec;
2705  LWORD o1, o2;
2706 
2707  ospec = PG_GETARG_CSTRING(1);
2708  if ( strlen(ospec) != 2 )
2709  {
2710  lwpgerror("Invalid ordinate specification. "
2711  "Need two letters from the set (x,y,z,m). "
2712  "Got '%s'", ospec);
2713  PG_RETURN_NULL();
2714  }
2715  o1 = ordname2ordval( ospec[0] );
2716  o2 = ordname2ordval( ospec[1] );
2717 
2718  in = PG_GETARG_GSERIALIZED_P_COPY(0);
2719 
2720  /* Check presence of given ordinates */
2721  if ( ( o1 == LWORD_M || o2 == LWORD_M ) && ! gserialized_has_m(in) )
2722  {
2723  lwpgerror("Geometry does not have an M ordinate");
2724  PG_RETURN_NULL();
2725  }
2726  if ( ( o1 == LWORD_Z || o2 == LWORD_Z ) && ! gserialized_has_z(in) )
2727  {
2728  lwpgerror("Geometry does not have a Z ordinate");
2729  PG_RETURN_NULL();
2730  }
2731 
2732  /* Nothing to do if swapping the same ordinate, pity for the copy... */
2733  if ( o1 == o2 ) PG_RETURN_POINTER(in);
2734 
2735  lwgeom = lwgeom_from_gserialized(in);
2736  lwgeom_swap_ordinates(lwgeom, o1, o2);
2737  out = geometry_serialize(lwgeom);
2738  lwgeom_free(lwgeom);
2739  PG_FREE_IF_COPY(in, 0);
2740  PG_RETURN_POINTER(out);
2741 }
2742 
2743 /*
2744  * ST_BoundingDiagonal(inp geometry, fits boolean)
2745  */
2746 Datum ST_BoundingDiagonal(PG_FUNCTION_ARGS);
2748 Datum ST_BoundingDiagonal(PG_FUNCTION_ARGS)
2749 {
2750  GSERIALIZED *geom_in = PG_GETARG_GSERIALIZED_P(0);
2751  GSERIALIZED *geom_out;
2752  bool fits = PG_GETARG_BOOL(1);
2753  LWGEOM *lwgeom_in = lwgeom_from_gserialized(geom_in);
2754  LWGEOM *lwgeom_out;
2755  const GBOX *gbox;
2756  int hasz = FLAGS_GET_Z(lwgeom_in->flags);
2757  int hasm = FLAGS_GET_M(lwgeom_in->flags);
2758  int srid = lwgeom_in->srid;
2759  POINT4D pt;
2760  POINTARRAY *pa;
2761 
2762  if ( fits ) {
2763  /* unregister any cached bbox to ensure it's recomputed */
2764  lwgeom_in->bbox = NULL;
2765  }
2766 
2767  gbox = lwgeom_get_bbox(lwgeom_in);
2768 
2769  if ( ! gbox )
2770  {
2771  lwgeom_out = lwgeom_construct_empty(LINETYPE, srid, hasz, hasm);
2772  }
2773  else
2774  {
2775  pa = ptarray_construct_empty(hasz, hasm, 2);
2776  pt.x = gbox->xmin;
2777  pt.y = gbox->ymin;
2778  pt.z = gbox->zmin;
2779  pt.m = gbox->mmin;
2780  ptarray_append_point(pa, &pt, LW_TRUE);
2781  pt.x = gbox->xmax;
2782  pt.y = gbox->ymax;
2783  pt.z = gbox->zmax;
2784  pt.m = gbox->mmax;
2785  ptarray_append_point(pa, &pt, LW_TRUE);
2786  lwgeom_out = lwline_as_lwgeom( lwline_construct(srid, NULL, pa) );
2787  }
2788 
2789  lwgeom_free(lwgeom_in);
2790  PG_FREE_IF_COPY(geom_in, 0);
2791 
2792  geom_out = geometry_serialize(lwgeom_out);
2793  lwgeom_free(lwgeom_out);
2794 
2795  PG_RETURN_POINTER(geom_out);
2796 }
2797 
2798 Datum ST_Scale(PG_FUNCTION_ARGS);
2800 Datum ST_Scale(PG_FUNCTION_ARGS)
2801 {
2802  GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P_COPY(0); /* will be modified */
2803  GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
2804  GSERIALIZED *ret;
2805  LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
2806  LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
2807  LWPOINT *lwpoint;
2808  POINT4D factors;
2809 
2810  lwpoint = lwgeom_as_lwpoint(lwgeom2);
2811  if ( lwpoint == NULL )
2812  {
2813  lwgeom_free(lwgeom1);
2814  lwgeom_free(lwgeom2);
2815  PG_FREE_IF_COPY(geom1, 0);
2816  PG_FREE_IF_COPY(geom2, 1);
2817  lwpgerror("Scale factor geometry parameter must be a point");
2818  PG_RETURN_NULL();
2819  }
2820  if ( ! lwpoint->point->npoints )
2821  {
2822  /* empty point, return input untouched */
2823  lwgeom_free(lwgeom1);
2824  lwgeom_free(lwgeom2);
2825  PG_FREE_IF_COPY(geom2, 1);
2826  PG_RETURN_POINTER(geom1);
2827  }
2828  getPoint4d_p(lwpoint->point, 0, &factors);
2829  if ( ! FLAGS_GET_Z(lwpoint->flags ) ) factors.z = 1;
2830  if ( ! FLAGS_GET_M(lwpoint->flags ) ) factors.m = 1;
2831 
2832  lwgeom_scale(lwgeom1, &factors);
2833 
2834  /* Construct GSERIALIZED */
2835  ret = geometry_serialize(lwgeom1);
2836 
2837  /* Cleanup */
2838  lwgeom_free(lwgeom1);
2839  lwgeom_free(lwgeom2);
2840  PG_FREE_IF_COPY(geom1, 0);
2841  PG_FREE_IF_COPY(geom2, 1);
2842 
2843  PG_RETURN_POINTER(ret);
2844 }
2845 
2846 Datum ST_Points(PG_FUNCTION_ARGS);
2848 Datum ST_Points(PG_FUNCTION_ARGS)
2849 {
2850  if (PG_ARGISNULL(0))
2851  {
2852  PG_RETURN_NULL();
2853  }
2854  else
2855  {
2856  GSERIALIZED* geom = PG_GETARG_GSERIALIZED_P(0);
2857  GSERIALIZED* ret;
2858  LWGEOM* lwgeom = lwgeom_from_gserialized(geom);
2859  LWMPOINT* result = lwmpoint_from_lwgeom(lwgeom);
2860 
2861  lwgeom_free(lwgeom);
2862 
2863  ret = geometry_serialize(lwmpoint_as_lwgeom(result));
2864  lwmpoint_free(result);
2865  PG_RETURN_POINTER(ret);
2866  }
2867 }
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:642
double x
Definition: liblwgeom.h:352
#define LINETYPE
Definition: liblwgeom.h:86
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:86
Datum LWGEOM_mem_size(PG_FUNCTION_ARGS)
double lwgeom_mindistance3d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling 3d min distance calculations and dwithin calculations.
Definition: measures3d.c:363
Datum LWGEOM_collect_garray(PG_FUNCTION_ARGS)
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:398
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:1075
double m
Definition: liblwgeom.h:352
#define MULTICURVETYPE
Definition: liblwgeom.h:95
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:1040
LWCOLLECTION * lwcollection_extract(LWCOLLECTION *col, int type)
Takes a potentially heterogeneous collection and returns a homogeneous collection consisting only of ...
Definition: lwcollection.c:369
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:244
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
double lwgeom_maxdistance2d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling max distance calculations and dfyllywithin calculations.
Definition: measures.c:181
Datum LWGEOM_longestline2d(PG_FUNCTION_ARGS)
Datum ST_BoundingDiagonal(PG_FUNCTION_ARGS)
int npoints
Definition: liblwgeom.h:371
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:757
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:50
Datum LWGEOM_maxdistance2d_linestring(PG_FUNCTION_ARGS)
Datum LWGEOM_noop(PG_FUNCTION_ARGS)
Datum ST_WrapX(PG_FUNCTION_ARGS)
#define POLYGONTYPE
Definition: liblwgeom.h:87
LWPOINT * lwpoint_make2d(int srid, double x, double y)
Definition: lwpoint.c:163
Datum area(PG_FUNCTION_ARGS)
LWGEOM * lwgeom_force_3dz(const LWGEOM *geom)
Definition: lwgeom.c:745
uint8_t flags
Definition: liblwgeom.h:397
double xmax
Definition: liblwgeom.h:293
Datum LWGEOM_makepoly(PG_FUNCTION_ARGS)
Datum LWGEOM_setpoint_linestring(PG_FUNCTION_ARGS)
POINTARRAY * ptarray_construct_empty(char hasz, char hasm, uint32_t maxpoints)
Create a new POINTARRAY with no points.
Definition: ptarray.c:70
void lwpoint_free(LWPOINT *pt)
Definition: lwpoint.c:213
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1099
#define MULTIPOINTTYPE
Definition: liblwgeom.h:88
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:1786
Datum LWGEOM_shortestline2d(PG_FUNCTION_ARGS)
Datum LWGEOM_mindistance3d(PG_FUNCTION_ARGS)
int gserialized_ndims(const GSERIALIZED *gser)
Return the number of dimensions (2, 3, 4) in a geometry.
Definition: g_serialized.c:60
void lwgeom_swap_ordinates(LWGEOM *in, LWORD o1, LWORD o2)
Swap ordinate values in every vertex of the geometry.
Definition: lwgeom.c:1513
#define FLAGS_GET_ZM(flags)
Definition: liblwgeom.h:153
#define TRIANGLETYPE
Definition: liblwgeom.h:98
int32_t lwgeom_get_srid(const LWGEOM *geom)
Return SRID number.
Definition: lwgeom.c:871
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:97
LWMPOINT * lwmpoint_from_lwgeom(const LWGEOM *g)
Definition: lwmpoint.c:127
int lwpoint_inside_circle(const LWPOINT *p, double cx, double cy, double rad)
Definition: lwgeom.c:615
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:482
Datum LWGEOM_length_linestring(PG_FUNCTION_ARGS)
void error_if_srid_mismatch(int srid1, int srid2)
Definition: lwutil.c:371
LWGEOM * lwgeom_as_multi(const LWGEOM *lwgeom)
Create a new LWGEOM of the appropriate MULTI* type.
Definition: lwgeom.c:333
Datum ST_CollectionExtract(PG_FUNCTION_ARGS)
double zoff
Definition: liblwgeom.h:270
LWPOINT * lwgeom_as_lwpoint(const LWGEOM *lwgeom)
Definition: lwgeom.c:129
int gserialized_has_bbox(const GSERIALIZED *gser)
Check if a GSERIALIZED has a bounding box without deserializing first.
Definition: g_serialized.c:40
LWGEOM * lwgeom_furthest_line_3d(LWGEOM *lw1, LWGEOM *lw2)
Definition: measures3d.c:94
LWGEOM * lwgeom_force_sfs(LWGEOM *geom, int version)
Definition: lwgeom.c:793
POINTARRAY * point
Definition: liblwgeom.h:411
double lwgeom_length_2d(const LWGEOM *geom)
Definition: lwgeom.c:1712
int gserialized_has_z(const GSERIALIZED *gser)
Check if a GSERIALIZED has a Z ordinate.
Definition: g_serialized.c:45
int lwgeom_has_z(const LWGEOM *geom)
Return LW_TRUE if geometry has Z ordinates.
Definition: lwgeom.c:885
void lwgeom_drop_bbox(LWGEOM *lwgeom)
Call this function to drop BBOX and SRID from LWGEOM.
Definition: lwgeom.c:635
int32_t srid
Definition: liblwgeom.h:399
LWGEOM * lwpoly_as_lwgeom(const LWPOLY *obj)
Definition: lwgeom.c:288
double ifac
Definition: liblwgeom.h:270
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:270
Datum LWGEOM_line_from_mpoint(PG_FUNCTION_ARGS)
Datum ST_Points(PG_FUNCTION_ARGS)
double xoff
Definition: liblwgeom.h:270
Datum LWGEOM_affine(PG_FUNCTION_ARGS)
void lwgeom_longitude_shift(LWGEOM *lwgeom)
Definition: lwgeom.c:951
double lwgeom_perimeter(const LWGEOM *geom)
Definition: lwgeom.c:1646
Datum LWGEOM_closestpoint3d(PG_FUNCTION_ARGS)
double afac
Definition: liblwgeom.h:270
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:79
Datum ST_SwapOrdinates(PG_FUNCTION_ARGS)
Datum postgis_svn_version(PG_FUNCTION_ARGS)
double lwgeom_maxdistance3d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling 3d max distance calculations and dfullywithin calculations.
Definition: measures3d.c:326
LWGEOM * lwgeom_closest_point_3d(const LWGEOM *lw1, const LWGEOM *lw2)
Definition: measures3d.c:100
LWPOINT * lwpoint_make3dm(int srid, double x, double y, double m)
Definition: lwpoint.c:184
Datum ST_IsCollection(PG_FUNCTION_ARGS)
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:701
double x
Definition: liblwgeom.h:328
Datum postgis_lib_version(PG_FUNCTION_ARGS)
LWPOLY * lwpoly_construct_envelope(int srid, double x1, double y1, double x2, double y2)
Definition: lwpoly.c:98
void lwgeom_force_clockwise(LWGEOM *lwgeom)
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:297
double ymin
Definition: liblwgeom.h:294
Datum postgis_scripts_released(PG_FUNCTION_ARGS)
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:218
Datum LWGEOM_dwithin(PG_FUNCTION_ARGS)
LWGEOM * lwgeom_homogenize(const LWGEOM *geom)
Definition: lwhomogenize.c:209
Datum ST_MakeEnvelope(PG_FUNCTION_ARGS)
Datum LWGEOM_longestline3d(PG_FUNCTION_ARGS)
LWGEOM * geom
LWGEOM * lwline_as_lwgeom(const LWLINE *obj)
Definition: lwgeom.c:298
void gbox_init(GBOX *gbox)
Zero out all the entries in the GBOX.
Definition: g_box.c:51
double xmin
Definition: liblwgeom.h:292
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:77
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:174
static LWORD ordname2ordval(char n)
const char * lwgeom_version(void)
Return lwgeom version string (not to be freed)
Definition: lwgeom_api.c:36
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:76
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:188
#define TINTYPE
Definition: liblwgeom.h:99
LWGEOM * lwgeom_force_2d(const LWGEOM *geom)
Strip out the Z/M components of an LWGEOM.
Definition: lwgeom.c:739
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:689
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:1048
uint8_t precision
Definition: cu_in_twkb.c:25
LWPOINT * lwpoint_make3dz(int srid, double x, double y, double z)
Definition: lwpoint.c:173
double lwgeom_maxdistance2d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initialazing max distance calculation.
Definition: measures.c:169
Datum ST_GeoHash(PG_FUNCTION_ARGS)
double cfac
Definition: liblwgeom.h:270
Datum ST_Scale(PG_FUNCTION_ARGS)
Datum LWGEOM_reverse(PG_FUNCTION_ARGS)
double ymax
Definition: liblwgeom.h:295
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:328
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:347
Datum LWGEOM_addpoint(PG_FUNCTION_ARGS)
#define FLAGS_GET_Z(flags)
Macros for manipulating the &#39;flags&#39; byte.
Definition: liblwgeom.h:140
LWGEOM * lwgeom_construct_empty(uint8_t type, int srid, char hasz, char hasm)
Definition: lwgeom.c:1851
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:270
double z
Definition: liblwgeom.h:352
Datum LWGEOM_force_4d(PG_FUNCTION_ARGS)
LWLINE * lwgeom_as_lwline(const LWGEOM *lwgeom)
Definition: lwgeom.c:138
int32_t srid
Definition: liblwgeom.h:410
#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:544
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:1298
PG_FUNCTION_INFO_V1(LWGEOM_mem_size)
find the size of geometry
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:90
Datum LWGEOM_dfullywithin3d(PG_FUNCTION_ARGS)
uint8_t flags
Definition: liblwgeom.h:408
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:55
#define WKT_EXTENDED
Definition: liblwgeom.h:2085
double lwgeom_perimeter_2d(const LWGEOM *geom)
Definition: lwgeom.c:1668
void lwgeom_reverse(LWGEOM *lwgeom)
Reverse vertex order of LWGEOM.
Definition: lwgeom.c:93
LWPOLY * lwpoly_from_lwlines(const LWLINE *shell, uint32_t nholes, const LWLINE **holes)
Definition: lwpoly.c:368
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:846
Datum LWGEOM_hasm(PG_FUNCTION_ARGS)
void lwgeom_drop_srid(LWGEOM *lwgeom)
Definition: lwgeom.c:711
#define MULTISURFACETYPE
Definition: liblwgeom.h:96
LWPOINT * lwpoint_make4d(int srid, double x, double y, double z, double m)
Definition: lwpoint.c:195
#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:1623
double mmin
Definition: liblwgeom.h:298
double zmin
Definition: liblwgeom.h:296
Datum postgis_libxml_version(PG_FUNCTION_ARGS)
double lwgeom_length(const LWGEOM *geom)
Definition: lwgeom.c:1690
LWGEOM * lwgeom_segmentize2d(LWGEOM *line, double dist)
Definition: lwgeom.c:717
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:85
double efac
Definition: liblwgeom.h:270
LWMPOINT * lwgeom_as_lwmpoint(const LWGEOM *lwgeom)
Definition: lwgeom.c:201
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition: lwgeom.c:648
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:141
Datum LWGEOM_longitude_shift(PG_FUNCTION_ARGS)
Datum LWGEOM_mindistance2d(PG_FUNCTION_ARGS)
uint8_t type
Definition: liblwgeom.h:396
type
Definition: ovdump.py:41
double mmax
Definition: liblwgeom.h:299
LWGEOM * lwpoint_as_lwgeom(const LWPOINT *obj)
Definition: lwgeom.c:303
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:751
double yoff
Definition: liblwgeom.h:270
Datum LWGEOM_ndims(PG_FUNCTION_ARGS)
LWGEOM * lwgeom_remove_repeated_points(const LWGEOM *in, double tolerance)
Remove repeated points!
Definition: lwgeom.c:1456
double lwgeom_maxdistance3d(const LWGEOM *lw1, const LWGEOM *lw2)
Function initializing 3d max distance calculation.
Definition: measures3d.c:314
LWGEOM * lwgeom_closest_line(const LWGEOM *lw1, const LWGEOM *lw2)
Definition: measures.c:42
int value
Definition: genraster.py:61
LWGEOM * lwgeom_as_curve(const LWGEOM *lwgeom)
Create a new LWGEOM of the appropriate CURVE* type.
Definition: lwgeom.c:373
Datum LWGEOM_asEWKT(PG_FUNCTION_ARGS)
void * lwalloc(size_t size)
Definition: lwutil.c:229
int lwgeom_is_empty(const LWGEOM *geom)
Return true or false depending on whether a geometry is an "empty" geometry (no vertices members) ...
Definition: lwgeom.c:1346
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:1189
Datum LWGEOM_nrings(PG_FUNCTION_ARGS)
Datum LWGEOM_makeline(PG_FUNCTION_ARGS)
double y
Definition: liblwgeom.h:352
#define MULTILINETYPE
Definition: liblwgeom.h:89
int azimuth_pt_pt(const POINT2D *p1, const POINT2D *p2, double *ret)
Compute the azimuth of segment AB in radians.
Definition: measures.c:2427
double gfac
Definition: liblwgeom.h:270
LWLINE * lwline_removepoint(LWLINE *line, uint32_t which)
Definition: lwline.c:363
Datum LWGEOM_inside_circle_point(PG_FUNCTION_ARGS)
unsigned char uint8_t
Definition: uthash.h:79
char * lwgeom_summary(const LWGEOM *lwgeom, int offset)
Definition: lwgeom_debug.c:158
int32_t srid
Definition: liblwgeom.h:467
int lwgeom_has_m(const LWGEOM *geom)
Return LW_TRUE if geometry has M ordinates.
Definition: lwgeom.c:892
#define TRUE
Definition: dbfopen.c:169
Datum LWGEOM_makepoint(PG_FUNCTION_ARGS)
Datum LWGEOM_makepoint3dm(PG_FUNCTION_ARGS)
int32_t gserialized_get_srid(const GSERIALIZED *s)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
Definition: g_serialized.c:100
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:270
Datum postgis_autocache_bbox(PG_FUNCTION_ARGS)
double bfac
Definition: liblwgeom.h:270
int getPoint4d_p(const POINTARRAY *pa, int n, POINT4D *point)
Definition: lwgeom_api.c:122
void lwgeom_affine(LWGEOM *geom, const AFFINE *affine)
Definition: lwgeom.c:1735
#define COLLECTIONTYPE
Definition: liblwgeom.h:91
This library is the generic geometry handling section of PostGIS.
uint8_t flags
Definition: liblwgeom.h:383
Datum LWGEOM_envelope(PG_FUNCTION_ARGS)
POINTARRAY * points
Definition: liblwgeom.h:422
LWGEOM * lwcollection_as_lwgeom(const LWCOLLECTION *obj)
Definition: lwgeom.c:268
LWGEOM * lwmpoint_as_lwgeom(const LWMPOINT *obj)
Definition: lwgeom.c:263