in common/src/main/java/org/apache/sedona/common/raster/RasterEditors.java [180:338]
public static GridCoverage2D resample(
GridCoverage2D raster,
double widthOrScale,
double heightOrScale,
double gridX,
double gridY,
boolean useScale,
String algorithm)
throws TransformException {
/*
* Old Parameters
*/
AffineTransform2D affine = RasterUtils.getGDALAffineTransform(raster);
int originalWidth = RasterAccessors.getWidth(raster),
originalHeight = RasterAccessors.getHeight(raster);
double upperLeftX = affine.getTranslateX(), upperLeftY = affine.getTranslateY();
double originalSkewX = affine.getShearX(), originalSkewY = affine.getShearY();
double originalScaleX = affine.getScaleX(), originalScaleY = affine.getScaleY();
CoordinateReferenceSystem crs = raster.getCoordinateReferenceSystem2D();
/*
* New Parameters
*/
int newWidth = useScale ? originalWidth : (int) Math.floor(widthOrScale);
int newHeight = useScale ? originalHeight : (int) Math.floor(heightOrScale);
double newScaleX = useScale ? widthOrScale : originalScaleX;
double newScaleY = useScale ? heightOrScale : originalScaleY;
double newUpperLeftX = upperLeftX, newUpperLeftY = upperLeftY;
if (noConfigChange(
originalWidth,
originalHeight,
upperLeftX,
upperLeftY,
originalScaleX,
originalScaleY,
newWidth,
newHeight,
gridX,
gridY,
newScaleX,
newScaleY,
useScale)) {
// no reconfiguration parameters provided
return raster;
}
Envelope2D envelope2D = raster.getEnvelope2D();
// process scale changes due to changes in widthOrScale and heightOrScale
if (!useScale) {
newScaleX = (Math.abs(envelope2D.getMaxX() - envelope2D.getMinX())) / newWidth;
newScaleY =
Math.signum(originalScaleY)
* Math.abs(envelope2D.getMaxY() - envelope2D.getMinY())
/ newHeight;
} else {
// height and width cannot have floating point, ceil them to next greatest integer in that
// case.
newWidth =
(int)
Math.ceil(
Math.abs(envelope2D.getMaxX() - envelope2D.getMinX()) / Math.abs(newScaleX));
newHeight =
(int)
Math.ceil(
Math.abs(envelope2D.getMaxY() - envelope2D.getMinY()) / Math.abs(newScaleY));
}
if (!approximateEquals(upperLeftX, gridX) || !approximateEquals(upperLeftY, gridY)) {
// change upperLefts to gridX/Y to check if any warping is needed
GridCoverage2D tempRaster =
setGeoReference(raster, gridX, gridY, newScaleX, newScaleY, originalSkewX, originalSkewY);
// check expected grid coordinates for old upperLefts
int[] expectedCellCoordinates =
RasterUtils.getGridCoordinatesFromWorld(tempRaster, upperLeftX, upperLeftY);
// get expected world coordinates at the expected grid coordinates
Point2D expectedGeoPoint =
RasterUtils.getWorldCornerCoordinates(
tempRaster, expectedCellCoordinates[0] + 1, expectedCellCoordinates[1] + 1);
// check for shift
if (!approximateEquals(expectedGeoPoint.getX(), upperLeftX)) {
if (!useScale) {
newScaleX = Math.abs(envelope2D.getMaxX() - expectedGeoPoint.getX()) / newWidth;
} else {
// width cannot have floating point, ceil it to next greatest integer in that case.
newWidth =
(int)
Math.ceil(
Math.abs(envelope2D.getMaxX() - expectedGeoPoint.getX())
/ Math.abs(newScaleX));
}
newUpperLeftX = expectedGeoPoint.getX();
}
if (!approximateEquals(expectedGeoPoint.getY(), upperLeftY)) {
if (!useScale) {
newScaleY =
Math.signum(newScaleY)
* Math.abs(envelope2D.getMinY() - expectedGeoPoint.getY())
/ newHeight;
} else {
// height cannot have floating point, ceil it to next greatest integer in that case.
newHeight =
(int)
Math.ceil(
Math.abs(envelope2D.getMinY() - expectedGeoPoint.getY())
/ Math.abs(newScaleY));
}
newUpperLeftY = expectedGeoPoint.getY();
}
}
MathTransform transform =
new AffineTransform2D(
newScaleX, originalSkewY, originalSkewX, newScaleY, newUpperLeftX, newUpperLeftY);
GridGeometry2D gridGeometry =
new GridGeometry2D(
new GridEnvelope2D(0, 0, newWidth, newHeight),
PixelInCell.CELL_CORNER,
transform,
crs,
null);
Interpolation resamplingAlgorithm = createInterpolationAlgorithm(algorithm);
GridCoverage2D newRaster;
GridCoverage2D noDataValueMask;
GridCoverage2D resampledNoDataValueMask;
if ((!Objects.isNull(algorithm) && !algorithm.isEmpty())
&& (algorithm.equalsIgnoreCase("Bilinear") || algorithm.equalsIgnoreCase("Bicubic"))) {
// Create and resample noDataValue mask
noDataValueMask = RasterUtils.extractNoDataValueMask(raster);
resampledNoDataValueMask =
resample(
noDataValueMask,
widthOrScale,
heightOrScale,
gridX,
-gridY,
useScale,
"NearestNeighbor");
// Replace noDataValues with mean of neighbors and resample
raster = RasterUtils.replaceNoDataValues(raster);
newRaster =
(GridCoverage2D)
Operations.DEFAULT.resample(raster, null, gridGeometry, resamplingAlgorithm);
// Apply resampled noDataValue mask to resampled raster
newRaster = RasterUtils.applyRasterMask(newRaster, resampledNoDataValueMask);
} else {
newRaster =
(GridCoverage2D)
Operations.DEFAULT.resample(raster, null, gridGeometry, resamplingAlgorithm);
}
return newRaster;
}