static int msContourLayerReadRaster(layerObj *layer, rectObj rect) { mapObj *map = layer->map; char **bands; char pointer[64], memDSPointer[128]; int band = 1; double adfGeoTransform[6], adfInvGeoTransform[6]; double llx, lly, urx, ury; rectObj copyRect, mapRect; int dst_xsize, dst_ysize; int virtual_grid_step_x, virtual_grid_step_y; int src_xoff, src_yoff, src_xsize, src_ysize; double map_cellsize_x, map_cellsize_y, dst_cellsize_x, dst_cellsize_y; GDALRasterBandH hBand = NULL; CPLErr eErr; contourLayerInfo *clinfo = (contourLayerInfo *) layer->layerinfo; if (layer->debug) msDebug("Entering msContourLayerReadRaster().\n"); if (clinfo == NULL || clinfo->hOrigDS == NULL) { msSetError(MS_MISCERR, "Assertion failed: Contour layer not opened!!!", "msContourLayerReadRaster()"); return MS_FAILURE; } bands = CSLTokenizeStringComplex( CSLFetchNameValue(layer->processing,"BANDS"), " ,", FALSE, FALSE ); if (CSLCount(bands) > 0) { band = atoi(bands[0]); if (band < 1 || band > GDALGetRasterCount(clinfo->hOrigDS)) { msSetError( MS_IMGERR, "BANDS PROCESSING directive includes illegal band '%d', should be from 1 to %d.", "msContourLayerReadRaster()", band, GDALGetRasterCount(clinfo->hOrigDS)); CSLDestroy(bands); return MS_FAILURE; } } CSLDestroy(bands); hBand = GDALGetRasterBand(clinfo->hOrigDS, band); if (hBand == NULL) { msSetError(MS_IMGERR, "Band %d does not exist on dataset.", "msContourLayerReadRaster()", band); return MS_FAILURE; } if (layer->projection.numargs > 0 && EQUAL(layer->projection.args[0], "auto")) { const char *wkt; wkt = GDALGetProjectionRef(clinfo->hOrigDS); if (wkt != NULL && strlen(wkt) > 0) { if (msOGCWKT2ProjectionObj(wkt, &(layer->projection), layer->debug) != MS_SUCCESS) { char msg[MESSAGELENGTH*2]; errorObj *ms_error = msGetErrorObj(); snprintf( msg, sizeof(msg), "%s\n" "PROJECTION AUTO cannot be used for this " "GDAL raster (`%s').", ms_error->message, layer->data); msg[MESSAGELENGTH-1] = '\0'; msSetError(MS_OGRERR, "%s","msDrawRasterLayer()", msg); return MS_FAILURE; } } } /* * Compute the georeferenced window of overlap, and read the source data * downsampled to match output resolution, or at full resolution if * output resolution is lower than the source resolution. * * A large portion of this overlap calculation code was borrowed from * msDrawRasterLayerGDAL(). * Would be possible to move some of this to a reusable function? * * Note: This code works only if no reprojection is involved. It would * need rework to support cases where output projection differs from source * data file projection. */ src_xsize = GDALGetRasterXSize(clinfo->hOrigDS); src_ysize = GDALGetRasterYSize(clinfo->hOrigDS); /* set the Dataset extent */ msGetGDALGeoTransform(clinfo->hOrigDS, map, layer, adfGeoTransform); clinfo->extent.minx = adfGeoTransform[0]; clinfo->extent.maxy = adfGeoTransform[3]; clinfo->extent.maxx = adfGeoTransform[0] + src_xsize * adfGeoTransform[1]; clinfo->extent.miny = adfGeoTransform[3] + src_ysize * adfGeoTransform[5]; if (layer->transform) { if (layer->debug) msDebug("msContourLayerReadRaster(): Entering transform.\n"); InvGeoTransform(adfGeoTransform, adfInvGeoTransform); mapRect = rect; map_cellsize_x = map_cellsize_y = map->cellsize; #ifdef USE_PROJ /* if necessary, project the searchrect to source coords */ if (msProjectionsDiffer( &(map->projection), &(layer->projection))) { if ( msProjectRect(&map->projection, &layer->projection, &mapRect) != MS_SUCCESS ) { msDebug("msContourLayerReadRaster(%s): unable to reproject map request rectangle into layer projection, canceling.\n", layer->name); return MS_FAILURE; } map_cellsize_x = MS_CELLSIZE(mapRect.minx, mapRect.maxx, map->width); map_cellsize_y = MS_CELLSIZE(mapRect.miny, mapRect.maxy, map->height); /* if the projection failed to project the extent requested, we need to calculate the cellsize to preserve the initial map cellsize ratio */ if ( (mapRect.minx < GEO_TRANS(adfGeoTransform,0,src_ysize)) || (mapRect.maxx > GEO_TRANS(adfGeoTransform,src_xsize,0)) || (mapRect.miny < GEO_TRANS(adfGeoTransform+3,0,src_ysize)) || (mapRect.maxy > GEO_TRANS(adfGeoTransform+3,src_xsize,0)) ) { int src_unit, dst_unit; src_unit = GetMapserverUnitUsingProj(&map->projection); dst_unit = GetMapserverUnitUsingProj(&layer->projection); if (src_unit == -1 || dst_unit == -1) { msDebug("msContourLayerReadRaster(%s): unable to reproject map request rectangle into layer projection, canceling.\n", layer->name); return MS_FAILURE; } map_cellsize_x = MS_CONVERT_UNIT(src_unit, dst_unit, MS_CELLSIZE(rect.minx, rect.maxx, map->width)); map_cellsize_y = MS_CONVERT_UNIT(src_unit, dst_unit, MS_CELLSIZE(rect.miny, rect.maxy, map->height)); } } #endif if (map_cellsize_x == 0 || map_cellsize_y == 0) { if (layer->debug) msDebug("msContourLayerReadRaster(): Cellsize can't be 0.\n"); return MS_FAILURE; } /* Adjust MapServer pixel model to GDAL pixel model */ mapRect.minx -= map_cellsize_x*0.5; mapRect.maxx += map_cellsize_x*0.5; mapRect.miny -= map_cellsize_y*0.5; mapRect.maxy += map_cellsize_y*0.5; /* * If raw data cellsize (from geotransform) is larger than output map_cellsize * then we want to extract only enough data to match the output map resolution * which means that GDAL will automatically sample the data on read. * * To prevent bad contour effects on tile edges, we adjust the target cellsize * to align the extracted window with a virtual grid based on the origin of the * raw data and a virtual grid step size corresponding to an integer sampling step. * * If source data has a greater cellsize (i.e. lower res) that requested ouptut map * then we use the raw data cellsize as target cellsize since there is no point in * interpolating the data for contours in this case. */ virtual_grid_step_x = (int)floor(map_cellsize_x / ABS(adfGeoTransform[1])); if (virtual_grid_step_x < 1) virtual_grid_step_x = 1; /* Do not interpolate data if grid sampling step < 1 */ virtual_grid_step_y = (int)floor(map_cellsize_y / ABS(adfGeoTransform[5])); if (virtual_grid_step_y < 1) virtual_grid_step_y = 1; /* Do not interpolate data if grid sampling step < 1 */ /* target cellsize is a multiple of raw data cellsize based on grid step*/ dst_cellsize_x = ABS(adfGeoTransform[1]) * virtual_grid_step_x; dst_cellsize_y = ABS(adfGeoTransform[5]) * virtual_grid_step_y; /* Compute overlap between source and target views */ copyRect = mapRect; if (copyRect.minx < GEO_TRANS(adfGeoTransform,0,src_ysize)) copyRect.minx = GEO_TRANS(adfGeoTransform,0,src_ysize); if (copyRect.maxx > GEO_TRANS(adfGeoTransform,src_xsize,0)) copyRect.maxx = GEO_TRANS(adfGeoTransform,src_xsize,0); if (copyRect.miny < GEO_TRANS(adfGeoTransform+3,0,src_ysize)) copyRect.miny = GEO_TRANS(adfGeoTransform+3,0,src_ysize); if (copyRect.maxy > GEO_TRANS(adfGeoTransform+3,src_xsize,0)) copyRect.maxy = GEO_TRANS(adfGeoTransform+3,src_xsize,0); if (copyRect.minx >= copyRect.maxx || copyRect.miny >= copyRect.maxy) { if (layer->debug) msDebug("msContourLayerReadRaster(): Error in overlap calculation.\n"); return MS_FAILURE; } /* * Convert extraction window to raster coordinates */ llx = GEO_TRANS(adfInvGeoTransform+0,copyRect.minx,copyRect.miny); lly = GEO_TRANS(adfInvGeoTransform+3,copyRect.minx,copyRect.miny); urx = GEO_TRANS(adfInvGeoTransform+0,copyRect.maxx,copyRect.maxy); ury = GEO_TRANS(adfInvGeoTransform+3,copyRect.maxx,copyRect.maxy); /* * Align extraction window with virtual grid * (keep in mind raster coordinates origin is at upper-left) * We also add an extra buffer to fix tile boundarie issues when zoomed */ llx = floor(llx / virtual_grid_step_x) * virtual_grid_step_x - (virtual_grid_step_x*5); urx = ceil(urx / virtual_grid_step_x) * virtual_grid_step_x + (virtual_grid_step_x*5); ury = floor(ury / virtual_grid_step_y) * virtual_grid_step_y - (virtual_grid_step_x*5); lly = ceil(lly / virtual_grid_step_y) * virtual_grid_step_y + (virtual_grid_step_x*5); src_xoff = MAX(0,(int) floor(llx+0.5)); src_yoff = MAX(0,(int) floor(ury+0.5)); src_xsize = MIN(MAX(0,(int) (urx - llx + 0.5)), GDALGetRasterXSize(clinfo->hOrigDS) - src_xoff); src_ysize = MIN(MAX(0,(int) (lly - ury + 0.5)), GDALGetRasterYSize(clinfo->hOrigDS) - src_yoff); /* Update the geographic extent (buffer added) */ /* TODO: a better way to go the geo_trans */ copyRect.minx = GEO_TRANS(adfGeoTransform+0,src_xoff,0); copyRect.maxx = GEO_TRANS(adfGeoTransform+0,src_xoff+src_xsize,0); copyRect.miny = GEO_TRANS(adfGeoTransform+3,0,src_yoff+src_ysize); copyRect.maxy = GEO_TRANS(adfGeoTransform+3,0,src_yoff); /* * If input window is to small then stop here */ if (src_xsize < 2 || src_ysize < 2) { if (layer->debug) msDebug("msContourLayerReadRaster(): input window too small, or no apparent overlap between map view and this window(1).\n"); return MS_FAILURE; } /* Target buffer size */ dst_xsize = (int)ceil((copyRect.maxx - copyRect.minx) / dst_cellsize_x); dst_ysize = (int)ceil((copyRect.maxy - copyRect.miny) / dst_cellsize_y); if (dst_xsize == 0 || dst_ysize == 0) { if (layer->debug) msDebug("msContourLayerReadRaster(): no apparent overlap between map view and this window(2).\n"); return MS_FAILURE; } if (layer->debug) msDebug( "msContourLayerReadRaster(): src=%d,%d,%d,%d, dst=%d,%d,%d,%d\n", src_xoff, src_yoff, src_xsize, src_ysize, 0, 0, dst_xsize, dst_ysize ); } else { src_xoff = 0; src_yoff = 0; dst_xsize = src_xsize = MIN(map->width,src_xsize); dst_ysize = src_ysize = MIN(map->height,src_ysize); } /* -------------------------------------------------------------------- */ /* Allocate buffer, and read data into it. */ /* -------------------------------------------------------------------- */ clinfo->buffer = (double *) malloc(sizeof(double) * dst_xsize * dst_ysize); if (clinfo->buffer == NULL) { msSetError(MS_MEMERR, "Malloc(): Out of memory.", "msContourLayerReadRaster()"); return MS_FAILURE; } eErr = GDALRasterIO(hBand, GF_Read, src_xoff, src_yoff, src_xsize, src_ysize, clinfo->buffer, dst_xsize, dst_ysize, GDT_Float64, 0, 0); if (eErr != CE_None) { msSetError( MS_IOERR, "GDALRasterIO() failed: %s", "msContourLayerReadRaster()", CPLGetLastErrorMsg() ); free(clinfo->buffer); return MS_FAILURE; } memset(pointer, 0, sizeof(pointer)); CPLPrintPointer(pointer, clinfo->buffer, sizeof(pointer)); sprintf(memDSPointer,"MEM:::DATAPOINTER=%s,PIXELS=%d,LINES=%d,BANDS=1,DATATYPE=Float64", pointer, dst_xsize, dst_ysize); clinfo->hDS = GDALOpen(memDSPointer, GA_ReadOnly); if (clinfo->hDS == NULL) { msSetError(MS_IMGERR, "Unable to open GDAL Memory dataset.", "msContourLayerReadRaster()"); free(clinfo->buffer); return MS_FAILURE; } adfGeoTransform[0] = copyRect.minx; adfGeoTransform[1] = dst_cellsize_x; adfGeoTransform[2] = 0; adfGeoTransform[3] = copyRect.maxy; adfGeoTransform[4] = 0; adfGeoTransform[5] = -dst_cellsize_y; clinfo->cellsize = MAX(dst_cellsize_x, dst_cellsize_y); { char buf[64]; sprintf(buf, "%lf", clinfo->cellsize); msInsertHashTable(&layer->metadata, "__data_cellsize__", buf); } GDALSetGeoTransform(clinfo->hDS, adfGeoTransform); return MS_SUCCESS; }
// Slot called when the menu item is triggered // If you created more menu items / toolbar buttons in initiGui, you should // create a separate handler for each action - this single run() method will // not be enough void Heatmap::run() { HeatmapGui d( mQGisIface->mainWindow(), QgisGui::ModalDialogFlags, &mSessionSettings ); //check that dialog found a suitable vector layer if ( !d.inputVectorLayer() ) { mQGisIface->messageBar()->pushMessage( tr( "Layer not found" ), tr( "The heatmap plugin requires at least one point vector layer" ), QgsMessageBar::INFO, mQGisIface->messageTimeout() ); return; } if ( d.exec() != QDialog::Accepted ) { return; } QgsVectorLayer* inputLayer = d.inputVectorLayer(); // Get the required data from the dialog QgsRectangle myBBox = d.bbox(); int columns = d.columns(); int rows = d.rows(); double cellsize = d.cellSizeX(); // or d.cellSizeY(); both have the same value mDecay = d.decayRatio(); KernelShape kernelShape = d.kernelShape(); OutputValues valueType = d.outputValues(); //is input layer multipoint? bool isMultiPoint = inputLayer->wkbType() == Qgis::WKBMultiPoint || inputLayer->wkbType() == Qgis::WKBMultiPoint25D; // Getting the rasterdataset in place GDALAllRegister(); GDALDriverH myDriver = GDALGetDriverByName( d.outputFormat().toUtf8() ); if ( !myDriver ) { mQGisIface->messageBar()->pushMessage( tr( "GDAL driver error" ), tr( "Cannot open the driver for the specified format" ), QgsMessageBar::WARNING, mQGisIface->messageTimeout() ); return; } double geoTransform[6] = { myBBox.xMinimum(), cellsize, 0, myBBox.yMinimum(), 0, cellsize }; GDALDatasetH emptyDataset = GDALCreate( myDriver, d.outputFilename().toUtf8(), columns, rows, 1, GDT_Float32, nullptr ); GDALSetGeoTransform( emptyDataset, geoTransform ); // Set the projection on the raster destination to match the input layer GDALSetProjection( emptyDataset, inputLayer->crs().toWkt().toLocal8Bit().data() ); GDALRasterBandH poBand = GDALGetRasterBand( emptyDataset, 1 ); GDALSetRasterNoDataValue( poBand, NO_DATA ); float* line = ( float * ) CPLMalloc( sizeof( float ) * columns ); for ( int i = 0; i < columns ; i++ ) { line[i] = NO_DATA; } // Write the empty raster for ( int i = 0; i < rows ; i++ ) { if ( GDALRasterIO( poBand, GF_Write, 0, i, columns, 1, line, columns, 1, GDT_Float32, 0, 0 ) != CE_None ) { QgsDebugMsg( "Raster IO Error" ); } } CPLFree( line ); //close the dataset GDALClose( emptyDataset ); // open the raster in GA_Update mode GDALDatasetH heatmapDS = GDALOpen( TO8F( d.outputFilename() ), GA_Update ); if ( !heatmapDS ) { mQGisIface->messageBar()->pushMessage( tr( "Raster update error" ), tr( "Could not open the created raster for updating. The heatmap was not generated." ), QgsMessageBar::WARNING ); return; } poBand = GDALGetRasterBand( heatmapDS, 1 ); QgsAttributeList myAttrList; int rField = 0; int wField = 0; // Handle different radius options double radius; double radiusToMapUnits = 1; int myBuffer = 0; if ( d.variableRadius() ) { rField = d.radiusField(); myAttrList.append( rField ); QgsDebugMsg( QString( "Radius Field index received: %1" ).arg( rField ) ); // If not using map units, then calculate a conversion factor to convert the radii to map units if ( d.radiusUnit() == HeatmapGui::LayerUnits ) { radiusToMapUnits = mapUnitsOf( 1, inputLayer->crs() ); } } else { radius = d.radius(); // radius returned by d.radius() is already in map units myBuffer = bufferSize( radius, cellsize ); } if ( d.weighted() ) { wField = d.weightField(); myAttrList.append( wField ); } // This might have attributes or mightnot have attibutes at all // based on the variableRadius() and weighted() QgsFeatureIterator fit = inputLayer->getFeatures( QgsFeatureRequest().setSubsetOfAttributes( myAttrList ) ); int totalFeatures = inputLayer->featureCount(); int counter = 0; QProgressDialog p( tr( "Rendering heatmap..." ), tr( "Abort" ), 0, totalFeatures, mQGisIface->mainWindow() ); p.setWindowTitle( tr( "QGIS" ) ); p.setWindowModality( Qt::ApplicationModal ); p.show(); QgsFeature myFeature; while ( fit.nextFeature( myFeature ) ) { counter++; p.setValue( counter ); QApplication::processEvents(); if ( p.wasCanceled() ) { mQGisIface->messageBar()->pushMessage( tr( "Heatmap generation aborted" ), tr( "QGIS will now load the partially-computed raster" ), QgsMessageBar::INFO, mQGisIface->messageTimeout() ); break; } const QgsGeometry* featureGeometry = myFeature.constGeometry(); if ( !featureGeometry ) { continue; } // convert the geometry to multipoint QgsMultiPoint multiPoints; if ( !isMultiPoint ) { QgsPoint myPoint = featureGeometry->asPoint(); // avoiding any empty points or out of extent points if (( myPoint.x() < myBBox.xMinimum() ) || ( myPoint.y() < myBBox.yMinimum() ) || ( myPoint.x() > myBBox.xMaximum() ) || ( myPoint.y() > myBBox.yMaximum() ) ) { continue; } multiPoints << myPoint; } else { multiPoints = featureGeometry->asMultiPoint(); } // If radius is variable then fetch it and calculate new pixel buffer size if ( d.variableRadius() ) { radius = myFeature.attribute( rField ).toDouble() * radiusToMapUnits; myBuffer = bufferSize( radius, cellsize ); } int blockSize = 2 * myBuffer + 1; //Block SIDE would be more appropriate double weight = 1.0; if ( d.weighted() ) { weight = myFeature.attribute( wField ).toDouble(); } //loop through all points in multipoint for ( QgsMultiPoint::const_iterator pointIt = multiPoints.constBegin(); pointIt != multiPoints.constEnd(); ++pointIt ) { // avoiding any empty points or out of extent points if ((( *pointIt ).x() < myBBox.xMinimum() ) || (( *pointIt ).y() < myBBox.yMinimum() ) || (( *pointIt ).x() > myBBox.xMaximum() ) || (( *pointIt ).y() > myBBox.yMaximum() ) ) { continue; } // calculate the pixel position unsigned int xPosition, yPosition; xPosition = ((( *pointIt ).x() - myBBox.xMinimum() ) / cellsize ) - myBuffer; yPosition = ((( *pointIt ).y() - myBBox.yMinimum() ) / cellsize ) - myBuffer; // get the data float *dataBuffer = ( float * ) CPLMalloc( sizeof( float ) * blockSize * blockSize ); if ( GDALRasterIO( poBand, GF_Read, xPosition, yPosition, blockSize, blockSize, dataBuffer, blockSize, blockSize, GDT_Float32, 0, 0 ) != CE_None ) { QgsDebugMsg( "Raster IO Error" ); } for ( int xp = 0; xp <= myBuffer; xp++ ) { for ( int yp = 0; yp <= myBuffer; yp++ ) { double distance = sqrt( pow( xp, 2.0 ) + pow( yp, 2.0 ) ); // is pixel outside search bandwidth of feature? if ( distance > myBuffer ) { continue; } double pixelValue = weight * calculateKernelValue( distance, myBuffer, kernelShape, valueType ); // clearing anamolies along the axes if ( xp == 0 && yp == 0 ) { pixelValue /= 4; } else if ( xp == 0 || yp == 0 ) { pixelValue /= 2; } int pos[4]; pos[0] = ( myBuffer + xp ) * blockSize + ( myBuffer + yp ); pos[1] = ( myBuffer + xp ) * blockSize + ( myBuffer - yp ); pos[2] = ( myBuffer - xp ) * blockSize + ( myBuffer + yp ); pos[3] = ( myBuffer - xp ) * blockSize + ( myBuffer - yp ); for ( int p = 0; p < 4; p++ ) { if ( dataBuffer[ pos[p] ] == NO_DATA ) { dataBuffer[ pos[p] ] = 0; } dataBuffer[ pos[p] ] += pixelValue; } } } if ( GDALRasterIO( poBand, GF_Write, xPosition, yPosition, blockSize, blockSize, dataBuffer, blockSize, blockSize, GDT_Float32, 0, 0 ) != CE_None ) { QgsDebugMsg( "Raster IO Error" ); } CPLFree( dataBuffer ); } } // Finally close the dataset GDALClose(( GDALDatasetH ) heatmapDS ); // Open the file in QGIS window if requested if ( d.addToCanvas() ) { mQGisIface->addRasterLayer( d.outputFilename(), QFileInfo( d.outputFilename() ).baseName() ); } }
CPLErr GDALWarpCutlineMasker( void *pMaskFuncArg, CPL_UNUSED int nBandCount, CPL_UNUSED GDALDataType eType, int nXOff, int nYOff, int nXSize, int nYSize, GByte ** /*ppImageData */, int bMaskIsFloat, void *pValidityMask ) { GDALWarpOptions *psWO = (GDALWarpOptions *) pMaskFuncArg; float *pafMask = (float *) pValidityMask; CPLErr eErr; GDALDriverH hMemDriver; if( nXSize < 1 || nYSize < 1 ) return CE_None; /* -------------------------------------------------------------------- */ /* Do some minimal checking. */ /* -------------------------------------------------------------------- */ if( !bMaskIsFloat ) { CPLAssert( FALSE ); return CE_Failure; } if( psWO == NULL || psWO->hCutline == NULL ) { CPLAssert( FALSE ); return CE_Failure; } hMemDriver = GDALGetDriverByName("MEM"); if (hMemDriver == NULL) { CPLError(CE_Failure, CPLE_AppDefined, "GDALWarpCutlineMasker needs MEM driver"); return CE_Failure; } /* -------------------------------------------------------------------- */ /* Check the polygon. */ /* -------------------------------------------------------------------- */ OGRGeometryH hPolygon = (OGRGeometryH) psWO->hCutline; OGREnvelope sEnvelope; if( wkbFlatten(OGR_G_GetGeometryType(hPolygon)) != wkbPolygon && wkbFlatten(OGR_G_GetGeometryType(hPolygon)) != wkbMultiPolygon ) { CPLAssert( FALSE ); return CE_Failure; } OGR_G_GetEnvelope( hPolygon, &sEnvelope ); if( sEnvelope.MaxX + psWO->dfCutlineBlendDist < nXOff || sEnvelope.MinX - psWO->dfCutlineBlendDist > nXOff + nXSize || sEnvelope.MaxY + psWO->dfCutlineBlendDist < nYOff || sEnvelope.MinY - psWO->dfCutlineBlendDist > nYOff + nYSize ) { // We are far from the blend line - everything is masked to zero. // It would be nice to realize no work is required for this whole // chunk! memset( pafMask, 0, sizeof(float) * nXSize * nYSize ); return CE_None; } /* -------------------------------------------------------------------- */ /* Create a byte buffer into which we can burn the */ /* mask polygon and wrap it up as a memory dataset. */ /* -------------------------------------------------------------------- */ GByte *pabyPolyMask = (GByte *) CPLCalloc( nXSize, nYSize ); GDALDatasetH hMemDS; double adfGeoTransform[6] = { 0.0, 1.0, 0.0, 0.0, 0.0, 1.0 }; char szDataPointer[100]; char *apszOptions[] = { szDataPointer, NULL }; memset( szDataPointer, 0, sizeof(szDataPointer) ); sprintf( szDataPointer, "DATAPOINTER=" ); CPLPrintPointer( szDataPointer+strlen(szDataPointer), pabyPolyMask, sizeof(szDataPointer) - strlen(szDataPointer) ); hMemDS = GDALCreate( hMemDriver, "warp_temp", nXSize, nYSize, 0, GDT_Byte, NULL ); GDALAddBand( hMemDS, GDT_Byte, apszOptions ); GDALSetGeoTransform( hMemDS, adfGeoTransform ); /* -------------------------------------------------------------------- */ /* Burn the polygon into the mask with 1.0 values. */ /* -------------------------------------------------------------------- */ int nTargetBand = 1; double dfBurnValue = 255.0; int anXYOff[2]; char **papszRasterizeOptions = NULL; if( CSLFetchBoolean( psWO->papszWarpOptions, "CUTLINE_ALL_TOUCHED", FALSE )) papszRasterizeOptions = CSLSetNameValue( papszRasterizeOptions, "ALL_TOUCHED", "TRUE" ); anXYOff[0] = nXOff; anXYOff[1] = nYOff; eErr = GDALRasterizeGeometries( hMemDS, 1, &nTargetBand, 1, &hPolygon, CutlineTransformer, anXYOff, &dfBurnValue, papszRasterizeOptions, NULL, NULL ); CSLDestroy( papszRasterizeOptions ); // Close and ensure data flushed to underlying array. GDALClose( hMemDS ); /* -------------------------------------------------------------------- */ /* In the case with no blend distance, we just apply this as a */ /* mask, zeroing out everything outside the polygon. */ /* -------------------------------------------------------------------- */ if( psWO->dfCutlineBlendDist == 0.0 ) { int i; for( i = nXSize * nYSize - 1; i >= 0; i-- ) { if( pabyPolyMask[i] == 0 ) ((float *) pValidityMask)[i] = 0.0; } } else { eErr = BlendMaskGenerator( nXOff, nYOff, nXSize, nYSize, pabyPolyMask, (float *) pValidityMask, hPolygon, psWO->dfCutlineBlendDist ); } /* -------------------------------------------------------------------- */ /* Clean up. */ /* -------------------------------------------------------------------- */ CPLFree( pabyPolyMask ); return eErr; }
/* Matlab Gateway routine */ void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { int nXYSize; double adfGeoTransform[6] = {0,1,0,0,0,1}, adfDstGeoTransform[6]; char *pszSRS_WKT = NULL; char **papszWarpOptions = NULL; GDALDatasetH hSrcDS, hDstDS; GDALDriverH hDriver; GDALRasterBandH hBand; GDALColorTableH hColorTable = NULL; OGRSpatialReference oSrcSRS, oDstSRS; GDALResampleAlg interpMethod = GRA_NearestNeighbour; GDALTransformerFunc pfnTransformer = NULL; CPLErr eErr; GDAL_GCP *pasGCPs = NULL; static int runed_once = FALSE; /* It will be set to true if reaches end of main */ const int *dim_array; int nx, ny, i, j, m, n, c, nBands, registration = 1; int n_dims, typeCLASS, nBytes; char *pszSrcSRS = NULL, *pszSrcWKT = NULL; char *pszDstSRS = NULL, *pszDstWKT = NULL; void *in_data; mxArray *mx_ptr; unsigned char *tmpByte, *outByte; unsigned short int *tmpUI16, *outUI16; short int *tmpI16, *outI16; int *tmpI32, *outI32; int nPixels=0, nLines=0, nForceWidth=0, nForceHeight=0; int nGCPCount = 0, nOrder = 0; unsigned int *tmpUI32, *outUI32; float *tmpF32, *outF32; double *tmpF64, *outF64, *ptr_d; double dfMinX=0, dfMaxX=0, dfMinY=0, dfMaxY=0, dfResX=0, dfResY=0; double adfExtent[4]; double dfXRes=0.0, dfYRes=0.0; double dfWarpMemoryLimit = 0.0; double *pdfDstNodata = NULL; char **papszMetadataOptions = NULL; char *tmp, *txt; if (nrhs == 2 && mxIsStruct(prhs[1])) { mx_ptr = mxGetField(prhs[1], 0, "ULx"); if (mx_ptr == NULL) mexErrMsgTxt("GDALWARP 'ULx' field not provided"); ptr_d = mxGetPr(mx_ptr); adfGeoTransform[0] = *ptr_d; mx_ptr = mxGetField(prhs[1], 0, "Xinc"); if (mx_ptr == NULL) mexErrMsgTxt("GDALWARP 'Xinc' field not provided"); ptr_d = mxGetPr(mx_ptr); adfGeoTransform[1] = *ptr_d; mx_ptr = mxGetField(prhs[1], 0, "ULy"); if (mx_ptr == NULL) mexErrMsgTxt("GDALWARP 'ULy' field not provided"); ptr_d = mxGetPr(mx_ptr); adfGeoTransform[3] = *ptr_d; mx_ptr = mxGetField(prhs[1], 0, "Yinc"); if (mx_ptr == NULL) mexErrMsgTxt("GDALWARP 'Yinc' field not provided"); ptr_d = mxGetPr(mx_ptr); adfGeoTransform[5] = -*ptr_d; /* -------- See for resolution requests ------------ */ mx_ptr = mxGetField(prhs[1], 0, "t_size"); if (mx_ptr != NULL) { ptr_d = mxGetPr(mx_ptr); if (mxGetN(mx_ptr) == 2) { nForceWidth = (int)ptr_d[0]; nForceHeight = (int)ptr_d[1]; } else if (mxGetN(mx_ptr) == 1) { /* pick max(nrow,ncol) */ if (mxGetM(prhs[0]) > getNK(prhs[0],1)) nForceHeight = mxGetM(prhs[0]); else nForceWidth = getNK(prhs[0], 1); } else { nForceHeight = mxGetM(prhs[0]); nForceWidth = getNK(prhs[0], 1); } } mx_ptr = mxGetField(prhs[1], 0, "t_res"); if (mx_ptr != NULL) { ptr_d = mxGetPr(mx_ptr); if (mxGetN(mx_ptr) == 2) { dfXRes = ptr_d[0]; dfYRes = ptr_d[1]; } else if (mxGetN(mx_ptr) == 1) { dfXRes = dfYRes = ptr_d[0]; } } /* -------------------------------------------------- */ /* -------- Change Warping cache size? ------------ */ mx_ptr = mxGetField(prhs[1], 0, "wm"); if (mx_ptr != NULL) { ptr_d = mxGetPr(mx_ptr); dfWarpMemoryLimit = *ptr_d * 1024 * 1024; } /* -------------------------------------------------- */ /* -------- Have a nodata value order? -------------- */ mx_ptr = mxGetField(prhs[1], 0, "nodata"); if (mx_ptr != NULL) { pdfDstNodata = mxGetPr(mx_ptr); } /* -------------------------------------------------- */ /* -------- See for projection stuff ---------------- */ mx_ptr = mxGetField(prhs[1], 0, "SrcProjSRS"); if (mx_ptr != NULL) pszSrcSRS = (char *)mxArrayToString(mx_ptr); mx_ptr = mxGetField(prhs[1], 0, "SrcProjWKT"); if (mx_ptr != NULL) pszSrcWKT = (char *)mxArrayToString(mx_ptr); mx_ptr = mxGetField(prhs[1], 0, "DstProjSRS"); if (mx_ptr != NULL) pszDstSRS = (char *)mxArrayToString(mx_ptr); mx_ptr = mxGetField(prhs[1], 0, "DstProjWKT"); if (mx_ptr != NULL) pszDstWKT = (char *)mxArrayToString(mx_ptr); /* -------------------------------------------------- */ /* -------- Do we have GCPs? ----------------------- */ mx_ptr = mxGetField(prhs[1], 0, "gcp"); if (mx_ptr != NULL) { nGCPCount = mxGetM(mx_ptr); if (mxGetN(mx_ptr) != 4) mexErrMsgTxt("GDALWARP: GCPs must be a Mx4 array"); ptr_d = mxGetPr(mx_ptr); pasGCPs = (GDAL_GCP *) mxCalloc( nGCPCount, sizeof(GDAL_GCP) ); GDALInitGCPs( 1, pasGCPs + nGCPCount - 1 ); for (i = 0; i < nGCPCount; i++) { pasGCPs[i].dfGCPPixel = ptr_d[i]; pasGCPs[i].dfGCPLine = ptr_d[i+nGCPCount]; pasGCPs[i].dfGCPX = ptr_d[i+2*nGCPCount]; pasGCPs[i].dfGCPY = ptr_d[i+3*nGCPCount]; pasGCPs[i].dfGCPZ = 0; } } /* ---- Have we an order request? --- */ mx_ptr = mxGetField(prhs[1], 0, "order"); if (mx_ptr != NULL) { ptr_d = mxGetPr(mx_ptr); nOrder = (int)*ptr_d; if (nOrder != -1 || nOrder != 0 || nOrder != 1 || nOrder != 2 || nOrder != 3) nOrder = 0; } /* -------------------------------------------------- */ mx_ptr = mxGetField(prhs[1], 0, "ResampleAlg"); if (mx_ptr != NULL) { txt = (char *)mxArrayToString(mx_ptr); if (!strcmp(txt,"nearest")) interpMethod = GRA_NearestNeighbour; else if (!strcmp(txt,"bilinear")) interpMethod = GRA_Bilinear; else if (!strcmp(txt,"cubic") || !strcmp(txt,"bicubic")) interpMethod = GRA_Cubic; else if (!strcmp(txt,"spline")) interpMethod = GRA_CubicSpline; } /* If grid limits were in grid registration, convert them to pixel reg */ mx_ptr = mxGetField(prhs[1], 0, "Reg"); if (mx_ptr != NULL) { ptr_d = mxGetPr(mx_ptr); registration = (int)ptr_d[0]; } if (registration == 0) { adfGeoTransform[0] -= adfGeoTransform[1]/2.; adfGeoTransform[3] -= adfGeoTransform[5]/2.; } } else { mexPrintf("Usage: B = gdalwarp_mex(IMG,HDR_STRUCT)\n\n"); mexPrintf("\tIMG -> is a Mx2 or Mx3 array with an grid/image data to reproject\n"); mexPrintf("\tHDR_STRUCT -> is a structure with the following fields:\n"); mexPrintf("\t\t'ULx' X coordinate of the uper left corner\n"); mexPrintf("\t\t'ULy' Y coordinate of the uper left corner\n"); mexPrintf("\t\t'Xinc' distance between columns in target grid/image coordinates\n"); mexPrintf("\t\t'Yinc' distance between rows in target grid/image coordinates\n"); mexPrintf("\t\t'SrcProjSRS', 'SrcProjWKT' -> Source projection string\n"); mexPrintf("\t\t'DstProjSRS', 'DstProjWKT' -> Target projection string\n"); mexPrintf("\t\t\tSRS stands for a string of the type used by proj4\n"); mexPrintf("\t\t\tWKT stands for a string on the 'Well Known Text' format\n\n"); mexPrintf("\t\t\tIf one of the Src or Dst fields is absent a GEOGRAPHIC WGS84 is assumed\n"); mexPrintf("\nOPTIONS\n"); mexPrintf("\t\t'gcp' a [Mx4] array with Ground Control Points\n"); mexPrintf("\t\t't_size' a [width height] vector to set output file size in pixels\n"); mexPrintf("\t\t't_res' a [xres yres] vector to set output file resolution (in target georeferenced units)\n"); mexPrintf("\t\t'wm' amount of memory (in megabytes) that the warp API is allowed to use for caching\n"); mexPrintf("\t\t'nodata' Set nodata values for output bands.\n"); mexPrintf("\t\t'ResampleAlg' To set up the algorithm used during warp operation. Options are: \n"); mexPrintf("\t\t\t'nearest' Use nearest neighbour resampling (default, fastest algorithm, worst interpolation quality).\n"); mexPrintf("\t\t\t'bilinear' Use bilinear resampling.\n"); mexPrintf("\t\t\t'cubic' Use cubic resampling.\n"); mexPrintf("\t\t\t'spline' Use cubic spline resampling.\n\n"); if (!runed_once) /* Do next call only at first time this MEX is loaded */ GDALAllRegister(); mexPrintf( "The following format drivers are configured and support Create() method:\n" ); for( i = 0; i < GDALGetDriverCount(); i++ ) { hDriver = GDALGetDriver(i); if( GDALGetMetadataItem( hDriver, GDAL_DCAP_CREATE, NULL ) != NULL) mexPrintf("%s: %s\n", GDALGetDriverShortName(hDriver), GDALGetDriverLongName(hDriver)); } return; } n_dims = mxGetNumberOfDimensions(prhs[0]); dim_array=mxGetDimensions(prhs[0]); ny = dim_array[0]; nx = dim_array[1]; nBands = dim_array[2]; if (n_dims == 2) /* Otherwise it would stay undefined */ nBands = 1; /* Find out in which data type was given the input array */ if (mxIsUint8(prhs[0])) { typeCLASS = GDT_Byte; nBytes = 1; outByte = (unsigned char *)mxMalloc (nx*ny * sizeof(unsigned char)); } else if (mxIsUint16(prhs[0])) { typeCLASS = GDT_UInt16; nBytes = 2; outUI16 = (unsigned short int *)mxMalloc (nx*ny * sizeof(short int)); } else if (mxIsInt16(prhs[0])) { typeCLASS = GDT_Int16; nBytes = 2; outI16 = (short int *)mxMalloc (nx*ny * sizeof(short int)); } else if (mxIsInt32(prhs[0])) { typeCLASS = GDT_Int32; nBytes = 4; outI32 = (int *)mxMalloc (nx*ny * sizeof(int)); } else if (mxIsUint32(prhs[0])) { typeCLASS = GDT_UInt32; nBytes = 4; outUI32 = (unsigned int *)mxMalloc (nx*ny * sizeof(int)); } else if (mxIsSingle(prhs[0])) { typeCLASS = GDT_Float32; nBytes = 4; outF32 = (float *)mxMalloc (nx*ny * sizeof(float)); } else if (mxIsDouble(prhs[0])) { typeCLASS = GDT_Float64; nBytes = 8; outF64 = (double *)mxMalloc (nx*ny * sizeof(double)); } else mexErrMsgTxt("GDALWARP Unknown input data class!"); in_data = (void *)mxGetData(prhs[0]); if (!runed_once) /* Do next call only at first time this MEX is loaded */ GDALAllRegister(); hDriver = GDALGetDriverByName( "MEM" ); hSrcDS = GDALCreate( hDriver, "mem", nx, ny, nBands, (GDALDataType)typeCLASS, NULL ); if (hSrcDS == NULL) { mexPrintf ("GDALOpen failed - %d\n%s\n", CPLGetLastErrorNo(), CPLGetLastErrorMsg()); return; } GDALSetGeoTransform( hSrcDS, adfGeoTransform ); /* ---------- Set the Source projection ---------------------------- */ /* If it was not provided assume it is Geog WGS84 */ if (pszSrcSRS == NULL && pszSrcWKT == NULL) oSrcSRS.SetWellKnownGeogCS( "WGS84" ); else if (pszSrcWKT != NULL) oSrcSRS.importFromWkt( &pszSrcWKT ); else { if( oSrcSRS.SetFromUserInput( pszSrcSRS ) != OGRERR_NONE ) mexErrMsgTxt("GDAL_WARP_MEX: Translating source SRS failed."); } if (pszSrcWKT == NULL) oSrcSRS.exportToWkt( &pszSrcWKT ); GDALSetProjection( hSrcDS, pszSrcWKT ); //pszSrcWKT = (char *)GDALGetProjectionRef( hSrcDS ); CPLAssert( pszSrcWKT != NULL && strlen(pszSrcWKT) > 0 ); /* ------------------------------------------------------------------ */ /* -------------- Copy input data into the hSrcDS dataset ----------- */ for (i = 1; i <= nBands; i++) { hBand = GDALGetRasterBand( hSrcDS, i ); nXYSize = (i-1)*nx*ny; switch( typeCLASS ) { case GDT_Byte: tmpByte = (unsigned char *)in_data; for (m = ny-1, c = 0; m >= 0; m--) for (n = 0; n < nx; n++) outByte[c++] = tmpByte[m + n*ny + nXYSize]; GDALRasterIO( hBand, GF_Write, 0, 0, nx, ny,outByte, nx, ny, (GDALDataType)typeCLASS, 0, 0 ); break; case GDT_UInt16: tmpUI16 = (unsigned short int *)in_data; for (m = ny-1, c = 0; m >= 0; m--) for (n = 0; n < nx; n++) outUI16[c++] = tmpUI16[m + n*ny + nXYSize]; GDALRasterIO( hBand, GF_Write, 0, 0, nx, ny,outUI16, nx, ny, (GDALDataType)typeCLASS, 0, 0 ); break; case GDT_Int16: tmpI16 = (short int *)in_data; for (m = ny-1, c = 0; m >= 0; m--) for (n = 0; n < nx; n++) outI16[c++] = tmpI16[m + n*ny + nXYSize]; GDALRasterIO( hBand, GF_Write, 0, 0, nx, ny,outI16, nx, ny, (GDALDataType)typeCLASS, 0, 0 ); break; case GDT_UInt32: tmpUI32 = (unsigned int *)in_data; for (m = ny-1, c = 0; m >= 0; m--) for (n = 0; n < nx; n++) outUI32[c++] = tmpUI32[m + n*ny + nXYSize]; GDALRasterIO( hBand, GF_Write, 0, 0, nx, ny,outUI32, nx, ny, (GDALDataType)typeCLASS, 0, 0 ); break; case GDT_Int32: tmpI32 = (int *)in_data; for (m = ny-1, c = 0; m >= 0; m--) for (n = 0; n < nx; n++) outI32[c++] = tmpI32[m + n*ny + nXYSize]; GDALRasterIO( hBand, GF_Write, 0, 0, nx, ny,outI32, nx, ny, (GDALDataType)typeCLASS, 0, 0 ); break; case GDT_Float32: tmpF32 = (float *)in_data; for (m = ny-1, c = 0; m >= 0; m--) for (n = 0; n < nx; n++) outF32[c++] = tmpF32[m + n*ny + nXYSize]; GDALRasterIO( hBand, GF_Write, 0, 0, nx, ny,outF32, nx, ny, (GDALDataType)typeCLASS, 0, 0 ); break; case GDT_Float64: tmpF64 = (double *)in_data; for (m = ny-1, c = 0; m >= 0; m--) for (n = 0; n < nx; n++) outF64[c++] = tmpF64[m + n*ny + nXYSize]; GDALRasterIO( hBand, GF_Write, 0, 0, nx, ny,outF64, nx, ny, (GDALDataType)typeCLASS, 0, 0 ); break; } } /* ---------- Set up the Target coordinate system ------------------- */ /* If it was not provided assume it is Geog WGS84 */ CPLErrorReset(); if (pszDstSRS == NULL && pszDstWKT == NULL) oDstSRS.SetWellKnownGeogCS( "WGS84" ); else if (pszDstWKT != NULL) oDstSRS.importFromWkt( &pszDstWKT ); else { if( oDstSRS.SetFromUserInput( pszDstSRS ) != OGRERR_NONE ) mexErrMsgTxt("GDAL_WARP_MEX: Translating target SRS failed."); } if (pszDstWKT == NULL) oDstSRS.exportToWkt( &pszDstWKT ); /* ------------------------------------------------------------------ */ if ( nGCPCount != 0 ) { if (GDALSetGCPs(hSrcDS, nGCPCount, pasGCPs, "") != CE_None) mexPrintf("GDALWARP WARNING: writing GCPs failed.\n"); } /* Create a transformer that maps from source pixel/line coordinates to destination georeferenced coordinates (not destination pixel line) We do that by omitting the destination dataset handle (setting it to NULL). */ void *hTransformArg; hTransformArg = GDALCreateGenImgProjTransformer(hSrcDS, pszSrcWKT, NULL, pszDstWKT, nGCPCount == 0 ? FALSE : TRUE, 0, nOrder); if( hTransformArg == NULL ) mexErrMsgTxt("GDALTRANSFORM: Generating transformer failed."); GDALTransformerInfo *psInfo = (GDALTransformerInfo*)hTransformArg; /* -------------------------------------------------------------------------- */ /* Get approximate output georeferenced bounds and resolution for file /* -------------------------------------------------------------------------- */ if (GDALSuggestedWarpOutput2(hSrcDS, GDALGenImgProjTransform, hTransformArg, adfDstGeoTransform, &nPixels, &nLines, adfExtent, 0) != CE_None ) { GDALClose(hSrcDS); mexErrMsgTxt("GDALWARP: GDALSuggestedWarpOutput2 failed."); } if (CPLGetConfigOption( "CHECK_WITH_INVERT_PROJ", NULL ) == NULL) { double MinX = adfExtent[0]; double MaxX = adfExtent[2]; double MaxY = adfExtent[3]; double MinY = adfExtent[1]; int bSuccess = TRUE; /* Check that the the edges of the target image are in the validity area */ /* of the target projection */ #define N_STEPS 20 for (i = 0; i <= N_STEPS && bSuccess; i++) { for (j = 0; j <= N_STEPS && bSuccess; j++) { double dfRatioI = i * 1.0 / N_STEPS; double dfRatioJ = j * 1.0 / N_STEPS; double expected_x = (1 - dfRatioI) * MinX + dfRatioI * MaxX; double expected_y = (1 - dfRatioJ) * MinY + dfRatioJ * MaxY; double x = expected_x; double y = expected_y; double z = 0; /* Target SRS coordinates to source image pixel coordinates */ if (!psInfo->pfnTransform(hTransformArg, TRUE, 1, &x, &y, &z, &bSuccess) || !bSuccess) bSuccess = FALSE; /* Source image pixel coordinates to target SRS coordinates */ if (!psInfo->pfnTransform(hTransformArg, FALSE, 1, &x, &y, &z, &bSuccess) || !bSuccess) bSuccess = FALSE; if (fabs(x - expected_x) > (MaxX - MinX) / nPixels || fabs(y - expected_y) > (MaxY - MinY) / nLines) bSuccess = FALSE; } } /* If not, retry with CHECK_WITH_INVERT_PROJ=TRUE that forces ogrct.cpp */ /* to check the consistency of each requested projection result with the */ /* invert projection */ if (!bSuccess) { CPLSetConfigOption( "CHECK_WITH_INVERT_PROJ", "TRUE" ); CPLDebug("WARP", "Recompute out extent with CHECK_WITH_INVERT_PROJ=TRUE"); if (GDALSuggestedWarpOutput2(hSrcDS, GDALGenImgProjTransform, hTransformArg, adfDstGeoTransform, &nPixels, &nLines, adfExtent, 0) != CE_None ) { GDALClose(hSrcDS); mexErrMsgTxt("GDALWARO: GDALSuggestedWarpOutput2 failed."); } } } /* -------------------------------------------------------------------- */ /* Expand the working bounds to include this region, ensure the */ /* working resolution is no more than this resolution. */ /* -------------------------------------------------------------------- */ if( dfMaxX == 0.0 && dfMinX == 0.0 ) { dfMinX = adfExtent[0]; dfMaxX = adfExtent[2]; dfMaxY = adfExtent[3]; dfMinY = adfExtent[1]; dfResX = adfDstGeoTransform[1]; dfResY = ABS(adfDstGeoTransform[5]); } else { dfMinX = MIN(dfMinX,adfExtent[0]); dfMaxX = MAX(dfMaxX,adfExtent[2]); dfMaxY = MAX(dfMaxY,adfExtent[3]); dfMinY = MIN(dfMinY,adfExtent[1]); dfResX = MIN(dfResX,adfDstGeoTransform[1]); dfResY = MIN(dfResY,ABS(adfDstGeoTransform[5])); } GDALDestroyGenImgProjTransformer( hTransformArg ); /* -------------------------------------------------------------------- */ /* Turn the suggested region into a geotransform and suggested */ /* number of pixels and lines. */ /* -------------------------------------------------------------------- */ adfDstGeoTransform[0] = dfMinX; adfDstGeoTransform[1] = dfResX; adfDstGeoTransform[2] = 0.0; adfDstGeoTransform[3] = dfMaxY; adfDstGeoTransform[4] = 0.0; adfDstGeoTransform[5] = -1 * dfResY; nPixels = (int) ((dfMaxX - dfMinX) / dfResX + 0.5); nLines = (int) ((dfMaxY - dfMinY) / dfResY + 0.5); /* -------------------------------------------------------------------- */ /* Did the user override some parameters? */ /* -------------------------------------------------------------------- */ if( dfXRes != 0.0 && dfYRes != 0.0 ) { dfMinX = adfDstGeoTransform[0]; dfMaxX = adfDstGeoTransform[0] + adfDstGeoTransform[1] * nPixels; dfMaxY = adfDstGeoTransform[3]; dfMinY = adfDstGeoTransform[3] + adfDstGeoTransform[5] * nLines; nPixels = (int) ((dfMaxX - dfMinX + (dfXRes/2.0)) / dfXRes); nLines = (int) ((dfMaxY - dfMinY + (dfYRes/2.0)) / dfYRes); adfDstGeoTransform[0] = dfMinX; adfDstGeoTransform[3] = dfMaxY; adfDstGeoTransform[1] = dfXRes; adfDstGeoTransform[5] = -dfYRes; } else if( nForceWidth != 0 && nForceHeight != 0 ) { dfXRes = (dfMaxX - dfMinX) / nForceWidth; dfYRes = (dfMaxY - dfMinY) / nForceHeight; adfDstGeoTransform[0] = dfMinX; adfDstGeoTransform[3] = dfMaxY; adfDstGeoTransform[1] = dfXRes; adfDstGeoTransform[5] = -dfYRes; nPixels = nForceWidth; nLines = nForceHeight; } else if( nForceWidth != 0) { dfXRes = (dfMaxX - dfMinX) / nForceWidth; dfYRes = dfXRes; adfDstGeoTransform[0] = dfMinX; adfDstGeoTransform[3] = dfMaxY; adfDstGeoTransform[1] = dfXRes; adfDstGeoTransform[5] = -dfYRes; nPixels = nForceWidth; nLines = (int) ((dfMaxY - dfMinY + (dfYRes/2.0)) / dfYRes); } else if( nForceHeight != 0) { dfYRes = (dfMaxY - dfMinY) / nForceHeight; dfXRes = dfYRes; adfDstGeoTransform[0] = dfMinX; adfDstGeoTransform[3] = dfMaxY; adfDstGeoTransform[1] = dfXRes; adfDstGeoTransform[5] = -dfYRes; nPixels = (int) ((dfMaxX - dfMinX + (dfXRes/2.0)) / dfXRes); nLines = nForceHeight; } /* --------------------- Create the output --------------------------- */ hDstDS = GDALCreate( hDriver, "mem", nPixels, nLines, GDALGetRasterCount(hSrcDS), (GDALDataType)typeCLASS, NULL ); CPLAssert( hDstDS != NULL ); /* -------------- Write out the projection definition ---------------- */ GDALSetProjection( hDstDS, pszDstWKT ); GDALSetGeoTransform( hDstDS, adfDstGeoTransform ); /* --------------------- Setup warp options -------------------------- */ GDALWarpOptions *psWO = GDALCreateWarpOptions(); psWO->hSrcDS = hSrcDS; psWO->hDstDS = hDstDS; psWO->nBandCount = nBands; psWO->panSrcBands = (int *) CPLMalloc(psWO->nBandCount * sizeof(int) ); psWO->panDstBands = (int *) CPLMalloc(psWO->nBandCount * sizeof(int) ); for( i = 0; i < nBands; i++ ) { psWO->panSrcBands[i] = i+1; psWO->panDstBands[i] = i+1; } if( dfWarpMemoryLimit != 0.0 ) psWO->dfWarpMemoryLimit = dfWarpMemoryLimit; /* --------------------- Setup the Resampling Algo ------------------- */ psWO->eResampleAlg = interpMethod; /* --------------------- Setup NODATA options ------------------------ */ papszWarpOptions = CSLSetNameValue(papszWarpOptions, "INIT_DEST", "NO_DATA" ); if ( pdfDstNodata == NULL && (typeCLASS == GDT_Float32 || typeCLASS == GDT_Float64) ) { pdfDstNodata = (double *) mxCalloc((size_t)1, sizeof(double)); *pdfDstNodata = mxGetNaN(); } else if (pdfDstNodata != NULL) { #define CLAMP(val,type,minval,maxval) \ do { if (val < minval) { val = minval; } \ else if (val > maxval) { val = maxval; } \ else if (val != (type)val) { val = (type)(val + 0.5); } } \ while(0) switch( typeCLASS ) { case GDT_Byte: CLAMP(pdfDstNodata[0], GByte, 0.0, 255.0); break; case GDT_UInt16: CLAMP(pdfDstNodata[0], GInt16, -32768.0, 32767.0); break; case GDT_Int16: CLAMP(pdfDstNodata[0], GUInt16, 0.0, 65535.0); break; case GDT_UInt32: CLAMP(pdfDstNodata[0], GInt32, -2147483648.0, 2147483647.0); break; case GDT_Int32: CLAMP(pdfDstNodata[0], GUInt32, 0.0, 4294967295.0); break; default: break; } } psWO->papszWarpOptions = CSLDuplicate(papszWarpOptions); if (pdfDstNodata != NULL) { psWO->padfDstNoDataReal = (double *) CPLMalloc(psWO->nBandCount*sizeof(double)); psWO->padfDstNoDataImag = (double *) CPLMalloc(psWO->nBandCount*sizeof(double)); for (i = 0; i < nBands; i++) { psWO->padfDstNoDataReal[i] = pdfDstNodata[0]; psWO->padfDstNoDataImag[i] = 0.0; GDALSetRasterNoDataValue( GDALGetRasterBand(hDstDS, i+1), pdfDstNodata[0]); } } /* ------------ Establish reprojection transformer ------------------- */ psWO->pTransformerArg = GDALCreateGenImgProjTransformer( hSrcDS, GDALGetProjectionRef(hSrcDS), hDstDS, GDALGetProjectionRef(hDstDS), nGCPCount == 0 ? FALSE : TRUE, 0.0, nOrder ); psWO->pfnTransformer = GDALGenImgProjTransform; /* ----------- Initialize and execute the warp operation ------------- */ GDALWarpOperation oOperation; oOperation.Initialize( psWO ); eErr = oOperation.ChunkAndWarpImage( 0, 0, GDALGetRasterXSize( hDstDS ), GDALGetRasterYSize( hDstDS ) ); CPLAssert( eErr == CE_None ); GDALDestroyGenImgProjTransformer( psWO->pTransformerArg ); GDALDestroyWarpOptions( psWO ); GDALClose( hSrcDS ); /* ------------ Free memory used to fill the hSrcDS dataset ---------- */ switch( typeCLASS ) { case GDT_Byte: mxFree((void *)outByte); break; case GDT_UInt16: mxFree((void *)outUI16); break; case GDT_Int16: mxFree((void *)outI16); break; case GDT_UInt32: mxFree((void *)outUI32); break; case GDT_Int32: mxFree((void *)outI32); break; case GDT_Float32: mxFree((void *)outF32); break; case GDT_Float64: mxFree((void *)outF64); break; } int out_dims[3]; out_dims[0] = nLines; out_dims[1] = nPixels; out_dims[2] = nBands; plhs[0] = mxCreateNumericArray (n_dims,out_dims,mxGetClassID(prhs[0]), mxREAL); tmp = (char *)mxCalloc(nPixels * nLines, nBytes); /* ------ Allocate memory to be used in filling the hDstDS dataset ---- */ switch( typeCLASS ) { case GDT_Byte: outByte = (unsigned char *)mxGetData(plhs[0]); break; case GDT_UInt16: outUI16 = (unsigned short int *)mxGetData(plhs[0]); break; case GDT_Int16: outI16 = (short int *)mxGetData(plhs[0]); break; case GDT_UInt32: outUI32 = (unsigned int *)mxGetData(plhs[0]); break; case GDT_Int32: outI32 = (int *)mxGetData(plhs[0]); break; case GDT_Float32: outF32 = (float *)mxGetData(plhs[0]); break; case GDT_Float64: outF64 = (double *)mxGetData(plhs[0]); break; } /* ----------- Copy the output hSrcDS dataset data into plhs ---------- */ for (i = 1; i <= nBands; i++) { hBand = GDALGetRasterBand( hDstDS, i ); GDALRasterIO( hBand, GF_Read, 0, 0, nPixels, nLines, tmp, nPixels, nLines, (GDALDataType)typeCLASS, 0, 0 ); nXYSize = (i-1) * nPixels * nLines; switch( typeCLASS ) { case GDT_Byte: for (m = nLines-1, c = 0; m >= 0; m--) for (n = 0; n < nPixels; n++) outByte[m + n*nLines + nXYSize] = tmp[c++]; break; case GDT_UInt16: tmpUI16 = (GUInt16 *) tmp; for (m = nLines-1, c = 0; m >= 0; m--) for (n = 0; n < nPixels; n++) outUI16[m + n*nLines + nXYSize] = tmpUI16[c++]; break; case GDT_Int16: tmpI16 = (GInt16 *) tmp; for (m = nLines-1, c = 0; m >= 0; m--) for (n = 0; n < nPixels; n++) outI16[m + n*nLines + nXYSize] = tmpI16[c++]; break; case GDT_UInt32: tmpUI32 = (GUInt32 *) tmp; for (m = nLines-1, c = 0; m >= 0; m--) for (n = 0; n < nPixels; n++) outUI32[m + n*nLines + nXYSize] = tmpUI32[c++]; break; case GDT_Int32: tmpI32 = (GInt32 *) tmp; for (m = nLines-1, c = 0; m >= 0; m--) for (n = 0; n < nPixels; n++) outI32[m + n*nLines + nXYSize] = tmpI32[c++]; break; case GDT_Float32: tmpF32 = (float *) tmp; for (m = nLines-1, c = 0; m >= 0; m--) for (n = 0; n < nPixels; n++) outF32[m + n*nLines + nXYSize] = tmpF32[c++]; break; case GDT_Float64: tmpF64 = (double *) tmp; for (m = nLines-1, c = 0; m >= 0; m--) for (n = 0; n < nPixels; n++) outF64[m + n*nLines + nXYSize] = tmpF64[c++]; break; } } mxFree(tmp); if (nGCPCount) { GDALDeinitGCPs( nGCPCount, pasGCPs ); /* makes this mex crash in the next call - Is it still true??? */ mxFree((void *) pasGCPs ); } if (nlhs == 2) plhs[1] = populate_metadata_struct (hDstDS, 1); runed_once = TRUE; /* Signals that next call won't need to call GDALAllRegister() again */ /*GDALDestroyDriverManager(); OGRFree(pszDstWKT);*/ GDALClose( hDstDS ); CSLDestroy( papszWarpOptions ); if (pszDstWKT && strlen(pszDstWKT) > 1 ) OGRFree(pszDstWKT); if (pszSrcWKT && strlen(pszSrcWKT) > 1 ) OGRFree(pszSrcWKT); }