]> granicus.if.org Git - postgis/commitdiff
Implement ST_ForceCurve (#2430)
authorSandro Santilli <strk@keybit.net>
Wed, 14 Aug 2013 22:40:16 +0000 (22:40 +0000)
committerSandro Santilli <strk@keybit.net>
Wed, 14 Aug 2013 22:40:16 +0000 (22:40 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@11803 b70326c6-7e19-0410-871a-916f4a2858ee

NEWS
liblwgeom/cunit/cu_libgeom.c
liblwgeom/liblwgeom.h.in
liblwgeom/lwcompound.c
liblwgeom/lwgeom.c
libpgcommon/lwgeom_pg.h
postgis/lwgeom_functions_basic.c
postgis/postgis.sql.in
regress/Makefile.in
regress/forcecurve.sql [new file with mode: 0644]
regress/forcecurve_expected [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index cd08fd79a91d2da3a631eb9ac195841b8b0d5f94..e28c707d058b2f54ef1ef02cdd0e8b29903a71a6 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -10,6 +10,8 @@ PostGIS 2.2.0
 
  * New Features *
 
+  - #2430, ST_ForceCurve
+
  * Enhancements *
 
   - Added missing variants of ST_TPI(), ST_TRI() and ST_Roughness()
index ae0e319f528311ee342ddd70a5f81dffaf976cb8..18c8deeba0a2355113baa17b9f73f023b29bf8f9 100644 (file)
@@ -891,6 +891,61 @@ static void test_lwgeom_same(void)
 
 }
 
+/*
+ * Test lwgeom_force_curve
+ */
+static void test_lwgeom_as_curve(void)
+{
+       LWGEOM *geom;
+       LWGEOM *geom2;
+       char *in_ewkt, *out_ewkt;
+
+       geom = lwgeom_from_wkt("LINESTRING(0 0, 10 0)", LW_PARSER_CHECK_NONE);
+       geom2 = lwgeom_as_curve(geom);
+       in_ewkt = "COMPOUNDCURVE((0 0,10 0))";
+       out_ewkt = lwgeom_to_ewkt(geom2);
+       if (strcmp(in_ewkt, out_ewkt))
+               fprintf(stderr, "\nExp:   %s\nObt:  %s\n", in_ewkt, out_ewkt);
+       CU_ASSERT_STRING_EQUAL(in_ewkt, out_ewkt);
+       lwfree(out_ewkt);
+       lwgeom_free(geom);
+       lwgeom_free(geom2);
+
+       geom = lwgeom_from_wkt("MULTILINESTRING((0 0, 10 0))", LW_PARSER_CHECK_NONE);
+       geom2 = lwgeom_as_curve(geom);
+       in_ewkt = "MULTICURVE((0 0,10 0))";
+       out_ewkt = lwgeom_to_ewkt(geom2);
+       if (strcmp(in_ewkt, out_ewkt))
+               fprintf(stderr, "\nExp:   %s\nObt:  %s\n", in_ewkt, out_ewkt);
+       CU_ASSERT_STRING_EQUAL(in_ewkt, out_ewkt);
+       lwfree(out_ewkt);
+       lwgeom_free(geom);
+       lwgeom_free(geom2);
+
+       geom = lwgeom_from_wkt("POLYGON((0 0, 10 0, 10 10, 0 10, 0 0))", LW_PARSER_CHECK_NONE);
+       geom2 = lwgeom_as_curve(geom);
+       in_ewkt = "CURVEPOLYGON((0 0,10 0,10 10,0 10,0 0))";
+       out_ewkt = lwgeom_to_ewkt(geom2);
+       if (strcmp(in_ewkt, out_ewkt))
+               fprintf(stderr, "\nExp:   %s\nObt:  %s\n", in_ewkt, out_ewkt);
+       CU_ASSERT_STRING_EQUAL(in_ewkt, out_ewkt);
+       lwfree(out_ewkt);
+       lwgeom_free(geom);
+       lwgeom_free(geom2);
+
+       geom = lwgeom_from_wkt("MULTIPOLYGON(((0 0, 10 0, 10 10, 0 10, 0 0)))", LW_PARSER_CHECK_NONE);
+       geom2 = lwgeom_as_curve(geom);
+       in_ewkt = "MULTISURFACE(((0 0,10 0,10 10,0 10,0 0)))";
+       out_ewkt = lwgeom_to_ewkt(geom2);
+       if (strcmp(in_ewkt, out_ewkt))
+               fprintf(stderr, "\nExp:   %s\nObt:  %s\n", in_ewkt, out_ewkt);
+       CU_ASSERT_STRING_EQUAL(in_ewkt, out_ewkt);
+       lwfree(out_ewkt);
+       lwgeom_free(geom);
+       lwgeom_free(geom2);
+
+}
+
 /*
 ** Used by test harness to register the tests in this file.
 */
@@ -914,6 +969,7 @@ CU_TestInfo libgeom_tests[] =
        PG_TEST(test_lwgeom_calculate_gbox),
        PG_TEST(test_lwgeom_is_empty),
        PG_TEST(test_lwgeom_same),
+       PG_TEST(test_lwgeom_as_curve),
        CU_TEST_INFO_NULL
 };
 CU_SuiteInfo libgeom_suite = {"libgeom",  NULL,  NULL, libgeom_tests};
index 688e7830c33fdbb2bf48c4ef537a70f08757f669..5d3ff05d8f94a4b25e876884c028f9f4bfe3303b 100644 (file)
@@ -580,6 +580,7 @@ extern LWPSURFACE *lwgeom_as_lwpsurface(const LWGEOM *lwgeom);
 extern LWTRIANGLE *lwgeom_as_lwtriangle(const LWGEOM *lwgeom);
 extern LWTIN *lwgeom_as_lwtin(const LWGEOM *lwgeom);
 extern LWGEOM *lwgeom_as_multi(const LWGEOM *lwgeom);
+extern LWGEOM *lwgeom_as_curve(const LWGEOM *lwgeom);
 
 /* Casts LW*->LWGEOM (always cast) */
 extern LWGEOM *lwtin_as_lwgeom(const LWTIN *obj);
@@ -946,6 +947,12 @@ extern int lwcurvepoly_add_ring(LWCURVEPOLY *poly, LWGEOM *ring);
 */
 extern int lwcompound_add_lwgeom(LWCOMPOUND *comp, LWGEOM *geom);
 
+/**
+* Construct an equivalent compound curve from a linestring. 
+* Compound curves can have linear components, so this works fine 
+*/
+extern LWCOMPOUND* lwcompound_construct_from_lwline(const LWLINE *lwpoly);
+
 /**
 * Construct an equivalent curve polygon from a polygon. Curve polygons
 * can have linear rings as their rings, so this works fine (in theory?)
index 8ff92e4cf2a1d5c1afc33f12e81c38bf37a341d2..a613746933369ad75a733c76225389e98b8405f6 100644 (file)
@@ -191,3 +191,12 @@ lwcompound_contains_point(const LWCOMPOUND *comp, const POINT2D *pt)
        /* Inside */
        return LW_INSIDE;
 }      
