PostGIS  2.1.10dev-r@@SVN_REVISION@@
postgis/lwgeom_geos_clean.c
Go to the documentation of this file.
1 /**********************************************************************
2  * $Id: lwgeom_geos.c 5258 2010-02-17 21:02:49Z strk $
3  *
4  * PostGIS - Spatial Types for PostgreSQL
5  * http://postgis.net
6  *
7  * Copyright 2009-2010 Sandro Santilli <strk@keybit.net>
8  *
9  * This is free software; you can redistribute and/or modify it under
10  * the terms of the GNU General Public Licence. See the COPYING file.
11  *
12  **********************************************************************
13  *
14  * ST_MakeValid
15  *
16  * Attempts to make an invalid geometries valid w/out losing
17  * points.
18  *
19  * Polygons may become lines or points or a collection of
20  * polygons lines and points (collapsed ring cases).
21  *
22  * Author: Sandro Santilli <strk@keybit.net>
23  *
24  * Work done for Faunalia (http://www.faunalia.it) with fundings
25  * from Regione Toscana - Sistema Informativo per il Governo
26  * del Territorio e dell'Ambiente (RT-SIGTA).
27  *
28  * Thanks to Dr. Horst Duester for previous work on a plpgsql version
29  * of the cleanup logic [1]
30  *
31  * Thanks to Andrea Peri for recommandations on constraints.
32  *
33  * [1] http://www.sogis1.so.ch/sogis/dl/postgis/cleanGeometry.sql
34  *
35  *
36  **********************************************************************/
37 
38 #include "postgres.h"
39 #include "fmgr.h"
40 #include "funcapi.h"
41 
42 #include "../postgis_config.h"
43 #include "lwgeom_geos.h"
44 #include "liblwgeom.h"
45 #include "liblwgeom_internal.h"
46 #include "lwgeom_pg.h"
47 
48 #include <string.h>
49 #include <assert.h>
50 
51 /* #define POSTGIS_DEBUG_LEVEL 4 */
52 
53 Datum ST_MakeValid(PG_FUNCTION_ARGS);
55 Datum ST_MakeValid(PG_FUNCTION_ARGS)
56 {
57 #if POSTGIS_GEOS_VERSION < 33
58  elog(ERROR, "You need GEOS-3.3.0 or up for ST_MakeValid");
59  PG_RETURN_NULL();
60 #else /* POSTGIS_GEOS_VERSION >= 33 */
61 
62  GSERIALIZED *in, *out;
63  LWGEOM *lwgeom_in, *lwgeom_out;
64 
65  in = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
66  lwgeom_in = lwgeom_from_gserialized(in);
67 
68  switch ( lwgeom_in->type )
69  {
70  case POINTTYPE:
71  case MULTIPOINTTYPE:
72  case LINETYPE:
73  case POLYGONTYPE:
74  case MULTILINETYPE:
75  case MULTIPOLYGONTYPE:
76  case COLLECTIONTYPE:
77  break;
78 
79  default:
80  lwerror("ST_MakeValid: unsupported geometry type %s",
81  lwtype_name(lwgeom_in->type));
82  PG_RETURN_NULL();
83  break;
84  }
85 
86  lwgeom_out = lwgeom_make_valid(lwgeom_in);
87  if ( ! lwgeom_out )
88  {
89  PG_FREE_IF_COPY(in, 0);
90  PG_RETURN_NULL();
91  }
92 
93  out = geometry_serialize(lwgeom_out);
94 
95  PG_RETURN_POINTER(out);
96 #endif /* POSTGIS_GEOS_VERSION >= 33 */
97 }
98 
99 #if POSTGIS_GEOS_VERSION >= 33
100 
101 /* Uses GEOS internally */
102 static LWGEOM* lwgeom_clean(LWGEOM* lwgeom_in);
103 static LWGEOM*
104 lwgeom_clean(LWGEOM* lwgeom_in)
105 {
106  LWGEOM* lwgeom_out;
107 
108  lwgeom_out = lwgeom_make_valid(lwgeom_in);
109  if ( ! lwgeom_out )
110  {
111  return NULL;
112  }
113 
114  /* Check dimensionality is the same as input */
115  if ( lwgeom_dimensionality(lwgeom_in) != lwgeom_dimensionality(lwgeom_out) )
116  {
117  lwnotice("lwgeom_clean: dimensional collapse (%d to %d)",
118  lwgeom_dimensionality(lwgeom_in), lwgeom_dimensionality(lwgeom_out));
119 
120  return NULL;
121  }
122 
123  /* Check that the output is not a collection if the input wasn't */
124  if ( lwgeom_out->type == COLLECTIONTYPE &&
125  lwgeom_in->type != COLLECTIONTYPE )
126  {
127  lwnotice("lwgeom_clean: mixed-type output (%s) "
128  "from single-type input (%s)",
129  lwtype_name(lwgeom_out->type),
130  lwtype_name(lwgeom_in->type));
131  return NULL;
132  }
133 
134  /* Force right-hand-rule (will only affect polygons) */
135  /* gout := ST_ForceRHR(gout); */
136 
137  /* Remove repeated duplicated points ? */
138  /* gout = ST_RemoveRepeatedPoints(gout); */
139 
140  return lwgeom_out;
141 }
142 
143 #endif /* POSTGIS_GEOS_VERSION >= 33 */
144 
145 
146 Datum ST_CleanGeometry(PG_FUNCTION_ARGS);
148 Datum ST_CleanGeometry(PG_FUNCTION_ARGS)
149 {
150 #if POSTGIS_GEOS_VERSION < 33
151  elog(ERROR, "You need GEOS-3.3.0 or up for ST_CleanGeometry");
152  PG_RETURN_NULL();
153 #else /* POSTGIS_GEOS_VERSION >= 33 */
154 
155  GSERIALIZED *in, *out;
156  LWGEOM *lwgeom_in, *lwgeom_out;
157 
158  in = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
159  lwgeom_in = lwgeom_from_gserialized(in);
160 
161  /* Short-circuit: empty geometry are the cleanest ! */
162 #if 0
163  if ( lwgeom_is_empty(lwgeom_in) )
164  {
165  out = geometry_serialize(lwgeom_in);
166  PG_FREE_IF_COPY(in, 0);
167  PG_RETURN_POINTER(out);
168  }
169 #endif
170 
171  lwgeom_out = lwgeom_clean(lwgeom_in);
172  if ( ! lwgeom_out )
173  {
174  PG_FREE_IF_COPY(in, 0);
175  PG_RETURN_NULL();
176  }
177 
178  out = geometry_serialize(lwgeom_out);
179  PG_RETURN_POINTER(out);
180 
181 #endif /* POSTGIS_GEOS_VERSION >= 33 */
182 }
183 
#define LINETYPE
Definition: liblwgeom.h:61
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
#define POLYGONTYPE
Definition: liblwgeom.h:62
Datum ST_CleanGeometry(PG_FUNCTION_ARGS)
#define MULTIPOINTTYPE
Definition: liblwgeom.h:63
int lwgeom_dimensionality(LWGEOM *geom)
Return the dimensionality (relating to point/line/poly) of an lwgeom.
Definition: lwgeom.c:1294
PG_FUNCTION_INFO_V1(ST_MakeValid)
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:67
void lwnotice(const char *fmt,...)
Write a notice out to the notice handler.
Definition: lwutil.c:54
const char * lwtype_name(uint8_t type)
Return the type name string associated with a type number (e.g.
Definition: lwutil.c:164
LWGEOM * lwgeom_make_valid(LWGEOM *geom)
Attempts to make an invalid geometries valid w/out losing points.
Datum ST_MakeValid(PG_FUNCTION_ARGS)
#define MULTIPOLYGONTYPE
Definition: liblwgeom.h:65
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)
#define POINTTYPE
LWTYPE numbers, used internally by PostGIS.
Definition: liblwgeom.h:60
uint8_t type
Definition: liblwgeom.h:352
static LWGEOM * lwgeom_clean(LWGEOM *lwgeom_in)
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:1229
#define MULTILINETYPE
Definition: liblwgeom.h:64
#define COLLECTIONTYPE
Definition: liblwgeom.h:66
This library is the generic geometry handling section of PostGIS.