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