]> granicus.if.org Git - postgis/commitdiff
Get rid of some tests in _ST_ConcaveHull and only attempt to make a polygon if the...
authorRegina Obe <lr@pcorp.us>
Tue, 5 Apr 2011 22:26:45 +0000 (22:26 +0000)
committerRegina Obe <lr@pcorp.us>
Tue, 5 Apr 2011 22:26:45 +0000 (22:26 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@7006 b70326c6-7e19-0410-871a-916f4a2858ee

postgis/postgis.sql.in.c
regress/Makefile.in
regress/concave_hull.sql [new file with mode: 0644]
regress/concave_hull_expected [new file with mode: 0644]

index e5436897175fc72dba3761aa620e1c8325a56767..2059c82518e91aab9e1ccc41fe39f570bde02cba 100644 (file)
@@ -5087,23 +5087,26 @@ CREATE OR REPLACE FUNCTION ST_MinimumBoundingCircle(geometry)
 -- Contributed by Regina Obe and Leo Hsu\r
 -- Availability: 2.0.0\r
 -----------------------------------------------------------------------\r
-CREATE OR REPLACE FUNCTION _ST_ConcaveHull(param_inputgeom geometry)\r
+CREATE OR REPLACE FUNCTION _st_concavehull(param_inputgeom geometry)\r
   RETURNS geometry AS\r
 $$\r
        DECLARE     \r
        vexhull GEOMETRY;\r
        var_resultgeom geometry;\r
+       var_inputgeom geometry;\r
        vexring GEOMETRY;\r
        cavering GEOMETRY;\r
        cavept geometry[];\r
        seglength double precision;\r
        var_tempgeom geometry;\r
+       scale_factor integer := 1;\r
        i integer;\r
        \r
        BEGIN\r
 \r
                -- First compute the ConvexHull of the geometry\r
                vexhull := ST_ConvexHull(param_inputgeom);\r
+               var_inputgeom := param_inputgeom;\r
                --A point really has no concave hull\r
                IF ST_GeometryType(vexhull) = 'ST_Point' OR ST_GeometryType(vexHull) = 'ST_LineString' THEN\r
                        RETURN vexhull;\r
@@ -5111,6 +5114,12 @@ $$
 \r
                -- convert the hull perimeter to a linestring so we can manipulate individual points\r
                vexring := CASE WHEN ST_GeometryType(vexhull) = 'ST_LineString' THEN vexhull ELSE ST_ExteriorRing(vexhull) END;\r
+               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\r
+                       scale_factor := 100;\r
+                       vexring := ST_Scale(vexring, scale_factor,scale_factor);\r
+                       var_inputgeom := ST_Scale(var_inputgeom, scale_factor, scale_factor);\r
+                       --RAISE NOTICE 'Scaling';\r
+               END IF;\r
                seglength := ST_Length(vexring)/least(ST_NPoints(vexring)*2,1000) ;\r
 \r
                vexring := ST_Segmentize(vexring, seglength);\r
@@ -5119,7 +5128,7 @@ $$
                        ARRAY(\r
 \r
                                SELECT \r
-                                       ST_ClosestPoint(param_inputgeom, pt ) As the_geom\r
+                                       ST_ClosestPoint(var_inputgeom, pt ) As the_geom\r
                                        FROM (\r
                                                SELECT  ST_PointN(vexring, n ) As pt, n\r
                                                        FROM \r
@@ -5129,34 +5138,27 @@ $$
                                )\r
                        )\r
                ; \r
+               \r
 \r
-               var_resultgeom := ST_MakePolygon(ST_MakeLine(geom)\r
+               var_resultgeom := ST_MakeLine(geom\r
                        FROM ST_Dump(cavering) As foo;\r
+\r
+               IF ST_IsSimple(var_resultgeom) THEN\r
+                       var_resultgeom := ST_MakePolygon(var_resultgeom);\r
+                       --RAISE NOTICE 'is Simple: %', var_resultgeom;\r
+               ELSE /** will not result in a valid polygon -- just return convex hull **/\r
+                       --RAISE NOTICE 'is not Simple: %', var_resultgeom;\r
+                       var_resultgeom := ST_ConvexHull(var_resultgeom);\r
+               END IF;\r
                \r
-               IF NOT ST_IsValid(var_resultgeom) THEN\r
-                   --RAISE NOTICE '_ST_Concavehull invalid %', ST_AsText(var_resultgeom);\r
-                   var_tempgeom := ST_BuildArea(var_resultgeom); -- try to make valid\r
-                   IF NOT ST_IsValid(var_tempgeom) THEN\r
-                               var_resultgeom := ST_Buffer(var_resultgeom,ST_Length(cavering)/1000, 'quad_segs=3'); -- try to make valid\r
-                   END IF;\r
-                    --if still invalid or doens't  contain the geometry just return convex hull\r
-                   IF NOT ST_IsValid(var_resultgeom) or ST_GeometryType(var_resultgeom) <> 'ST_Polygon' THEN\r
-                               var_resultgeom := ST_ConvexHull(param_inputgeom);\r
-                   ELSIF ST_GeometryType(param_inputgeom) ILIKE '%Geometry%' THEN\r
-                               IF EXISTS(SELECT geom FROM ST_Dump(param_inputgeom) WHERE NOT ST_Covers(var_resultgeom,geom) ) THEN \r
-                               --we have to explode inputgeom since geos doesn't support geometrycollections for containment check\r
-                                  var_resultgeom := ST_ConvexHull(param_inputgeom);\r
-                               END IF;\r
-                       ELSIF NOT ST_Contains(var_resultgeom, param_inputgeom) THEN\r
-                               var_resultgeom := ST_ConvexHull(param_inputgeom);\r
-                       END IF;\r
+               IF scale_factor > 1 THEN -- scale the result back\r
+                       var_resultgeom := ST_Scale(var_resultgeom, 1/scale_factor, 1/scale_factor);\r
                END IF;\r
                RETURN var_resultgeom;\r
        \r
        END;\r
 $$\r
-  LANGUAGE 'plpgsql' IMMUTABLE STRICT\r
-  COST 100;\r
+  LANGUAGE plpgsql IMMUTABLE STRICT;\r
   \r
 CREATE OR REPLACE FUNCTION ST_ConcaveHull(param_geom geometry, param_pctconvex float, param_allow_holes boolean) RETURNS geometry AS\r
 $$\r
index 380da3688c1a7c0610e0c002f40666f8a86025d5..1c930d7c195acbdad94c9aaecad0d5de7a9af748 100644 (file)
@@ -86,7 +86,8 @@ TESTS = \
        tickets \
        remove_repeated_points \
        split \
-       relate
+       relate \
+       concave_hull
 
 # TESTS += wmsservers_old
 
diff --git a/regress/concave_hull.sql b/regress/concave_hull.sql
new file mode 100644 (file)
index 0000000..9b26a01
--- /dev/null
@@ -0,0 +1,42 @@
+-- $Id$\r
+-- Tests to confirm the concave hull area is <= convex hull and \r
+-- covers the original geometry (can't use covers because always gives topo errors with 3.3\r
+SELECT \r
+       'ST_ConcaveHull MultiPolygon 0.95', ST_Area(ST_Intersection(geom,ST_ConcaveHull(\r
+               geom, 0.95) )) = ST_Area(geom) As encloses_geom, \r
+               (ST_Area(ST_ConvexHull(geom)) \r
+               - ST_Area(ST_ConcaveHull(geom, 0.95))) < (0.95 * ST_Area(ST_ConvexHull(geom) ) ) As reached_target\r
+FROM ST_Union(ST_GeomFromText('POLYGON((175 150, 20 40, \r
+                       50 60, 125 100, 175 150))'),\r
+               ST_Buffer(ST_GeomFromText('POINT(110 170)'), 20)\r
+               ) As geom;\r
+               \r
+SELECT \r
+       'ST_ConcaveHull Lines 0.80', ST_Intersection(geom,ST_ConcaveHull(\r
+               geom, 0.80) ) = geom As encloses_geom, \r
+               (ST_Area(ST_ConvexHull(geom)) \r
+               - ST_Area(ST_ConcaveHull(geom, 0.80))) < (0.80 * ST_Area(ST_ConvexHull(geom) ) ) As reached_target\r
+\r
+FROM ST_GeomFromText('MULTILINESTRING((106 164,30 112,74 70,82 112,130 94,\r
+       130 62,122 40,156 32,162 76,172 88),\r
+(132 178,134 148,128 136,96 128,132 108,150 130,\r
+170 142,174 110,156 96,158 90,158 88),\r
+(22 64,66 28,94 38,94 68,114 76,112 30,\r
+132 10,168 18,178 34,186 52,184 74,190 100,\r
+190 122,182 148,178 170,176 184,156 164,146 178,\r
+132 186,92 182,56 158,36 150,62 150,76 128,88 118))') As geom;\r
+\r
+-- test holes vs. no holes - holes should still enclose but have smaller area than no holes --\r
+SELECT \r
+       'ST_ConcaveHull Lines 0.80 holes', ST_Intersection(geom,ST_ConcaveHull(\r
+               geom, 0.80, true) ) = geom As encloses_geom, \r
+               ST_Area(ST_ConcaveHull(geom, 0.80, true)) < ST_Area(ST_ConcaveHull(geom, 0.80)) As reached_target\r
+\r
+FROM ST_GeomFromText('MULTILINESTRING((106 164,30 112,74 70,82 112,130 94,\r
+       130 62,122 40,156 32,162 76,172 88),\r
+(132 178,134 148,128 136,96 128,132 108,150 130,\r
+170 142,174 110,156 96,158 90,158 88),\r
+(22 64,66 28,94 38,94 68,114 76,112 30,\r
+132 10,168 18,178 34,186 52,184 74,190 100,\r
+190 122,182 148,178 170,176 184,156 164,146 178,\r
+132 186,92 182,56 158,36 150,62 150,76 128,88 118))') As geom;\r
diff --git a/regress/concave_hull_expected b/regress/concave_hull_expected
new file mode 100644 (file)
index 0000000..f81537c
--- /dev/null
@@ -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