</refentry>
+ <refentry id="ST_3DDifference">
+ <refnamediv>
+ <refname>ST_3DDifference</refname>
+
+ <refpurpose>Perform 3D difference</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>geometry <function>ST_3DDifference</function></funcdef>
+ <paramdef><type>geometry</type> <parameter>geom1</parameter></paramdef>
+ <paramdef><type>geometry</type> <parameter>geom2</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsection>
+ <title>Description</title>
+
+ <para>Availability: 2.2.0</para>
+ <para>&sfcgal_required;</para>
+ <para>&Z_support;</para>
+ <para>&P_support;</para>
+ <para>&T_support;</para>
+ </refsection>
+ </refentry>
+
+ <refentry id="ST_3DUnion">
+ <refnamediv>
+ <refname>ST_3DUnion</refname>
+
+ <refpurpose>Perform 3D union</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>geometry <function>ST_3DUnion</function></funcdef>
+ <paramdef><type>geometry</type> <parameter>geom1</parameter></paramdef>
+ <paramdef><type>geometry</type> <parameter>geom2</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsection>
+ <title>Description</title>
+
+ <para>Availability: 2.2.0</para>
+ <para>&sfcgal_required;</para>
+ <para>&Z_support;</para>
+ <para>&P_support;</para>
+ <para>&T_support;</para>
+ </refsection>
+ </refentry>
+
+
<refentry id="ST_3DArea">
<refnamediv>
<refname>ST_3DArea</refname>
</refentry>
+ <refentry id="ST_Volume">
+ <refnamediv>
+ <refname>ST_Volume</refname>
+
+ <refpurpose>Computes the volume.</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>float<function>ST_Volume</function></funcdef>
+ <paramdef><type>geometry</type> <parameter>geom1</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsection>
+ <title>Description</title>
+
+ <para>Availability: 2.2.0</para>
+ <para>&sfcgal_required;</para>
+ <para>&Z_support;</para>
+ <para>&P_support;</para>
+ <para>&T_support;</para>
+ </refsection>
+
+ </refentry>
+
+ <refentry id="ST_MakeSolid">
+ <refnamediv>
+ <refname>ST_MakeSolid</refname>
+
+ <refpurpose>Cast the geometry into a solid. No check is performed. To obtain a valid solid, the input geometry must be a closed Polyhedral Surface or a closed TIN.</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>geometry<function>ST_MakeSolid</function></funcdef>
+ <paramdef><type>geometry</type> <parameter>geom1</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsection>
+ <title>Description</title>
+
+ <para>Availability: 2.2.0</para>
+ <para>&sfcgal_required;</para>
+ <para>&Z_support;</para>
+ <para>&P_support;</para>
+ <para>&T_support;</para>
+ </refsection>
+
+ </refentry>
+
+ <refentry id="ST_IsSolid">
+ <refnamediv>
+ <refname>ST_IsSolid</refname>
+
+ <refpurpose>Test if the geometry is a solid. No validity check is performed.</refpurpose>
+ </refnamediv>
+
+ <refsynopsisdiv>
+ <funcsynopsis>
+ <funcprototype>
+ <funcdef>boolean<function>ST_IsSolid</function></funcdef>
+ <paramdef><type>geometry</type> <parameter>geom1</parameter></paramdef>
+ </funcprototype>
+ </funcsynopsis>
+ </refsynopsisdiv>
+
+ <refsection>
+ <title>Description</title>
+
+ <para>Availability: 2.2.0</para>
+ <para>&sfcgal_required;</para>
+ <para>&Z_support;</para>
+ <para>&P_support;</para>
+ <para>&T_support;</para>
+ </refsection>
+
+ </refentry>
+
+
+
</sect1>
Datum intersects(PG_FUNCTION_ARGS);
Datum intersects3d(PG_FUNCTION_ARGS);
Datum intersection(PG_FUNCTION_ARGS);
+Datum difference(PG_FUNCTION_ARGS);
+Datum geomunion(PG_FUNCTION_ARGS);
Datum area(PG_FUNCTION_ARGS);
Datum distance(PG_FUNCTION_ARGS);
Datum distance3d(PG_FUNCTION_ARGS);
Datum (*intersects_fn) (PG_FUNCTION_ARGS);
Datum (*intersects3d_fn) (PG_FUNCTION_ARGS);
Datum (*intersection_fn) (PG_FUNCTION_ARGS);
+ Datum (*difference_fn) (PG_FUNCTION_ARGS);
+ Datum (*union_fn) (PG_FUNCTION_ARGS);
Datum (*area_fn) (PG_FUNCTION_ARGS);
Datum (*distance_fn) (PG_FUNCTION_ARGS);
Datum (*distance3d_fn) (PG_FUNCTION_ARGS);
.intersects_fn = geos_intersects,
.intersects3d_fn = intersects3d_dwithin,
.intersection_fn = geos_intersection,
+ .difference_fn = geos_difference,
+ .union_fn = geos_geomunion,
.area_fn = LWGEOM_area_polygon,
.distance_fn = LWGEOM_mindistance2d,
.distance3d_fn = LWGEOM_mindistance3d
.intersects_fn = sfcgal_intersects,
.intersects3d_fn = sfcgal_intersects3D,
.intersection_fn = sfcgal_intersection,
+ .difference_fn = sfcgal_difference,
+ .union_fn = sfcgal_union,
.area_fn = sfcgal_area,
.distance_fn = sfcgal_distance,
.distance3d_fn = sfcgal_distance3D
return (*lwgeom_backend->intersection_fn)( fcinfo );
}
+PG_FUNCTION_INFO_V1(difference);
+Datum difference(PG_FUNCTION_ARGS)
+{
+ return (*lwgeom_backend->difference_fn)( fcinfo );
+}
+
+PG_FUNCTION_INFO_V1(geomunion);
+Datum geomunion(PG_FUNCTION_ARGS)
+{
+ return (*lwgeom_backend->union_fn)( fcinfo );
+}
+
PG_FUNCTION_INFO_V1(area);
Datum area(PG_FUNCTION_ARGS)
{
Datum geos_intersection(PG_FUNCTION_ARGS);
Datum convexhull(PG_FUNCTION_ARGS);
Datum topologypreservesimplify(PG_FUNCTION_ARGS);
-Datum difference(PG_FUNCTION_ARGS);
+Datum geos_difference(PG_FUNCTION_ARGS);
Datum boundary(PG_FUNCTION_ARGS);
Datum symdifference(PG_FUNCTION_ARGS);
-Datum geomunion(PG_FUNCTION_ARGS);
+Datum geos_geomunion(PG_FUNCTION_ARGS);
Datum issimple(PG_FUNCTION_ARGS);
Datum isring(PG_FUNCTION_ARGS);
Datum pointonsurface(PG_FUNCTION_ARGS);
* );
*
*/
-PG_FUNCTION_INFO_V1(geomunion);
-Datum geomunion(PG_FUNCTION_ARGS)
+PG_FUNCTION_INFO_V1(geos_geomunion);
+Datum geos_geomunion(PG_FUNCTION_ARGS)
{
GSERIALIZED *geom1;
GSERIALIZED *geom2;
* 'POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))',
* 'POLYGON((5 5, 15 5, 15 7, 5 7, 5 5))');
*/
-PG_FUNCTION_INFO_V1(difference);
-Datum difference(PG_FUNCTION_ARGS)
+PG_FUNCTION_INFO_V1(geos_difference);
+Datum geos_difference(PG_FUNCTION_ARGS)
{
GSERIALIZED *geom1;
GSERIALIZED *geom2;
Datum geos_intersects(PG_FUNCTION_ARGS);
Datum geos_intersection(PG_FUNCTION_ARGS);
+Datum geos_difference(PG_FUNCTION_ARGS);
+Datum geos_geomunion(PG_FUNCTION_ARGS);
Datum LWGEOM_area_polygon(PG_FUNCTION_ARGS);
Datum LWGEOM_mindistance2d(PG_FUNCTION_ARGS);
Datum LWGEOM_mindistance3d(PG_FUNCTION_ARGS);
Datum sfcgal_intersects3D(PG_FUNCTION_ARGS);
Datum sfcgal_intersection(PG_FUNCTION_ARGS);
Datum sfcgal_intersection3D(PG_FUNCTION_ARGS);
+Datum sfcgal_difference(PG_FUNCTION_ARGS);
+Datum sfcgal_difference3D(PG_FUNCTION_ARGS);
+Datum sfcgal_union(PG_FUNCTION_ARGS);
+Datum sfcgal_union3D(PG_FUNCTION_ARGS);
+Datum sfcgal_volume(PG_FUNCTION_ARGS);
Datum sfcgal_extrude(PG_FUNCTION_ARGS);
Datum sfcgal_straight_skeleton(PG_FUNCTION_ARGS);
Datum sfcgal_approximate_medial_axis(PG_FUNCTION_ARGS);
Datum sfcgal_triangulate(PG_FUNCTION_ARGS);
Datum sfcgal_tesselate(PG_FUNCTION_ARGS);
Datum sfcgal_minkowski_sum(PG_FUNCTION_ARGS);
+Datum sfcgal_make_solid(PG_FUNCTION_ARGS);
+Datum sfcgal_is_solid(PG_FUNCTION_ARGS);
GSERIALIZED *geometry_serialize(LWGEOM *lwgeom);
PG_RETURN_POINTER(output);
}
+PG_FUNCTION_INFO_V1(sfcgal_difference);
+Datum sfcgal_difference(PG_FUNCTION_ARGS)
+{
+ GSERIALIZED *input0, *input1, *output;
+ sfcgal_geometry_t *geom0, *geom1;
+ sfcgal_geometry_t *result;
+ srid_t srid;
+
+ sfcgal_postgis_init();
+
+ input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+ srid = gserialized_get_srid(input0);
+ input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+ geom0 = POSTGIS2SFCGALGeometry(input0);
+ PG_FREE_IF_COPY(input0, 0);
+ geom1 = POSTGIS2SFCGALGeometry(input1);
+ PG_FREE_IF_COPY(input1, 1);
+
+ result = sfcgal_geometry_difference(geom0, geom1);
+ sfcgal_geometry_delete(geom0);
+ sfcgal_geometry_delete(geom1);
+
+ output = SFCGALGeometry2POSTGIS(result, 0, srid);
+ sfcgal_geometry_delete(result);
+
+ PG_RETURN_POINTER(output);
+}
+
+
+PG_FUNCTION_INFO_V1(sfcgal_difference3D);
+Datum sfcgal_difference3D(PG_FUNCTION_ARGS)
+{
+ GSERIALIZED *input0, *input1, *output;
+ sfcgal_geometry_t *geom0, *geom1;
+ sfcgal_geometry_t *result;
+ srid_t srid;
+
+ sfcgal_postgis_init();
+
+ input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+ srid = gserialized_get_srid(input0);
+ input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+ geom0 = POSTGIS2SFCGALGeometry(input0);
+ PG_FREE_IF_COPY(input0, 0);
+ geom1 = POSTGIS2SFCGALGeometry(input1);
+ PG_FREE_IF_COPY(input1, 1);
+
+ result = sfcgal_geometry_difference_3d(geom0, geom1);
+ sfcgal_geometry_delete(geom0);
+ sfcgal_geometry_delete(geom1);
+
+ output = SFCGALGeometry2POSTGIS(result, 0, srid);
+ sfcgal_geometry_delete(result);
+
+ PG_RETURN_POINTER(output);
+}
+
+PG_FUNCTION_INFO_V1(sfcgal_union);
+Datum sfcgal_union(PG_FUNCTION_ARGS)
+{
+ GSERIALIZED *input0, *input1, *output;
+ sfcgal_geometry_t *geom0, *geom1;
+ sfcgal_geometry_t *result;
+ srid_t srid;
+
+ sfcgal_postgis_init();
+
+ input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+ srid = gserialized_get_srid(input0);
+ input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+ geom0 = POSTGIS2SFCGALGeometry(input0);
+ PG_FREE_IF_COPY(input0, 0);
+ geom1 = POSTGIS2SFCGALGeometry(input1);
+ PG_FREE_IF_COPY(input1, 1);
+
+ result = sfcgal_geometry_union(geom0, geom1);
+ sfcgal_geometry_delete(geom0);
+ sfcgal_geometry_delete(geom1);
+
+ output = SFCGALGeometry2POSTGIS(result, 0, srid);
+ sfcgal_geometry_delete(result);
+
+ PG_RETURN_POINTER(output);
+}
+
+
+PG_FUNCTION_INFO_V1(sfcgal_union3D);
+Datum sfcgal_union3D(PG_FUNCTION_ARGS)
+{
+ GSERIALIZED *input0, *input1, *output;
+ sfcgal_geometry_t *geom0, *geom1;
+ sfcgal_geometry_t *result;
+ srid_t srid;
+
+ sfcgal_postgis_init();
+
+ input0 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+ srid = gserialized_get_srid(input0);
+ input1 = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(1));
+ geom0 = POSTGIS2SFCGALGeometry(input0);
+ PG_FREE_IF_COPY(input0, 0);
+ geom1 = POSTGIS2SFCGALGeometry(input1);
+ PG_FREE_IF_COPY(input1, 1);
+
+ result = sfcgal_geometry_union_3d(geom0, geom1);
+ sfcgal_geometry_delete(geom0);
+ sfcgal_geometry_delete(geom1);
+
+ output = SFCGALGeometry2POSTGIS(result, 0, srid);
+ sfcgal_geometry_delete(result);
+
+ PG_RETURN_POINTER(output);
+}
+
+PG_FUNCTION_INFO_V1(sfcgal_volume);
+Datum sfcgal_volume(PG_FUNCTION_ARGS)
+{
+ GSERIALIZED *input;
+ sfcgal_geometry_t *geom;
+ double result;
+
+ sfcgal_postgis_init();
+
+ input = (GSERIALIZED*) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+ geom = POSTGIS2SFCGALGeometry(input);
+
+ result = sfcgal_geometry_volume(geom);
+ sfcgal_geometry_delete(geom);
+
+ PG_FREE_IF_COPY(input, 0);
+
+ PG_RETURN_FLOAT8(result);
+}
PG_FUNCTION_INFO_V1(sfcgal_minkowski_sum);
Datum sfcgal_minkowski_sum(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(result);
}
+PG_FUNCTION_INFO_V1(sfcgal_is_solid);
+Datum sfcgal_is_solid(PG_FUNCTION_ARGS)
+{
+ int result;
+ GSERIALIZED *input = PG_GETARG_GSERIALIZED_P(0);
+ LWGEOM *lwgeom = lwgeom_from_gserialized(input);
+ PG_FREE_IF_COPY(input, 0);
+ if (! lwgeom)
+ {
+ lwerror("sfcgal_is_solid: Unable to deserialize input");
+ }
+ result = FLAGS_GET_SOLID( lwgeom->flags );
+
+ lwgeom_free(lwgeom);
+
+ PG_RETURN_BOOL(result);
+}
+
+PG_FUNCTION_INFO_V1(sfcgal_make_solid);
+Datum sfcgal_make_solid(PG_FUNCTION_ARGS)
+{
+ GSERIALIZED *output;
+ GSERIALIZED *input = PG_GETARG_GSERIALIZED_P(0);
+ LWGEOM *lwgeom = lwgeom_from_gserialized(input);
+ PG_FREE_IF_COPY(input, 0);
+ if (! lwgeom)
+ {
+ lwerror("sfcgal_make_solid: Unable to deserialize input");
+ }
+
+ FLAGS_SET_SOLID( lwgeom->flags, 1);
+
+ output = geometry_serialize( lwgeom );
+ lwgeom_free(lwgeom);
+
+ PG_RETURN_POINTER(output);
+}
+
Datum sfcgal_intersects(PG_FUNCTION_ARGS);
Datum sfcgal_intersects3D(PG_FUNCTION_ARGS);
Datum sfcgal_intersection(PG_FUNCTION_ARGS);
+Datum sfcgal_difference3D(PG_FUNCTION_ARGS);
+Datum sfcgal_difference(PG_FUNCTION_ARGS);
+Datum sfcgal_union3D(PG_FUNCTION_ARGS);
+Datum sfcgal_union(PG_FUNCTION_ARGS);
+Datum sfcgal_volume(PG_FUNCTION_ARGS);
Datum sfcgal_triangulate(PG_FUNCTION_ARGS);
Datum sfcgal_area(PG_FUNCTION_ARGS);
Datum sfcgal_distance(PG_FUNCTION_ARGS);
Datum sfcgal_distance3D(PG_FUNCTION_ARGS);
+Datum sfcgal_make_solid(PG_FUNCTION_ARGS);
+Datum sfcgal_is_solid(PG_FUNCTION_ARGS);
/* Initialize sfcgal with PostGIS error handlers */
AS 'MODULE_PATHNAME','sfcgal_intersection3D'
LANGUAGE 'c' IMMUTABLE STRICT
COST 100;
+
+-- Availability: 2.2
+CREATE OR REPLACE FUNCTION ST_3DDifference(geom1 geometry, geom2 geometry)
+ RETURNS geometry
+ AS 'MODULE_PATHNAME','sfcgal_difference3D'
+ LANGUAGE 'c' IMMUTABLE STRICT
+ COST 100;
+
+-- Availability: 2.2
+CREATE OR REPLACE FUNCTION ST_3DUnion(geom1 geometry, geom2 geometry)
+ RETURNS geometry
+ AS 'MODULE_PATHNAME','sfcgal_union3D'
+ LANGUAGE 'c' IMMUTABLE STRICT
+ COST 100;
-- Availability: 2.1.0
CREATE OR REPLACE FUNCTION ST_Tesselate(geometry)
LANGUAGE 'c' IMMUTABLE STRICT
COST 100;
+-- Availability: 2.2
+CREATE OR REPLACE FUNCTION ST_Volume(geometry)
+ RETURNS FLOAT8
+ AS 'MODULE_PATHNAME','sfcgal_volume'
+ LANGUAGE 'c' IMMUTABLE STRICT
+ COST 100;
+
+-- Availability: 2.2
+CREATE OR REPLACE FUNCTION ST_MakeSolid(geometry)
+ RETURNS geometry
+ AS 'MODULE_PATHNAME','sfcgal_make_solid'
+ LANGUAGE 'c' IMMUTABLE STRICT
+ COST 100;
+
+-- Availability: 2.2
+CREATE OR REPLACE FUNCTION ST_IsSolid(geometry)
+ RETURNS boolean
+ AS 'MODULE_PATHNAME','sfcgal_is_solid'
+ LANGUAGE 'c' IMMUTABLE STRICT
+ COST 100;
+
COMMIT;
-- Tests to confirm the concave hull area is <= convex hull and
-- covers the original geometry (can't use covers because always gives topo errors with 3.3
+-- vmora: the small tolerance for area comes from the reordering of the geometry that
+-- cause small errors on area to cummulate (difference of 5e-13 on 2224 in this case)
SELECT
'ST_ConcaveHull MultiPolygon 0.95', ST_Area(ST_Intersection(geom,ST_ConcaveHull(
- geom, 0.95) )) = ST_Area(geom) As encloses_geom,
+ geom, 0.95) )) - ST_Area(geom) < 1e-9 As encloses_geom,
(ST_Area(ST_ConvexHull(geom))
- ST_Area(ST_ConcaveHull(geom, 0.95))) < (0.95 * ST_Area(ST_ConvexHull(geom) ) ) As reached_target
FROM ST_Union(ST_GeomFromText('POLYGON((175 150, 20 40,
WITH inp AS (SELECT
'POLYGON EMPTY'::geometry as empty,
'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry
- ) SELECT 'ST_Union(geometry, empty) == geometry', ST_AsEWKT(ST_Union(geometry, empty)) FROM inp;
+ ) SELECT 'ST_Union(geometry, empty) == geometry', ST_Equals(ST_ExteriorRing(ST_Union(geometry, empty)), 'LINESTRING(0 0, 10 0, 5 5, 0 0)'::geometry) FROM inp;
WITH inp AS (SELECT
'POLYGON EMPTY'::geometry as empty
) SELECT 'ST_Union(empty, empty) == empty', ST_IsEmpty(ST_Union(empty, empty)) FROM inp;
WITH inp AS (SELECT
'POLYGON EMPTY'::geometry as empty,
'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry
- ) SELECT 'ST_Difference(geometry, empty) == geometry', ST_AsEWKT(ST_Difference(geometry, empty)) FROM inp;
+ ) SELECT 'ST_Difference(geometry, empty) == geometry', ST_Equals(ST_ExteriorRing(ST_Difference(geometry, empty)), 'LINESTRING(0 0, 10 0, 5 5, 0 0)'::geometry) FROM inp;
WITH inp AS (SELECT
'POLYGON EMPTY'::geometry as empty,
'POLYGON((0 0, 10 0, 5 5, 0 0))'::geometry as geometry
T3.17|
T3.18|
ST_Buffer(empty, tolerance) == empty|t
-ST_Union(geometry, empty) == geometry|POLYGON((0 0,10 0,5 5,0 0))
+ST_Union(geometry, empty) == geometry|t
ST_Union(empty, empty) == empty|t
ST_Intersection(geometry, empty) == geometry|t
ST_Intersection(empty, empty) == empty|t
-ST_Difference(geometry, empty) == geometry|POLYGON((0 0,10 0,5 5,0 0))
+ST_Difference(geometry, empty) == geometry|t
ST_Difference(empty, geometry) == empty|t
ST_Distance(geometry, empty) == NULL|inf
ST_DWithin(geometry, empty, tolerance) == FALSE|f
isvalid|f
isvalid|t
intersection|POINT(-0 -0)
-difference|MULTILINESTRING((0 10,0 2),(0 -2,0 -10))
+difference|MULTILINESTRING((0 -2,0 -10),(0 10,0 2))
boundary|MULTILINESTRING((0 0,0 10,10 10,10 0,0 0),(2 2,2 4,4 4,4 2,2 2))
symdifference|GEOMETRYCOLLECTION(LINESTRING(2 2,4 4),LINESTRING(10 10,20 20),POLYGON((0 0,0 10,10 10,10 0,0 0),(4 4,2 4,2 2,4 2,4 4)))
issimple|t