+
+LWCOMPOUND *
+lwcompound_construct_from_lwline(const LWLINE *lwline)
+{
+  LWCOMPOUND* ogeom = lwcompound_construct_empty(lwline->srid, FLAGS_GET_Z(lwline->flags), FLAGS_GET_M(lwline->flags));
+  lwcompound_add_lwgeom(ogeom, lwgeom_clone((LWGEOM*)lwline));
+       /* ogeom->bbox = lwline->bbox; */
+  return ogeom;
+}
index 55a5ccd56faf6b7d767239a014014cee0ad8b66a..4221f1c4713cc9733604ba168f53aed99177ee99 100644 (file)
@@ -261,7 +261,7 @@ LWGEOM *lwpoint_as_lwgeom(const LWPOINT *obj)
 /**
 ** Look-up for the correct MULTI* type promotion for singleton types.
 */
-static uint8_t MULTITYPE[17] =
+static uint8_t MULTITYPE[NUMTYPES] =
 {
        0,
        MULTIPOINTTYPE,        /*  1 */
@@ -274,7 +274,7 @@ static uint8_t MULTITYPE[17] =
        POLYHEDRALSURFACETYPE, /* 11 */
        0, 0,
        TINTYPE,               /* 14 */
-       0,0
+       0
 };
 
 /**
@@ -317,6 +317,50 @@ lwgeom_as_multi(const LWGEOM *lwgeom)
        return ogeom;
 }
 
+/**
+* Create a new LWGEOM of the appropriate CURVE* type.
+*/
+LWGEOM *
+lwgeom_as_curve(const LWGEOM *lwgeom)
+{
+       LWGEOM *ogeom;
+       int type = lwgeom->type;
+/*
+  int hasz = FLAGS_GET_Z(lwgeom->flags);
+  int hasm = FLAGS_GET_M(lwgeom->flags);
+  int srid = lwgeom->srid;
+*/
+
+       switch(type)
+       {
+               case LINETYPE:
+      /* turn to COMPOUNDCURVE */
+      ogeom = (LWGEOM*)lwcompound_construct_from_lwline((LWLINE*)lwgeom);
+      break;
+               case POLYGONTYPE:
+      ogeom = (LWGEOM*)lwcurvepoly_construct_from_lwpoly(lwgeom_as_lwpoly(lwgeom));
+      break;
+               case MULTILINETYPE:
+      /* turn to MULTICURVE */
+      ogeom = lwgeom_clone(lwgeom);
+      ogeom->type = MULTICURVETYPE;
+      break;
+               case MULTIPOLYGONTYPE:
+      /* turn to MULTISURFACE */
+      ogeom = lwgeom_clone(lwgeom);
+      ogeom->type = MULTISURFACETYPE;
+      break;
+               case COLLECTIONTYPE:
+               default:
+      ogeom = lwgeom_clone(lwgeom);
+      break;
+  }
+
+  /* TODO: copy bbox from input geom ? */
+
+  return ogeom;
+}
+
 
 /**
 * Free the containing LWGEOM and the associated BOX. Leave the underlying 
index 3d392e84f78ccd11131d6fc837b01071e11d9c18..90526be47eb1352b3fabd55735acf6fdb1915d5a 100644 (file)
@@ -150,6 +150,7 @@ Datum LWGEOM_force_3dz(PG_FUNCTION_ARGS);
 Datum LWGEOM_force_4d(PG_FUNCTION_ARGS);
 Datum LWGEOM_force_collection(PG_FUNCTION_ARGS);
 Datum LWGEOM_force_multi(PG_FUNCTION_ARGS);
+Datum LWGEOM_force_curve(PG_FUNCTION_ARGS);
 
 Datum LWGEOMFromWKB(PG_FUNCTION_ARGS);
 Datum WKBFromLWGEOM(PG_FUNCTION_ARGS);
index bb975e99115a20fa8da0353a8b30b2154e873e6c..2e5727b246fc030615cdd03a8dcec84cdf696368 100644 (file)
@@ -519,6 +519,29 @@ Datum LWGEOM_force_multi(PG_FUNCTION_ARGS)
        PG_RETURN_POINTER(result);
 }
 
+/** transform input geometry to a curved type */
+PG_FUNCTION_INFO_V1(LWGEOM_force_curve);
+Datum LWGEOM_force_curve(PG_FUNCTION_ARGS)
+{
+       GSERIALIZED *geom = (GSERIALIZED *)PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+       GSERIALIZED *result;
+       LWGEOM *lwgeom;
+       LWGEOM *ogeom;
+
+       POSTGIS_DEBUG(2, "LWGEOM_force_curve called");
+
+  /* TODO: early out if input is already a curve */
+
+       lwgeom = lwgeom_from_gserialized(geom);
+       ogeom = lwgeom_as_curve(lwgeom);
+
+       result = geometry_serialize(ogeom);
+
+       PG_FREE_IF_COPY(geom, 0);
+
+       PG_RETURN_POINTER(result);
+}
+
 /** transform input geometry to a SFS 1.1 geometry type compliant */
 PG_FUNCTION_INFO_V1(LWGEOM_force_sfs);
 Datum LWGEOM_force_sfs(PG_FUNCTION_ARGS)
