public static GridCoverage2D resample()

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;
  }