Skip to content

Commit

Permalink
[GEOS-8105] WCS 2.0 GetCoverage ignores service level overview policy…
Browse files Browse the repository at this point in the history
… and disallow reader subsampling
  • Loading branch information
aaime committed Apr 21, 2017
1 parent 6c96bbe commit 8a84e72
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 44 deletions.
52 changes: 36 additions & 16 deletions src/wcs2_0/src/main/java/org/geoserver/wcs2_0/GetCoverage.java
Expand Up @@ -898,7 +898,7 @@ private GridCoverage2D readCoverage(CoverageInfo cinfo, GridCoverageRequest requ
// let's create a subsetting GG2D (Taking overviews and requested scaling into account)
MathTransform transform = getMathTransform(reader,
requestedEnvelope != null ? requestedEnvelope : subset, request,
PixelInCell.CELL_CENTER, scaling, preAppliedScale);
PixelInCell.CELL_CENTER, scaling);
readGG = new GridGeometry2D(
PixelInCell.CELL_CENTER,
transform,
Expand Down Expand Up @@ -932,37 +932,62 @@ private GridCoverage2D readCoverage(CoverageInfo cinfo, GridCoverageRequest requ
// === read
// check limits
WCSUtils.checkInputLimits(wcs,cinfo,reader,readGG);
Hints readHints = new Hints();
readHints.putAll(hints);
if(request.getOverviewPolicy() != null) {
hints.add(new Hints(Hints.OVERVIEW_POLICY, request.getOverviewPolicy()));
}
coverage= RequestUtils.readBestCoverage(
reader,
readParameters,
readGG,
spatialInterpolation,
request.getOverviewPolicy(),
hints);
// check limits again
readHints);
if (coverage != null) {
// check limits again
if (incrementalInputSize == null) {
WCSUtils.checkInputLimits(wcs, coverage);
} else {
// Check for each coverage added if the total coverage dimension exceeds the maximum limit
// If the size is exceeded an exception is thrown
incrementalInputSize.addSize(coverage);
}

// see what scaling factors the reader actually applied
if(scaling != null) {
MathTransform cmt = coverage.getGridGeometry().getGridToCRS();
MathTransform rmt = reader.getOriginalGridToWorld(PixelInCell.CELL_CENTER);
if (!(cmt instanceof AffineTransform2D) || !(rmt instanceof AffineTransform2D)) {
LOGGER.log(Level.FINE, "Cannot check if the returned coverage "
+ "matched the requested resolution due to a non affine "
+ "grid to world backing it");
} else {
AffineTransform2D cat = (AffineTransform2D) cmt;
AffineTransform2D rat = (AffineTransform2D) rmt;
preAppliedScale[0] = cat.getScaleX() / rat.getScaleX();
preAppliedScale[1] = cat.getScaleY() / rat.getScaleY();
}
}

}

// return
return coverage;
}

