ST_Envelope(raster) in C instead of ST_Envelope(ST_ConvexHull(raster)). ticket #2828
authorBborie Park <bkpark at ucdavis.edu>
Sat, 26 Jul 2014 13:47:29 +0000 (13:47 +0000)
committerBborie Park <bkpark at ucdavis.edu>
Sat, 26 Jul 2014 13:47:29 +0000 (13:47 +0000)
git-svn-id: http://svn.osgeo.org/postgis/trunk@12832 b70326c6-7e19-0410-871a-916f4a2858ee

NEWS
raster/rt_core/librtcore.h
raster/rt_core/rt_geometry.c
raster/rt_pg/rtpg_geometry.c
raster/rt_pg/rtpostgis.sql.in
raster/test/cunit/cu_raster_geometry.c
raster/test/regress/Makefile.in

diff --git a/NEWS b/NEWS
index dcff590cf561ca320f99ef71d5773550d50c1158..890f3b2ff41da05e010519292c7efc93085f6fec 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -55,6 +55,7 @@ PostGIS 2.2.0
   - #2747, Add support for GDAL 2.0
   - #2754, SFCGAL can now be installed with CREATE EXTENSION
        Vincent Mora (Oslandia)
+  - #2828, Convert ST_Envelope(raster) from SQL to C
 
  * Bug Fixes *
 
index 2f7c29a06807428815bdd3b67f3bbeb8f3d3a792..fb647bc0ebaa43c11ddd4f869107a25980364ae4 100644 (file)
@@ -1350,10 +1350,17 @@ rt_errorstate rt_raster_get_convex_hull(rt_raster raster, LWGEOM **hull);
  *
  * @return ES_NONE if success, ES_ERROR if error
  */
