/**
   * <strong>Reprojecting</strong><br>
   * The new grid geometry can have a different coordinate reference system than the underlying grid
   * geometry. For example, a grid coverage can be reprojected from a geodetic coordinate reference
   * system to Universal Transverse Mercator CRS.
   *
   * @param coverage GridCoverage2D
   * @param sourceCRS CoordinateReferenceSystem
   * @param targetCRS CoordinateReferenceSystem
   * @return GridCoverage2D
   * @throws WcsException
   */
  public static GridCoverage2D reproject(
      GridCoverage2D coverage,
      final CoordinateReferenceSystem sourceCRS,
      final CoordinateReferenceSystem targetCRS,
      final Interpolation interpolation)
      throws WcsException {
    // ///////////////////////////////////////////////////////////////////
    //
    // REPROJECT
    //
    //
    // ///////////////////////////////////////////////////////////////////
    if (!CRS.equalsIgnoreMetadata(sourceCRS, targetCRS)) {
      /*
       * Operations.DEFAULT.resample( coverage, targetCRS, null,
       * Interpolation.getInstance(Interpolation.INTERP_NEAREST))
       */
      final ParameterValueGroup param = (ParameterValueGroup) resampleParams.clone();
      param.parameter("Source").setValue(coverage);
      param.parameter("CoordinateReferenceSystem").setValue(targetCRS);
      param.parameter("GridGeometry").setValue(null);
      param.parameter("InterpolationType").setValue(interpolation);

      coverage = (GridCoverage2D) resampleFactory.doOperation(param, hints);
    }

    return coverage;
  }
 /**
  * Constructs a conversion from a set of parameters. The properties given in argument follow the
  * same rules than for the {@link AbstractCoordinateOperation} constructor.
  *
  * @param properties Set of properties. Should contains at least {@code "name"}.
  * @param method The operation method.
  * @param parameters The parameter values.
  */
 public DefiningConversion(
     final Map<String, ?> properties,
     final OperationMethod method,
     final ParameterValueGroup parameters) {
   super(properties, null, null, null, method);
   ensureNonNull("parameters", parameters);
   this.parameters = parameters.clone();
 }
  /**
   * <strong>Cropping</strong><br>
   * The crop operation is responsible for selecting geographic subareas of the source coverage.
   *
   * @param coverage Coverage
   * @param sourceEnvelope GeneralEnvelope
   * @param sourceCRS CoordinateReferenceSystem
   * @param destinationEnvelopeInSourceCRS GeneralEnvelope
   * @return GridCoverage2D
   * @throws WcsException
   */
  public static GridCoverage2D crop(
      final Coverage coverage,
      final GeneralEnvelope sourceEnvelope,
      final CoordinateReferenceSystem sourceCRS,
      final GeneralEnvelope destinationEnvelopeInSourceCRS,
      final Boolean conserveEnvelope)
      throws WcsException {
    // ///////////////////////////////////////////////////////////////////
    //
    // CROP
    //
    //
    // ///////////////////////////////////////////////////////////////////
    final GridCoverage2D croppedGridCoverage;

    // intersect the envelopes
    final GeneralEnvelope intersectionEnvelope =
        new GeneralEnvelope(destinationEnvelopeInSourceCRS);
    intersectionEnvelope.setCoordinateReferenceSystem(sourceCRS);
    intersectionEnvelope.intersect((GeneralEnvelope) sourceEnvelope);

    // dow we have something to show?
    if (intersectionEnvelope.isEmpty()) {
      throw new WcsException("The Intersection is null. Check the requested BBOX!");
    }

    if (!intersectionEnvelope.equals((GeneralEnvelope) sourceEnvelope)) {
      // get the cropped grid geometry
      // final GridGeometry2D cropGridGeometry = getCroppedGridGeometry(
      // intersectionEnvelope, gridCoverage);

      /* Operations.DEFAULT.crop(coverage, intersectionEnvelope) */
      final ParameterValueGroup param = (ParameterValueGroup) cropParams.clone();
      param.parameter("Source").setValue(coverage);
      param.parameter("Envelope").setValue(intersectionEnvelope);
      // param.parameter("ConserveEnvelope").setValue(conserveEnvelope);

      croppedGridCoverage = (GridCoverage2D) cropFactory.doOperation(param, hints);
    } else {
      croppedGridCoverage = (GridCoverage2D) coverage;
    }

    // prefetch to be faster afterwards.
    // This step is important since at this stage we might be loading tiles
    // from disk
    croppedGridCoverage.prefetch(intersectionEnvelope.toRectangle2D());

    return croppedGridCoverage;
  }
  /**
   * <strong>Scaling</strong><br>
   * Let user to scale down to the EXACT needed resolution. This step does not prevent from having
   * loaded an overview of the original image based on the requested scale.
   *
   * @param coverage GridCoverage2D
   * @param newGridRange GridRange
   * @param sourceCoverage GridCoverage
   * @param sourceCRS CoordinateReferenceSystem
   * @param destinationEnvelopeInSourceCRS
   * @return GridCoverage2D
   */
  public static GridCoverage2D scale(
      final GridCoverage2D coverage,
      final GridEnvelope newGridRange,
      final GridCoverage sourceCoverage,
      final CoordinateReferenceSystem sourceCRS,
      final GeneralEnvelope destinationEnvelopeInSourceCRS) {
    // ///////////////////////////////////////////////////////////////////
    //
    // SCALE to the needed resolution
    // Let me now scale down to the EXACT needed resolution. This step does
    // not prevent from having loaded an overview of the original image
    // based on the requested scale.
    //
    // ///////////////////////////////////////////////////////////////////
    GridGeometry2D scaledGridGeometry =
        new GridGeometry2D(
            newGridRange,
            (destinationEnvelopeInSourceCRS != null)
                ? destinationEnvelopeInSourceCRS
                : sourceCoverage.getEnvelope());

    /*
     * Operations.DEFAULT.resample( coverage, sourceCRS, scaledGridGeometry,
     * Interpolation.getInstance(Interpolation.INTERP_NEAREST));
     */
    final ParameterValueGroup param = (ParameterValueGroup) resampleParams.clone();
    param.parameter("Source").setValue(coverage);
    param.parameter("CoordinateReferenceSystem").setValue(sourceCRS);
    param.parameter("GridGeometry").setValue(scaledGridGeometry);
    param
        .parameter("InterpolationType")
        .setValue(Interpolation.getInstance(Interpolation.INTERP_NEAREST));

    final GridCoverage2D scaledGridCoverage =
        (GridCoverage2D) resampleFactory.doOperation(param, hints);

    return scaledGridCoverage;
  }
 /** Returns the parameter values. */
 @Override
 public ParameterValueGroup getParameterValues() {
   return (parameters != null) ? parameters.clone() : super.getParameterValues();
 }