PostGIS  2.5.0beta2dev-r@@SVN_REVISION@@
lwgeom_backend_api.c
Go to the documentation of this file.
1 /**********************************************************************
2  *
3  * PostGIS - Spatial Types for PostgreSQL
4  * http://postgis.net
5  *
6  * PostGIS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * PostGIS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with PostGIS. If not, see <http://www.gnu.org/licenses/>.
18  *
19  **********************************************************************
20  *
21  * Copyright 2012-2013 Oslandia <infos@oslandia.com>
22  *
23  **********************************************************************/
24 
25 
26 #include "postgres.h"
27 #include "fmgr.h"
28 #include "utils/guc.h" /* for custom variables */
29 
30 #include "../postgis_config.h"
31 #include "lwgeom_pg.h"
32 #include "liblwgeom.h"
33 
34 #include "lwgeom_backend_api.h"
35 #include "lwgeom_geos.h"
36 #if HAVE_SFCGAL
37 #include "lwgeom_sfcgal.h"
38 #endif
39 
40 Datum intersects(PG_FUNCTION_ARGS);
41 Datum intersects3d(PG_FUNCTION_ARGS);
42 Datum intersection(PG_FUNCTION_ARGS);
43 Datum difference(PG_FUNCTION_ARGS);
44 Datum geomunion(PG_FUNCTION_ARGS);
45 Datum area(PG_FUNCTION_ARGS);
46 Datum distance(PG_FUNCTION_ARGS);
47 Datum distance3d(PG_FUNCTION_ARGS);
48 
49 Datum intersects3d_dwithin(PG_FUNCTION_ARGS);
50 
51 
53 {
54  const char* name;
55  Datum (*intersects_fn) (PG_FUNCTION_ARGS);
56  Datum (*intersects3d_fn) (PG_FUNCTION_ARGS);
57  Datum (*intersection_fn) (PG_FUNCTION_ARGS);
58  Datum (*difference_fn) (PG_FUNCTION_ARGS);
59  Datum (*union_fn) (PG_FUNCTION_ARGS);
60  Datum (*area_fn) (PG_FUNCTION_ARGS);
61  Datum (*distance_fn) (PG_FUNCTION_ARGS);
62  Datum (*distance3d_fn) (PG_FUNCTION_ARGS);
63 };
64 
65 #if HAVE_SFCGAL
66 #define LWGEOM_NUM_BACKENDS 2
67 #else
68 #define LWGEOM_NUM_BACKENDS 1
69 #endif
70 
72  { .name = "geos",
73  .intersects_fn = geos_intersects,
74  .intersects3d_fn = intersects3d_dwithin,
75  .intersection_fn = geos_intersection,
76  .difference_fn = geos_difference,
77  .union_fn = geos_geomunion,
78  .area_fn = LWGEOM_area_polygon,
79  .distance_fn = LWGEOM_mindistance2d,
80  .distance3d_fn = LWGEOM_mindistance3d
81  },
82 #if HAVE_SFCGAL
83  { .name = "sfcgal",
84  .intersects_fn = sfcgal_intersects,
85  .intersects3d_fn = sfcgal_intersects3D,
86  .intersection_fn = sfcgal_intersection,
87  .difference_fn = sfcgal_difference,
88  .union_fn = sfcgal_union,
89  .area_fn = sfcgal_area,
90  .distance_fn = sfcgal_distance,
91  .distance3d_fn = sfcgal_distance3D
92  }
93 #endif
94 };
95 
96 
97 /* Geometry Backend */
99 struct lwgeom_backend_definition* lwgeom_backend = &lwgeom_backends[0];
100 
101 static void lwgeom_backend_switch( const char* newvalue, __attribute__((__unused__)) void* extra )
102 {
103  int i;
104 
105  if (!newvalue) { return; }
106 
107  for ( i = 0; i < LWGEOM_NUM_BACKENDS; ++i ) {
108  if ( !strcmp(lwgeom_backends[i].name, newvalue) ) {
109  lwgeom_backend = &lwgeom_backends[i];
110  return;
111  }
112  }
113  lwpgerror("Can't find %s geometry backend", newvalue );
114 }
115 
117 {
118  /* #2382 Before trying to create a user GUC, make sure */
119  /* that the name is not already in use. Why would it be in use? */
120  /* During an upgrade, a prior copy of the PostGIS library will */
121  /* already be loaded in memory and the GUC already defined. We */
122  /* can skip GUC definition in this case, so we just return. */
123  static const char *guc_name = "postgis.backend";
124  // const char *guc_installed = GetConfigOption(guc_name, TRUE, FALSE);
125 
126  /* Uh oh, this GUC name already exists. Ordinarily we could just go on */
127  /* our way, but the way the postgis.backend works is by using the "assign" */
128  /* callback to change which backend is in use by flipping a global variable */
129  /* over. This saves the overhead of looking up the engine every time, at */
130  /* the expense of the extra complexity. */
131  if ( postgis_guc_find_option(guc_name) )
132  {
133  /* In this narrow case the previously installed GUC is tied to the callback in */
134  /* the previously loaded library. Probably this is happening during an */
135  /* upgrade, so the old library is where the callback ties to. */
136  elog(WARNING, "'%s' is already set and cannot be changed until you reconnect", guc_name);
137  return;
138  }
139 
140  /* Good, the GUC name is not already in use, so this must be a fresh */
141  /* and clean new load of the library, and we can define the user GUC */
142  DefineCustomStringVariable( guc_name, /* name */
143  "Sets the PostGIS Geometry Backend.", /* short_desc */
144  "Sets the PostGIS Geometry Backend (allowed values are 'geos' or 'sfcgal')", /* long_desc */
145  &lwgeom_backend_name, /* valueAddr */
146  (char *)lwgeom_backends[0].name, /* bootValue */
147  PGC_USERSET, /* GucContext context */
148  0, /* int flags */
149  NULL, /* GucStringCheckHook check_hook */
150  lwgeom_backend_switch, /* GucStringAssignHook assign_hook */
151  NULL /* GucShowHook show_hook */
152  );
153 }
154 
155 #if 0
156 
157 backend/utils/misc/guc.h
158 int GetNumConfigOptions(void) returns num_guc_variables
159 
160 backend/utils/misc/guc_tables.h
161 struct config_generic ** get_guc_variables(void)
162 
163 
164 
165 
166 #endif
167 
169 Datum intersects(PG_FUNCTION_ARGS)
170 {
171  return (*lwgeom_backend->intersects_fn)( fcinfo );
172 }
173 
175 Datum intersection(PG_FUNCTION_ARGS)
176 {
177  return (*lwgeom_backend->intersection_fn)( fcinfo );
178 }
179 
181 Datum difference(PG_FUNCTION_ARGS)
182 {
183  return (*lwgeom_backend->difference_fn)( fcinfo );
184 }
185 
187 Datum geomunion(PG_FUNCTION_ARGS)
188 {
189  return (*lwgeom_backend->union_fn)( fcinfo );
190 }
191 
193 Datum area(PG_FUNCTION_ARGS)
194 {
195  return (*lwgeom_backend->area_fn)( fcinfo );
196 }
197 
199 Datum distance(PG_FUNCTION_ARGS)
200 {
201  return (*lwgeom_backend->distance_fn)( fcinfo );
202 }
203 
205 Datum distance3d(PG_FUNCTION_ARGS)
206 {
207  return (*lwgeom_backend->distance3d_fn)( fcinfo );
208 }
209 
211 Datum intersects3d(PG_FUNCTION_ARGS)
212 {
213  return (*lwgeom_backend->intersects3d_fn)( fcinfo );
214 }
215 
216 
217 
218 /* intersects3d through dwithin
219  * used by the 'geos' backend
220  */
222 Datum intersects3d_dwithin(PG_FUNCTION_ARGS)
223 {
224  double mindist;
225  GSERIALIZED *geom1 = PG_GETARG_GSERIALIZED_P(0);
226  GSERIALIZED *geom2 = PG_GETARG_GSERIALIZED_P(1);
227  LWGEOM *lwgeom1 = lwgeom_from_gserialized(geom1);
228  LWGEOM *lwgeom2 = lwgeom_from_gserialized(geom2);
229 
230  error_if_srid_mismatch(lwgeom1->srid, lwgeom2->srid);
231 
232  mindist = lwgeom_mindistance3d_tolerance(lwgeom1,lwgeom2,0.0);
233 
234  PG_FREE_IF_COPY(geom1, 0);
235  PG_FREE_IF_COPY(geom2, 1);
236  /*empty geometries cases should be right handled since return from underlying
237  functions should be FLT_MAX which causes false as answer*/
238  PG_RETURN_BOOL(0.0 == mindist);
239 }
double lwgeom_mindistance3d_tolerance(const LWGEOM *lw1, const LWGEOM *lw2, double tolerance)
Function handling 3d min distance calculations and dwithin calculations.
Definition: measures3d.c:363
Datum(* distance_fn)(PG_FUNCTION_ARGS)
Datum geomunion(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(intersects)
Datum distance3d(PG_FUNCTION_ARGS)
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
static void lwgeom_backend_switch(const char *newvalue, __attribute__((__unused__)) void *extra)
Datum(* difference_fn)(PG_FUNCTION_ARGS)
Datum area(PG_FUNCTION_ARGS)
#define __attribute__(x)
Definition: liblwgeom.h:200
Datum intersects3d_dwithin(PG_FUNCTION_ARGS)
Datum LWGEOM_mindistance3d(PG_FUNCTION_ARGS)
char * lwgeom_backend_name
Datum sfcgal_distance3D(PG_FUNCTION_ARGS)
void error_if_srid_mismatch(int srid1, int srid2)
Definition: lwutil.c:338
Datum(* union_fn)(PG_FUNCTION_ARGS)
Datum intersection(PG_FUNCTION_ARGS)
int32_t srid
Definition: liblwgeom.h:401
Datum geos_geomunion(PG_FUNCTION_ARGS)
void lwgeom_init_backend()
Datum(* distance3d_fn)(PG_FUNCTION_ARGS)
Datum intersects(PG_FUNCTION_ARGS)
Datum sfcgal_intersects3D(PG_FUNCTION_ARGS)
Datum(* intersects3d_fn)(PG_FUNCTION_ARGS)
struct lwgeom_backend_definition * lwgeom_backend
Datum intersects3d(PG_FUNCTION_ARGS)
Datum(* area_fn)(PG_FUNCTION_ARGS)
Datum distance(PG_FUNCTION_ARGS)
Datum sfcgal_union(PG_FUNCTION_ARGS)
Datum sfcgal_intersects(PG_FUNCTION_ARGS)
Datum LWGEOM_area_polygon(PG_FUNCTION_ARGS)
#define LWGEOM_NUM_BACKENDS
Datum geos_intersects(PG_FUNCTION_ARGS)
Datum LWGEOM_mindistance2d(PG_FUNCTION_ARGS)
Datum sfcgal_distance(PG_FUNCTION_ARGS)
Datum geos_difference(PG_FUNCTION_ARGS)
Datum sfcgal_intersection(PG_FUNCTION_ARGS)
Datum sfcgal_area(PG_FUNCTION_ARGS)
Datum(* intersection_fn)(PG_FUNCTION_ARGS)
Datum sfcgal_difference(PG_FUNCTION_ARGS)
Datum(* intersects_fn)(PG_FUNCTION_ARGS)
Datum geos_intersection(PG_FUNCTION_ARGS)
struct lwgeom_backend_definition lwgeom_backends[LWGEOM_NUM_BACKENDS]
This library is the generic geometry handling section of PostGIS.
Datum difference(PG_FUNCTION_ARGS)