From c131910b48bbf4ac57fada3d1e207dbded626084 Mon Sep 17 00:00:00 2001 From: Bborie Park Date: Sat, 16 Feb 2013 01:00:33 +0000 Subject: [PATCH] Faster ST_Union() done using memcpy when possible git-svn-id: http://svn.osgeo.org/postgis/trunk@11095 b70326c6-7e19-0410-871a-916f4a2858ee --- raster/rt_pg/rt_pg.c | 280 ++++++++++++++++++++++++-- raster/test/regress/rt_union.sql | 34 ++++ raster/test/regress/rt_union_expected | 55 +++++ 3 files changed, 348 insertions(+), 21 deletions(-) diff --git a/raster/rt_pg/rt_pg.c b/raster/rt_pg/rt_pg.c index 69366cb5f..09fdfd8b5 100644 --- a/raster/rt_pg/rt_pg.c +++ b/raster/rt_pg/rt_pg.c @@ -15793,6 +15793,7 @@ struct rtpg_union_arg_t { static void rtpg_union_arg_destroy(rtpg_union_arg arg) { int i = 0; int j = 0; + int k = 0; if (arg->bandarg != NULL) { for (i = 0; i < arg->numband; i++) { @@ -15802,6 +15803,9 @@ static void rtpg_union_arg_destroy(rtpg_union_arg arg) { for (j = 0; j < arg->bandarg[i].numraster; j++) { if (arg->bandarg[i].raster[j] == NULL) continue; + + for (k = rt_raster_get_num_bands(arg->bandarg[i].raster[j]) - 1; k >= 0; k--) + rt_band_destroy(rt_raster_get_band(arg->bandarg[i].raster[j], k)); rt_raster_destroy(arg->bandarg[i].raster[j]); } @@ -16153,9 +16157,11 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS) int isempty[2] = {0}; int hasband[2] = {0}; int nargs = 0; + double _offset[4] = {0.}; int i = 0; int j = 0; + int k = 0; rt_iterator itrset; char *utypename = NULL; @@ -16164,6 +16170,14 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS) int hasnodata = 1; double nodataval = 0; + rt_raster iraster = NULL; + rt_band iband = NULL; + int reuserast = 0; + int y = 0; + uint16_t _dim[2] = {0}; + void *vals = NULL; + uint16_t nvals = 0; + POSTGIS_RT_DEBUG(3, "Starting..."); /* cannot be called directly as this is exclusive aggregate function */ @@ -16391,6 +16405,9 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS) /* by raster */ for (j = 0; j < iwr->bandarg[i].numraster; j++) { + reuserast = 0; + + /* type of union */ utype = iwr->bandarg[i].uniontype; /* raster flags */ @@ -16466,37 +16483,258 @@ Datum RASTER_union_transfn(PG_FUNCTION_ARGS) itrset[1].nbnodata = 0; } - /* pass everything to iterator */ - noerr = rt_raster_iterator( - itrset, 2, - ET_UNION, NULL, - pixtype, - hasnodata, nodataval, - 0, 0, - &utype, - rtpg_union_callback, - &_raster - ); + /* if rasters AND bands are present, use copy approach */ + if (!isempty[0] && !isempty[1] && hasband[0] && hasband[1]) { + POSTGIS_RT_DEBUG(3, "using line method"); + + /* generate empty out raster */ + if (rt_raster_from_two_rasters( + iwr->bandarg[i].raster[j], raster, + ET_UNION, + &iraster, _offset + ) != ES_NONE) { + elog(ERROR, "RASTER_union_transfn: Unable to create internal raster"); + + pfree(itrset); + rtpg_union_arg_destroy(iwr); + if (raster != NULL) { + rt_raster_destroy(raster); + PG_FREE_IF_COPY(pgraster, 1); + } - if (noerr != ES_NONE) { - elog(ERROR, "RASTER_union_transfn: Unable to run raster iterator function"); + MemoryContextSwitchTo(oldcontext); + PG_RETURN_NULL(); + } + POSTGIS_RT_DEBUGF(4, "_offset = %f, %f, %f, %f", + _offset[0], _offset[1], _offset[2], _offset[3]); - pfree(itrset); - rtpg_union_arg_destroy(iwr); - if (raster != NULL) { - rt_raster_destroy(raster); - PG_FREE_IF_COPY(pgraster, 1); + /* rasters are spatially the same? */ + if ( + rt_raster_get_width(iwr->bandarg[i].raster[j]) == rt_raster_get_width(iraster) && + rt_raster_get_height(iwr->bandarg[i].raster[j]) == rt_raster_get_height(iraster) + ) { + double igt[6] = {0}; + double gt[6] = {0}; + + rt_raster_get_geotransform_matrix(iwr->bandarg[i].raster[j], gt); + rt_raster_get_geotransform_matrix(iraster, igt); + + reuserast = 1; + for (k = 0; k < 6; k++) { + if (FLT_NEQ(gt[k], igt[k])) { + reuserast = 0; + break; + } + } } - MemoryContextSwitchTo(oldcontext); - PG_RETURN_NULL(); + /* use internal raster */ + if (!reuserast) { + /* create band of same type */ + if (rt_raster_generate_new_band( + iraster, + pixtype, + nodataval, + hasnodata, nodataval, + 0 + ) == -1) { + elog(ERROR, "RASTER_union_transfn: Unable to add new band to internal raster"); + + pfree(itrset); + rtpg_union_arg_destroy(iwr); + rt_raster_destroy(iraster); + if (raster != NULL) { + rt_raster_destroy(raster); + PG_FREE_IF_COPY(pgraster, 1); + } + + MemoryContextSwitchTo(oldcontext); + PG_RETURN_NULL(); + } + iband = rt_raster_get_band(iraster, 0); + + /* copy working raster to output raster */ + _dim[0] = rt_raster_get_width(iwr->bandarg[i].raster[j]); + _dim[1] = rt_raster_get_height(iwr->bandarg[i].raster[j]); + for (y = 0; y < _dim[1]; y++) { + POSTGIS_RT_DEBUGF(4, "Getting pixel line of working raster at (x, y, length) = (0, %d, %d)", y, _dim[0]); + if (rt_band_get_pixel_line( + _band, + 0, y, + _dim[0], + &vals, &nvals + ) != ES_NONE) { + elog(ERROR, "RASTER_union_transfn: Unable to get pixel line from band of working raster"); + + pfree(itrset); + rtpg_union_arg_destroy(iwr); + rt_band_destroy(iband); + rt_raster_destroy(iraster); + if (raster != NULL) { + rt_raster_destroy(raster); + PG_FREE_IF_COPY(pgraster, 1); + } + + MemoryContextSwitchTo(oldcontext); + PG_RETURN_NULL(); + } + + POSTGIS_RT_DEBUGF(4, "Setting pixel line at (x, y, length) = (%d, %d, %d)", (int) _offset[0], (int) _offset[1] + y, nvals); + if (rt_band_set_pixel_line( + iband, + (int) _offset[0], (int) _offset[1] + y, + vals, nvals + ) != ES_NONE) { + elog(ERROR, "RASTER_union_transfn: Unable to set pixel line to band of internal raster"); + + pfree(itrset); + rtpg_union_arg_destroy(iwr); + rt_band_destroy(iband); + rt_raster_destroy(iraster); + if (raster != NULL) { + rt_raster_destroy(raster); + PG_FREE_IF_COPY(pgraster, 1); + } + + MemoryContextSwitchTo(oldcontext); + PG_RETURN_NULL(); + } + } + } + else { + rt_raster_destroy(iraster); + iraster = iwr->bandarg[i].raster[j]; + iband = rt_raster_get_band(iraster, 0); + } + + /* run iterator for extent of input raster */ + noerr = rt_raster_iterator( + itrset, 2, + ET_LAST, NULL, + pixtype, + hasnodata, nodataval, + 0, 0, + &utype, + rtpg_union_callback, + &_raster + ); + if (noerr != ES_NONE) { + elog(ERROR, "RASTER_union_transfn: Unable to run raster iterator function"); + + pfree(itrset); + rtpg_union_arg_destroy(iwr); + if (!reuserast) { + rt_band_destroy(iband); + rt_raster_destroy(iraster); + } + if (raster != NULL) { + rt_raster_destroy(raster); + PG_FREE_IF_COPY(pgraster, 1); + } + + MemoryContextSwitchTo(oldcontext); + PG_RETURN_NULL(); + } + + /* with iterator raster, copy data to output raster */ + _band = rt_raster_get_band(_raster, 0); + _dim[0] = rt_raster_get_width(_raster); + _dim[1] = rt_raster_get_height(_raster); + for (y = 0; y < _dim[1]; y++) { + POSTGIS_RT_DEBUGF(4, "Getting pixel line of iterator raster at (x, y, length) = (0, %d, %d)", y, _dim[0]); + if (rt_band_get_pixel_line( + _band, + 0, y, + _dim[0], + &vals, &nvals + ) != ES_NONE) { + elog(ERROR, "RASTER_union_transfn: Unable to get pixel line from band of working raster"); + + pfree(itrset); + rtpg_union_arg_destroy(iwr); + if (!reuserast) { + rt_band_destroy(iband); + rt_raster_destroy(iraster); + } + if (raster != NULL) { + rt_raster_destroy(raster); + PG_FREE_IF_COPY(pgraster, 1); + } + + MemoryContextSwitchTo(oldcontext); + PG_RETURN_NULL(); + } + + POSTGIS_RT_DEBUGF(4, "Setting pixel line at (x, y, length) = (%d, %d, %d)", (int) _offset[2], (int) _offset[3] + y, nvals); + if (rt_band_set_pixel_line( + iband, + (int) _offset[2], (int) _offset[3] + y, + vals, nvals + ) != ES_NONE) { + elog(ERROR, "RASTER_union_transfn: Unable to set pixel line to band of internal raster"); + + pfree(itrset); + rtpg_union_arg_destroy(iwr); + if (!reuserast) { + rt_band_destroy(iband); + rt_raster_destroy(iraster); + } + if (raster != NULL) { + rt_raster_destroy(raster); + PG_FREE_IF_COPY(pgraster, 1); + } + + MemoryContextSwitchTo(oldcontext); + PG_RETURN_NULL(); + } + } + + /* free _raster */ + rt_band_destroy(_band); + rt_raster_destroy(_raster); + + /* replace working raster with output raster */ + _raster = iraster; + } + else { + POSTGIS_RT_DEBUG(3, "using pixel method"); + + /* pass everything to iterator */ + noerr = rt_raster_iterator( + itrset, 2, + ET_UNION, NULL, + pixtype, + hasnodata, nodataval, + 0, 0, + &utype, + rtpg_union_callback, + &_raster + ); + + if (noerr != ES_NONE) { + elog(ERROR, "RASTER_union_transfn: Unable to run raster iterator function"); + + pfree(itrset); + rtpg_union_arg_destroy(iwr); + if (raster != NULL) { + rt_raster_destroy(raster); + PG_FREE_IF_COPY(pgraster, 1); + } + + MemoryContextSwitchTo(oldcontext); + PG_RETURN_NULL(); + } } /* replace working raster */ - if (iwr->bandarg[i].raster[j] != NULL) + if (iwr->bandarg[i].raster[j] != NULL && !reuserast) { + for (k = rt_raster_get_num_bands(iwr->bandarg[i].raster[j]) - 1; k >= 0; k--) + rt_band_destroy(rt_raster_get_band(iwr->bandarg[i].raster[j], k)); rt_raster_destroy(iwr->bandarg[i].raster[j]); + } iwr->bandarg[i].raster[j] = _raster; } + } pfree(itrset); diff --git a/raster/test/regress/rt_union.sql b/raster/test/regress/rt_union.sql index 60846c652..17cb480d2 100644 --- a/raster/test/regress/rt_union.sql +++ b/raster/test/regress/rt_union.sql @@ -396,5 +396,39 @@ FROM ( ) foo ORDER BY uniontype, y, x; +TRUNCATE raster_union_out; +TRUNCATE raster_union_in; + +INSERT INTO raster_union_in + SELECT 60, ST_AddBand(ST_MakeEmptyRaster(2, 2, 2, -2, 1, -1, 0, 0, 0), 1, '8BUI', 1, 0) AS rast UNION ALL + SELECT 61, ST_AddBand(ST_MakeEmptyRaster(2, 2, 0, 0, 1, -1, 0, 0, 0), 1, '8BUI', 2, 0) AS rast UNION ALL + SELECT 62, ST_AddBand(ST_MakeEmptyRaster(2, 2, 2, 0, 1, -1, 0, 0, 0), 1, '8BUI', 3, 0) AS rast UNION ALL + SELECT 63, ST_AddBand(ST_MakeEmptyRaster(2, 2, -1, -3, 1, -1, 0, 0, 0), 1, '8BUI', 4, 0) AS rast UNION ALL + SELECT 64, ST_AddBand(ST_MakeEmptyRaster(2, 2, -2, 4, 1, -1, 0, 0, 0), 1, '8BUI', 5, 0) AS rast +; + +INSERT INTO raster_union_out + SELECT + 'LAST', + ST_Union(rast) AS rast + FROM raster_union_in; + +SELECT + (ST_Metadata(rast)).* +FROM raster_union_out; + +SELECT + uniontype, + x, + y, + val +FROM ( + SELECT + uniontype, + (ST_PixelAsPoints(rast)).* + FROM raster_union_out +) foo +ORDER BY uniontype, y, x; + DROP TABLE IF EXISTS raster_union_in; DROP TABLE IF EXISTS raster_union_out; diff --git a/raster/test/regress/rt_union_expected b/raster/test/regress/rt_union_expected index 56b9eb5dd..b9befe6bc 100644 --- a/raster/test/regress/rt_union_expected +++ b/raster/test/regress/rt_union_expected @@ -634,3 +634,58 @@ LAST|1|4| LAST|2|4| LAST|3|4| LAST|4|4| +-2|4|6|9|1|-1|0|0|0|1 +LAST|1|1|5 +LAST|2|1|5 +LAST|3|1| +LAST|4|1| +LAST|5|1| +LAST|6|1| +LAST|1|2|5 +LAST|2|2|5 +LAST|3|2| +LAST|4|2| +LAST|5|2| +LAST|6|2| +LAST|1|3| +LAST|2|3| +LAST|3|3| +LAST|4|3| +LAST|5|3| +LAST|6|3| +LAST|1|4| +LAST|2|4| +LAST|3|4| +LAST|4|4| +LAST|5|4| +LAST|6|4| +LAST|1|5| +LAST|2|5| +LAST|3|5|2 +LAST|4|5|2 +LAST|5|5|3 +LAST|6|5|3 +LAST|1|6| +LAST|2|6| +LAST|3|6|2 +LAST|4|6|2 +LAST|5|6|3 +LAST|6|6|3 +LAST|1|7| +LAST|2|7| +LAST|3|7| +LAST|4|7| +LAST|5|7|1 +LAST|6|7|1 +LAST|1|8| +LAST|2|8|4 +LAST|3|8|4 +LAST|4|8| +LAST|5|8|1 +LAST|6|8|1 +LAST|1|9| +LAST|2|9|4 +LAST|3|9|4 +LAST|4|9| +LAST|5|9| +LAST|6|9| -- 2.50.1