-rt_errorstate rt_raster_get_envelope(
-       rt_raster raster,
-       rt_envelope *env
-);
+rt_errorstate rt_raster_get_envelope(rt_raster raster, rt_envelope *env);
+
+/**
+ * Get raster's envelope as a geometry
+ *
+ * @param raster : the raster to get info from
+ * @param **env : pointer to envelope geom
+ *
+ * @return ES_NONE if success, ES_ERROR if error
+ */
+rt_errorstate rt_raster_get_envelope_geom(rt_raster raster, LWGEOM **env);
 
 /**
  * Get raster perimeter
index 45e23fe894fe341c89fa5da2830d874622b8468c..e0006063840a759f9953365c245d4f9de0845f44 100644 (file)
@@ -674,6 +674,135 @@ rt_raster_pixel_as_polygon(rt_raster rast, int x, int y)
     return poly;
 }
 
+/******************************************************************************
+* rt_raster_get_envelope_geom()
+******************************************************************************/
+
+/**
+ * Get raster's envelope as a geometry
+ *
+ * @param raster : the raster to get info from
+ * @param **env : pointer to envelope
+ *
+ * @return ES_NONE if success, ES_ERROR if error
+ */
+rt_errorstate
+rt_raster_get_envelope_geom(rt_raster raster, LWGEOM **env) {
+       double gt[6] = {0.0};
+       int srid = SRID_UNKNOWN;
+
+       POINTARRAY *pts = NULL;
+       POINT4D p4d;
+
+       assert(env != NULL);
+       *env = NULL;
+
+       /* raster is NULL, envelope is NULL */
+       if (raster == NULL)
+               return ES_NONE;
+
+       /* raster metadata */
+       srid = rt_raster_get_srid(raster);
+       rt_raster_get_geotransform_matrix(raster, gt);
+
+       RASTER_DEBUGF(
+               3,
+               "rt_raster_get_envelope: raster is %dx%d",
+               raster->width,
+               raster->height
+       ); 
+
+       /* return point or line since at least one of the two dimensions is 0 */
+       if ((!raster->width) || (!raster->height)) {
+               p4d.x = gt[0];
+               p4d.y = gt[3];
+
+               /* return point */
+               if (!raster->width && !raster->height) {
+                       LWPOINT *point = lwpoint_make2d(srid, p4d.x, p4d.y);
+                       *env = lwpoint_as_lwgeom(point);
+               }
+               /* return linestring */
+               else {
+                       LWLINE *line = NULL;
+                       pts = ptarray_construct_empty(0, 0, 2);
+
+                       /* first point of line */
+                       ptarray_append_point(pts, &p4d, LW_TRUE);
+
+                       /* second point of line */
+                       if (rt_raster_cell_to_geopoint(
+                               raster,
+                               rt_raster_get_width(raster), rt_raster_get_height(raster),
+                               &p4d.x, &p4d.y,
+                               gt
+                       ) != ES_NONE) {
+                               rterror("rt_raster_get_envelope: Could not get second point for linestring");
+                               return ES_ERROR;
+                       }
+                       ptarray_append_point(pts, &p4d, LW_TRUE);
+                       line = lwline_construct(srid, NULL, pts);
+
+                       *env = lwline_as_lwgeom(line);
+               }
+
+               return ES_NONE;
+       }
+       else {
+               rt_envelope rtenv;
+               int err = ES_NONE;
+               POINTARRAY **rings = NULL;
+               LWPOLY* poly = NULL;
+
+               /* only one ring */
+               rings = (POINTARRAY **) rtalloc(sizeof (POINTARRAY*));
+               if (!rings) {
+                       rterror("rt_raster_get_envelope_geom: Could not allocate memory for polygon ring");
+                       return ES_ERROR;
+               }
+               rings[0] = ptarray_construct(0, 0, 5);
+               if (!rings[0]) {
+                       rterror("rt_raster_get_envelope_geom: Could not construct point array");
+                       return ES_ERROR;
+               }
+               pts = rings[0];
+
+               err = rt_raster_get_envelope(raster, &rtenv);
+               if (err != ES_NONE) {
+                       rterror("rt_raster_get_envelope_geom: Could not get raster envelope");
+                       return err;
+               }
+
+               /* build ring */
+
+               /* minx, maxy */
+               p4d.x = rtenv.MinX;
+               p4d.y = rtenv.MaxY;
+               ptarray_set_point4d(pts, 0, &p4d);
+               ptarray_set_point4d(pts, 4, &p4d);
+
+               /* maxx, maxy */
+               p4d.x = rtenv.MaxX;
+               p4d.y = rtenv.MaxY;
+               ptarray_set_point4d(pts, 1, &p4d);
+
+               /* maxx, miny */
+               p4d.x = rtenv.MaxX;
+               p4d.y = rtenv.MinY;
+               ptarray_set_point4d(pts, 2, &p4d);
+
+               /* minx, miny */
+               p4d.x = rtenv.MinX;
+               p4d.y = rtenv.MinY;
+               ptarray_set_point4d(pts, 3, &p4d);
+
+               poly = lwpoly_construct(srid, 0, 1, rings);
+               *env = lwpoly_as_lwgeom(poly);
+       }
+
+       return ES_NONE;
+}
+
 /******************************************************************************
 * rt_raster_get_convex_hull()
 ******************************************************************************/
index 69d881964ca5b7cec93f9859c2c8a5cbb4bae6e6..e7bf184102101c83c37bfb1c30b7b5e3e21ab437 100644 (file)
@@ -47,6 +47,7 @@
 #include "rtpostgis.h"
 #include "rtpg_internal.h"
 
+Datum RASTER_envelope(PG_FUNCTION_ARGS);
 Datum RASTER_convex_hull(PG_FUNCTION_ARGS);
 Datum RASTER_dumpAsPolygons(PG_FUNCTION_ARGS);
 
@@ -59,9 +60,64 @@ Datum RASTER_getPolygon(PG_FUNCTION_ARGS);
 /* rasterize a geometry */
 Datum RASTER_asRaster(PG_FUNCTION_ARGS);
 
