Get rid of some tests in _ST_ConcaveHull and only attempt to make a polygon if the line is simple. ST_Covers is causing me quite a bit of greif as a testing tool. don't recall so many topo node this and that in GEOS 3.2 ST_Covers. Also add in some regress tests for ST_ConcaveHull -- more to come.

git-svn-id: http://svn.osgeo.org/postgis/trunk@7006 b70326c6-7e19-0410-871a-916f4a2858ee
This commit is contained in:
Regina Obe 2011-04-05 22:26:45 +00:00
parent e1c23bbf5c
commit 3cc1d00614
4 changed files with 73 additions and 25 deletions

View file

@ -5087,23 +5087,26 @@ CREATE OR REPLACE FUNCTION ST_MinimumBoundingCircle(geometry)
-- Contributed by Regina Obe and Leo Hsu
-- Availability: 2.0.0
-----------------------------------------------------------------------
CREATE OR REPLACE FUNCTION _ST_ConcaveHull(param_inputgeom geometry)
CREATE OR REPLACE FUNCTION _st_concavehull(param_inputgeom geometry)
RETURNS geometry AS
$$
DECLARE
vexhull GEOMETRY;
var_resultgeom geometry;
var_inputgeom geometry;
vexring GEOMETRY;
cavering GEOMETRY;
cavept geometry[];
seglength double precision;
var_tempgeom geometry;
scale_factor integer := 1;
i integer;
BEGIN
-- First compute the ConvexHull of the geometry
vexhull := ST_ConvexHull(param_inputgeom);
var_inputgeom := param_inputgeom;
--A point really has no concave hull
IF ST_GeometryType(vexhull) = 'ST_Point' OR ST_GeometryType(vexHull) = 'ST_LineString' THEN
RETURN vexhull;
@ -5111,6 +5114,12 @@ $$
-- convert the hull perimeter to a linestring so we can manipulate individual points
vexring := CASE WHEN ST_GeometryType(vexhull) = 'ST_LineString' THEN vexhull ELSE ST_ExteriorRing(vexhull) END;
IF abs(ST_X(ST_PointN(vexring,1))) < 1 THEN --scale the geometry to prevent stupid precision errors - not sure it works so make low for now
scale_factor := 100;
vexring := ST_Scale(vexring, scale_factor,scale_factor);
var_inputgeom := ST_Scale(var_inputgeom, scale_factor, scale_factor);
--RAISE NOTICE 'Scaling';
END IF;
seglength := ST_Length(vexring)/least(ST_NPoints(vexring)*2,1000) ;
vexring := ST_Segmentize(vexring, seglength);
@ -5119,7 +5128,7 @@ $$
ARRAY(
SELECT
ST_ClosestPoint(param_inputgeom, pt ) As the_geom
ST_ClosestPoint(var_inputgeom, pt ) As the_geom
FROM (
SELECT ST_PointN(vexring, n ) As pt, n
FROM
@ -5129,34 +5138,27 @@ $$
)
)
;
var_resultgeom := ST_MakePolygon(ST_MakeLine(geom))
FROM ST_Dump(cavering) As foo;
IF NOT ST_IsValid(var_resultgeom) THEN
--RAISE NOTICE '_ST_Concavehull invalid %', ST_AsText(var_resultgeom);
var_tempgeom := ST_BuildArea(var_resultgeom); -- try to make valid
IF NOT ST_IsValid(var_tempgeom) THEN
var_resultgeom := ST_Buffer(var_resultgeom,ST_Length(cavering)/1000, 'quad_segs=3'); -- try to make valid
END IF;
--if still invalid or doens't contain the geometry just return convex hull
IF NOT ST_IsValid(var_resultgeom) or ST_GeometryType(var_resultgeom) <> 'ST_Polygon' THEN
var_resultgeom := ST_ConvexHull(param_inputgeom);
ELSIF ST_GeometryType(param_inputgeom) ILIKE '%Geometry%' THEN
IF EXISTS(SELECT geom FROM ST_Dump(param_inputgeom) WHERE NOT ST_Covers(var_resultgeom,geom) ) THEN
--we have to explode inputgeom since geos doesn't support geometrycollections for containment check
var_resultgeom := ST_ConvexHull(param_inputgeom);
END IF;
ELSIF NOT ST_Contains(var_resultgeom, param_inputgeom) THEN
var_resultgeom := ST_ConvexHull(param_inputgeom);
END IF;
var_resultgeom := ST_MakeLine(geom)
FROM ST_Dump(cavering) As foo;
IF ST_IsSimple(var_resultgeom) THEN
var_resultgeom := ST_MakePolygon(var_resultgeom);
--RAISE NOTICE 'is Simple: %', var_resultgeom;
ELSE /** will not result in a valid polygon -- just return convex hull **/
--RAISE NOTICE 'is not Simple: %', var_resultgeom;
var_resultgeom := ST_ConvexHull(var_resultgeom);
END IF;
IF scale_factor > 1 THEN -- scale the result back
var_resultgeom := ST_Scale(var_resultgeom, 1/scale_factor, 1/scale_factor);
END IF;
RETURN var_resultgeom;
END;
$$
LANGUAGE 'plpgsql' IMMUTABLE STRICT
COST 100;
LANGUAGE plpgsql IMMUTABLE STRICT;
CREATE OR REPLACE FUNCTION ST_ConcaveHull(param_geom geometry, param_pctconvex float, param_allow_holes boolean) RETURNS geometry AS
$$

