/**
  * This method is responsible for computing the resolutions in for the provided grid geometry in
  * the provided crs.
  *
  * <p>It is worth to note that the returned resolution array is of length of 2 and it always is
  * lon, lat for the moment.<br>
  * It might be worth to remove the axes reordering code when we are confident enough with the code
  * to handle the north-up crs.
  *
  * <p>TODO use orthodromic distance?
  *
  * @param envelope the GeneralEnvelope
  * @param dim
  * @param crs
  * @throws DataSourceException
  */
 protected static final double[] getResolution(
     GeneralEnvelope envelope, Rectangle2D dim, CoordinateReferenceSystem crs)
     throws DataSourceException {
   double[] requestedRes = null;
   try {
     if (dim != null && envelope != null && crs != null) {
       // do we need to transform the originalEnvelope?
       final CoordinateReferenceSystem envelopeCrs2D =
           CRS.getHorizontalCRS(envelope.getCoordinateReferenceSystem());
       if (envelopeCrs2D != null && !CRS.equalsIgnoreMetadata(crs, envelopeCrs2D)) {
         CoordinateOperationFactory operationFactory = CRS.getCoordinateOperationFactory(true);
         CoordinateOperation op = operationFactory.createOperation(envelopeCrs2D, crs);
         envelope = CRS.transform(op, envelope);
         envelope.setCoordinateReferenceSystem(crs);
       }
       requestedRes = new double[2];
       requestedRes[0] = envelope.getSpan(0) / dim.getWidth();
       requestedRes[1] = envelope.getSpan(1) / dim.getHeight();
     }
     return requestedRes;
   } catch (TransformException e) {
     throw new DataSourceException("Unable to get resolution", e);
   } catch (FactoryException e) {
     throw new DataSourceException("Unable to get resolution", e);
   }
 }
  /**
   * Transforms the referenced envelope to the specified coordinate reference system using the
   * specified amount of points.
   *
   * <p>This method can handle the case where the envelope contains the North or South pole, or when
   * it cross the &plusmn;180� longitude.
   *
   * @param targetCRS The target coordinate reference system.
   * @param lenient {@code true} if datum shift should be applied even if there is insuffisient
   *     information. Otherwise (if {@code false}), an exception is thrown in such case.
   * @param numPointsForTransformation The number of points to use for sampling the envelope.
   * @return The transformed envelope.
   * @throws FactoryException if the math transform can't be determined.
   * @throws TransformException if at least one coordinate can't be transformed.
   * @see CRS#transform(CoordinateOperation, org.opengis.geometry.Envelope)
   * @since 2.3
   */
  public ReferencedEnvelope transform(
      final CoordinateReferenceSystem targetCRS,
      final boolean lenient,
      final int numPointsForTransformation)
      throws TransformException, FactoryException {
    if (crs == null) {
      if (isEmpty()) {
        // We don't have a CRS yet because we are still empty, being empty is
        // something we can represent in the targetCRS
        return new ReferencedEnvelope(targetCRS);
      } else {
        // really this is a the code that created this ReferencedEnvelope
        throw new NullPointerException(
            "Unable to transform referenced envelope, crs has not yet been provided.");
      }
    }
    if (getDimension() != targetCRS.getCoordinateSystem().getDimension()) {
      if (lenient) {
        return JTS.transformTo3D(this, targetCRS, lenient, numPointsForTransformation);
      } else {
        throw new MismatchedDimensionException(
            Errors.format(
                ErrorKeys.MISMATCHED_DIMENSION_$3,
                crs.getName().getCode(),
                new Integer(getDimension()),
                new Integer(targetCRS.getCoordinateSystem().getDimension())));
      }
    }
    /*
     * Gets a first estimation using an algorithm capable to take singularity in account
     * (North pole, South pole, 180� longitude). We will expand this initial box later.
     */
    CoordinateOperationFactory coordinateOperationFactory =
        CRS.getCoordinateOperationFactory(lenient);

    final CoordinateOperation operation =
        coordinateOperationFactory.createOperation(crs, targetCRS);
    final GeneralEnvelope transformed = CRS.transform(operation, this);
    transformed.setCoordinateReferenceSystem(targetCRS);

    /*
     * Now expands the box using the usual utility methods.
     */
    final ReferencedEnvelope target = new ReferencedEnvelope(transformed);
    final MathTransform transform = operation.getMathTransform();
    JTS.transform(this, target, transform, numPointsForTransformation);

    return target;
  }