Commit b5bd6836 authored by Paul Ramsey's avatar Paul Ramsey

Expose GEOS 3.9 ST_MaximumInscribedCircle, References #4687

parent 99673801
Pipeline #143902796 passed with stage
in 28 minutes and 41 seconds
......@@ -8,6 +8,8 @@ Only tickets not included in 3.1.0alpha1
* New features *
- #4656, Cast a geojson_text::geometry for implicit GeoJSON ingestion (Raúl Marín)
- #4687, Expose GEOS MaximumInscribedCircle (Paul Ramsey)
-
* Enhancements *
- #4681, ST_GetFaceGeometry: print corruption information (Sandro Santilli)
......
......@@ -104,6 +104,8 @@ IMAGES= \
../images/st_longestline01.png \
../images/st_longestline02.png \
../images/st_longestline03.png \
../images/st_maximuminscribedcircle01.png \
../images/st_maximuminscribedcircle02.png \
../images/st_minimumboundingcircle01.png \
../images/st_minkowskisum01.png \
../images/st_minkowskisum02.png \
......
Style3; POLYGON((142.492109375 107.353515625,141.67394661457 99.0465697135533,139.250899869331 91.0588550748945,135.316085466842 83.6973351030254,130.020716117923 77.2449088820768,123.568289896975 71.9495395331576,116.206769925106 68.0147251306694,108.219055286447 65.5916783854305,99.9121093750001 64.773515625,91.6051634635533 65.5916783854304,83.6174488248946 68.0147251306694,76.2559288530254 71.9495395331576,69.8035026320769 77.2449088820767,64.5081332831577 83.6973351030253,60.5733188806695 91.0588550748944,58.1502721354305 99.0465697135531,57.332109375 107.353515625,58.1502721354304 115.660461536447,60.5733188806693 123.648176175105,64.5081332831575 131.009696146975,69.8035026320767 137.462122367923,76.2559288530252 142.757491716842,83.6174488248943 146.692306119331,91.6051634635531 149.11535286457,99.9121093749998 149.933515625,108.219055286447 149.11535286457,116.206769925105 146.692306119331,123.568289896974 142.757491716843,130.020716117923 137.462122367923,135.316085466842 131.009696146975,139.250899869331 123.648176175106,141.67394661457 115.660461536447,142.492109375 107.353515625))
Style1-thinline;LINESTRING(100 40, 10 150, 100 150, 190 150, 100 40)
Style2-mediumline;POINT(99.912109375 107.353515625)
Style2-mediumline;POINT(66.9548654084158 80.3884978341584)
Style2-mediumline;LINESTRING(99.912109375 107.353515625,66.9548654084158 80.3884978341584)
Style3;POLYGON((133.9034375 110.4296875,133.137154482481 102.649485457997,130.86775325655 95.1682722172802,127.182445638626 88.2735466071783,122.22285593372 82.2302690662805,116.179578392822 77.2706793613745,109.28485278272 73.5853717434499,101.803639542003 71.3159705175192,94.0234375000001 70.5496875,86.2432354579969 71.3159705175192,78.7620222172803 73.5853717434499,71.8672966071783 77.2706793613744,65.8240190662806 82.2302690662804,60.8644293613746 88.2735466071782,57.1791217434499 95.1682722172801,54.9097205175192 102.649485457997,54.1434375 110.4296875,54.9097205175191 118.209889542003,57.1791217434498 125.69110278272,60.8644293613744 132.585828392822,65.8240190662804 138.629105933719,71.8672966071781 143.588695638625,78.7620222172801 147.27400325655,86.2432354579966 149.543404482481,94.0234374999998 150.3096875,101.803639542003 149.543404482481,109.28485278272 147.27400325655,116.179578392822 143.588695638626,122.222855933719 138.62910593372,127.182445638625 132.585828392822,130.86775325655 125.69110278272,133.137154482481 118.209889542003,133.9034375 110.4296875))
Style1-thinline;MULTILINESTRING((100 40, 10 150), (10 160, 100 150), (190 150, 80 40))
Style2-mediumline;POINT(94.0234375 110.4296875)
Style2-mediumline;POINT(122.2265625 82.2265625)
Style2-mediumline;LINESTRING(94.0234375 110.4296875,122.2265625 82.2265625)
This diff is collapsed.
......@@ -105,6 +105,7 @@ Datum ST_UnaryUnion(PG_FUNCTION_ARGS);
Datum ST_Equals(PG_FUNCTION_ARGS);
Datum ST_BuildArea(PG_FUNCTION_ARGS);
Datum ST_DelaunayTriangles(PG_FUNCTION_ARGS);
Datum ST_MaximumInscribedCircle(PG_FUNCTION_ARGS);
Datum pgis_union_geometry_array(PG_FUNCTION_ARGS);
Datum pgis_geometry_union_finalfn(PG_FUNCTION_ARGS);
......@@ -333,6 +334,128 @@ Datum ST_FrechetDistance(PG_FUNCTION_ARGS)
#endif /* POSTGIS_GEOS_VERSION >= 37 */
}
/**
* @brief Compute the Frechet distance with optional densification thanks to the corresponding GEOS function
* @example ST_FrechetDistance {@link #frechetdistance} - SELECT ST_FrechetDistance(
* 'LINESTRING (0 0, 50 200, 100 0, 150 200, 200 0)'::geometry,
* 'LINESTRING (0 200, 200 150, 0 100, 200 50, 0 0)'::geometry, 0.5);
*/
PG_FUNCTION_INFO_V1(ST_MaximumInscribedCircle);
Datum ST_MaximumInscribedCircle(PG_FUNCTION_ARGS)
{
#if POSTGIS_GEOS_VERSION < 39
lwpgerror("The GEOS version this PostGIS binary "
"was compiled against (%d) doesn't support "
"'GEOSMaximumInscribedCircle' function (3.9.0+ required)",
POSTGIS_GEOS_VERSION);
PG_RETURN_NULL();
#else /* POSTGIS_GEOS_VERSION >= 39 */
GSERIALIZED* geom;
GSERIALIZED* center;
GSERIALIZED* nearest;
TupleDesc resultTupleDesc;
HeapTuple resultTuple;
Datum result;
Datum result_values[3];
bool result_is_null[3];
double radius = 0.0;
int32 srid = SRID_UNKNOWN;
bool is3d;
if (PG_ARGISNULL(0))
PG_RETURN_NULL();
geom = PG_GETARG_GSERIALIZED_P(0);
srid = gserialized_get_srid(geom);
is3d = gserialized_has_z(geom);
/* Empty geometry? Return POINT EMPTY with zero radius */
if (gserialized_is_empty(geom))
{
LWGEOM* lwcenter = (LWGEOM*) lwpoint_construct_empty(gserialized_get_srid(geom), LW_FALSE, LW_FALSE);
LWGEOM* lwnearest = (LWGEOM*) lwpoint_construct_empty(gserialized_get_srid(geom), LW_FALSE, LW_FALSE);
center = geometry_serialize(lwcenter);
nearest = geometry_serialize(lwnearest);
radius = 0.0;
}
else
{
GEOSGeometry *g1;
GEOSGeometry *g2;
GBOX gbox;
if (!gserialized_get_gbox_p(geom, &gbox))
PG_RETURN_NULL();
initGEOS(lwpgnotice, lwgeom_geos_error);
double width = gbox.xmax - gbox.xmin;
double height = gbox.ymax - gbox.ymin;
double size = width > height ? width : height;
double tolerance = size / 1000.0;
g1 = POSTGIS2GEOS(geom);
if (!g1)
HANDLE_GEOS_ERROR("Geometry could not be converted to GEOS");
int gtype = gserialized_get_type(geom);
if (gtype == POLYGONTYPE || gtype == MULTIPOLYGONTYPE)
{
g2 = GEOSMaximumInscribedCircle(g1, tolerance);
if (!g2)
{
lwpgerror("Error calculating GEOSMaximumInscribedCircle.");
GEOSGeom_destroy(g1);
PG_RETURN_NULL();
}
}
else
{
g2 = GEOSLargestEmptyCircle(g1, NULL, tolerance);
if (!g2)
{
lwpgerror("Error calculating GEOSLargestEmptyCircle.");
GEOSGeom_destroy(g1);
PG_RETURN_NULL();
}
}
GEOSGeometry *gcenter = GEOSGeomGetStartPoint(g2);
GEOSGeometry *gnearest = GEOSGeomGetEndPoint(g2);
GEOSDistance(gcenter, gnearest, &radius);
GEOSSetSRID(gcenter, srid);
GEOSSetSRID(gnearest, srid);
center = GEOS2POSTGIS(gcenter, is3d);
nearest = GEOS2POSTGIS(gnearest, is3d);
GEOSGeom_destroy(gcenter);
GEOSGeom_destroy(gnearest);
GEOSGeom_destroy(g2);
GEOSGeom_destroy(g1);
}
get_call_result_type(fcinfo, NULL, &resultTupleDesc);
BlessTupleDesc(resultTupleDesc);
result_values[0] = PointerGetDatum(center);
result_is_null[0] = false;
result_values[1] = PointerGetDatum(nearest);
result_is_null[1] = false;
result_values[2] = Float8GetDatum(radius);
result_is_null[2] = false;
resultTuple = heap_form_tuple(resultTupleDesc, result_values, result_is_null);
result = HeapTupleGetDatum(resultTuple);
PG_RETURN_DATUM(result);
#endif /* POSTGIS_GEOS_VERSION >= 39 */
}
/**
* @brief This is the final function for GeomUnion
* aggregate. Will have as input an array of Geometries.
......
......@@ -3550,6 +3550,19 @@ CREATE OR REPLACE FUNCTION ST_FrechetDistance(geom1 geometry, geom2 geometry, fl
LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE
_COST_HIGH;
-- Availability: 2.4.0
CREATE OR REPLACE FUNCTION ST_FrechetDistance(geom1 geometry, geom2 geometry, float8 default -1)
RETURNS FLOAT8
AS 'MODULE_PATHNAME', 'ST_FrechetDistance'
LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE
_COST_HIGH;
-- Availability: 3.1.0
CREATE OR REPLACE FUNCTION ST_MaximumInscribedCircle(geometry, OUT center geometry, OUT nearest geometry, OUT radius double precision)
AS 'MODULE_PATHNAME', 'ST_MaximumInscribedCircle'
LANGUAGE 'c' IMMUTABLE STRICT PARALLEL SAFE
_COST_HIGH;
-- PostGIS equivalent function: difference(geom1 geometry, geom2 geometry)
CREATE OR REPLACE FUNCTION ST_Difference(geom1 geometry, geom2 geometry)
RETURNS geometry
......
......@@ -186,6 +186,11 @@ ifeq ($(shell expr "$(POSTGIS_GEOS_VERSION)" ">=" 38),1)
geos38
endif
ifeq ($(shell expr "$(POSTGIS_GEOS_VERSION)" ">=" 39),1)
# GEOS-3.0 adds stable maximuminscribedcircle implementation
TESTS += \
geos39
endif
ifeq ($(INTERRUPTTESTS),yes)
# Allow CI servers to configure --with-interrupt-tests
......
SELECT 'mic-box' AS name, st_astext(center) AS center,
st_astext(nearest) AS nearest,
round(radius::numeric,4) AS radius
FROM ST_MaximumInscribedCircle('Polygon((0 0, 100 0, 100 100, 0 100, 0 0))'::geometry);
SELECT 'mic-empty' AS name, st_astext(center) AS center,
st_astext(nearest) AS nearest,
round(radius::numeric,4) AS radius
FROM ST_MaximumInscribedCircle('Polygon Empty'::geometry);
SELECT 'mic-null' AS name, center, nearest, radius
FROM ST_MaximumInscribedCircle(NULL);
SELECT 'mic-line' AS name, st_astext(center) AS center,
st_astext(nearest) AS nearest,
round(radius::numeric,4) AS radius
FROM ST_MaximumInscribedCircle('LINESTRING(0 0, 100 0, 100 100, 0 100, 0 0)'::geometry);
SELECT 'mic-mpoint' AS name, st_astext(center) AS center,
st_astext(nearest) AS nearest,
round(radius::numeric,4) AS radius
FROM ST_MaximumInscribedCircle('MULTIPOINT(0 0, 100 0, 100 100, 0 100, 0 0)'::geometry);
SELECT 'mic-point' AS name, st_astext(center) AS center,
st_astext(nearest) AS nearest,
round(radius::numeric,4) AS radius
FROM ST_MaximumInscribedCircle('POINT(0 0)'::geometry);
mic-box|POINT(50 50)|POINT(50 0)|50.0000
mic-empty|POINT EMPTY|POINT EMPTY|0.0000
mic-null|||
mic-line|POINT(50 50)|POINT(50 0)|50.0000
mic-mpoint|POINT(50 50)|POINT(0 0)|70.7107
mic-point|POINT(0 0)|POINT(0 0)|0.0000
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment