final List<Rule> rules = getActiveRules(style, params.getScaleDenominator());
if (rules.size() == 0) {
return null;
}
GetMapRequest getMap = params.getGetMapRequest();
WMSMapContent mc = new WMSMapContent(getMap);
try {
// prepare the fake web map content
mc.setTransparent(true);
mc.setBuffer(params.getBuffer());
mc.getViewport().setBounds(new ReferencedEnvelope(getMap.getBbox(), getMap.getCrs()));
mc.setMapWidth(getMap.getWidth());
mc.setMapHeight(getMap.getHeight());
FeatureLayer layer = getLayer(params, style);
mc.addLayer(layer);
// setup the env variables just like in the original GetMap
RenderingVariables.setupEnvironmentVariables(mc);
// setup the transformation from screen to world space
AffineTransform worldToScreen = RendererUtilities.worldToScreenTransform(
params.getRequestedBounds(), new Rectangle(params.getWidth(), params.getHeight()));
AffineTransform screenToWorld = worldToScreen.createInverse();
// apply uom rescale on the rules
rescaleRules(rules, params);
// setup the area we are actually going to paint
int radius = getSearchRadius(params, rules, layer, getMap, screenToWorld);
if(radius < buffer) {
radius = buffer;
}
Envelope targetRasterSpace = new Envelope(params.getX() - radius, params.getX() + radius,
params.getY() - radius, params.getY() + radius);
Envelope targetModelSpace = JTS.transform(targetRasterSpace, new AffineTransform2D(screenToWorld));
// prepare the image we are going to check rendering against
int paintAreaSize = radius * 2 + 1;
final BufferedImage image = ImageTypeSpecifier.createFromBufferedImageType(
BufferedImage.TYPE_INT_ARGB).createBufferedImage(paintAreaSize,
paintAreaSize);
image.setAccelerationPriority(0);
// and now the listener that will check for painted pixels
int mid = radius;
int hitAreaSize = buffer * 2 + 1;
Rectangle hitArea = new Rectangle(mid - buffer, mid - buffer, hitAreaSize, hitAreaSize);
final FeatureInfoRenderListener featureInfoListener = new FeatureInfoRenderListener(
image, hitArea, maxFeatures, params.getPropertyNames());
// update the map context
mc.getViewport().setBounds(new ReferencedEnvelope(targetModelSpace, getMap.getCrs()));
mc.setMapWidth(paintAreaSize);
mc.setMapHeight(paintAreaSize);
// and now run the rendering _almost_ like a GetMap
RenderedImageMapOutputFormat rim = new RenderedImageMapOutputFormat(wms) {
private Graphics2D graphics;
@Override
protected RenderedImage prepareImage(int width, int height, IndexColorModel palette,
boolean transparent) {
return image;
}
@Override
protected Graphics2D getGraphics(boolean transparent, Color bgColor,
RenderedImage preparedImage, Map<Key, Object> hintsMap) {
graphics = super.getGraphics(transparent, bgColor, preparedImage,
hintsMap);
return graphics;
}
@Override
protected void onBeforeRender(StreamingRenderer renderer) {
// force the renderer into serial painting mode, as we need to check what
// was painted to decide which features to include in the results
Map hints = renderer.getRendererHints();
hints.put(StreamingRenderer.OPTIMIZE_FTS_RENDERING_KEY, Boolean.FALSE);
// disable antialiasing to speed up rendering
hints.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF);
// TODO: should we disable the screenmap as well?
featureInfoListener.setGraphics(graphics);
featureInfoListener.setRenderer(renderer);
renderer.addRenderListener(featureInfoListener);
}
};
rim.produceMap(mc);
List<SimpleFeature> features = featureInfoListener.getFeatures();
return aggregateByFeatureType(features);
} finally {
mc.dispose();
}
}