private MathTransform getMathTransform(GridCoverage2DReader reader, Envelope subset,
GridCoverageRequest request, PixelInCell pixelInCell, ScalingType scaling, double[] preAppliedScale) throws IOException {
final OverviewPolicy overviewPolicy = request.getOverviewPolicy();
MathTransform getMathTransform(GridCoverage2DReader reader, Envelope subset,
GridCoverageRequest request, PixelInCell pixelInCell, ScalingType scaling) throws IOException {
// return the original grid to world only if there is no scaling, the overview policy
// is going to be taken care of when sending data to the image reader (failing to do
// so will cause OOM or get the processing thread blocked for a long time because
// the reader is no more allowed to use subsampling)
ScalingPolicy scalingPolicy = scaling == null ? null : ScalingPolicy.getPolicy(scaling);
if (overviewPolicy == null || overviewPolicy == OverviewPolicy.IGNORE || scaling == null ||
scalingPolicy == null || scalingPolicy == ScalingPolicy.ScaleToExtent) {
if (scalingPolicy == null || scalingPolicy == ScalingPolicy.DoNothing) {
return reader.getOriginalGridToWorld(pixelInCell);
}

// here we are already assuming to work off an affine transform
MathTransform transform = reader.getOriginalGridToWorld(pixelInCell);
AffineTransform af = (AffineTransform) transform;

Expand All @@ -973,14 +998,9 @@ private MathTransform getMathTransform(GridCoverage2DReader reader, Envelope sub
// Getting the requested resolution, taking the requested scaling into account
final double[] requestedResolution = computeRequestedResolution(scaling, subset, nativeResX, nativeResY);

// Getting the read resolution from the reader, based on the Overview Policy
final double[] readResolution = reader.getReadingResolutions(overviewPolicy, requestedResolution);

// setup a scaling to get the transformation to be used to access the specified overview
// setup a scaling to get the desired resolution while allowing the reader to apply subsampling
AffineTransform scale = new AffineTransform();
preAppliedScale[0] = readResolution[0] / nativeResX;
preAppliedScale[1] = readResolution[1] / nativeResY;
scale.scale(preAppliedScale[0], preAppliedScale[1]);
scale.scale(requestedResolution[0] / nativeResX, requestedResolution[1] / nativeResY);
AffineTransform finalTransform = new AffineTransform(af);
finalTransform.concatenate(scale);
return ProjectiveTransform.create(finalTransform);
Expand All @@ -998,7 +1018,7 @@ private double[] computeRequestedResolution(ScalingType scaling, Envelope subset
double nativeResX, double nativeResY) {
ScalingPolicy policy = ScalingPolicy.getPolicy(scaling);
double[] requestedResolution = new double[2];
if (policy == ScalingPolicy.ScaleToSize) {
if (policy == ScalingPolicy.ScaleToSize || policy == ScalingPolicy.ScaleToExtent) {
int[] scalingSize = ScalingPolicy.getTargetSize(scaling);

// Getting the requested resolution (using envelope and requested scaleSize)
Expand Down
84 changes: 56 additions & 28 deletions src/wcs2_0/src/main/java/org/geoserver/wcs2_0/ScalingPolicy.java
Expand Up @@ -472,37 +472,65 @@ public static ScalingPolicy getPolicy(ScalingType scaling) {
*
*/
public static int[] getTargetSize(ScalingType scaling) {
final ScaleToSizeType scaleType = scaling.getScaleToSize();
if (scaleType == null) {
if(scaling.getScaleToSize() != null) {
final ScaleToSizeType scaleType = scaling.getScaleToSize();
final EList<TargetAxisSizeType> targetAxisSizeElements = scaleType.getTargetAxisSize();

TargetAxisSizeType xSize = null, ySize = null;
for (TargetAxisSizeType axisSizeType : targetAxisSizeElements) {
final String axisName = axisSizeType.getAxis();
if (axisName.equals("http://www.opengis.net/def/axis/OGC/1/i") || axisName.equals("i")) {
xSize = axisSizeType;
} else if (axisName.equals("http://www.opengis.net/def/axis/OGC/1/j") || axisName.equals("j")) {
ySize = axisSizeType;
} else {
// TODO remove when supporting TIME and ELEVATION
throw new WCS20Exception("Scale Axis Undefined",
WCS20Exception.WCS20ExceptionCode.ScaleAxisUndefined, axisName);
}
}
final int sizeX = (int) xSize.getTargetSize();// TODO should this be int?
if (sizeX <= 0) {
throw new WCS20Exception("Invalid target size",
WCS20Exception.WCS20ExceptionCode.InvalidExtent, Integer.toString(sizeX));
}
final int sizeY = (int) ySize.getTargetSize();// TODO should this be int?
if (sizeY <= 0) {
throw new WCS20Exception("Invalid target size",
WCS20Exception.WCS20ExceptionCode.InvalidExtent, Integer.toString(sizeY));
}
return new int[] { sizeX, sizeY };
} else if(scaling.getScaleToExtent() != null) {
ScaleToExtentType ste = scaling.getScaleToExtent();
TargetAxisExtentType xSize = null, ySize = null;
for (TargetAxisExtentType axisSizeType : ste.getTargetAxisExtent()) {
final String axisName = axisSizeType.getAxis();
if (axisName.equals("http://www.opengis.net/def/axis/OGC/1/i") || axisName.equals("i")) {
xSize = axisSizeType;
} else if (axisName.equals("http://www.opengis.net/def/axis/OGC/1/j") || axisName.equals("j")) {
ySize = axisSizeType;
} else {
// TODO remove when supporting TIME and ELEVATION
throw new WCS20Exception("Scale Axis Undefined",
WCS20Exception.WCS20ExceptionCode.ScaleAxisUndefined, axisName);
}
}
final int sizeX = (int) (xSize.getHigh() - xSize.getLow());// TODO should this be int?
if (sizeX <= 0) {
throw new WCS20Exception("Invalid target extent, high is greater than low",
WCS20Exception.WCS20ExceptionCode.InvalidExtent, Integer.toString((int) xSize.getHigh()));
}
final int sizeY = (int) (ySize.getHigh() - ySize.getLow());
if (sizeY <= 0) {
throw new WCS20Exception("Invalid target extent, high is greater than low",
WCS20Exception.WCS20ExceptionCode.InvalidExtent, Integer.toString((int) ySize.getHigh()));
}
return new int[] { sizeX, sizeY };

} else {
throw new IllegalArgumentException("targe size can not be computed from this type of scaling: "
+ getPolicy(scaling));
}
final EList<TargetAxisSizeType> targetAxisSizeElements = scaleType.getTargetAxisSize();

TargetAxisSizeType xSize = null, ySize = null;
for (TargetAxisSizeType axisSizeType : targetAxisSizeElements) {
final String axisName = axisSizeType.getAxis();
if (axisName.equals("http://www.opengis.net/def/axis/OGC/1/i") || axisName.equals("i")) {
xSize = axisSizeType;
} else if (axisName.equals("http://www.opengis.net/def/axis/OGC/1/j") || axisName.equals("j")) {
ySize = axisSizeType;
} else {
// TODO remove when supporting TIME and ELEVATION
throw new WCS20Exception("Scale Axis Undefined",
WCS20Exception.WCS20ExceptionCode.ScaleAxisUndefined, axisName);
}
}
final int sizeX = (int) xSize.getTargetSize();// TODO should this be int?
if (sizeX <= 0) {
throw new WCS20Exception("Invalid target size",
WCS20Exception.WCS20ExceptionCode.InvalidExtent, Integer.toString(sizeX));
}
final int sizeY = (int) ySize.getTargetSize();// TODO should this be int?
if (sizeY <= 0) {
throw new WCS20Exception("Invalid target size",
WCS20Exception.WCS20ExceptionCode.InvalidExtent, Integer.toString(sizeY));
}
return new int[] { sizeX, sizeY };
}

/**
Expand Down

0 comments on commit 8a84e72

Please sign in to comment.