31 #include "../../postgis_config.h" 72 _rti_warp_arg
arg = NULL;
76 rterror(
"_rti_warp_arg_init: Could not allocate memory for _rti_warp_arg");
108 if (arg->
dst.
ds != NULL)
109 GDALClose(arg->
dst.
ds);
114 GDALDeregisterDriver(arg->
dst.
drv);
115 GDALDestroyDriver(arg->
dst.
drv);
118 if (arg->
src.
ds != NULL)
119 GDALClose(arg->
src.
ds);
124 GDALDeregisterDriver(arg->
src.
drv);
125 GDALDestroyDriver(arg->
src.
drv);
128 if (arg->
transform.func == GDALApproxTransform) {
130 GDALDestroyGenImgProjTransformer(arg->
transform.arg.imgproj);
133 if (arg->
wopts != NULL)
134 GDALDestroyWarpOptions(arg->
wopts);
137 for (i = 0; i < arg->
transform.option.len; i++) {
138 if (arg->
transform.option.item[i] != NULL)
180 const char *src_srs,
const char *dst_srs,
181 double *scale_x,
double *scale_y,
182 int *width,
int *height,
183 double *ul_xw,
double *ul_yw,
184 double *grid_xw,
double *grid_yw,
185 double *skew_x,
double *skew_y,
186 GDALResampleAlg resample_alg,
double max_err
189 char *dst_options[] = {
"SUBCLASS=VRTWarpedDataset", NULL};
190 _rti_warp_arg
arg = NULL;
194 GDALRasterBandH
band;
197 GDALDataType gdal_pt = GDT_Unknown;
201 double dst_extent[4];
205 double _skew[2] = {0};
206 double _scale[2] = {0};
218 assert(NULL != raster);
223 rterror(
"rt_raster_gdal_warp: Could not initialize internal variables");
232 if (max_err < 0.) max_err = 0.125;
236 if (src_srs != NULL) {
238 if (dst_srs != NULL && strcmp(src_srs, dst_srs) != 0) {
239 RASTER_DEBUG(4,
"Warp operation does include a reprojection");
244 rterror(
"rt_raster_gdal_warp: Could not convert srs values to GDAL accepted format");
251 RASTER_DEBUG(4,
"Warp operation does NOT include reprojection");
254 else if (dst_srs != NULL) {
256 rterror(
"rt_raster_gdal_warp: SRS required for input raster if SRS provided for warped raster");
263 if (NULL == arg->
src.
ds) {
264 rterror(
"rt_raster_gdal_warp: Could not convert raster to GDAL MEM format");
272 src_srs == NULL && dst_srs == NULL &&
277 #if POSTGIS_DEBUG_LEVEL > 3 278 GDALGetGeoTransform(arg->
src.
ds, gt);
279 RASTER_DEBUGF(3,
"GDAL MEM geotransform: %f, %f, %f, %f, %f, %f",
280 gt[0], gt[1], gt[2], gt[3], gt[4], gt[5]);
285 RASTER_DEBUGF(3,
"raster geotransform: %f, %f, %f, %f, %f, %f",
286 gt[0], gt[1], gt[2], gt[3], gt[4], gt[5]);
294 double ngt[6] = {166021.4431, 0.1, 0, 10000000.0000, 0, -0.1};
296 rtwarn(
"Raster has default geotransform. Adjusting metadata for use of GDAL Warp API");
300 GDALSetGeoTransform(arg->
src.
ds, ngt);
301 GDALFlushCache(arg->
src.
ds);
307 #if POSTGIS_DEBUG_LEVEL > 3 308 GDALGetGeoTransform(arg->
src.
ds, gt);
309 RASTER_DEBUGF(3,
"GDAL MEM geotransform: %f, %f, %f, %f, %f, %f",
310 gt[0], gt[1], gt[2], gt[3], gt[4], gt[5]);
319 if (NULL == arg->
transform.option.item) {
320 rterror(
"rt_raster_gdal_warp: Could not allocation memory for transform options");
324 memset(arg->
transform.option.item, 0,
sizeof(
char *) * (arg->
transform.option.len + 1));
326 for (i = 0; i < arg->
transform.option.len; i++) {
328 const char *lbl = i ?
"DST_SRS=" :
"SRC_SRS=";
329 size_t sz =
sizeof(char) * (strlen(lbl) + 1);
330 if ( srs ) sz += strlen(srs);
332 if (NULL == arg->
transform.option.item[i]) {
333 rterror(
"rt_raster_gdal_warp: Could not allocation memory for transform options");
337 sprintf(arg->
transform.option.item[i],
"%s%s", lbl, srs ? srs :
"");
345 arg->
transform.arg.transform = GDALCreateGenImgProjTransformer2(arg->
src.
ds, NULL, arg->
transform.option.item);
346 if (NULL == arg->
transform.arg.transform) {
347 rterror(
"rt_raster_gdal_warp: Could not create GDAL transformation object for output dataset creation");
353 cplerr = GDALSuggestedWarpOutput2(
354 arg->
src.
ds, GDALGenImgProjTransform,
355 arg->
transform.arg.transform, _gt, &(_dim[0]), &(_dim[1]), dst_extent, 0);
356 if (cplerr != CE_None) {
357 rterror(
"rt_raster_gdal_warp: Could not get GDAL suggested warp output for output dataset creation");
361 GDALDestroyGenImgProjTransformer(arg->
transform.arg.transform);
371 RASTER_DEBUGF(3,
"Suggested geotransform: %f, %f, %f, %f, %f, %f",
372 _gt[0], _gt[1], _gt[2], _gt[3], _gt[4], _gt[5]);
375 extent.
MinX = dst_extent[0];
376 extent.
MinY = dst_extent[1];
377 extent.
MaxX = dst_extent[2];
378 extent.
MaxY = dst_extent[3];
388 ((NULL != scale_x) || (NULL != scale_y)) &&
389 ((NULL != width) || (NULL != height))
391 rterror(
"rt_raster_gdal_warp: Scale X/Y and width/height are mutually exclusive. Only provide one");
398 _dim[0] = abs(*width);
399 _scale[0] = fabs((extent.
MaxX - extent.
MinX) / ((
double) _dim[0]));
402 if (NULL != height) {
403 _dim[1] = abs(*height);
404 _scale[1] = fabs((extent.
MaxY - extent.
MinY) / ((
double) _dim[1]));
409 ((NULL != scale_x) && (
FLT_NEQ(*scale_x, 0.0))) &&
410 ((NULL != scale_y) && (
FLT_NEQ(*scale_y, 0.0)))
412 _scale[0] = fabs(*scale_x);
413 _scale[1] = fabs(*scale_y);
426 ((NULL != scale_x) && (NULL == scale_y)) ||
427 ((NULL == scale_x) && (NULL != scale_y))
429 rterror(
"rt_raster_gdal_warp: Both X and Y scale values must be provided for scale");
436 _scale[0] = fabs(_gt[1]);
437 _scale[1] = fabs(_gt[5]);
440 RASTER_DEBUGF(4,
"Using scale: %f x %f", _scale[0], -1 * _scale[1]);
443 if (NULL != skew_x) {
457 if (NULL != skew_y) {
489 if (skewedrast == NULL) {
490 rterror(
"rt_raster_gdal_warp: Could not compute skewed raster");
496 _dim[0] = skewedrast->
width;
498 _dim[1] = skewedrast->
height;
508 _dim[0] = (int) fmax((fabs(extent.
MaxX - extent.
MinX) + (_scale[0] / 2.)) / _scale[0], 1);
510 _dim[1] = (int) fmax((fabs(extent.
MaxY - extent.
MinY) + (_scale[1] / 2.)) / _scale[1], 1);
515 rterror(
"rt_raster_gdal_warp: Out of memory allocating temporary raster");
526 RASTER_DEBUGF(3,
"Temp raster's geotransform: %f, %f, %f, %f, %f, %f",
527 _gt[0], _gt[1], _gt[2], _gt[3], _gt[4], _gt[5]);
528 RASTER_DEBUGF(3,
"Temp raster's dimensions (width x height): %d x %d",
538 RASTER_DEBUGF(4,
"Using user-specified upper-left corner: %f, %f", *ul_xw, *ul_yw);
546 ((NULL != ul_xw) && (NULL == ul_yw)) ||
547 ((NULL == ul_xw) && (NULL != ul_yw))
549 rterror(
"rt_raster_gdal_warp: Both X and Y upper-left corner values must be provided");
558 (NULL != grid_xw) || (NULL != grid_yw)
563 ((NULL != grid_xw) && (NULL == grid_yw)) ||
564 ((NULL == grid_xw) && (NULL != grid_yw))
566 rterror(
"rt_raster_gdal_warp: Both X and Y alignment values must be provided");
572 RASTER_DEBUGF(4,
"Aligning extent to user-specified grid: %f, %f", *grid_xw, *grid_yw);
580 RASTER_DEBUG(3,
"Skipping raster alignment as it is already aligned to grid");
595 rterror(
"rt_raster_gdal_warp: Could not compute raster pixel for spatial coordinates");
607 rterror(
"rt_raster_gdal_warp: Could not compute spatial coordinates for raster pixel");
618 else if (NULL == scale_x) {
630 rterror(
"rt_raster_gdal_warp: Could not compute spatial coordinates for raster pixel");
636 rast->
scaleX = fabs((_c[0] - _w[0]) / ((
double) rast->
width));
642 else if (NULL == scale_y) {
654 rterror(
"rt_raster_gdal_warp: Could not compute spatial coordinates for raster pixel");
661 rast->
scaleY = -1 * fabs((_c[1] - _w[1]) / ((
double) rast->
height));
676 _dim[0] = rast->
width;
682 (NULL != scale_x) && (*scale_x < 0.)
684 (NULL != scale_y) && (*scale_y > 0)
699 rterror(
"rt_raster_gdal_warp: Could not compute spatial coordinates for raster pixel");
709 if (NULL != skew_x &&
FLT_NEQ(*skew_x, 0))
723 rterror(
"rt_raster_gdal_warp: Could not compute spatial coordinates for raster pixel");
733 if (NULL != skew_y &&
FLT_NEQ(*skew_y, 0))
741 RASTER_DEBUGF(3,
"Applied geotransform: %f, %f, %f, %f, %f, %f",
742 _gt[0], _gt[1], _gt[2], _gt[3], _gt[4], _gt[5]);
743 RASTER_DEBUGF(3,
"Raster dimensions (width x height): %d x %d",
746 if ( _dim[0] == 0 || _dim[1] == 0 ) {
747 rterror(
"rt_raster_gdal_warp: The width (%d) or height (%d) of the warped raster is zero", _dim[0], _dim[1]);
758 arg->
dst.
drv = GDALGetDriverByName(
"VRT");
759 if (NULL == arg->
dst.
drv) {
760 rterror(
"rt_raster_gdal_warp: Could not load the output GDAL VRT driver");
766 arg->
dst.
ds = GDALCreate(arg->
dst.
drv,
"", _dim[0], _dim[1], 0, GDT_Byte, dst_options);
767 if (NULL == arg->
dst.
ds) {
768 rterror(
"rt_raster_gdal_warp: Could not create GDAL VRT dataset");
774 if (arg->
dst.
srs != NULL) {
775 cplerr = GDALSetProjection(arg->
dst.
ds, arg->
dst.
srs);
776 if (cplerr != CE_None) {
777 rterror(
"rt_raster_gdal_warp: Could not set projection");
785 cplerr = GDALSetGeoTransform(arg->
dst.
ds, _gt);
786 if (cplerr != CE_None) {
787 rterror(
"rt_raster_gdal_warp: Could not set geotransform");
794 for (i = 0; i < numBands; i++) {
796 if (NULL == rtband) {
797 rterror(
"rt_raster_gdal_warp: Could not get band %d for adding to VRT dataset", i);
804 if (gdal_pt == GDT_Unknown)
805 rtwarn(
"rt_raster_gdal_warp: Unknown pixel type for band %d", i);
807 cplerr = GDALAddBand(arg->
dst.
ds, gdal_pt, NULL);
808 if (cplerr != CE_None) {
809 rterror(
"rt_raster_gdal_warp: Could not add band to VRT dataset");
816 band = GDALGetRasterBand(arg->
dst.
ds, i + 1);
818 rterror(
"rt_raster_gdal_warp: Could not get GDAL band for additional processing");
827 if (GDALSetRasterNoDataValue(band, nodata) != CE_None)
828 rtwarn(
"rt_raster_gdal_warp: Could not set nodata value for band %d", i);
829 RASTER_DEBUGF(3,
"nodata value set to %f", GDALGetRasterNoDataValue(band, NULL));
834 arg->
transform.arg.transform = arg->
transform.arg.imgproj = GDALCreateGenImgProjTransformer2(
838 if (NULL == arg->
transform.arg.transform) {
839 rterror(
"rt_raster_gdal_warp: Could not create GDAL transformation object");
843 arg->
transform.func = GDALGenImgProjTransform;
847 arg->
transform.arg.transform = arg->
transform.arg.approx = GDALCreateApproxTransformer(
848 GDALGenImgProjTransform,
851 if (NULL == arg->
transform.arg.transform) {
852 rterror(
"rt_raster_gdal_warp: Could not create GDAL approximate transformation object");
857 arg->
transform.func = GDALApproxTransform;
861 arg->
wopts = GDALCreateWarpOptions();
862 if (NULL == arg->
wopts) {
863 rterror(
"rt_raster_gdal_warp: Could not create GDAL warp options object");
869 arg->
wopts->eResampleAlg = resample_alg;
874 arg->
wopts->papszWarpOptions = (
char **) CPLMalloc(
sizeof(
char *) * 2);
875 arg->
wopts->papszWarpOptions[0] = (
char *) CPLMalloc(
sizeof(
char) * (strlen(
"INIT_DEST=NO_DATA") + 1));
876 strcpy(arg->
wopts->papszWarpOptions[0],
"INIT_DEST=NO_DATA");
877 arg->
wopts->papszWarpOptions[1] = NULL;
880 arg->
wopts->nBandCount = numBands;
881 arg->
wopts->panSrcBands = (
int *) CPLMalloc(
sizeof(
int) * arg->
wopts->nBandCount);
882 arg->
wopts->panDstBands = (
int *) CPLMalloc(
sizeof(
int) * arg->
wopts->nBandCount);
883 for (i = 0; i < arg->
wopts->nBandCount; i++)
884 arg->
wopts->panDstBands[i] = arg->
wopts->panSrcBands[i] = i + 1;
889 arg->
wopts->padfSrcNoDataReal = (
double *) CPLMalloc(numBands *
sizeof(
double));
890 arg->
wopts->padfDstNoDataReal = (
double *) CPLMalloc(numBands *
sizeof(
double));
891 arg->
wopts->padfSrcNoDataImag = (
double *) CPLMalloc(numBands *
sizeof(
double));
892 arg->
wopts->padfDstNoDataImag = (
double *) CPLMalloc(numBands *
sizeof(
double));
894 NULL == arg->
wopts->padfSrcNoDataReal ||
895 NULL == arg->
wopts->padfDstNoDataReal ||
896 NULL == arg->
wopts->padfSrcNoDataImag ||
897 NULL == arg->
wopts->padfDstNoDataImag
899 rterror(
"rt_raster_gdal_warp: Out of memory allocating nodata mapping");
903 for (i = 0; i < numBands; i++) {
906 rterror(
"rt_raster_gdal_warp: Could not process bands for nodata values");
916 arg->
wopts->padfSrcNoDataReal[i] = -123456.789;
922 arg->
wopts->padfDstNoDataReal[i] = arg->
wopts->padfSrcNoDataReal[i];
923 arg->
wopts->padfDstNoDataImag[i] = arg->
wopts->padfSrcNoDataImag[i] = 0.0;
924 RASTER_DEBUGF(4,
"Mapped nodata value for band %d: %f (%f) => %f (%f)",
926 arg->
wopts->padfSrcNoDataReal[i], arg->
wopts->padfSrcNoDataImag[i],
927 arg->
wopts->padfDstNoDataReal[i], arg->
wopts->padfDstNoDataImag[i]
934 cplerr = GDALInitializeWarpedVRT(arg->
dst.
ds, arg->
wopts);
935 if (cplerr != CE_None) {
936 rterror(
"rt_raster_gdal_warp: Could not warp raster");
943 GDALFlushCache(arg->
dst.
ds);
953 rterror(
"rt_raster_gdal_warp: Could not warp raster");
959 double gt[6] = {0, 1, 0, 0, 0, -1};
964 gt[1] = _scale[0] * 10;
965 gt[5] = -1 * _scale[1] * 10;
struct _rti_warp_arg_t::@13::@15 arg
rt_raster rt_raster_gdal_warp(rt_raster raster, const char *src_srs, const char *dst_srs, double *scale_x, double *scale_y, int *width, int *height, double *ul_xw, double *ul_yw, double *grid_xw, double *grid_yw, double *skew_x, double *skew_y, GDALResampleAlg resample_alg, double max_err)
Return a warped raster using GDAL Warp API.
int rt_raster_get_num_bands(rt_raster raster)
struct _rti_warp_arg_t * _rti_warp_arg
raster
Be careful!! Zeros function's input parameter can be a (height x width) array, not (width x height): ...
void rt_raster_set_geotransform_matrix(rt_raster raster, double *gt)
Set raster's geotransform using 6-element array.
void rt_raster_get_geotransform_matrix(rt_raster raster, double *gt)
Get 6-element array of raster geotransform matrix.
void rt_raster_set_skews(rt_raster raster, double skewX, double skewY)
Set skews about the X and Y axis.
GDALDatasetH rt_raster_to_gdal_mem(rt_raster raster, const char *srs, uint32_t *bandNums, int *excludeNodataValues, int count, GDALDriverH *rtn_drv, int *destroy_rtn_drv)
Return GDAL dataset using GDAL MEM driver from raster.
void rterror(const char *fmt,...)
Wrappers used for reporting errors and info.
void * rtalloc(size_t size)
Wrappers used for managing memory.
static _rti_warp_arg _rti_warp_arg_init()
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
rt_errorstate rt_raster_cell_to_geopoint(rt_raster raster, double xr, double yr, double *xw, double *yw, double *gt)
Convert an xr, yr raster point to an xw, yw point on map.
GDALDataType rt_util_pixtype_to_gdal_datatype(rt_pixtype pt)
Convert rt_pixtype to GDALDataType.
int rt_util_gdal_driver_registered(const char *drv)
void rtwarn(const char *fmt,...)
void rt_raster_set_scale(rt_raster raster, double scaleX, double scaleY)
Set scale in projection units.
void rt_raster_set_offsets(rt_raster raster, double x, double y)
Set insertion points in projection units.
#define SRID_UNKNOWN
Unknown SRID value.
static void _rti_warp_arg_destroy(_rti_warp_arg arg)
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
struct _rti_warp_arg_t::@13::@14 option
void rt_raster_set_srid(rt_raster raster, int32_t srid)
Set raster's SRID.
#define RASTER_DEBUGF(level, msg,...)
int32_t rt_raster_get_srid(rt_raster raster)
Get raster's SRID.
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
rt_errorstate rt_raster_geopoint_to_cell(rt_raster raster, double xw, double yw, double *xr, double *yr, double *igt)
Convert an xw, yw map point to a xr, yr raster point.
rt_raster rt_raster_new(uint32_t width, uint32_t height)
Construct a raster with given dimensions.
void rtdealloc(void *mem)
#define RASTER_DEBUG(level, msg)
struct _rti_warp_arg_t::@12 src
This library is the generic raster handling section of PostGIS.
char * rt_util_gdal_convert_sr(const char *srs, int proj4)
rt_pixtype rt_band_get_pixtype(rt_band band)
Return pixeltype of this band.
struct _rti_warp_arg_t::@12 dst
rt_raster rt_raster_compute_skewed_raster(rt_envelope extent, double *skew, double *scale, double tolerance)
rt_raster rt_raster_from_gdal_dataset(GDALDatasetH ds)
Return a raster from a GDAL dataset.