PostGIS 3.0.6dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
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
34Datum postgis_sfcgal_version(PG_FUNCTION_ARGS);
35
36Datum sfcgal_from_ewkt(PG_FUNCTION_ARGS);
37Datum sfcgal_area3D(PG_FUNCTION_ARGS);
38Datum sfcgal_intersection3D(PG_FUNCTION_ARGS);
39Datum sfcgal_difference3D(PG_FUNCTION_ARGS);
40Datum sfcgal_union3D(PG_FUNCTION_ARGS);
41Datum sfcgal_volume(PG_FUNCTION_ARGS);
42Datum sfcgal_extrude(PG_FUNCTION_ARGS);
43Datum sfcgal_straight_skeleton(PG_FUNCTION_ARGS);
44Datum sfcgal_approximate_medial_axis(PG_FUNCTION_ARGS);
45Datum sfcgal_is_planar(PG_FUNCTION_ARGS);
46Datum sfcgal_orientation(PG_FUNCTION_ARGS);
47Datum sfcgal_force_lhr(PG_FUNCTION_ARGS);
48Datum ST_ConstrainedDelaunayTriangles(PG_FUNCTION_ARGS);
49Datum sfcgal_tesselate(PG_FUNCTION_ARGS);
50Datum sfcgal_minkowski_sum(PG_FUNCTION_ARGS);
51Datum sfcgal_make_solid(PG_FUNCTION_ARGS);
52Datum sfcgal_is_solid(PG_FUNCTION_ARGS);
53Datum postgis_sfcgal_noop(PG_FUNCTION_ARGS);
54
56char *text_to_cstring(const text *textptr);
57
58static int __sfcgal_init = 0;
59
60void
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 */
74sfcgal_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 */
90sfcgal_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 */
108SFCGALGeometry2POSTGIS(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 */
124SFCGALPreparedGeometry2POSTGIS(const sfcgal_prepared_geometry_t *geom, int force3D)
125{
127 sfcgal_prepared_geometry_geometry(geom), force3D, sfcgal_prepared_geometry_srid(geom));
128}
129
130/* Conversion from EWKT to GSERIALIZED */
132Datum 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
149Datum 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
169Datum 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
189Datum 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
209Datum 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
233Datum 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
257Datum 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
281Datum 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
305Datum 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
329Datum 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
357Datum 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
385Datum 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
413Datum 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
433Datum 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
461Datum 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
491Datum 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
499Datum 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
516Datum 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
533Datum 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)...
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
sfcgal_geometry_t * LWGEOM2SFCGAL(const LWGEOM *geom)
const char * lwgeom_sfcgal_version()
LWGEOM * SFCGAL2LWGEOM(const sfcgal_geometry_t *geom, int force3D, int32_t srid)
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 * lwalloc(size_t size)
Definition lwutil.c:227
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
#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)
Datum sfcgal_force_lhr(PG_FUNCTION_ARGS)
Datum postgis_sfcgal_version(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(sfcgal_from_ewkt)
Datum sfcgal_from_ewkt(PG_FUNCTION_ARGS)
Datum sfcgal_orientation(PG_FUNCTION_ARGS)
Datum sfcgal_intersection3D(PG_FUNCTION_ARGS)
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)
Datum sfcgal_approximate_medial_axis(PG_FUNCTION_ARGS)
Datum ST_ConstrainedDelaunayTriangles(PG_FUNCTION_ARGS)
sfcgal_geometry_t * POSTGIS2SFCGALGeometry(GSERIALIZED *pglwgeom)
sfcgal_prepared_geometry_t * POSTGIS2SFCGALPreparedGeometry(GSERIALIZED *pglwgeom)
Datum postgis_sfcgal_noop(PG_FUNCTION_ARGS)
Datum sfcgal_is_solid(PG_FUNCTION_ARGS)
GSERIALIZED * SFCGALGeometry2POSTGIS(const sfcgal_geometry_t *geom, int force3D, int32_t SRID)
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)
Datum sfcgal_straight_skeleton(PG_FUNCTION_ARGS)
GSERIALIZED * SFCGALPreparedGeometry2POSTGIS(const sfcgal_prepared_geometry_t *geom, int force3D)
Datum sfcgal_volume(PG_FUNCTION_ARGS)
Datum sfcgal_union3D(PG_FUNCTION_ARGS)
lwflags_t flags
Definition liblwgeom.h:447