//// STEP 3: Computes the target image layout ////
//// STEP 4: Applies the JAI operation ("Affine", "Warp", etc) ////
//// ////
////////////////////////////////////////////////////////////////////////////////////////
final CoordinateOperationFactory factory =
ReferencingFactoryFinder.getCoordinateOperationFactory(hints);
final MathTransformFactory mtFactory;
if (factory instanceof AbstractCoordinateOperationFactory) {
mtFactory = ((AbstractCoordinateOperationFactory) factory).getMathTransformFactory();
} else {
mtFactory = ReferencingFactoryFinder.getMathTransformFactory(hints);
}
/*
* Computes the INVERSE of the math transform from [Source Grid] to [Target Grid].
* The transform will be computed using the following path:
*
* Target Grid --> Target CRS --> Source CRS --> Source Grid
* ^ ^ ^
* step 1 step 2 step 3
*
* If source and target CRS are equal, a shorter path is used. This special
* case is needed because 'sourceCRS' and 'targetCRS' may be null.
*
* Target Grid --> Common CRS --> Source Grid
* ^ ^
* step 1 step 3
*/
final MathTransform step1, step2, step3, allSteps, allSteps2D;
if (CRS.equalsIgnoreMetadata(sourceCRS, targetCRS)) {
/*
* Note: targetGG should not be null, otherwise 'existingCoverage(...)' should
* have already detected that this resample is not doing anything.
*/
if (!targetGG.isDefined(GridGeometry2D.GRID_TO_CRS_BITMASK)) {
step1 = sourceGG.getGridToCRS(CORNER); // Really sourceGG, not targetGG
step2 = IdentityTransform.create(step1.getTargetDimensions());
step3 = step1.inverse();
allSteps = IdentityTransform.create(step1.getSourceDimensions());
targetGG = new GridGeometry2D(targetGG.getGridRange(), step1, targetCRS);
} else {
step1 = targetGG.getGridToCRS(CORNER);
step2 = IdentityTransform.create(step1.getTargetDimensions());
step3 = sourceGG.getGridToCRS(CORNER).inverse();
allSteps = mtFactory.createConcatenatedTransform(step1, step3);
if (!targetGG.isDefined(GridGeometry2D.GRID_RANGE_BITMASK)) {
/*
* If the target grid range was not explicitly specified, a grid range will be
* automatically computed in such a way that it will maps to the same envelope
* (at least approximatively).
*/
Envelope gridRange;
gridRange = toEnvelope(sourceGG.getGridRange());
gridRange = CRS.transform(allSteps.inverse(), gridRange);
targetGG = new GridGeometry2D(new GeneralGridEnvelope(gridRange,PixelInCell.CELL_CORNER), targetGG.getGridToCRS(PixelInCell.CELL_CENTER), targetCRS);
}
}
} else {
if (sourceCRS == null) {
throw new CannotReprojectException(Errors.format(ErrorKeys.UNSPECIFIED_CRS));
}
final Envelope sourceEnvelope;
final GeneralEnvelope targetEnvelope;
final CoordinateOperation operation = factory.createOperation(sourceCRS, targetCRS);
final boolean force2D = (sourceCRS != compatibleSourceCRS);
step2 = factory.createOperation(targetCRS, compatibleSourceCRS).getMathTransform();
step3 = (force2D ? sourceGG.getGridToCRS2D(CORNER) : sourceGG.getGridToCRS(CORNER)).inverse();
sourceEnvelope = sourceCoverage.getEnvelope(); // Don't force this one to 2D.
targetEnvelope = CRS.transform(operation, sourceEnvelope);
targetEnvelope.setCoordinateReferenceSystem(targetCRS);
// 'targetCRS' may be different than the one set by CRS.transform(...).