/* (c) 2015 Open Source Geospatial Foundation - all rights reserved * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.wms.map; import java.awt.Rectangle; import java.awt.image.BufferedImage; import java.awt.image.renderable.ParameterBlock; import javax.media.jai.ROI; import javax.media.jai.RenderedOp; import javax.xml.namespace.QName; import org.geoserver.catalog.CoverageInfo; import org.geoserver.data.test.MockData; import org.geoserver.data.test.SystemTestData; import org.geoserver.wms.GetMapRequest; import org.geoserver.wms.WMSMapContent; import org.geoserver.wms.WMSTestSupport; import org.geotools.coverage.grid.io.GridCoverage2DReader; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.map.GridReaderLayer; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.geotools.resources.image.ImageUtilities; import org.geotools.styling.Style; import org.junit.After; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.opengis.coverage.grid.GridEnvelope; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.Envelope; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; /** * Unit test for very slow WMS GetMap response times when the requested * bounding box is much smaller than the resolution of the raster data * and advanced projection handling is disabled. */ public class TinyRasterBoundingBoxTest extends WMSTestSupport { @BeforeClass public static void disableAdvancedProjection() { System.setProperty("ENABLE_ADVANCED_PROJECTION", "false"); } private WMSMapContent map; private BufferedImage image; private RenderedOp op; @Before public void setUp() { GetMapRequest request = new GetMapRequest(); request.setFormat("image/png"); this.map = new WMSMapContent(); this.map.setMapWidth(256); this.map.setMapHeight(256); this.map.setTransparent(true); this.map.setRequest(request); } @Override protected void onSetUp(SystemTestData testData) throws Exception { super.onSetUp(testData); testData.addDefaultRasterLayer(MockData.TASMANIA_DEM, getCatalog()); testData.addStyle("rainfall", "rainfall.sld", MockData.class, getCatalog()); } @After public void tearDown() { ImageUtilities.disposeImage(this.op); this.map.dispose(); this.map = null; this.image = null; this.op = null; } @Test public void testTinyRasterBboxContained() throws Exception { CoverageInfo coverageInfo = addRasterToMap(MockData.TASMANIA_DEM); Envelope env = coverageInfo.boundingBox(); Coordinate center = env.centre(); GridEnvelope range = coverageInfo.getGrid().getGridRange(); double offset = (env.getMaxX() - env.getMinX()) / range.getSpan(0) / 10.0; Rectangle imageBounds = produceMap(center.x + offset, center.x + 2 * offset, center.y + offset, center.y + 2 * offset); assertNotBlank("testTinyRasterBboxContained", this.image); assertEquals("Mosaic", this.op.getOperationName()); Rectangle roiBounds = getRoiBounds(); assertTrue("Expected " + imageBounds + " to contain " + roiBounds, imageBounds.contains(roiBounds)); } @Test public void testTinyRasterBboxIntersection() throws Exception { CoverageInfo coverageInfo = addRasterToMap(MockData.TASMANIA_DEM); Envelope env = coverageInfo.boundingBox(); GridEnvelope range = coverageInfo.getGrid().getGridRange(); double offset = (env.getMaxX() - env.getMinX()) / range.getSpan(0) / 20.0; Rectangle imageBounds = produceMap(env.getMinX() - offset, env.getMinX() + offset, env.getMaxY() - offset, env.getMaxY() + offset); assertNotBlank("testTinyRasterBboxIntersection", this.image); assertEquals("Mosaic", this.op.getOperationName()); Rectangle roiBounds = getRoiBounds(); assertTrue("Expected " + imageBounds + " to contain " + roiBounds, imageBounds.contains(roiBounds)); } @Test public void testTinyRasterBboxNoIntersection() throws Exception { CoverageInfo coverageInfo = addRasterToMap(MockData.TASMANIA_DEM); Envelope env = coverageInfo.boundingBox(); GridEnvelope range = coverageInfo.getGrid().getGridRange(); double offset = (env.getMaxX() - env.getMinX()) / range.getSpan(0) / 10.0; Rectangle imageBounds = produceMap(env.getMaxX() + offset, env.getMaxX() + 2 * offset, env.getMinY() - 2 * offset, env.getMinY() - offset); assertNotBlank("testTinyRasterBboxNoIntersection", this.image); assertEquals("Mosaic", this.op.getOperationName()); Rectangle roiBounds = getRoiBounds(); assertTrue("Expected " + imageBounds + " to contain " + roiBounds, imageBounds.contains(roiBounds)); } private CoverageInfo addRasterToMap(QName typeName) throws Exception { CoverageInfo coverageInfo = getCatalog().getCoverageByName( typeName.getNamespaceURI(), typeName.getLocalPart()); GridCoverage2DReader reader = (GridCoverage2DReader) coverageInfo.getGridCoverageReader(null, null); Style style = getCatalog().getStyleByName("rainfall").getStyle(); this.map.addLayer(new GridReaderLayer(reader, style)); return coverageInfo; } private Rectangle getRoiBounds() { ParameterBlock pb = this.op.getParameterBlock(); ROI[] rois = (ROI[]) pb.getObjectParameter(2); return rois[0].getBounds(); } private Rectangle produceMap(double minX, double maxX, double minY, double maxY) { this.map.getViewport().setBounds(new ReferencedEnvelope( minX, maxX, minY, maxY, DefaultGeographicCRS.WGS84)); RenderedImageMapOutputFormat rasterMapProducer = new RenderedImageMapOutputFormat(getWMS()); RenderedImageMap imageMap = rasterMapProducer.produceMap(this.map); this.op = (RenderedOp) imageMap.getImage(); this.image = this.op.getAsBufferedImage(); imageMap.dispose(); return new Rectangle(0, 0, this.image.getWidth(), this.image.getHeight()); } }