PostGIS  3.0.6dev-r@@SVN_REVISION@@
postgis/lwgeom_sfcgal.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 #include "postgres.h"
26 #include "fmgr.h"
27 #include "utils/builtins.h"
28 #include "../liblwgeom/liblwgeom.h"
29 
30 #include "lwgeom_pg.h"
31 #include "lwgeom_sfcgal.h"
32 #include "../postgis_config.h"
33 
34 Datum postgis_sfcgal_version(PG_FUNCTION_ARGS);
35 
36 Datum sfcgal_from_ewkt(PG_FUNCTION_ARGS);
37 Datum sfcgal_area3D(PG_FUNCTION_ARGS);
38 Datum sfcgal_intersection3D(PG_FUNCTION_ARGS);
39 Datum sfcgal_difference3D(PG_FUNCTION_ARGS);
40 Datum sfcgal_union3D(PG_FUNCTION_ARGS);
41 Datum sfcgal_volume(PG_FUNCTION_ARGS);
42 Datum sfcgal_extrude(PG_FUNCTION_ARGS);
43 Datum sfcgal_straight_skeleton(PG_FUNCTION_ARGS);
44 Datum sfcgal_approximate_medial_axis(PG_FUNCTION_ARGS);
45 Datum sfcgal_is_planar(PG_FUNCTION_ARGS);
46 Datum sfcgal_orientation(PG_FUNCTION_ARGS);
47 Datum sfcgal_force_lhr(PG_FUNCTION_ARGS);
48 Datum ST_ConstrainedDelaunayTriangles(PG_FUNCTION_ARGS);
49 Datum sfcgal_tesselate(PG_FUNCTION_ARGS);
50 Datum sfcgal_minkowski_sum(PG_FUNCTION_ARGS);
51 Datum sfcgal_make_solid(PG_FUNCTION_ARGS);
52 Datum sfcgal_is_solid(PG_FUNCTION_ARGS);
53 Datum postgis_sfcgal_noop(PG_FUNCTION_ARGS);
54 
56 char *text_to_cstring(const text *textptr);
57 
58 static int __sfcgal_init = 0;
59 
60 void
62 {
63  if (!__sfcgal_init)
64  {
65  sfcgal_init();
66  sfcgal_set_error_handlers((sfcgal_error_handler_t)(void *)lwpgnotice,
67  (sfcgal_error_handler_t)(void *)lwpgerror);
68  sfcgal_set_alloc_handlers(lwalloc, lwfree);
69  __sfcgal_init = 1;
70  }
71 }
72 
73 /* Conversion from GSERIALIZED* to SFCGAL::Geometry */
74 sfcgal_geometry_t *
76 {
77  sfcgal_geometry_t *g;
78  LWGEOM *lwgeom = lwgeom_from_gserialized(pglwgeom);
79 
80  if (!lwgeom)
81  lwpgerror("POSTGIS2SFCGALGeometry: Unable to deserialize input");
82 
83  g = LWGEOM2SFCGAL(lwgeom);
84  lwgeom_free(lwgeom);
85 
86  return g;
87 }
88 
89 /* Conversion from GSERIALIZED* to SFCGAL::PreparedGeometry */
90 sfcgal_prepared_geometry_t *
92 {
93  sfcgal_geometry_t *g;
94  LWGEOM *lwgeom = lwgeom_from_gserialized(pglwgeom);
95 
96  if (!lwgeom)
97  lwpgerror("POSTGIS2SFCGALPreparedGeometry: Unable to deserialize input");
98 
99  g = LWGEOM2SFCGAL(lwgeom);
100 
101  lwgeom_free(lwgeom);
102 
103  return sfcgal_prepared_geometry_create_from_geometry(g, gserialized_get_srid(pglwgeom));
104 }
105 
106 /* Conversion from SFCGAL::Geometry to GSERIALIZED */
107 GSERIALIZED *
108 SFCGALGeometry2POSTGIS(const sfcgal_geometry_t *geom, int force3D, int32_t SRID)
109 {
110  GSERIALIZED *result;
111  LWGEOM *lwgeom = SFCGAL2LWGEOM(geom, force3D, SRID);
112 
113  if (lwgeom_needs_bbox(lwgeom) == LW_TRUE)
114  lwgeom_add_bbox(lwgeom);
115 
116  result = geometry_serialize(lwgeom);
117  lwgeom_free(lwgeom);
118 
119  return result;
120 }
121 
122 /* Conversion from SFCGAL::PreparedGeometry to GSERIALIZED */
123 GSERIALIZED *
124 SFCGALPreparedGeometry2POSTGIS(const sfcgal_prepared_geometry_t *geom, int force3D)
125 {
126  return SFCGALGeometry2POSTGIS(
127  sfcgal_prepared_geometry_geometry(geom), force3D, sfcgal_prepared_geometry_srid(geom));
128 }
129 
130 /* Conversion from EWKT to GSERIALIZED */
132 Datum sfcgal_from_ewkt(PG_FUNCTION_ARGS)
133 {
134  GSERIALIZED *result;
135  sfcgal_prepared_geometry_t *g;
136  text *wkttext = PG_GETARG_TEXT_P(0);
137  char *cstring = text_to_cstring(wkttext);
138 
140 
141  g = sfcgal_io_read_ewkt(cstring, strlen(cstring));
142 
143  result = SFCGALPreparedGeometry2POSTGIS(g, 0);
144  sfcgal_prepared_geometry_delete(g);
145  PG_RETURN_POINTER(result);
146 }
147 
149 Datum sfcgal_area3D(PG_FUNCTION_ARGS)
150 {
151  GSERIALIZED *input;
152  sfcgal_geometry_t *geom;
153  double result;
154 
156 
157  input = PG_GETARG_GSERIALIZED_P(0);
158  geom = POSTGIS2SFCGALGeometry(input);
159 
160  result = sfcgal_geometry_area_3d(geom);
161  sfcgal_geometry_delete(geom);
162 
163  PG_FREE_IF_COPY(input, 0);
164 
165  PG_RETURN_FLOAT8(result);
166 }
167 
169 Datum sfcgal_is_planar(PG_FUNCTION_ARGS)
170 {
171  GSERIALIZED *input;
172  sfcgal_geometry_t *geom;
173  int result;
174 
176 
177  input = PG_GETARG_GSERIALIZED_P(0);
178  geom = POSTGIS2SFCGALGeometry(input);
179 
180  result = sfcgal_geometry_is_planar(geom);
181  sfcgal_geometry_delete(geom);
182 
183  PG_FREE_IF_COPY(input, 0);
184 
185  PG_RETURN_BOOL(result);
186 }
187 
189 Datum sfcgal_orientation(PG_FUNCTION_ARGS)
190 {
191  GSERIALIZED *input;
192  sfcgal_geometry_t *geom;
193  int result;
194 
196 
197  input = PG_GETARG_GSERIALIZED_P(0);
198  geom = POSTGIS2SFCGALGeometry(input);
199 
200  result = sfcgal_geometry_orientation(geom);
201  sfcgal_geometry_delete(geom);
202 
203  PG_FREE_IF_COPY(input, 0);
204 
205  PG_RETURN_INT32(result);
206 }
207 
209 Datum sfcgal_tesselate(PG_FUNCTION_ARGS)
210 {
211  GSERIALIZED *input, *output;
212  sfcgal_geometry_t *geom;
213  sfcgal_geometry_t *result;
214  srid_t srid;
215 
217 
218  input = PG_GETARG_GSERIALIZED_P(0);
219  srid = gserialized_get_srid(input);
220  geom = POSTGIS2SFCGALGeometry(input);
221  PG_FREE_IF_COPY(input, 0);
222 
223  result = sfcgal_geometry_tesselate(geom);
224  sfcgal_geometry_delete(geom);
225 
226  output = SFCGALGeometry2POSTGIS(result, 0, srid);
227  sfcgal_geometry_delete(result);
228 
229  PG_RETURN_POINTER(output);
230 }
231 
233 Datum ST_ConstrainedDelaunayTriangles(PG_FUNCTION_ARGS)
234 {
235  GSERIALIZED *input, *output;
236  sfcgal_geometry_t *geom;
237  sfcgal_geometry_t *result;
238  srid_t srid;
239 
241 
242  input = PG_GETARG_GSERIALIZED_P(0);
243  srid = gserialized_get_srid(input);
244  geom = POSTGIS2SFCGALGeometry(input);
245  PG_FREE_IF_COPY(input, 0);
246 
247  result = sfcgal_geometry_triangulate_2dz(geom);
248  sfcgal_geometry_delete(geom);
249 
250  output = SFCGALGeometry2POSTGIS(result, 0, srid);
251  sfcgal_geometry_delete(result);
252 
253  PG_RETURN_POINTER(output);
254 }
255 
257 Datum sfcgal_force_lhr(PG_FUNCTION_ARGS)
258 {
259  GSERIALIZED *input, *output;
260  sfcgal_geometry_t *geom;
261  sfcgal_geometry_t *result;
262  srid_t srid;
263 
265 
266  input = PG_GETARG_GSERIALIZED_P(0);
267  srid = gserialized_get_srid(input);
268  geom = POSTGIS2SFCGALGeometry(input);
269  PG_FREE_IF_COPY(input, 0);
270 
271  result = sfcgal_geometry_force_lhr(geom);
272  sfcgal_geometry_delete(geom);
273 
274  output = SFCGALGeometry2POSTGIS(result, 0, srid);
275  sfcgal_geometry_delete(result);
276 
277  PG_RETURN_POINTER(output);
278 }
279 
281 Datum sfcgal_straight_skeleton(PG_FUNCTION_ARGS)
282 {
283  GSERIALIZED *input, *output;
284  sfcgal_geometry_t *geom;
285  sfcgal_geometry_t *result;
286  srid_t srid;
287 
289 
290  input = PG_GETARG_GSERIALIZED_P(0);
291  srid = gserialized_get_srid(input);
292  geom = POSTGIS2SFCGALGeometry(input);
293  PG_FREE_IF_COPY(input, 0);
294 
295  result = sfcgal_geometry_straight_skeleton(geom);
296  sfcgal_geometry_delete(geom);
297 
298  output = SFCGALGeometry2POSTGIS(result, 0, srid);
299  sfcgal_geometry_delete(result);
300 
301  PG_RETURN_POINTER(output);
302 }
303 
305 Datum sfcgal_approximate_medial_axis(PG_FUNCTION_ARGS)
306 {
307  GSERIALIZED *input, *output;
308  sfcgal_geometry_t *geom;
309  sfcgal_geometry_t *result;
310  srid_t srid;
311 
313 
314  input = PG_GETARG_GSERIALIZED_P(0);
315  srid = gserialized_get_srid(input);
316  geom = POSTGIS2SFCGALGeometry(input);
317  PG_FREE_IF_COPY(input, 0);
318 
319  result = sfcgal_geometry_approximate_medial_axis(geom);
320  sfcgal_geometry_delete(geom);
321 
322  output = SFCGALGeometry2POSTGIS(result, 0, srid);
323  sfcgal_geometry_delete(result);
324 
325  PG_RETURN_POINTER(output);
326 }
327 
329 Datum sfcgal_intersection3D(PG_FUNCTION_ARGS)
330 {
331  GSERIALIZED *input0, *input1, *output;
332  sfcgal_geometry_t *geom0, *geom1;
333  sfcgal_geometry_t *result;
334  srid_t srid;
335 
337 
338  input0 = PG_GETARG_GSERIALIZED_P(0);
339  srid = gserialized_get_srid(input0);
340  input1 = PG_GETARG_GSERIALIZED_P(1);
341  geom0 = POSTGIS2SFCGALGeometry(input0);
342  PG_FREE_IF_COPY(input0, 0);
343  geom1 = POSTGIS2SFCGALGeometry(input1);
344  PG_FREE_IF_COPY(input1, 1);
345 
346  result = sfcgal_geometry_intersection_3d(geom0, geom1);
347  sfcgal_geometry_delete(geom0);
348  sfcgal_geometry_delete(geom1);
349 
350  output = SFCGALGeometry2POSTGIS(result, 0, srid);
351  sfcgal_geometry_delete(result);
352 
353  PG_RETURN_POINTER(output);
354 }
355 
357 Datum sfcgal_difference3D(PG_FUNCTION_ARGS)
358 {
359  GSERIALIZED *input0, *input1, *output;
360  sfcgal_geometry_t *geom0, *geom1;
361  sfcgal_geometry_t *result;
362  srid_t srid;
363 
365 
366  input0 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
367  srid = gserialized_get_srid(input0);
368  input1 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
369  geom0 = POSTGIS2SFCGALGeometry(input0);
370  PG_FREE_IF_COPY(input0, 0);
371  geom1 = POSTGIS2SFCGALGeometry(input1);
372  PG_FREE_IF_COPY(input1, 1);
373 
374  result = sfcgal_geometry_difference_3d(geom0, geom1);
375  sfcgal_geometry_delete(geom0);
376  sfcgal_geometry_delete(geom1);
377 
378  output = SFCGALGeometry2POSTGIS(result, 0, srid);
379  sfcgal_geometry_delete(result);
380 
381  PG_RETURN_POINTER(output);
382 }
383 
385 Datum sfcgal_union3D(PG_FUNCTION_ARGS)
386 {
387  GSERIALIZED *input0, *input1, *output;
388  sfcgal_geometry_t *geom0, *geom1;
389  sfcgal_geometry_t *result;
390  srid_t srid;
391 
393 
394  input0 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
395  srid = gserialized_get_srid(input0);
396  input1 = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
397  geom0 = POSTGIS2SFCGALGeometry(input0);
398  PG_FREE_IF_COPY(input0, 0);
399  geom1 = POSTGIS2SFCGALGeometry(input1);
400  PG_FREE_IF_COPY(input1, 1);
401 
402  result = sfcgal_geometry_union_3d(geom0, geom1);
403  sfcgal_geometry_delete(geom0);
404  sfcgal_geometry_delete(geom1);
405 
406  output = SFCGALGeometry2POSTGIS(result, 0, srid);
407  sfcgal_geometry_delete(result);
408 
409  PG_RETURN_POINTER(output);
410 }
411 
413 Datum sfcgal_volume(PG_FUNCTION_ARGS)
414 {
415  GSERIALIZED *input;
416  sfcgal_geometry_t *geom;
417  double result;
418 
420 
421  input = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
422  geom = POSTGIS2SFCGALGeometry(input);
423 
424  result = sfcgal_geometry_volume(geom);
425  sfcgal_geometry_delete(geom);
426 
427  PG_FREE_IF_COPY(input, 0);
428 
429  PG_RETURN_FLOAT8(result);
430 }
431 
433 Datum sfcgal_minkowski_sum(PG_FUNCTION_ARGS)
434 {
435  GSERIALIZED *input0, *input1, *output;
436  sfcgal_geometry_t *geom0, *geom1;
437  sfcgal_geometry_t *result;
438  srid_t srid;
439 
441 
442  input0 = PG_GETARG_GSERIALIZED_P(0);
443  srid = gserialized_get_srid(input0);
444  input1 = PG_GETARG_GSERIALIZED_P(1);
445  geom0 = POSTGIS2SFCGALGeometry(input0);
446  PG_FREE_IF_COPY(input0, 0);
447  geom1 = POSTGIS2SFCGALGeometry(input1);
448  PG_FREE_IF_COPY(input1, 1);
449 
450  result = sfcgal_geometry_minkowski_sum(geom0, geom1);
451  sfcgal_geometry_delete(geom0);
452  sfcgal_geometry_delete(geom1);
453 
454  output = SFCGALGeometry2POSTGIS(result, 0, srid);
455  sfcgal_geometry_delete(result);
456 
457  PG_RETURN_POINTER(output);
458 }
459 
461 Datum sfcgal_extrude(PG_FUNCTION_ARGS)
462 {
463  GSERIALIZED *input, *output;
464  sfcgal_geometry_t *geom;
465  sfcgal_geometry_t *result;
466  double dx, dy, dz;
467  srid_t srid;
468 
470 
471  input = PG_GETARG_GSERIALIZED_P(0);
472  srid = gserialized_get_srid(input);
473 
474  geom = POSTGIS2SFCGALGeometry(input);
475  PG_FREE_IF_COPY(input, 0);
476 
477  dx = PG_GETARG_FLOAT8(1);
478  dy = PG_GETARG_FLOAT8(2);
479  dz = PG_GETARG_FLOAT8(3);
480 
481  result = sfcgal_geometry_extrude(geom, dx, dy, dz);
482  sfcgal_geometry_delete(geom);
483 
484  output = SFCGALGeometry2POSTGIS(result, 0, srid);
485  sfcgal_geometry_delete(result);
486 
487  PG_RETURN_POINTER(output);
488 }
489 
491 Datum postgis_sfcgal_version(PG_FUNCTION_ARGS)
492 {
493  const char *ver = lwgeom_sfcgal_version();
494  text *result = cstring_to_text(ver);
495  PG_RETURN_POINTER(result);
496 }
497 
499 Datum sfcgal_is_solid(PG_FUNCTION_ARGS)
500 {
501  int result;
502  GSERIALIZED *input = PG_GETARG_GSERIALIZED_P(0);
503  LWGEOM *lwgeom = lwgeom_from_gserialized(input);
504  PG_FREE_IF_COPY(input, 0);
505  if (!lwgeom)
506  elog(ERROR, "sfcgal_is_solid: Unable to deserialize input");
507 
508  result = lwgeom_is_solid(lwgeom);
509 
510  lwgeom_free(lwgeom);
511 
512  PG_RETURN_BOOL(result);
513 }
514 
516 Datum sfcgal_make_solid(PG_FUNCTION_ARGS)
517 {
518  GSERIALIZED *output;
519  GSERIALIZED *input = PG_GETARG_GSERIALIZED_P(0);
520  LWGEOM *lwgeom = lwgeom_from_gserialized(input);
521  if (!lwgeom)
522  elog(ERROR, "sfcgal_make_solid: Unable to deserialize input");
523 
524  FLAGS_SET_SOLID(lwgeom->flags, 1);
525 
526  output = geometry_serialize(lwgeom);
527  lwgeom_free(lwgeom);
528  PG_FREE_IF_COPY(input, 0);
529  PG_RETURN_POINTER(output);
530 }
531 
533 Datum postgis_sfcgal_noop(PG_FUNCTION_ARGS)
534 {
535  GSERIALIZED *input, *output;
536  LWGEOM *geom, *result;
537 
539 
540  input = PG_GETARG_GSERIALIZED_P(0);
541  geom = lwgeom_from_gserialized(input);
542  if (!geom)
543  elog(ERROR, "sfcgal_noop: Unable to deserialize input");
544 
545  result = lwgeom_sfcgal_noop(geom);
546  lwgeom_free(geom);
547  if (!result)
548  elog(ERROR, "sfcgal_noop: Unable to deserialize lwgeom");
549 
550  output = geometry_serialize(result);
551  PG_FREE_IF_COPY(input, 0);
552  PG_RETURN_POINTER(output);
553 }
LWGEOM * lwgeom_sfcgal_noop(const LWGEOM *geom_in)
int32_t gserialized_get_srid(const GSERIALIZED *g)
Extract the SRID from the serialized form (it is packed into three bytes so this is a handy function)...
Definition: gserialized.c:126
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
Definition: gserialized.c:239
sfcgal_geometry_t * LWGEOM2SFCGAL(const LWGEOM *geom)
LWGEOM * SFCGAL2LWGEOM(const sfcgal_geometry_t *geom, int force3D, int32_t srid)
const char * lwgeom_sfcgal_version()
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1138
int lwgeom_needs_bbox(const LWGEOM *geom)
Check whether or not a lwgeom is big enough to warrant a bounding box.
Definition: lwgeom.c:1191
void lwfree(void *mem)
Definition: lwutil.c:242
int lwgeom_is_solid(const LWGEOM *geom)
Return LW_TRUE if geometry has SOLID flag.
Definition: lwgeom.c:930
void * lwalloc(size_t size)
Definition: lwutil.c:227
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:107
#define FLAGS_SET_SOLID(flags, value)
Definition: liblwgeom.h:191
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition: lwgeom.c:677
Datum sfcgal_make_solid(PG_FUNCTION_ARGS)
static int __sfcgal_init
char * text_to_cstring(const text *textptr)
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)
Datum sfcgal_force_lhr(PG_FUNCTION_ARGS)
Datum postgis_sfcgal_version(PG_FUNCTION_ARGS)
sfcgal_geometry_t * POSTGIS2SFCGALGeometry(GSERIALIZED *pglwgeom)
PG_FUNCTION_INFO_V1(sfcgal_from_ewkt)
sfcgal_prepared_geometry_t * POSTGIS2SFCGALPreparedGeometry(GSERIALIZED *pglwgeom)
Datum sfcgal_from_ewkt(PG_FUNCTION_ARGS)
Datum sfcgal_orientation(PG_FUNCTION_ARGS)
Datum sfcgal_intersection3D(PG_FUNCTION_ARGS)
Datum sfcgal_approximate_medial_axis(PG_FUNCTION_ARGS)
Datum ST_ConstrainedDelaunayTriangles(PG_FUNCTION_ARGS)
Datum postgis_sfcgal_noop(PG_FUNCTION_ARGS)
Datum sfcgal_is_solid(PG_FUNCTION_ARGS)
Datum sfcgal_area3D(PG_FUNCTION_ARGS)
void sfcgal_postgis_init(void)
Datum sfcgal_is_planar(PG_FUNCTION_ARGS)
Datum sfcgal_difference3D(PG_FUNCTION_ARGS)
Datum sfcgal_extrude(PG_FUNCTION_ARGS)
Datum sfcgal_tesselate(PG_FUNCTION_ARGS)
Datum sfcgal_minkowski_sum(PG_FUNCTION_ARGS)
GSERIALIZED * SFCGALPreparedGeometry2POSTGIS(const sfcgal_prepared_geometry_t *geom, int force3D)
Datum sfcgal_straight_skeleton(PG_FUNCTION_ARGS)
Datum sfcgal_volume(PG_FUNCTION_ARGS)
GSERIALIZED * SFCGALGeometry2POSTGIS(const sfcgal_geometry_t *geom, int force3D, int32_t SRID)
Datum sfcgal_union3D(PG_FUNCTION_ARGS)
lwflags_t flags
Definition: liblwgeom.h:447