+/* ---------------------------------------------------------------- */
+/*  Raster envelope                                                 */
+/* ---------------------------------------------------------------- */
+PG_FUNCTION_INFO_V1(RASTER_envelope);
+Datum RASTER_envelope(PG_FUNCTION_ARGS)
+{
+       rt_pgraster *pgraster;
+       rt_raster raster;
+       LWGEOM *geom = NULL;
+       GSERIALIZED* gser = NULL;
+       size_t gser_size;
+       int err = ES_NONE;
+
+       bool minhull = FALSE;
+
+       if (PG_ARGISNULL(0))
+               PG_RETURN_NULL();
+
+       pgraster = (rt_pgraster *) PG_DETOAST_DATUM_SLICE(
+               PG_GETARG_DATUM(0),
+               0,
+               sizeof(struct rt_raster_serialized_t)
+       );
+       raster = rt_raster_deserialize(pgraster, TRUE);
+
+       if (!raster) {
+               PG_FREE_IF_COPY(pgraster, 0);
+               elog(ERROR, "RASTER_envelope: Could not deserialize raster");
+               PG_RETURN_NULL();
+       }
+
+       err = rt_raster_get_envelope_geom(raster, &geom);
+
+       rt_raster_destroy(raster);
+       PG_FREE_IF_COPY(pgraster, 0);
+
+       if (err != ES_NONE) {
+               elog(ERROR, "RASTER_envelope: Could not get raster's envelope");
+               PG_RETURN_NULL();
+       }
+       else if (geom == NULL) {
+               elog(NOTICE, "Raster's envelope is NULL");
+               PG_RETURN_NULL();
+       }
+
+       gser = gserialized_from_lwgeom(geom, 0, &gser_size);
+       lwgeom_free(geom);
+
+       SET_VARSIZE(gser, gser_size);
+       PG_RETURN_POINTER(gser);
+}
+
 /**
  * Return the convex hull of this raster
  */
