/**
   * Crops the image representing a full tile set to the required dimension and returns it, but
   * keeps minx and miny being zero.
   *
   * @param fullTilesRaster
   * @param tiledImageGridRange
   * @param cropTo
   * @return
   */
  private RenderedImage cropToRequiredDimension(
      final RenderedImage fullTilesRaster, final GridEnvelope cropTo) {
    GridEnvelope2D crop =
        new GridEnvelope2D(
            cropTo.getLow(0), cropTo.getLow(1), cropTo.getSpan(0), cropTo.getSpan(1));

    GridEnvelope2D origDim =
        new GridEnvelope2D(
            fullTilesRaster.getMinX(),
            fullTilesRaster.getMinY(),
            fullTilesRaster.getWidth(),
            fullTilesRaster.getHeight());
    if (!origDim.contains(crop)) {
      throw new IllegalArgumentException(
          "Original image (" + origDim + ") does not contain desired dimension (" + crop + ")");
    } else if (origDim.equals(crop)) {
      if (LOGGER.isLoggable(Level.FINER)) {
        LOGGER.finer(
            "No need to crop image, full tiled dimension and target one "
                + "do match: original: "
                + fullTilesRaster.getWidth()
                + "x"
                + fullTilesRaster.getHeight()
                + ", target: "
                + crop.getSpan(0)
                + "x"
                + crop.getSpan(1));
      }
      return fullTilesRaster;
    }

    ParameterBlock cropParams = new ParameterBlock();

    cropParams.addSource(fullTilesRaster); // Source
    // cropParams.add(Float.valueOf(cropTo.x - tiledImageGridRange.x)); // x origin for each
    // band
    // cropParams.add(Float.valueOf(cropTo.y - tiledImageGridRange.y)); // y origin for each
    // band
    cropParams.add(Float.valueOf(crop.getLow(0))); // x origin for each band
    cropParams.add(Float.valueOf(crop.getLow(1))); // y origin for each band
    cropParams.add(Float.valueOf(crop.getSpan(0))); // width for each band
    cropParams.add(Float.valueOf(crop.getSpan(1))); // height for each band

    final RenderingHints hints =
        new RenderingHints(JAI.KEY_OPERATION_BOUND, OpImage.OP_NETWORK_BOUND);
    RenderedImage image = JAI.create("Crop", cropParams, hints);

    // assert cropTo.x - tiledImageGridRange.x == image.getMinX();
    // assert cropTo.y - tiledImageGridRange.y == image.getMinY();
    assert crop.getLow(0) == image.getMinX();
    assert crop.getLow(1) == image.getMinY();
    assert crop.getSpan(0) == image.getWidth();
    assert crop.getSpan(1) == image.getHeight();

    // assert cropTo.x == image.getMinX();
    // assert cropTo.y == image.getMinY();
    // assert cropTo.width == image.getWidth();
    // assert cropTo.height == image.getHeight();
    return image;
  }
  public static JGrassRegion getJGrassRegionFromGridCoverage(GridCoverage2D gridCoverage2D)
      throws InvalidGridGeometryException, TransformException {
    Envelope2D env = gridCoverage2D.getEnvelope2D();
    GridEnvelope2D worldToGrid = gridCoverage2D.getGridGeometry().worldToGrid(env);

    double xRes = env.getWidth() / worldToGrid.getWidth();
    double yRes = env.getHeight() / worldToGrid.getHeight();

    JGrassRegion region =
        new JGrassRegion(env.getMinX(), env.getMaxX(), env.getMinY(), env.getMaxY(), xRes, yRes);

    return region;
  }