PostGIS  2.1.10dev-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  * Wrapper around SFCGAL for 3D functions
7  *
8  * Copyright 2012-2013 Oslandia <infos@oslandia.com>
9  *
10  * This is free software; you can redistribute and/or modify it under
11  * the terms of the GNU General Public Licence. See the COPYING file.
12  *
13  **********************************************************************/
14 
15 #include "postgres.h"
16 #include "fmgr.h"
17 #include "../liblwgeom/liblwgeom.h"
18 
19 #include "../postgis_config.h"
20 
21 #include "lwgeom_pg.h"
22 #include "lwgeom_sfcgal.h"
23 
24 
25 Datum postgis_sfcgal_version(PG_FUNCTION_ARGS);
26 
27 Datum sfcgal_from_ewkt(PG_FUNCTION_ARGS);
28 Datum sfcgal_distance(PG_FUNCTION_ARGS);
29 Datum sfcgal_distance3D(PG_FUNCTION_ARGS);
30 Datum sfcgal_area(PG_FUNCTION_ARGS);
31 Datum sfcgal_area3D(PG_FUNCTION_ARGS);
32 Datum sfcgal_intersects(PG_FUNCTION_ARGS);
33 Datum sfcgal_intersects3D(PG_FUNCTION_ARGS);
34 Datum sfcgal_intersection(PG_FUNCTION_ARGS);
35 Datum sfcgal_intersection3D(PG_FUNCTION_ARGS);
36 Datum sfcgal_extrude(PG_FUNCTION_ARGS);
37 Datum sfcgal_straight_skeleton(PG_FUNCTION_ARGS);
38 Datum sfcgal_is_planar(PG_FUNCTION_ARGS);
39 Datum sfcgal_orientation(PG_FUNCTION_ARGS);
40 Datum sfcgal_force_lhr(PG_FUNCTION_ARGS);
41 Datum sfcgal_triangulate(PG_FUNCTION_ARGS);
42 Datum sfcgal_tesselate(PG_FUNCTION_ARGS);
43 Datum sfcgal_minkowski_sum(PG_FUNCTION_ARGS);
44 
45 
47 char* text2cstring(const text *textptr);
48 
49 static int __sfcgal_init = 0;
50 
52 {
53  if ( ! __sfcgal_init ) {
54  sfcgal_init();
55  sfcgal_set_error_handlers((sfcgal_error_handler_t) lwnotice, (sfcgal_error_handler_t) lwerror);
56  sfcgal_set_alloc_handlers(lwalloc, lwfree);
57  __sfcgal_init = 1;
58  }
59 }
60 
61 
62 /* Conversion from GSERIALIZED* to SFCGAL::Geometry */
63 sfcgal_geometry_t* POSTGIS2SFCGALGeometry(GSERIALIZED *pglwgeom)
64 {
65  sfcgal_geometry_t* g;
66  LWGEOM *lwgeom = lwgeom_from_gserialized(pglwgeom);
67 
68  if (! lwgeom)
69  {
70  lwerror("POSTGIS2SFCGALGeometry: Unable to deserialize input");
71  }
72  g = LWGEOM2SFCGAL(lwgeom);
73  lwgeom_free(lwgeom);
74 
75  return g;
76 }
77 
78 
79 /* Conversion from GSERIALIZED* to SFCGAL::PreparedGeometry */
80 sfcgal_prepared_geometry_t* POSTGIS2SFCGALPreparedGeometry(GSERIALIZED *pglwgeom)
81 {
82  sfcgal_geometry_t* g;
83  LWGEOM *lwgeom = lwgeom_from_gserialized(pglwgeom);
84 
85  if (!lwgeom)
86  {
87  lwerror("POSTGIS2SFCGALPreparedGeometry: Unable to deserialize input");
88  }
89  g = LWGEOM2SFCGAL(lwgeom);
90 
91  lwgeom_free(lwgeom);
92 
93  return sfcgal_prepared_geometry_create_from_geometry(g, gserialized_get_srid(pglwgeom));
94 }
95 
96 
97 /* Conversion from SFCGAL::Geometry to GSERIALIZED */
98 GSERIALIZED* SFCGALGeometry2POSTGIS(const sfcgal_geometry_t* geom, int force3D, int SRID)
99 {
101  LWGEOM* lwgeom = SFCGAL2LWGEOM(geom, force3D, SRID);
102 
103  if (lwgeom_needs_bbox(lwgeom) == LW_TRUE)
104  lwgeom_add_bbox(lwgeom);
105 
106  result = geometry_serialize(lwgeom);
107  lwgeom_free(lwgeom);
108 
109  return result;
110 }
111 
112 
113 /* Conversion from SFCGAL::PreparedGeometry to GSERIALIZED */
114 GSERIALIZED* SFCGALPreparedGeometry2POSTGIS(const sfcgal_prepared_geometry_t* geom, int force3D)
115 {
116  return SFCGALGeometry2POSTGIS(sfcgal_prepared_geometry_geometry(geom),
117  force3D, sfcgal_prepared_geometry_srid(geom));
118 }
119 
120 
121 /* Conversion from EWKT to GSERIALIZED */
123 Datum sfcgal_from_ewkt(PG_FUNCTION_ARGS)
124 {
126  sfcgal_prepared_geometry_t* g;
127  text *wkttext = PG_GETARG_TEXT_P(0);
128  char *cstring = text2cstring(wkttext);
129 
131 
132  g = sfcgal_io_read_ewkt( cstring, strlen(cstring) );
133 
134  result = SFCGALPreparedGeometry2POSTGIS( g, 0 );
135  sfcgal_prepared_geometry_delete( g );
136  PG_RETURN_POINTER(result);
137 }
138 
139 
141 Datum sfcgal_area(PG_FUNCTION_ARGS)
142  {
144  sfcgal_geometry_t *geom;
145  double result;
146 
148 
149  input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
150  geom = POSTGIS2SFCGALGeometry(input);
151 
152  result = sfcgal_geometry_area(geom);
153  sfcgal_geometry_delete(geom);
154 
155  PG_FREE_IF_COPY(input, 0);
156 
157  PG_RETURN_FLOAT8(result);
158 }
159 
160 
162 Datum sfcgal_area3D(PG_FUNCTION_ARGS)
163  {
165  sfcgal_geometry_t *geom;
166  double result;
167 
169 
170  input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
171  geom = POSTGIS2SFCGALGeometry(input);
172 
173  result = sfcgal_geometry_area_3d(geom);
174  sfcgal_geometry_delete(geom);
175 
176  PG_FREE_IF_COPY(input, 0);
177 
178  PG_RETURN_FLOAT8(result);
179 }
180 
181 
183 Datum sfcgal_is_planar(PG_FUNCTION_ARGS)
184 {
186  sfcgal_geometry_t *geom;
187  int result;
188 
190 
191  input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
192  geom = POSTGIS2SFCGALGeometry(input);
193 
194  result = sfcgal_geometry_is_planar(geom);
195  sfcgal_geometry_delete(geom);
196 
197  PG_FREE_IF_COPY(input, 0);
198 
199  PG_RETURN_BOOL(result);
200 }
201 
202 
204 Datum sfcgal_orientation(PG_FUNCTION_ARGS)
205 {
207  sfcgal_geometry_t *geom;
208  int result;
209 
211 
212  input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
213  geom = POSTGIS2SFCGALGeometry(input);
214 
215  result = sfcgal_geometry_orientation(geom);
216  sfcgal_geometry_delete(geom);
217 
218  PG_FREE_IF_COPY(input, 0);
219 
220  PG_RETURN_INT32(result);
221 }
222 
223 
225 Datum sfcgal_intersects(PG_FUNCTION_ARGS)
226 {
227  GSERIALIZED *input0, *input1;
228  sfcgal_geometry_t *geom0, *geom1;
229  int result;
230 
232 
233  input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
234  input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
235  geom0 = POSTGIS2SFCGALGeometry(input0);
236  PG_FREE_IF_COPY(input0, 0);
237  geom1 = POSTGIS2SFCGALGeometry(input1);
238  PG_FREE_IF_COPY(input1, 1);
239 
240  result = sfcgal_geometry_intersects(geom0, geom1);
241  sfcgal_geometry_delete(geom0);
242  sfcgal_geometry_delete(geom1);
243 
244  PG_RETURN_BOOL(result);
245 }
246 
247 
249 Datum sfcgal_intersects3D(PG_FUNCTION_ARGS)
250 {
251  GSERIALIZED *input0, *input1;
252  sfcgal_geometry_t *geom0, *geom1;
253  int result;
254 
256 
257  input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
258  input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
259  geom0 = POSTGIS2SFCGALGeometry(input0);
260  PG_FREE_IF_COPY(input0, 0);
261  geom1 = POSTGIS2SFCGALGeometry(input1);
262  PG_FREE_IF_COPY(input1, 1);
263 
264  result = sfcgal_geometry_intersects_3d(geom0, geom1);
265  sfcgal_geometry_delete(geom0);
266  sfcgal_geometry_delete(geom1);
267 
268  PG_RETURN_BOOL(result);
269 }
270 
271 
273 Datum sfcgal_distance(PG_FUNCTION_ARGS)
274 {
275  GSERIALIZED *input0, *input1;
276  sfcgal_geometry_t *geom0, *geom1;
277  double result;
278 
280 
281  input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
282  input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
283  geom0 = POSTGIS2SFCGALGeometry(input0);
284  PG_FREE_IF_COPY(input0, 0);
285  geom1 = POSTGIS2SFCGALGeometry(input1);
286  PG_FREE_IF_COPY(input1, 1);
287 
288  result = sfcgal_geometry_distance(geom0, geom1);
289  sfcgal_geometry_delete(geom0);
290  sfcgal_geometry_delete(geom1);
291 
292  PG_RETURN_FLOAT8(result);
293 }
294 
295 
297 Datum sfcgal_distance3D(PG_FUNCTION_ARGS)
298 {
299  GSERIALIZED *input0, *input1;
300  sfcgal_geometry_t *geom0, *geom1;
301  double result;
302 
304 
305  input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
306  input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
307  geom0 = POSTGIS2SFCGALGeometry(input0);
308  PG_FREE_IF_COPY(input0, 0);
309  geom1 = POSTGIS2SFCGALGeometry(input1);
310  PG_FREE_IF_COPY(input1, 1);
311 
312  result = sfcgal_geometry_distance_3d(geom0, geom1);
313  sfcgal_geometry_delete(geom0);
314  sfcgal_geometry_delete(geom1);
315 
316  PG_RETURN_FLOAT8(result);
317 }
318 
319 
321 Datum sfcgal_tesselate(PG_FUNCTION_ARGS)
322 {
323  GSERIALIZED *input, *output;
324  sfcgal_geometry_t *geom;
325  sfcgal_geometry_t *result;
326  srid_t srid;
327 
329 
330  input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
331  srid = gserialized_get_srid(input);
332  geom = POSTGIS2SFCGALGeometry(input);
333  PG_FREE_IF_COPY(input, 0);
334 
335  result = sfcgal_geometry_tesselate(geom);
336  sfcgal_geometry_delete(geom);
337 
338  output = SFCGALGeometry2POSTGIS(result, 0, srid);
339  sfcgal_geometry_delete(result);
340 
341  PG_RETURN_POINTER(output);
342 }
343 
344 
346 Datum sfcgal_triangulate(PG_FUNCTION_ARGS)
347 {
348  GSERIALIZED *input, *output;
349  sfcgal_geometry_t *geom;
350  sfcgal_geometry_t *result;
351  srid_t srid;
352 
354 
355  input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
356  srid = gserialized_get_srid(input);
357  geom = POSTGIS2SFCGALGeometry(input);
358  PG_FREE_IF_COPY(input, 0);
359 
360  result = sfcgal_geometry_triangulate_2dz(geom);
361  sfcgal_geometry_delete(geom);
362 
363  output = SFCGALGeometry2POSTGIS(result, 0, srid);
364  sfcgal_geometry_delete(result);
365 
366  PG_RETURN_POINTER(output);
367 }
368 
369 
371 Datum sfcgal_force_lhr(PG_FUNCTION_ARGS)
372 {
373  GSERIALIZED *input, *output;
374  sfcgal_geometry_t *geom;
375  sfcgal_geometry_t *result;
376  srid_t srid;
377 
379 
380  input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
381  srid = gserialized_get_srid(input);
382  geom = POSTGIS2SFCGALGeometry(input);
383  PG_FREE_IF_COPY(input, 0);
384 
385  result = sfcgal_geometry_force_lhr(geom);
386  sfcgal_geometry_delete(geom);
387 
388  output = SFCGALGeometry2POSTGIS(result, 0, srid);
389  sfcgal_geometry_delete(result);
390 
391  PG_RETURN_POINTER(output);
392 }
393 
394 
396 Datum sfcgal_straight_skeleton(PG_FUNCTION_ARGS)
397 {
398  GSERIALIZED *input, *output;
399  sfcgal_geometry_t *geom;
400  sfcgal_geometry_t *result;
401  srid_t srid;
402 
404 
405  input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
406  srid = gserialized_get_srid(input);
407  geom = POSTGIS2SFCGALGeometry(input);
408  PG_FREE_IF_COPY(input, 0);
409 
410  result = sfcgal_geometry_straight_skeleton(geom);
411  sfcgal_geometry_delete(geom);
412 
413  output = SFCGALGeometry2POSTGIS(result, 0, srid);
414  sfcgal_geometry_delete(result);
415 
416  PG_RETURN_POINTER(output);
417 }
418 
419 
421 Datum sfcgal_intersection(PG_FUNCTION_ARGS)
422 {
423  GSERIALIZED *input0, *input1, *output;
424  sfcgal_geometry_t *geom0, *geom1;
425  sfcgal_geometry_t *result;
426  srid_t srid;
427 
429 
430  input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
431  srid = gserialized_get_srid(input0);
432  input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
433  geom0 = POSTGIS2SFCGALGeometry(input0);
434  PG_FREE_IF_COPY(input0, 0);
435  geom1 = POSTGIS2SFCGALGeometry(input1);
436  PG_FREE_IF_COPY(input1, 1);
437 
438  result = sfcgal_geometry_intersection(geom0, geom1);
439  sfcgal_geometry_delete(geom0);
440  sfcgal_geometry_delete(geom1);
441 
442  output = SFCGALGeometry2POSTGIS(result, 0, srid);
443  sfcgal_geometry_delete(result);
444 
445  PG_RETURN_POINTER(output);
446 }
447 
448 
450 Datum sfcgal_intersection3D(PG_FUNCTION_ARGS)
451 {
452  GSERIALIZED *input0, *input1, *output;
453  sfcgal_geometry_t *geom0, *geom1;
454  sfcgal_geometry_t *result;
455  srid_t srid;
456 
458 
459  input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
460  srid = gserialized_get_srid(input0);
461  input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
462  geom0 = POSTGIS2SFCGALGeometry(input0);
463  PG_FREE_IF_COPY(input0, 0);
464  geom1 = POSTGIS2SFCGALGeometry(input1);
465  PG_FREE_IF_COPY(input1, 1);
466 
467  result = sfcgal_geometry_intersection_3d(geom0, geom1);
468  sfcgal_geometry_delete(geom0);
469  sfcgal_geometry_delete(geom1);
470 
471  output = SFCGALGeometry2POSTGIS(result, 0, srid);
472  sfcgal_geometry_delete(result);
473 
474  PG_RETURN_POINTER(output);
475 }
476 
477 
479 Datum sfcgal_minkowski_sum(PG_FUNCTION_ARGS)
480 {
481  GSERIALIZED *input0, *input1, *output;
482  sfcgal_geometry_t *geom0, *geom1;
483  sfcgal_geometry_t *result;
484  srid_t srid;
485 
487 
488  input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
489  srid = gserialized_get_srid(input0);
490  input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
491  geom0 = POSTGIS2SFCGALGeometry(input0);
492  PG_FREE_IF_COPY(input0, 0);
493  geom1 = POSTGIS2SFCGALGeometry(input1);
494  PG_FREE_IF_COPY(input1, 1);
495 
496  result = sfcgal_geometry_minkowski_sum(geom0, geom1);
497  sfcgal_geometry_delete(geom0);
498  sfcgal_geometry_delete(geom1);
499 
500  output = SFCGALGeometry2POSTGIS(result, 0, srid);
501  sfcgal_geometry_delete(result);
502 
503  PG_RETURN_POINTER(output);
504 }
505 
506 
508 Datum sfcgal_extrude(PG_FUNCTION_ARGS)
509 {
510  GSERIALIZED *input, *output;
511  sfcgal_geometry_t *geom;
512  sfcgal_geometry_t *result;
513  double dx, dy, dz;
514  srid_t srid;
515 
517 
518  input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
519  srid = gserialized_get_srid(input);
520 
521  geom = POSTGIS2SFCGALGeometry(input);
522  PG_FREE_IF_COPY(input, 0);
523 
524  dx = PG_GETARG_FLOAT8(1);
525  dy = PG_GETARG_FLOAT8(2);
526  dz = PG_GETARG_FLOAT8(3);
527 
528  result = sfcgal_geometry_extrude(geom, dx, dy, dz);
529  sfcgal_geometry_delete(geom);
530 
531  output = SFCGALGeometry2POSTGIS(result, 0, srid);
532  sfcgal_geometry_delete(result);
533 
534  PG_RETURN_POINTER(output);
535 }
536 
538 Datum postgis_sfcgal_version(PG_FUNCTION_ARGS)
539 {
540  const char *ver = lwgeom_sfcgal_version();
541  text *result = cstring2text(ver);
542  PG_RETURN_POINTER(result);
543 }
544 
GSERIALIZED * SFCGALPreparedGeometry2POSTGIS(const sfcgal_prepared_geometry_t *geom, int force3D)
Datum sfcgal_is_planar(PG_FUNCTION_ARGS)
Datum sfcgal_extrude(PG_FUNCTION_ARGS)
void lwfree(void *mem)
Definition: lwutil.c:190
LWGEOM * lwgeom_from_gserialized(const GSERIALIZED *g)
Allocate a new LWGEOM from a GSERIALIZED.
void lwgeom_free(LWGEOM *geom)
Definition: lwgeom.c:1006
sfcgal_geometry_t * POSTGIS2SFCGALGeometry(GSERIALIZED *pglwgeom)
GSERIALIZED * SFCGALGeometry2POSTGIS(const sfcgal_geometry_t *geom, int force3D, int SRID)
Datum sfcgal_distance3D(PG_FUNCTION_ARGS)
Datum sfcgal_minkowski_sum(PG_FUNCTION_ARGS)
static int input(void)
char ** result
Definition: liblwgeom.h:218
Datum sfcgal_orientation(PG_FUNCTION_ARGS)
void lwerror(const char *fmt,...)
Write a notice out to the error handler.
Definition: lwutil.c:67
const char * lwgeom_sfcgal_version()
void lwnotice(const char *fmt,...)
Write a notice out to the notice handler.
Definition: lwutil.c:54
Datum sfcgal_force_lhr(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(sfcgal_from_ewkt)
Datum sfcgal_intersection3D(PG_FUNCTION_ARGS)
sfcgal_geometry_t * LWGEOM2SFCGAL(const LWGEOM *geom)
Datum sfcgal_area3D(PG_FUNCTION_ARGS)
Datum sfcgal_triangulate(PG_FUNCTION_ARGS)
#define LW_TRUE
Return types for functions with status returns.
Definition: liblwgeom.h:51
Datum sfcgal_intersects3D(PG_FUNCTION_ARGS)
char * text2cstring(const text *textptr)
Datum sfcgal_straight_skeleton(PG_FUNCTION_ARGS)
Datum postgis_sfcgal_version(PG_FUNCTION_ARGS)
sfcgal_prepared_geometry_t * POSTGIS2SFCGALPreparedGeometry(GSERIALIZED *pglwgeom)
void sfcgal_postgis_init(void)
Datum sfcgal_from_ewkt(PG_FUNCTION_ARGS)
GSERIALIZED * geometry_serialize(LWGEOM *lwgeom)
Datum sfcgal_intersects(PG_FUNCTION_ARGS)
void lwgeom_add_bbox(LWGEOM *lwgeom)
Compute a bbox if not already computed.
Definition: lwgeom.c:555
Datum sfcgal_distance(PG_FUNCTION_ARGS)
Datum sfcgal_intersection(PG_FUNCTION_ARGS)
Datum sfcgal_area(PG_FUNCTION_ARGS)
void * lwalloc(size_t size)
Definition: lwutil.c:175
static int __sfcgal_init
int lwgeom_needs_bbox(const LWGEOM *geom)
Check whether or not a lwgeom is big enough to warrant a bounding box.
Definition: lwgeom.c:1059
Datum sfcgal_tesselate(PG_FUNCTION_ARGS)
LWGEOM * SFCGAL2LWGEOM(const sfcgal_geometry_t *geom, int force3D, int srid)
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:70