+/* ---------------------------------------------------------------- */
+/*  Raster convex hull                                              */
+/* ---------------------------------------------------------------- */
 PG_FUNCTION_INFO_V1(RASTER_convex_hull);
 Datum RASTER_convex_hull(PG_FUNCTION_ARGS)
 {
index 558d3d32e3ea3bcf26db1cc7dc630a8f35869b75..f90eee62b2a9cd815c3f8d91930c00fb7bf64e63 100644 (file)
@@ -112,6 +112,11 @@ CREATE TYPE geomval AS (
 -- Raster Accessors
 -----------------------------------------------------------------------
 
+CREATE OR REPLACE FUNCTION st_envelope(raster)
+       RETURNS geometry
+       AS 'MODULE_PATHNAME','RASTER_envelope'
+       LANGUAGE 'c' IMMUTABLE STRICT;
+
 CREATE OR REPLACE FUNCTION st_convexhull(raster)
     RETURNS geometry
     AS 'MODULE_PATHNAME','RASTER_convex_hull'
@@ -130,11 +135,6 @@ CREATE OR REPLACE FUNCTION box3d(raster)
     AS 'select box3d(st_convexhull($1))'
     LANGUAGE 'sql' IMMUTABLE STRICT;
 
-CREATE OR REPLACE FUNCTION st_envelope(raster)
-    RETURNS geometry
-    AS 'select st_envelope(st_convexhull($1))'
-    LANGUAGE 'sql' IMMUTABLE STRICT;
-
 CREATE OR REPLACE FUNCTION st_height(raster)
     RETURNS integer
     AS 'MODULE_PATHNAME','RASTER_getHeight'
index c4eb2f5f3ea90428768ec1c80cc94a704b049a03..7ab31ae5b971d46711ba579afbe647ccc867da11 100644 (file)
 #include "CUnit/Basic.h"
 #include "cu_tester.h"
 
+static void test_raster_envelope() {
+       rt_raster raster = NULL;
+       rt_envelope rtenv;
+
+       /* width = 0, height = 0 */
+       raster = rt_raster_new(0, 0);
+       CU_ASSERT(raster != NULL);
+
+       rt_raster_set_offsets(raster, 0.5, 0.5);
+       rt_raster_set_scale(raster, 1, -1);
+
+       CU_ASSERT_EQUAL(rt_raster_get_envelope(raster, &rtenv), ES_NONE);
+       CU_ASSERT_DOUBLE_EQUAL(rtenv.MinX, 0.5, DBL_EPSILON);
+       CU_ASSERT_DOUBLE_EQUAL(rtenv.MaxX, 0.5, DBL_EPSILON);
+       CU_ASSERT_DOUBLE_EQUAL(rtenv.MinY, 0.5, DBL_EPSILON);
+       CU_ASSERT_DOUBLE_EQUAL(rtenv.MaxY, 0.5, DBL_EPSILON);
+       cu_free_raster(raster);
+
+       /* width = 0 */
+       raster = rt_raster_new(0, 5);
+       CU_ASSERT(raster != NULL);
+
+       rt_raster_set_offsets(raster, 0.5, 0.5);
+       rt_raster_set_scale(raster, 1, -1);
+
+       CU_ASSERT_EQUAL(rt_raster_get_envelope(raster, &rtenv), ES_NONE);
+       CU_ASSERT_DOUBLE_EQUAL(rtenv.MinX, 0.5, DBL_EPSILON);
+       CU_ASSERT_DOUBLE_EQUAL(rtenv.MaxX, 0.5, DBL_EPSILON);
+       CU_ASSERT_DOUBLE_EQUAL(rtenv.MinY, -4.5, DBL_EPSILON);
+       CU_ASSERT_DOUBLE_EQUAL(rtenv.MaxY, 0.5, DBL_EPSILON);
+       cu_free_raster(raster);
+
+       /* height = 0 */
+       raster = rt_raster_new(5, 0);
+       CU_ASSERT(raster != NULL);
+
+       rt_raster_set_offsets(raster, 0.5, 0.5);
+       rt_raster_set_scale(raster, 1, -1);
+
+       CU_ASSERT_EQUAL(rt_raster_get_envelope(raster, &rtenv), ES_NONE);
+       CU_ASSERT_DOUBLE_EQUAL(rtenv.MinX, 0.5, DBL_EPSILON);
+       CU_ASSERT_DOUBLE_EQUAL(rtenv.MaxX, 5.5, DBL_EPSILON);
+       CU_ASSERT_DOUBLE_EQUAL(rtenv.MinY, 0.5, DBL_EPSILON);
+       CU_ASSERT_DOUBLE_EQUAL(rtenv.MaxY, 0.5, DBL_EPSILON);
+       cu_free_raster(raster);
+
+       /* normal raster */
+       raster = rt_raster_new(5, 5);
+       CU_ASSERT(raster != NULL);
+
+       rt_raster_set_offsets(raster, 0.5, 0.5);
+       rt_raster_set_scale(raster, 1, -1);
+
+       CU_ASSERT_EQUAL(rt_raster_get_envelope(raster, &rtenv), ES_NONE);
+       CU_ASSERT_DOUBLE_EQUAL(rtenv.MinX, 0.5, DBL_EPSILON);
+       CU_ASSERT_DOUBLE_EQUAL(rtenv.MaxX, 5.5, DBL_EPSILON);
+       CU_ASSERT_DOUBLE_EQUAL(rtenv.MinY, -4.5, DBL_EPSILON);
+       CU_ASSERT_DOUBLE_EQUAL(rtenv.MaxY, 0.5, DBL_EPSILON);
+       cu_free_raster(raster);
+}
+
+static void test_raster_envelope_geom() {
+       rt_raster raster = NULL;
+       LWGEOM *env = NULL;
+       LWPOLY *poly = NULL;
+       POINTARRAY *ring = NULL;
+       POINT4D pt;
+
+       /* NULL raster */
+       CU_ASSERT_EQUAL(rt_raster_get_envelope_geom(NULL, &env), ES_NONE);
+       CU_ASSERT(env == NULL);
+
+       /* width = 0, height = 0 */
+       raster = rt_raster_new(0, 0);
+       CU_ASSERT(raster != NULL);
+
+       CU_ASSERT_EQUAL(rt_raster_get_envelope_geom(raster, &env), ES_NONE);
+       CU_ASSERT_EQUAL(env->type, POINTTYPE);
+       lwgeom_free(env);
+       cu_free_raster(raster);
+
+       /* width = 0 */
+       raster = rt_raster_new(0, 256);
+       CU_ASSERT(raster != NULL);
+
+       CU_ASSERT_EQUAL(rt_raster_get_envelope_geom(raster, &env), ES_NONE);
+       CU_ASSERT_EQUAL(env->type, LINETYPE);
+       lwgeom_free(env);
+       cu_free_raster(raster);
+
+       /* height = 0 */
+       raster = rt_raster_new(256, 0);
+       CU_ASSERT(raster != NULL);
+
+       CU_ASSERT_EQUAL(rt_raster_get_envelope_geom(raster, &env), ES_NONE);
+       CU_ASSERT_EQUAL(env->type, LINETYPE);
+       lwgeom_free(env);
+       cu_free_raster(raster);
+
+       /* normal raster */
+       raster = rt_raster_new(5, 5);
+       CU_ASSERT(raster != NULL);
+
+       rt_raster_set_offsets(raster, 0.5, 0.5);
+       rt_raster_set_scale(raster, 1, -1);
+
+       CU_ASSERT_EQUAL(rt_raster_get_envelope_geom(raster, &env), ES_NONE);
+       poly = lwgeom_as_lwpoly(env);
+       CU_ASSERT_EQUAL(poly->srid, rt_raster_get_srid(raster));
+       CU_ASSERT_EQUAL(poly->nrings, 1);
+
+       ring = poly->rings[0];
+       CU_ASSERT(ring != NULL);
+       CU_ASSERT_EQUAL(ring->npoints, 5);
+
+       getPoint4d_p(ring, 0, &pt);
+       CU_ASSERT_DOUBLE_EQUAL(pt.x, 0.5, DBL_EPSILON);
+       CU_ASSERT_DOUBLE_EQUAL(pt.y, 0.5, DBL_EPSILON);
+
+       getPoint4d_p(ring, 1, &pt);
+       CU_ASSERT_DOUBLE_EQUAL(pt.x, 5.5, DBL_EPSILON);
+       CU_ASSERT_DOUBLE_EQUAL(pt.y, 0.5, DBL_EPSILON);
+
+       getPoint4d_p(ring, 2, &pt);
+       CU_ASSERT_DOUBLE_EQUAL(pt.x, 5.5, DBL_EPSILON);
+       CU_ASSERT_DOUBLE_EQUAL(pt.y, -4.5, DBL_EPSILON);
+
+       getPoint4d_p(ring, 3, &pt);
+       CU_ASSERT_DOUBLE_EQUAL(pt.x, 0.5, DBL_EPSILON);
+       CU_ASSERT_DOUBLE_EQUAL(pt.y, -4.5, DBL_EPSILON);
+
+       getPoint4d_p(ring, 4, &pt);
+       CU_ASSERT_DOUBLE_EQUAL(pt.x, 0.5, DBL_EPSILON);
+       CU_ASSERT_DOUBLE_EQUAL(pt.y, 0.5, DBL_EPSILON);
+
+       lwgeom_free(env);
+       cu_free_raster(raster);
+}
+
 static void test_raster_convex_hull() {
        rt_raster raster = NULL;
        LWGEOM *hull = NULL;
@@ -434,9 +573,8 @@ static void test_raster_pixel_as_polygon() {
 
 /* register tests */
 CU_TestInfo raster_geometry_tests[] = {
-       /* TODO: rt_raster_envelope()
        PG_TEST(test_raster_envelope),
-       */
+       PG_TEST(test_raster_envelope_geom),
        PG_TEST(test_raster_convex_hull),
        PG_TEST(test_raster_surface),
        PG_TEST(test_raster_perimeter),
index cf21cb663e0c47ddfa55e84a3e6f88ca3efe18ac..fe9892f1037d3dcc40753ff3ad98a774cd96d6e6 100644 (file)
@@ -76,7 +76,8 @@ TEST_PROPS = \
        rt_metadata \
        rt_rastertoworldcoord \
        rt_worldtorastercoord \
-       rt_convexhull
+       rt_convexhull \
+       rt_envelope
 
 TEST_BANDPROPS = \
        rt_band_properties \