View file

@ -86,7 +86,8 @@ TESTS = \
tickets \
remove_repeated_points \
split \
relate
relate \
concave_hull
# TESTS += wmsservers_old

42
regress/concave_hull.sql Normal file
View file

@ -0,0 +1,42 @@
-- $Id$
-- 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
SELECT
'ST_ConcaveHull MultiPolygon 0.95', ST_Area(ST_Intersection(geom,ST_ConcaveHull(
geom, 0.95) )) = ST_Area(geom) 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,
50 60, 125 100, 175 150))'),
ST_Buffer(ST_GeomFromText('POINT(110 170)'), 20)
) As geom;
SELECT
'ST_ConcaveHull Lines 0.80', ST_Intersection(geom,ST_ConcaveHull(
geom, 0.80) ) = geom As encloses_geom,
(ST_Area(ST_ConvexHull(geom))
- ST_Area(ST_ConcaveHull(geom, 0.80))) < (0.80 * ST_Area(ST_ConvexHull(geom) ) ) As reached_target
FROM ST_GeomFromText('MULTILINESTRING((106 164,30 112,74 70,82 112,130 94,
130 62,122 40,156 32,162 76,172 88),
(132 178,134 148,128 136,96 128,132 108,150 130,
170 142,174 110,156 96,158 90,158 88),
(22 64,66 28,94 38,94 68,114 76,112 30,
132 10,168 18,178 34,186 52,184 74,190 100,
190 122,182 148,178 170,176 184,156 164,146 178,
132 186,92 182,56 158,36 150,62 150,76 128,88 118))') As geom;
-- test holes vs. no holes - holes should still enclose but have smaller area than no holes --
SELECT
'ST_ConcaveHull Lines 0.80 holes', ST_Intersection(geom,ST_ConcaveHull(
geom, 0.80, true) ) = geom As encloses_geom,
ST_Area(ST_ConcaveHull(geom, 0.80, true)) < ST_Area(ST_ConcaveHull(geom, 0.80)) As reached_target
FROM ST_GeomFromText('MULTILINESTRING((106 164,30 112,74 70,82 112,130 94,
130 62,122 40,156 32,162 76,172 88),
(132 178,134 148,128 136,96 128,132 108,150 130,
170 142,174 110,156 96,158 90,158 88),
(22 64,66 28,94 38,94 68,114 76,112 30,
132 10,168 18,178 34,186 52,184 74,190 100,
190 122,182 148,178 170,176 184,156 164,146 178,
132 186,92 182,56 158,36 150,62 150,76 128,88 118))') As geom;

View file

@ -0,0 +1,3 @@
ST_ConcaveHull MultiPolygon 0.95|t|t
ST_ConcaveHull Lines 0.80|t|t
ST_ConcaveHull Lines 0.80 holes|t|t