Transposer { public VortexGrid transpose(){ if (angle == 0 && (stormCenterX == null || stormCenterX.isNaN()) && (stormCenterY == null || stormCenterY.isNaN())){ return grid; } VortexGrid sanatized; String desc = grid.description().toLowerCase(); if (desc.contains("precipitation") || desc.contains("precip") || desc.contains("precip") && desc.contains("rate") || desc.contains("qpe01h") || ((desc.contains("short") && desc.contains("wave") || desc.contains("solar")) && desc.contains("radiation")) || ((desc.contains("snow")) && (desc.contains("water")) && (desc.contains("equivalent"))) || desc.contains("albedo")) { sanatized = Sanitizer.builder() .inputGrid(grid) .minimumThreshold(0) .minimumReplacementValue(Float.NaN) .build() .sanitize(); } else { sanatized = grid; } Dataset datasetIn = RasterUtils.getDatasetFromVortexGrid(sanatized); if (debug) { ArrayList<String> options = new ArrayList<>(); options.add("-of"); options.add("Gtiff"); TranslateOptions translateOptions1 = new TranslateOptions(new Vector<>(options)); Path pathToPreTransposed = Paths.get(tempDir.toString(), "pre-transpose.tif"); Dataset out = gdal.Translate(pathToPreTransposed.toString(), datasetIn, translateOptions1); out.FlushCache(); out.delete(); } double[] geoTransform = datasetIn.GetGeoTransform(); double dx = geoTransform[1]; double dy = geoTransform[5]; double originX = geoTransform[0]; double originY = geoTransform[3]; int nx = datasetIn.GetRasterXSize(); int ny = datasetIn.GetRasterYSize(); double terminusX = originX + dx * nx; double terminusY = originY + dy * ny; double width = Math.abs(terminusX - originX); double height = Math.abs(terminusY - originY); double centerX = originX + Math.signum(dx) * 0.5 * width; double centerY = originY + Math.signum(dy) * 0.5 * height; double x1 = originX - centerX; double y1 = originY - centerY; Band band = datasetIn.GetRasterBand(1); float[] data = new float[nx * ny]; band.ReadRaster(0, 0, nx, ny, GDT_Float32, data); band.delete(); double angleRad = Math.toRadians(angle); double adjustedCenterX; if (stormCenterX != null && !Double.isNaN(stormCenterX)){ adjustedCenterX = stormCenterX; } else { adjustedCenterX = centerX; } double adjustedCenterY; if (stormCenterY != null && !Double.isNaN(stormCenterY)){ adjustedCenterY = stormCenterY; } else { adjustedCenterY = centerY; } double[] transposedGeoTransform = new double[]{ adjustedCenterX + Math.signum(dx) * (x1 * Math.cos(angleRad) + y1 * Math.sin(angleRad)), Math.cos(angleRad) * dx, -Math.sin(angleRad) * dx, adjustedCenterY + Math.signum(dy) * (x1 * Math.sin(angleRad) - y1 * Math.cos(angleRad)), Math.sin(angleRad) * dy, Math.cos(angleRad) * dy }; Dataset transposed = gdal.GetDriverByName("MEM").Create("", nx, ny, 1, GDT_Float32); transposed.SetGeoTransform(transposedGeoTransform); transposed.SetProjection(datasetIn.GetProjection()); Band transposedBand = transposed.GetRasterBand(1); transposedBand.WriteRaster(0, 0, nx, ny, data); transposedBand.FlushCache(); transposed.FlushCache(); datasetIn.delete(); if (debug) { ArrayList<String> options = new ArrayList<>(); options.add("-of"); options.add("Gtiff"); TranslateOptions translateOptions = new TranslateOptions(new Vector<>(options)); Path pathToTransposed = Paths.get(tempDir.toString(), "transposed.tif"); Dataset out = gdal.Translate(pathToTransposed.toString(), transposed, translateOptions); out.FlushCache(); translateOptions.delete(); out.delete(); } ArrayList<String> options = new ArrayList<>(); options.add("-of"); options.add("MEM"); options.add("-r"); options.add("bilinear"); WarpOptions warpOptions = new WarpOptions(new Vector<>(options)); Dataset[] datasets = new Dataset[]{transposed}; Dataset transposedWarped = gdal.Warp( "", datasets, warpOptions ); transposedWarped.FlushCache(); warpOptions.delete(); transposed.delete(); double[] transposedWarpedGeoTransform = transposedWarped.GetGeoTransform(); double transposedDx = transposedWarpedGeoTransform[1]; double transposedDy = transposedWarpedGeoTransform[5]; double transposedOriginX = transposedWarpedGeoTransform[0]; double transposedOriginY = transposedWarpedGeoTransform[3]; int transposedNx = transposedWarped.GetRasterXSize(); int transposedNy = transposedWarped.GetRasterYSize(); double transposedTerminusX = transposedOriginX + transposedDx * transposedNx; double transposedTerminusY = transposedOriginY + transposedDy * transposedNy; double cellSize = grid.dx(); double maxX = Math.ceil(Math.max(transposedOriginX, transposedTerminusX) / cellSize) * cellSize; double minX = Math.floor(Math.min(transposedOriginX, transposedTerminusX) / cellSize) * cellSize; double maxY = Math.ceil(Math.max(transposedOriginY, transposedTerminusY) / cellSize) * cellSize; double minY = Math.floor(Math.min(transposedOriginY, transposedTerminusY) / cellSize) * cellSize; options.clear(); options.add("-of"); options.add("MEM"); options.add("-te"); options.add(Double.toString(minX)); options.add(Double.toString(minY)); options.add(Double.toString(maxX)); options.add(Double.toString(maxY)); options.add("-tr"); options.add(Double.toString(cellSize)); options.add(Double.toString(cellSize)); options.add("-r"); options.add("bilinear"); Dataset transposedResampled = gdal.Warp( "", new Dataset[]{transposedWarped}, new WarpOptions(new Vector<>(options)) ); transposedResampled.FlushCache(); transposedWarped.delete(); double[] resampledGeoTransform = transposedResampled.GetGeoTransform(); double resampledDx = resampledGeoTransform[1]; double resampledDy = resampledGeoTransform[5]; double resampledOriginX = resampledGeoTransform[0]; double resampledOriginY = resampledGeoTransform[3]; int resampledNx = transposedResampled.GetRasterXSize(); int resampledNy = transposedResampled.GetRasterYSize(); Band resampledBand = transposedResampled.GetRasterBand(1); float[] resampledData = new float[resampledNx * resampledNy]; resampledBand.ReadRaster(0, 0, resampledNx, resampledNy, resampledData); transposedResampled.delete(); resampledBand.delete(); VortexGrid resampledGrid = VortexGrid.builder() .dx(resampledDx).dy(resampledDy) .nx(resampledNx).ny(resampledNy) .originX(resampledOriginX).originY(resampledOriginY) .wkt(grid.wkt()).data(resampledData).units(grid.units()) .fileName(grid.fileName()).shortName(grid.shortName()) .fullName(grid.shortName()).description(grid.description()) .startTime(grid.startTime()).endTime(grid.endTime()).interval(grid.interval()) .build(); if (debug) { Dataset transposedResampledGrid = RasterUtils.getDatasetFromVortexGrid(resampledGrid); options.clear(); options.add("-of"); options.add("Gtiff"); TranslateOptions translateOptions = new TranslateOptions(new Vector<>(options)); Path pathToTransposedResampled = Paths.get(tempDir.toString(), "transposed-resampled.tif"); Dataset out = gdal.Translate(pathToTransposedResampled.toString(), transposedResampledGrid, translateOptions); out.FlushCache(); out.delete(); } return resampledGrid; } private  Transposer(TransposerBuilder builder); static TransposerBuilder builder(); VortexGrid transpose();  }
@Test void testTranspose(){ String inFile = new File(getClass().getResource( "/normalizer/qpe.dss").getFile()).toString(); String variableName = " DataReader reader = DataReader.builder() .path(inFile) .variable(variableName) .build(); List<VortexGrid> grids = reader.getDtos().stream().map(grid -> (VortexGrid)grid).collect(Collectors.toList()); VortexGrid grid = grids.get(0); Transposer transposer = Transposer.builder() .grid(grid) .angle(30) .build(); transposer.transpose(); }