index 42d871dc676f93b1fac27fb58a07244c9739a58c..f5c3d1c1cc709c4633a284faf533078d5c5d5899 100644 (file)
@@ -1277,6 +1277,12 @@ CREATE OR REPLACE FUNCTION ST_Multi(geometry)
        AS 'MODULE_PATHNAME', 'LWGEOM_force_multi'
        LANGUAGE 'c' IMMUTABLE STRICT;
 
+-- Availability: 2.2.0
+CREATE OR REPLACE FUNCTION ST_ForceCurve(geometry)
+       RETURNS geometry
+       AS 'MODULE_PATHNAME', 'LWGEOM_force_curve'
+       LANGUAGE 'c' IMMUTABLE STRICT;
+
 -- Availability: 2.1.0
 CREATE OR REPLACE FUNCTION ST_ForceSFS(geometry)
        RETURNS geometry
index 06c723eee8f0a97a70c1133894137b5c64fd1841..d975a518fc1d1c8f32faeee0d841e26311389303 100644 (file)
@@ -81,6 +81,7 @@ TESTS = \
        summary \
        affine \
        empty \
+  forcecurve \
        measures \
        legacy \
        long_xact \
diff --git a/regress/forcecurve.sql b/regress/forcecurve.sql
new file mode 100644 (file)
index 0000000..b655ba3
--- /dev/null
@@ -0,0 +1,12 @@
+SELECT '1', ST_AsText(ST_ForceCurve('POINT(0 0)'));
+SELECT '2', ST_AsText(ST_ForceCurve('MULTIPOINT((0 0))'));
+SELECT '3', ST_AsText(ST_ForceCurve('LINESTRING(0 0, 10 0)'));
+SELECT '4', ST_AsText(ST_ForceCurve('MULTILINESTRING((0 0, 10 0),(30 0, 30 2))'));
+SELECT '5', ST_AsText(ST_ForceCurve('POLYGON((0 0,10 0,10 10,0 10,0 0))'));
+SELECT '6', ST_AsText(ST_ForceCurve('MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0)))'));
+SELECT '7', ST_AsText(ST_ForceCurve('GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0))))'));
+SELECT '8', ST_AsText(ST_ForceCurve('CIRCULARSTRING(0 0,10 1,20 0)'));
+SELECT '9', ST_AsText(ST_ForceCurve('COMPOUNDCURVE(CIRCULARSTRING(0 0,10 1,20 0))'));
+SELECT '10', ST_AsText(ST_ForceCurve('MULTICURVE(COMPOUNDCURVE(CIRCULARSTRING(0 0,10 1,20 0)))'));
+SELECT '11', ST_AsText(ST_ForceCurve('CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0,10 1,20 0),(20 0,0 0)))'));
+SELECT '12', ST_AsText(ST_ForceCurve('MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0,10 1,20 0),(20 0,0 0))))'));
diff --git a/regress/forcecurve_expected b/regress/forcecurve_expected
new file mode 100644 (file)
index 0000000..e4e7846
--- /dev/null
@@ -0,0 +1,12 @@
+1|POINT(0 0)
+2|MULTIPOINT(0 0)
+3|COMPOUNDCURVE((0 0,10 0))
+4|MULTICURVE((0 0,10 0),(30 0,30 2))
+5|CURVEPOLYGON((0 0,10 0,10 10,0 10,0 0))
+6|MULTISURFACE(((0 0,10 0,10 10,0 10,0 0)))
+7|GEOMETRYCOLLECTION(MULTIPOLYGON(((0 0,10 0,10 10,0 10,0 0))))
+8|CIRCULARSTRING(0 0,10 1,20 0)
+9|COMPOUNDCURVE(CIRCULARSTRING(0 0,10 1,20 0))
+10|MULTICURVE(COMPOUNDCURVE(CIRCULARSTRING(0 0,10 1,20 0)))
+11|CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0,10 1,20 0),(20 0,0 0)))
+12|MULTISURFACE(CURVEPOLYGON(COMPOUNDCURVE(CIRCULARSTRING(0 0,10 1,20 0),(20 0,0 0))))