public static double[] GetClippedGeoTransform(string gdalDataset, PixelLims subsetCoords) { if (!System.IO.File.Exists(gdalDataset)) { throw new ArgumentException("File does not exist!"); } Dataset ds = Gdal.Open(gdalDataset, Access.GA_ReadOnly); if (ds == null) { throw new ArgumentException("Can't open " + gdalDataset); } double[] inGT = new double[6]; ds.GetGeoTransform(inGT); var topLeftLongIn = inGT[0]; var topLeftLatIn = inGT[3]; var resX = inGT[1]; var resY = inGT[5]; if (inGT[2] != 0.0 || inGT[4] != 0) { throw new InvalidOperationException("Only datasets with zero skew parameters (i.e. those aligned north-south) are supported"); } var topLeftLongOut = topLeftLongIn + subsetCoords.WestPixelCoord * resX; var topLeftLatOut = topLeftLatIn + subsetCoords.NorthPixelCoord * resY; var clippedGT = new double[] { topLeftLongOut, resX, 0.0, topLeftLatOut, 0.0, resY }; return(clippedGT); }
public static bool WritePartTiff(string Filename, float[] Data, PixelLims WriteShape) { var ds = Gdal.Open(Filename, Access.GA_Update); var band = ds.GetRasterBand(1); var fileShapeX = ds.RasterXSize; var fileShapeY = ds.RasterYSize; var writeSizeX = WriteShape.EastPixelCoord - WriteShape.WestPixelCoord; var writeSizeY = WriteShape.SouthPixelCoord - WriteShape.NorthPixelCoord; if (WriteShape.SouthPixelCoord > fileShapeY || WriteShape.EastPixelCoord > fileShapeX || writeSizeX * writeSizeY != Data.Length) { return(false); } int dataBlockSizeX, dataBlockSizeY; band.GetBlockSize(out dataBlockSizeX, out dataBlockSizeY); if (dataBlockSizeX != writeSizeX || dataBlockSizeY != writeSizeY || WriteShape.WestPixelCoord % dataBlockSizeX != 0 || WriteShape.NorthPixelCoord % dataBlockSizeY != 0) { // only for testing, we will allow non-whole block writing eventually return(false); } band.WriteRaster( (int)WriteShape.WestPixelCoord, (int)WriteShape.NorthPixelCoord, (int)writeSizeX, (int)writeSizeY, Data, (int)writeSizeX, (int)writeSizeY, 0, 0); band.FlushCache(); ds.FlushCache(); return(true); }
public double[] GetSubsetGeoTransform(PixelLims TileCoords) { string firstFilename = m_FileDates.First().Value; var res = GDAL_Operations.GetClippedGeoTransform(firstFilename, TileCoords); return(res); }
private static Dataset CreateTiff(string Filename, double[] GeoTransform, string Projection, PixelLims shape, bool CreateCompressed, float?NDV, int?BlockSize) { var creationOpts = new List <string>(); if (CreateCompressed) { creationOpts = new List <string>() { "COMPRESS=DEFLATE", "ZLEVEL=9", "TILED=YES", "SPARSE_OK=FALSE", "BIGTIFF=YES", "NUM_THREADS=ALL_CPUS" }; } if (BlockSize.HasValue) { creationOpts.Add("BLOCKXSIZE=" + BlockSize.Value.ToString()); creationOpts.Add("BLOCKYSIZE=" + BlockSize.Value.ToString()); } var drv = Gdal.GetDriverByName("GTiff"); var shapeX = shape.EastPixelCoord - shape.WestPixelCoord; var shapeY = shape.SouthPixelCoord - shape.NorthPixelCoord; var ds = drv.Create(Filename, (int)shapeX, (int)shapeY, 1, DataType.GDT_Float32, creationOpts.ToArray()); ds.SetGeoTransform(GeoTransform); ds.SetProjection(Projection); var band = ds.GetRasterBand(1); if (NDV.HasValue) { band.SetNoDataValue(NDV.Value); } return(ds); }
public static bool WriteWholeTiff(string Filename, float[] Data, double[] GeoTransform, string Projection, PixelLims shape, bool CreateCompressed, float?NDV) { // we will create a tiff with tiles (blocks) but let the size of them be specified automatically var ds = CreateTiff(Filename, GeoTransform, Projection, shape, CreateCompressed, NDV, null); var creationOpts = new string[0]; if (CreateCompressed) { creationOpts = new string[] { "COMPRESS=DEFLATE", "ZLEVEL=9", "TILED=YES", "SPARSE_OK=FALSE", "BIGTIFF=YES" }; } var drv = Gdal.GetDriverByName("GTiff"); var shapeX = shape.EastPixelCoord - shape.WestPixelCoord; var shapeY = shape.SouthPixelCoord - shape.NorthPixelCoord; if (shapeX * shapeY != Data.Length) { return(false); } var band = ds.GetRasterBand(1); band.WriteRaster(0, 0, (int)shapeX, (int)shapeY, Data, (int)shapeX, (int)shapeY, 0, 0); band.FlushCache(); ds.FlushCache(); return(true); }
/// <summary> /// Runs TS model for all cells of all tiles required to cover the given bounding box at the given tile size. /// Any tile wholly in the sea will be skipped (no output files generated) /// </summary> /// <param name="WestDegrees"></param> /// <param name="EastDegrees"></param> /// <param name="NorthDegrees"></param> /// <param name="SouthDegrees"></param> /// <param name="TileSize"></param> public void RunAllTiles() { var globalGT = _maxReader.GeoTransform; var lims = _cfg.spatialLimits; var pxOverall = GDAL_Operations.CalculatePixelCoordsOfBlock(globalGT, lims.WestLimitDegrees, lims.EastLimitDegrees, lims.NorthLimitDegrees, lims.SouthLimitDegrees ); var TileSize = _cfg.modelRunConfig.MaxTileSizePx; var latsToRun = _maxReader.GetSubsetLatitudeCoords((int)pxOverall.NorthPixelCoord, (int)(pxOverall.SouthPixelCoord - pxOverall.NorthPixelCoord)); var lonsToRun = _maxReader.GetSubsetLongitudeCoords((int)pxOverall.WestPixelCoord, (int)(pxOverall.EastPixelCoord - pxOverall.WestPixelCoord)); var nTilesX = (int)Math.Ceiling((double)lonsToRun.Length / TileSize); var nTilesY = (int)Math.Ceiling((double)latsToRun.Length / TileSize); var nTilesTotal = nTilesX * nTilesY; string tileDir = lims.WestLimitDegrees.ToString() + "W-" + lims.EastLimitDegrees.ToString() + "E-" + lims.NorthLimitDegrees.ToString() + "N-" + lims.SouthLimitDegrees.ToString() + "S-" + TileSize.ToString() + "px_tiles"; Console.WriteLine("Initiating run of " + nTilesTotal.ToString() + " tiles"); var runDir = nTilesTotal == 1 ? _cfg.dataPathConfig.OutputFolder : System.IO.Path.Combine(_cfg.dataPathConfig.OutputFolder, tileDir); System.IO.Directory.CreateDirectory(runDir); for (int tileRow = 0; tileRow < nTilesY; tileRow++) { int yOff = (int)pxOverall.NorthPixelCoord + tileRow * TileSize; int yEnd = yOff + TileSize; int thisTileYSize = TileSize; if (yEnd > pxOverall.SouthPixelCoord) { thisTileYSize = (int)pxOverall.SouthPixelCoord - yOff; } for (int tileCol = 0; tileCol < nTilesX; tileCol++) { var tileNum = tileRow * nTilesX + tileCol + 1; string tilenameLocPart; if (nTilesTotal > 1) { tilenameLocPart = ".r" + tileRow.ToString("D3") + "_c" + tileCol.ToString("D3") + ".tif"; } else { tilenameLocPart = ".tif"; } if (System.IO.Directory.EnumerateFiles(runDir, "*" + tilenameLocPart).Count() != 0) { System.Console.WriteLine("Tile " + tileNum.ToString() + " appears to be already done, skipping"); continue; } int xOff = (int)pxOverall.WestPixelCoord + tileCol * TileSize; int xEnd = xOff + TileSize; int thisTileXSize = TileSize; if (xEnd > pxOverall.EastPixelCoord) { thisTileXSize = (int)pxOverall.EastPixelCoord - xOff; } var tileCoords = new PixelLims(xOff, xOff + thisTileXSize, yOff, yOff + thisTileYSize); var cellRes = RunTile(xOff, yOff, thisTileXSize, thisTileYSize); if (cellRes.Length == 0) { // whole tile was in masked / sea area. Do not bother to write output. Console.WriteLine("Tile " + tileNum.ToString() + " was wholly in sea - skipped"); continue; } Console.WriteLine("Tile computation completed, writing output"); var tileRes = TransposeCellData( cellRes, thisTileXSize, thisTileYSize); var tileGT = _maxReader.GetSubsetGeoTransform(tileCoords); var tileProj = _maxReader.Projection; // write each tile to a separate tiff file - we can mosaic them later. var tileLims = new PixelLims(0, thisTileXSize, 0, thisTileYSize); for (int t = 0; t < tileRes.Length; t++) { var tData = tileRes[t]; string fn = _cfg.modelRunConfig.OutputFileTag + "." + _outputDates[t].Date.ToString("yyyy.MM") + tilenameLocPart; string outFile = System.IO.Path.Combine(runDir, fn); GDAL_Operations.WriteWholeTiff(outFile, tData, tileGT, tileProj, tileLims, true, _maxReader.NoDataValue); } Console.WriteLine("Tile " + tileNum.ToString() + " finished - wrote " + tileRes.Length.ToString() + " files"); } } }