final Rectangle finalRasterArea = finalRasterAreaDouble.getBounds();
// intersection with the original range in order to not try to crop outside the image bounds
Rectangle.intersect(finalRasterArea, sourceGridRange, finalRasterArea);
if(finalRasterArea.isEmpty())
throw new CannotCropException(Errors.format(ErrorKeys.CANT_CROP));
// //
//
// It is worth to point out that doing a crop the G2W transform
// should not change while the envelope might change as
// a consequence of the rounding of the underlying image datum
// which uses integer factors or in case the G2W is very
// complex. Note that we will always strive to
// conserve the original grid-to-world transform.
//
// //
// we do not have to crop in this case (should not really happen at
// this time)
if (finalRasterArea.equals(sourceGridRange) && isSimpleTransform && cropROI==null)
return sourceCoverage;
// //
//
// if I get here I have something to crop
// using the world-to-grid transform for going from envelope to the
// new grid range.
//
// //
final double minX = finalRasterArea.getMinX();
final double minY = finalRasterArea.getMinY();
final double width = finalRasterArea.getWidth();
final double height =finalRasterArea.getHeight();
// //
//
// Check if we need to use mosaic or crop
//
// //
final PlanarImage croppedImage;
final ParameterBlock pbj = new ParameterBlock();
pbj.addSource(sourceImage);
java.awt.Polygon rasterSpaceROI=null;
String operatioName=null;
if (!isSimpleTransform || cropROI!=null) {
// /////////////////////////////////////////////////////////////////////
//
// We don't have a simple scale and translate transform, JAI
// crop MAY NOT suffice. Let's decide whether or not we'll use
// the Mosaic.
//
// /////////////////////////////////////////////////////////////////////
Polygon modelSpaceROI = FeatureUtilities.getPolygon(cropEnvelope, GFACTORY);
// //
//
// Now convert this polygon back into a shape for the source
// raster space.
//
// //
final List<Point2D> points = new ArrayList<Point2D>(5);
rasterSpaceROI = FeatureUtilities.convertPolygonToPointArray(modelSpaceROI, ProjectiveTransform.create(sourceWorldToGridTransform), points);
if(rasterSpaceROI==null||rasterSpaceROI.getBounds().isEmpty())
if(finalRasterArea.isEmpty())
throw new CannotCropException(Errors.format(ErrorKeys.CANT_CROP));
final boolean doMosaic = forceMosaic ? true : decideJAIOperation(roiTolerance, rasterSpaceROI.getBounds2D(), points);
if (doMosaic || cropROI != null) {
// prepare the params for the mosaic
final ROI[] roiarr;
try {
if(cropROI != null) {
final Shape cropRoiLS2 = new LiteShape2(cropROI, ProjectiveTransform.create(sourceWorldToGridTransform), null, false);
final ROIShape cropRS = new ROIShape(cropRoiLS2);
roiarr = new ROI[]{cropRS};
} else {
final ROIShape roi = new ROIShape(rasterSpaceROI);
roiarr = new ROI[]{roi};
}
} catch (FactoryException ex) {
throw new CannotCropException(Errors.format(ErrorKeys.CANT_CROP), ex);
}
pbj.add(MosaicDescriptor.MOSAIC_TYPE_OVERLAY);
pbj.add(null);
pbj.add(roiarr);
pbj.add(null);
pbj.add(CoverageUtilities.getBackgroundValues(sourceCoverage));
//prepare the final layout
final Rectangle bounds = rasterSpaceROI.getBounds2D().getBounds();
Rectangle.intersect(bounds, sourceGridRange, bounds);
if(bounds.isEmpty())
throw new CannotCropException(Errors.format(ErrorKeys.CANT_CROP));
// we do not have to crop in this case (should not really happen at
// this time)
if (!doMosaic && bounds.getBounds().equals(sourceGridRange) && isSimpleTransform)
return sourceCoverage;
// nice trick, we use the layout to do the actual crop
final Rectangle boundsInt=bounds.getBounds();
layout.setMinX(boundsInt.x);
layout.setWidth(boundsInt.width );
layout.setMinY(boundsInt.y);
layout.setHeight( boundsInt.height);
operatioName = "Mosaic";
}
}
//do we still have to set the operation name? If so that means we have to go for crop.
if(operatioName==null) {
// executing the crop
pbj.add((float) minX);
pbj.add((float) minY);
pbj.add((float) width);
pbj.add((float) height);
operatioName = "GTCrop";
}
// //
//
// Apply operation
//
// //
if (!useProvidedProcessor) {
croppedImage = JAI.create(operatioName, pbj, targetHints);
} else {
croppedImage = processor.createNS(operatioName, pbj, targetHints);
}
//conserve the input grid to world transformation
Map sourceProperties = sourceCoverage.getProperties();
Map properties = null;
if (sourceProperties != null && !sourceProperties.isEmpty()) {
properties = new HashMap(sourceProperties);
}
if (rasterSpaceROI != null) {
if (properties != null) {
properties.put("GC_ROI", rasterSpaceROI);
} else {
properties = Collections.singletonMap("GC_ROI", rasterSpaceROI);
}
}
return new GridCoverageFactory(hints).create(
sourceCoverage.getName(),
croppedImage,
new GridGeometry2D(
new GridEnvelope2D(croppedImage.getBounds()),
sourceGridGeometry.getGridToCRS2D(PixelOrientation.CENTER),
sourceCoverage.getCoordinateReferenceSystem()
),
(GridSampleDimension[]) (actionTaken == 1 ?null :sourceCoverage.getSampleDimensions().clone()),
new GridCoverage[] { sourceCoverage }, properties);
} catch (TransformException e) {
throw new CannotCropException(Errors.format(ErrorKeys.CANT_CROP), e);
} catch (NoninvertibleTransformException e) {
throw new CannotCropException(Errors.format(ErrorKeys.CANT_CROP), e);
}
}