[postgis-tickets] [SCM] PostGIS branch master updated. 3.2.0beta1-42-g98d041b06

git at osgeo.org git at osgeo.org
Fri Nov 26 10:34:42 PST 2021


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "PostGIS".

The branch, master has been updated
       via  98d041b06e3dfcdc9ae71bdd82171254d16d0673 (commit)
       via  6450b84fd313edbd74018e6aaf265cad613bbe80 (commit)
       via  7d298d74d241a5df8db1722c8496e359bcff63d7 (commit)
       via  f7ffa44d231a9cbf4d3612b2052e260a5f19802a (commit)
       via  934f4ab40da66f414535d6974d254d6cedb68b8b (commit)
       via  6b6c72e12ffb0012544aa7073c4066bbd8d07d77 (commit)
       via  94d4588acb7552642f6736faae2926d71c76f5ee (commit)
       via  159242a9a1e619293a4cf35d3424ca227b0fbae5 (commit)
      from  b58339cce2df86cca7d6b5ad97e415836edc9caf (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit 98d041b06e3dfcdc9ae71bdd82171254d16d0673
Merge: b58339cce 6450b84fd
Author: Darafei Praliaskouski <me at komzpa.net>
Date:   Fri Nov 26 21:33:59 2021 +0300

    Merge "Pixel as centroids optimization"
    
    Closes https://github.com/postgis/postgis/pull/648


commit 6450b84fd313edbd74018e6aaf265cad613bbe80
Merge: b58339cce 7d298d74d
Author: Sergei <managerzf168 at gmail.com>
Date:   Fri Nov 26 21:06:19 2021 +0300

    Merge 7d298d74d241a5df8db1722c8496e359bcff63d7 into b58339cce2df86cca7d6b5ad97e415836edc9caf


commit 7d298d74d241a5df8db1722c8496e359bcff63d7
Author: sergei sh <managerzf168 at gmail.com>
Date:   Fri Nov 26 11:14:14 2021 +0300

    NEWS entry added

diff --git a/NEWS b/NEWS
index bc5cda4d1..4d2ab5aee 100644
--- a/NEWS
+++ b/NEWS
@@ -63,6 +63,7 @@ PostGIS 3.2.0
   - #4986, GIST indexes on Postgres 14 are now created faster using Hilbert-sorting method.
            (Han Wang, Aliaksandr Kalenik, Darafei Praliaskouski, Giuseppe Broccolo)
   - #4949, Use proj_normalize_for_visualization to hand "axis swap" decisions (Paul Ramsey)
+  - ST_PixelAsCentroids, ST_PixelAsCentroid reimplemented on top of a C function (Sergei Shoulbakov)
 
  * New features*
   - #4923, topology.ValidateTopologyRelation (Sandro Santilli)

commit f7ffa44d231a9cbf4d3612b2052e260a5f19802a
Author: sergei sh <managerzf168 at gmail.com>
Date:   Thu Nov 25 21:00:48 2021 +0300

    postgis_raster SRF notice message fix: "NULL" to "empty set"

diff --git a/raster/rt_pg/rtpg_geometry.c b/raster/rt_pg/rtpg_geometry.c
index c98e26ae3..a4059a8bc 100644
--- a/raster/rt_pg/rtpg_geometry.c
+++ b/raster/rt_pg/rtpg_geometry.c
@@ -243,7 +243,7 @@ Datum RASTER_dumpAsPolygons(PG_FUNCTION_ARGS) {
 		numbands = rt_raster_get_num_bands(raster);
 
 		if (nband < 1 || nband > numbands) {
-			elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
+			elog(NOTICE, "Invalid band index (must use 1-based). Returning empty set");
 			rt_raster_destroy(raster);
 			PG_FREE_IF_COPY(pgraster, 0);
 			MemoryContextSwitchTo(oldcontext);
@@ -255,7 +255,7 @@ Datum RASTER_dumpAsPolygons(PG_FUNCTION_ARGS) {
 
 		/* see if band is NODATA */
 		if (rt_band_get_isnodata_flag(rt_raster_get_band(raster, nband - 1))) {
-			POSTGIS_RT_DEBUGF(3, "Band at index %d is NODATA. Returning NULL", nband);
+			POSTGIS_RT_DEBUGF(3, "Band at index %d is NODATA. Returning empty set", nband);
 			rt_raster_destroy(raster);
 			PG_FREE_IF_COPY(pgraster, 0);
 			MemoryContextSwitchTo(oldcontext);
@@ -436,9 +436,9 @@ Datum RASTER_getPixelPolygons(PG_FUNCTION_ARGS)
 			SRF_RETURN_DONE(funcctx);
 		}
 
-		/* raster empty, return NULL */
+		/* raster empty, return empty set */
 		if (rt_raster_is_empty(raster)) {
-			elog(NOTICE, "Raster is empty. Returning NULL");
+			elog(NOTICE, "Raster is empty. Returning empty set");
 			rt_raster_destroy(raster);
 			PG_FREE_IF_COPY(pgraster, 0);
 			MemoryContextSwitchTo(oldcontext);
@@ -452,7 +452,7 @@ Datum RASTER_getPixelPolygons(PG_FUNCTION_ARGS)
 			POSTGIS_RT_DEBUGF(3, "# of bands %d", numbands);
 
 			if (nband < 1 || nband > numbands) {
-				elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
+				elog(NOTICE, "Invalid band index (must use 1-based). Returning empty set");
 				rt_raster_destroy(raster);
 				PG_FREE_IF_COPY(pgraster, 0);
 				MemoryContextSwitchTo(oldcontext);
@@ -461,7 +461,7 @@ Datum RASTER_getPixelPolygons(PG_FUNCTION_ARGS)
 
 			band = rt_raster_get_band(raster, nband - 1);
 			if (!band) {
-				elog(NOTICE, "Could not find band at index %d. Returning NULL", nband);
+				elog(NOTICE, "Could not find band at index %d. Returning empty set", nband);
 				rt_raster_destroy(raster);
 				PG_FREE_IF_COPY(pgraster, 0);
 				MemoryContextSwitchTo(oldcontext);
@@ -742,9 +742,9 @@ Datum RASTER_getPixelCentroids(PG_FUNCTION_ARGS)
 			SRF_RETURN_DONE(funcctx);
 		}
 
-		/* raster empty, return NULL */
+		/* raster empty, return empty set */
 		if (rt_raster_is_empty(raster)) {
-			elog(NOTICE, "Raster is empty. Returning NULL");
+			elog(NOTICE, "Raster is empty. Returning empty set");
 			rt_raster_destroy(raster);
 			PG_FREE_IF_COPY(pgraster, 0);
 			MemoryContextSwitchTo(oldcontext);
@@ -759,7 +759,7 @@ Datum RASTER_getPixelCentroids(PG_FUNCTION_ARGS)
 
 			/* check band index */
 			if (nband < 1 || nband > numbands) {
-				elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
+				elog(NOTICE, "Invalid band index (must use 1-based). Returning empty set");
 				rt_raster_destroy(raster);
 				PG_FREE_IF_COPY(pgraster, 0);
 				MemoryContextSwitchTo(oldcontext);
@@ -769,7 +769,7 @@ Datum RASTER_getPixelCentroids(PG_FUNCTION_ARGS)
 			/* get band */
 			band = rt_raster_get_band(raster, nband - 1);
 			if (!band) {
-				elog(NOTICE, "Could not find band at index %d. Returning NULL", nband);
+				elog(NOTICE, "Could not find band at index %d. Returning empty set", nband);
 
 				rt_raster_destroy(raster);
 				PG_FREE_IF_COPY(pgraster, 0);

commit 934f4ab40da66f414535d6974d254d6cedb68b8b
Author: sergei sh <managerzf168 at gmail.com>
Date:   Thu Nov 25 14:20:20 2021 +0300

    RASTER_getPixelCentroids memory reallocation fix

diff --git a/raster/rt_pg/rtpg_geometry.c b/raster/rt_pg/rtpg_geometry.c
index daf414d3d..c98e26ae3 100644
--- a/raster/rt_pg/rtpg_geometry.c
+++ b/raster/rt_pg/rtpg_geometry.c
@@ -846,7 +846,8 @@ Datum RASTER_getPixelCentroids(PG_FUNCTION_ARGS)
 				/* allocate space for new point */
 				if (!pixcount) {
 					pix = palloc(sizeof(struct rt_pixel_t) * (pixcount + 1));
-				} {
+				}
+				else {
 					pix = repalloc(pix, sizeof(struct rt_pixel_t) * (pixcount + 1));
 				}
 				if (pix == NULL) {

commit 6b6c72e12ffb0012544aa7073c4066bbd8d07d77
Author: sergei sh <managerzf168 at gmail.com>
Date:   Wed Nov 24 14:26:25 2021 +0300

    ST_PixelAsCentroids rotated raster test

diff --git a/raster/test/regress/rt_pixelascentroids.sql b/raster/test/regress/rt_pixelascentroids.sql
index c8065f2bc..d4f03bb22 100644
--- a/raster/test/regress/rt_pixelascentroids.sql
+++ b/raster/test/regress/rt_pixelascentroids.sql
@@ -65,4 +65,13 @@ SELECT ST_AsText(ST_PixelAsCentroid(rast, 1, 1)) FROM raster_pixelascentroids;
 SELECT ST_AsText(ST_PixelAsCentroid(rast, 1, 2)) FROM raster_pixelascentroids;
 SELECT ST_AsText(ST_PixelAsCentroid(rast, -1, -1)) FROM raster_pixelascentroids;
 
+
+TRUNCATE TABLE raster_pixelascentroids;
+INSERT INTO raster_pixelascentroids VALUES(
+	ST_AddBand(
+		ST_MakeEmptyRaster(3, 3, 0, 0, 2, 2, -1, 1, 0),
+		1, '32BUI', 0, 0));
+SELECT x, y, ST_AsText(geom) FROM raster_pixelascentroids, lateral ST_PixelAsCentroids(rast, 1, FALSE) foo;
+
+
 DROP TABLE IF EXISTS raster_pixelascentroids;
diff --git a/raster/test/regress/rt_pixelascentroids_expected b/raster/test/regress/rt_pixelascentroids_expected
index dba7baf7a..fcfa81313 100644
--- a/raster/test/regress/rt_pixelascentroids_expected
+++ b/raster/test/regress/rt_pixelascentroids_expected
@@ -152,3 +152,12 @@ NOTICE:  table "raster_pixelascentroids" does not exist, skipping
 POINT(0.5 -0.5)
 POINT(0.5 -1.5)
 POINT(-1.5 1.5)
+1|1|POINT(0.5 1.5)
+2|1|POINT(2.5 2.5)
+3|1|POINT(4.5 3.5)
+1|2|POINT(-0.5 3.5)
+2|2|POINT(1.5 4.5)
+3|2|POINT(3.5 5.5)
+1|3|POINT(-1.5 5.5)
+2|3|POINT(0.5 6.5)
+3|3|POINT(2.5 7.5)

commit 94d4588acb7552642f6736faae2926d71c76f5ee
Author: sergei sh <managerzf168 at gmail.com>
Date:   Tue Nov 23 17:24:04 2021 +0300

    RASTER_getPixelCentroids signed/unsigned comparison fix

diff --git a/raster/rt_pg/rtpg_geometry.c b/raster/rt_pg/rtpg_geometry.c
index 65fd09168..daf414d3d 100644
--- a/raster/rt_pg/rtpg_geometry.c
+++ b/raster/rt_pg/rtpg_geometry.c
@@ -668,6 +668,7 @@ Datum RASTER_getPixelCentroids(PG_FUNCTION_ARGS)
 	rt_pixel pix = NULL;
 	rt_pixel pix2;
 	int call_cntr;
+	int max_calls;
 	int i = 0;
 
 	if (SRF_IS_FIRSTCALL()) {
@@ -925,11 +926,12 @@ Datum RASTER_getPixelCentroids(PG_FUNCTION_ARGS)
 	funcctx = SRF_PERCALL_SETUP();
 
 	call_cntr = funcctx->call_cntr;
+	max_calls = funcctx->max_calls;
 	tupdesc = funcctx->tuple_desc;
 	pix2 = funcctx->user_fctx;
 
 	/* do when there is more left to send */
-	if (call_cntr < funcctx->max_calls) {
+	if (call_cntr < max_calls) {
 		Datum values[VALUES_LENGTH];
 		bool nulls[VALUES_LENGTH];
 		HeapTuple tuple;

commit 159242a9a1e619293a4cf35d3424ca227b0fbae5
Author: sergei sh <managerzf168 at gmail.com>
Date:   Tue Nov 23 15:54:19 2021 +0300

    ST_PixelAsCentroids, ST_PixelAsCentroid implemented over C function RASTER_getPixelCentroids

diff --git a/raster/rt_core/librtcore.h b/raster/rt_core/librtcore.h
index 889ee7c98..3d813d24f 100644
--- a/raster/rt_core/librtcore.h
+++ b/raster/rt_core/librtcore.h
@@ -1549,6 +1549,17 @@ rt_raster_compute_skewed_raster(
  */
 LWPOLY* rt_raster_pixel_as_polygon(rt_raster raster, int x, int y);
 
+/**
+ * Get a raster pixel centroid point.
+ *
+ * @param raster : the raster to get pixel from
+ * @param x : the column number
+ * @param y : the row number
+ *
+ * @return the pixel centroid point, or NULL on error.
+ */
+LWPOINT* rt_raster_pixel_as_centroid_point(rt_raster rast, int x, int y);
+
 /**
  * Get a raster as a surface (multipolygon).  If a band is specified,
  * those pixels with value (not NODATA) contribute to the area
diff --git a/raster/rt_core/rt_geometry.c b/raster/rt_core/rt_geometry.c
index d8e0e31f4..b33452ad3 100644
--- a/raster/rt_core/rt_geometry.c
+++ b/raster/rt_core/rt_geometry.c
@@ -654,6 +654,44 @@ rt_raster_pixel_as_polygon(rt_raster rast, int x, int y)
     return poly;
 }
 
+/******************************************************************************
+* rt_raster_pixel_as_centroid_point()
+******************************************************************************/
+
+/**
+ * Get a raster pixel centroid point.
+ *
+ * @param raster : the raster to get pixel from
+ * @param x : the column number
+ * @param y : the row number
+ *
+ * @return the pixel centroid point, or NULL on error.
+ */
+LWPOINT*
+rt_raster_pixel_as_centroid_point(rt_raster rast, int x, int y)
+{
+    double scale_x, scale_y;
+    double skew_x, skew_y;
+    double ul_x, ul_y;
+    int32_t srid;
+    double center_x, center_y;
+    LWPOINT* point;
+
+    scale_x = rt_raster_get_x_scale(rast);
+    scale_y = rt_raster_get_y_scale(rast);
+    skew_x = rt_raster_get_x_skew(rast);
+    skew_y = rt_raster_get_y_skew(rast);
+    ul_x = rt_raster_get_x_offset(rast);
+    ul_y = rt_raster_get_y_offset(rast);
+    srid = rt_raster_get_srid(rast);
+
+    center_x = scale_x * x + skew_x * y + ul_x + (scale_x + skew_x) * 0.5;
+    center_y = scale_y * y + skew_y * x + ul_y + (scale_y + skew_y) * 0.5;
+    point = lwpoint_make2d(srid, center_x, center_y);
+
+    return point;
+}
+
 /******************************************************************************
 * rt_raster_get_envelope_geom()
 ******************************************************************************/
diff --git a/raster/rt_pg/rtpg_geometry.c b/raster/rt_pg/rtpg_geometry.c
index 29eaa17db..65fd09168 100644
--- a/raster/rt_pg/rtpg_geometry.c
+++ b/raster/rt_pg/rtpg_geometry.c
@@ -50,6 +50,9 @@ Datum RASTER_dumpAsPolygons(PG_FUNCTION_ARGS);
 /* Get pixel geographical shape */
 Datum RASTER_getPixelPolygons(PG_FUNCTION_ARGS);
 
+/* Get pixel centroid points */
+Datum RASTER_getPixelCentroids(PG_FUNCTION_ARGS);
+
 /* Get raster band's polygon */
 Datum RASTER_getPolygon(PG_FUNCTION_ARGS);
 
@@ -651,6 +654,322 @@ Datum RASTER_getPixelPolygons(PG_FUNCTION_ARGS)
 	}
 }
 
+#undef VALUES_LENGTH
+#define VALUES_LENGTH 4
+
+/**
+ * Return centroid points of all pixels
+ */
+PG_FUNCTION_INFO_V1(RASTER_getPixelCentroids);
+Datum RASTER_getPixelCentroids(PG_FUNCTION_ARGS)
+{
+	FuncCallContext *funcctx;
+	TupleDesc tupdesc;
+	rt_pixel pix = NULL;
+	rt_pixel pix2;
+	int call_cntr;
+	int i = 0;
+
+	if (SRF_IS_FIRSTCALL()) {
+		MemoryContext oldcontext;
+		rt_pgraster *pgraster = NULL;
+		rt_raster raster = NULL;
+		rt_band band = NULL;
+		int nband = 1;
+		int numbands;
+		bool hasband = FALSE;
+		bool exclude_nodata_value = TRUE;
+		bool nocolumnx = TRUE;
+		bool norowy = TRUE;
+		int x = 0;
+		int y = 0;
+		int bounds[4] = {0};
+		int pixcount = 0;
+		double value = 0;
+		int isnodata = 0;
+
+		LWPOINT* point = NULL;
+
+		POSTGIS_RT_DEBUG(3, "RASTER_getPixelCentroids first call");
+
+		/* create a function context for cross-call persistence */
+		funcctx = SRF_FIRSTCALL_INIT();
+
+		/* switch to memory context appropriate for multiple function calls */
+		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+		/* raster */
+		if (PG_ARGISNULL(0)) {
+			MemoryContextSwitchTo(oldcontext);
+			SRF_RETURN_DONE(funcctx);
+		}
+		pgraster = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
+
+		/* band */
+		if (!PG_ARGISNULL(1)) {
+			nband = PG_GETARG_INT32(1);
+			hasband = TRUE;
+		}
+
+		/* column */
+		if (!PG_ARGISNULL(2)) {
+			bounds[0] = PG_GETARG_INT32(2);
+			bounds[1] = bounds[0];
+			nocolumnx = FALSE;
+		}
+
+		/* row */
+		if (!PG_ARGISNULL(3)) {
+			bounds[2] = PG_GETARG_INT32(3);
+			bounds[3] = bounds[2];
+			norowy = FALSE;
+		}
+
+		/* exclude NODATA */
+		if (!PG_ARGISNULL(4))
+			exclude_nodata_value = PG_GETARG_BOOL(4);
+
+		/* deserialize raster */
+		raster = rt_raster_deserialize(pgraster, FALSE);
+		if (!raster) {
+			PG_FREE_IF_COPY(pgraster, 0);
+			ereport(ERROR, (
+				errcode(ERRCODE_OUT_OF_MEMORY),
+				errmsg("Could not deserialize raster")
+			));
+			MemoryContextSwitchTo(oldcontext);
+			SRF_RETURN_DONE(funcctx);
+		}
+
+		/* raster empty, return NULL */
+		if (rt_raster_is_empty(raster)) {
+			elog(NOTICE, "Raster is empty. Returning NULL");
+			rt_raster_destroy(raster);
+			PG_FREE_IF_COPY(pgraster, 0);
+			MemoryContextSwitchTo(oldcontext);
+			SRF_RETURN_DONE(funcctx);
+		}
+
+		/* band specified, load band and info */
+		if (hasband) {
+			numbands = rt_raster_get_num_bands(raster);
+			POSTGIS_RT_DEBUGF(3, "band %d", nband);
+			POSTGIS_RT_DEBUGF(3, "# of bands %d", numbands);
+
+			/* check band index */
+			if (nband < 1 || nband > numbands) {
+				elog(NOTICE, "Invalid band index (must use 1-based). Returning NULL");
+				rt_raster_destroy(raster);
+				PG_FREE_IF_COPY(pgraster, 0);
+				MemoryContextSwitchTo(oldcontext);
+				SRF_RETURN_DONE(funcctx);
+			}
+
+			/* get band */
+			band = rt_raster_get_band(raster, nband - 1);
+			if (!band) {
+				elog(NOTICE, "Could not find band at index %d. Returning NULL", nband);
+
+				rt_raster_destroy(raster);
+				PG_FREE_IF_COPY(pgraster, 0);
+
+				MemoryContextSwitchTo(oldcontext);
+				SRF_RETURN_DONE(funcctx);
+			}
+
+			if (!rt_band_get_hasnodata_flag(band))
+				exclude_nodata_value = FALSE;
+		}
+
+		/* set bounds if columnx, rowy not set */
+		if (nocolumnx) {
+			bounds[0] = 1;
+			bounds[1] = rt_raster_get_width(raster);
+		}
+		if (norowy) {
+			bounds[2] = 1;
+			bounds[3] = rt_raster_get_height(raster);
+		}
+		POSTGIS_RT_DEBUGF(3, "bounds (min x, max x, min y, max y) = (%d, %d, %d, %d)",
+			bounds[0], bounds[1], bounds[2], bounds[3]);
+
+		/* rowy */
+		pixcount = 0;
+		for (y = bounds[2]; y <= bounds[3]; y++) {
+			/* columnx */
+			for (x = bounds[0]; x <= bounds[1]; x++) {
+
+				value = 0;
+				isnodata = TRUE;
+
+				if (hasband) {
+					if (rt_band_get_pixel(band, x - 1, y - 1, &value, &isnodata) != ES_NONE) {
+						/* free already created centroid points */
+						for (i = 0; i < pixcount; i++)
+							lwgeom_free(pix[i].geom);
+						if (pixcount) pfree(pix);
+
+						rt_band_destroy(band);
+						rt_raster_destroy(raster);
+						PG_FREE_IF_COPY(pgraster, 0);
+
+						MemoryContextSwitchTo(oldcontext);
+						elog(ERROR, "RASTER_getPixelCentroids: Could not get pixel value");
+						SRF_RETURN_DONE(funcctx);
+					}
+
+					/* don't continue if pixel is NODATA and to exclude NODATA */
+					if (isnodata && exclude_nodata_value) {
+						POSTGIS_RT_DEBUG(5, "pixel value is NODATA and exclude_nodata_value = TRUE");
+						continue;
+					}
+				}
+
+				/* geometry */
+				point = rt_raster_pixel_as_centroid_point(raster, x - 1, y - 1);
+				if (!point) {
+					/*  free already created centroid points */
+					for (i = 0; i < pixcount; i++)
+						lwgeom_free(pix[i].geom);
+					if (pixcount) pfree(pix);
+
+					if (hasband) rt_band_destroy(band);
+					rt_raster_destroy(raster);
+					PG_FREE_IF_COPY(pgraster, 0);
+
+					MemoryContextSwitchTo(oldcontext);
+					elog(ERROR, "RASTER_getPixelCentroids: Could not get pixel centroid");
+					SRF_RETURN_DONE(funcctx);
+				}
+
+				/* allocate space for new point */
+				if (!pixcount) {
+					pix = palloc(sizeof(struct rt_pixel_t) * (pixcount + 1));
+				} {
+					pix = repalloc(pix, sizeof(struct rt_pixel_t) * (pixcount + 1));
+				}
+				if (pix == NULL) {
+					lwpoint_free(point);
+
+					if (hasband) rt_band_destroy(band);
+					rt_raster_destroy(raster);
+					PG_FREE_IF_COPY(pgraster, 0);
+
+					MemoryContextSwitchTo(oldcontext);
+					elog(ERROR, "RASTER_getPixelCentroids: Could not allocate memory for storing pixel centroids");
+					SRF_RETURN_DONE(funcctx);
+				}
+
+				/* set pixel geometry */
+				pix[pixcount].geom = (LWGEOM *) point;
+				POSTGIS_RT_DEBUGF(5, "point @ %p", point);
+				POSTGIS_RT_DEBUGF(5, "geom @ %p", pix[pixcount].geom);
+
+				/* set pixel coordinates */
+				pix[pixcount].x = x;
+				pix[pixcount].y = y;
+
+				/* set pixel value */
+				pix[pixcount].value = value;
+
+				/* NODATA */
+				if (hasband) {
+					if (exclude_nodata_value)
+						pix[pixcount].nodata = isnodata;
+					else
+						pix[pixcount].nodata = FALSE;
+				}
+				else {
+					pix[pixcount].nodata = isnodata;
+				}
+
+				/* update pixcount*/
+				pixcount++;
+			}
+		}
+
+		/* cleanup */
+		if (hasband) rt_band_destroy(band);
+		rt_raster_destroy(raster);
+		PG_FREE_IF_COPY(pgraster, 0);
+
+		/* shortcut if no pixcount */
+		if (pixcount < 1) {
+			elog(NOTICE, "No pixels found for band %d", nband);
+			MemoryContextSwitchTo(oldcontext);
+			SRF_RETURN_DONE(funcctx);
+		}
+
+		/* store pixel data */
+		funcctx->user_fctx = pix;
+
+		/* set total number of tuples to be returned */
+		funcctx->max_calls = pixcount;
+		POSTGIS_RT_DEBUGF(3, "pixcount = %d", pixcount);
+
+		/* build a tuple descriptor for our result type */
+		if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) {
+			ereport(ERROR, (
+				errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+				errmsg("function returning record called in context that cannot accept type record")
+			));
+		}
+		/* set tuple descriptor */
+		BlessTupleDesc(tupdesc);
+		funcctx->tuple_desc = tupdesc;
+
+		MemoryContextSwitchTo(oldcontext);
+	}
+
+	/* stuff done on every call of the function */
+	funcctx = SRF_PERCALL_SETUP();
+
+	call_cntr = funcctx->call_cntr;
+	tupdesc = funcctx->tuple_desc;
+	pix2 = funcctx->user_fctx;
+
+	/* do when there is more left to send */
+	if (call_cntr < funcctx->max_calls) {
+		Datum values[VALUES_LENGTH];
+		bool nulls[VALUES_LENGTH];
+		HeapTuple tuple;
+		Datum result;
+
+		GSERIALIZED *gser = NULL;
+		size_t gser_size = 0;
+
+		POSTGIS_RT_DEBUGF(3, "call number %d", call_cntr);
+
+		memset(nulls, FALSE, sizeof(bool) * VALUES_LENGTH);
+
+		/* convert LWGEOM go GSERIALIZED */
+		gser = gserialized_from_lwgeom(pix2[call_cntr].geom, &gser_size);
+		lwgeom_free(pix2[call_cntr].geom); /* free geometry object */
+
+		/* set result tuple data */
+		values[0] = PointerGetDatum(gser);
+		if (pix2[call_cntr].nodata)
+			nulls[1] = TRUE;
+		else
+			values[1] = Float8GetDatum(pix2[call_cntr].value);
+		values[2] = Int32GetDatum(pix2[call_cntr].x);
+		values[3] = Int32GetDatum(pix2[call_cntr].y);
+
+		/* build a tuple */
+		tuple = heap_form_tuple(tupdesc, values, nulls);
+
+		/* make the tuple into a datum */
+		result = HeapTupleGetDatum(tuple);
+
+		SRF_RETURN_NEXT(funcctx, result);
+	}
+	/* do when there is no more left */
+	else {
+		pfree(pix2);
+		SRF_RETURN_DONE(funcctx);
+	}
+}
+
 /**
  * Get raster band's polygon
  */
diff --git a/raster/rt_pg/rtpostgis.sql.in b/raster/rt_pg/rtpostgis.sql.in
index 8ed06dd7e..baac9d676 100644
--- a/raster/rt_pg/rtpostgis.sql.in
+++ b/raster/rt_pg/rtpostgis.sql.in
@@ -5169,6 +5169,22 @@ CREATE OR REPLACE FUNCTION st_pixelaspoint(rast raster, x integer, y integer)
 -----------------------------------------------------------------------
 -- ST_PixelAsCentroids
 -----------------------------------------------------------------------
+CREATE OR REPLACE FUNCTION _st_pixelascentroids(
+	rast raster,
+	band integer DEFAULT 1,
+	columnx integer DEFAULT NULL,
+	rowy integer DEFAULT NULL,
+	exclude_nodata_value boolean DEFAULT TRUE
+	)
+	RETURNS TABLE(
+		geom geometry,
+		val double precision,
+		x integer,
+		y integer
+	)
+	AS 'MODULE_PATHNAME', 'RASTER_getPixelCentroids'
+	LANGUAGE 'c' IMMUTABLE PARALLEL SAFE;
+
 -- Changed: 3.1.2
 CREATE OR REPLACE FUNCTION st_pixelascentroids(
 	rast raster,
@@ -5180,7 +5196,7 @@ CREATE OR REPLACE FUNCTION st_pixelascentroids(
 		x int,
 		y int
 	)
-	AS $$ SELECT @extschema at .ST_Centroid(geom), val, x, y FROM @extschema at ._ST_pixelaspolygons($1, $2, NULL, NULL, $3) $$
+	AS $$ SELECT geom, val, x, y FROM @extschema at ._ST_pixelascentroids($1, $2, NULL, NULL, $3) $$
 	LANGUAGE 'sql' IMMUTABLE STRICT PARALLEL SAFE;
 
 -----------------------------------------------------------------------
@@ -5189,7 +5205,7 @@ CREATE OR REPLACE FUNCTION st_pixelascentroids(
 
 CREATE OR REPLACE FUNCTION st_pixelascentroid(rast raster, x integer, y integer)
 	RETURNS geometry
-	AS $$ SELECT @extschema at .ST_Centroid(geom) FROM @extschema at ._ST_pixelaspolygons($1, NULL, $2, $3) $$
+	AS $$ SELECT geom FROM @extschema at ._ST_pixelascentroids($1, NULL, $2, $3) $$
 	LANGUAGE 'sql' IMMUTABLE STRICT PARALLEL SAFE;
 
 -----------------------------------------------------------------------

-----------------------------------------------------------------------

Summary of changes:
 NEWS                                             |   1 +
 raster/rt_core/librtcore.h                       |  11 +
 raster/rt_core/rt_geometry.c                     |  38 +++
 raster/rt_pg/rtpg_geometry.c                     | 334 ++++++++++++++++++++++-
 raster/rt_pg/rtpostgis.sql.in                    |  20 +-
 raster/test/regress/rt_pixelascentroids.sql      |   9 +
 raster/test/regress/rt_pixelascentroids_expected |   9 +
 7 files changed, 414 insertions(+), 8 deletions(-)


hooks/post-receive
-- 
PostGIS


More information about the postgis-tickets mailing list