package org.geotools.renderer.lite; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; import java.io.Serializable; import java.net.URL; import java.util.Collections; import java.util.HashMap; import java.util.Map; import org.geotools.TestData; import org.geotools.data.DataStore; import org.geotools.data.DataUtilities; import org.geotools.data.shapefile.ShapefileDataStoreFactory; import org.geotools.data.simple.SimpleFeatureSource; import org.geotools.data.simple.SimpleFeatureStore; import org.geotools.factory.CommonFactoryFinder; import org.geotools.feature.simple.SimpleFeatureBuilder; import org.geotools.feature.simple.SimpleFeatureTypeBuilder; import org.geotools.geometry.jts.JTSFactoryFinder; import org.geotools.geometry.jts.ReferencedEnvelope; import org.geotools.map.FeatureLayer; import org.geotools.map.MapContent; import org.geotools.map.MapViewport; import org.geotools.referencing.crs.DefaultGeographicCRS; import org.geotools.renderer.style.FontCache; import org.geotools.styling.ExternalGraphic; import org.geotools.styling.FeatureTypeStyle; import org.geotools.styling.Graphic; import org.geotools.styling.PointPlacement; import org.geotools.styling.PointSymbolizer; import org.geotools.styling.Rule; import org.geotools.styling.Style; import org.geotools.styling.StyleBuilder; import org.geotools.styling.StyleFactory; import org.geotools.styling.TextSymbolizer; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.opengis.feature.simple.SimpleFeature; import org.opengis.feature.simple.SimpleFeatureType; import com.vividsolutions.jts.geom.Coordinate; import com.vividsolutions.jts.geom.GeometryFactory; import com.vividsolutions.jts.geom.Point; /** * @author Sebastian Graca, ISPiK S.A. */ public class ScreenMapShapefileTest { private DataStore shapeFileDataStore; private SimpleFeatureType featureType; private SimpleFeature feature; @Before public void setUp() throws Exception { SimpleFeatureTypeBuilder ftb = new SimpleFeatureTypeBuilder(); ftb.setName("render-test"); ftb.add("the_geom", Point.class, DefaultGeographicCRS.WGS84); ftb.setDefaultGeometry("the_geom"); ftb.add("name", String.class); featureType = ftb.buildFeatureType(); GeometryFactory gf = JTSFactoryFinder.getGeometryFactory(); SimpleFeatureBuilder fb = new SimpleFeatureBuilder(featureType); fb.set("the_geom", gf.createPoint(new Coordinate(10, 10))); fb.set("name", "The name"); feature = fb.buildFeature(null); File shpFile = new File("./target/screenMapTest/" + feature.getFeatureType().getName().getLocalPart() + ".shp"); shpFile.getParentFile().mkdirs(); ShapefileDataStoreFactory dataStoreFactory = new ShapefileDataStoreFactory(); Map<String, Serializable> params = new HashMap<String, Serializable>(); params.put(ShapefileDataStoreFactory.URLP.key, shpFile.toURI().toURL()); shapeFileDataStore = dataStoreFactory.createNewDataStore(params); shapeFileDataStore.createSchema(feature.getFeatureType()); SimpleFeatureStore featureStore = (SimpleFeatureStore) shapeFileDataStore .getFeatureSource(shapeFileDataStore.getTypeNames()[0]); featureStore.addFeatures(DataUtilities.collection(feature)); FontCache.getDefaultInstance().registerFont( Font.createFont(Font.TRUETYPE_FONT, TestData.getResource(this, "Vera.ttf") .openStream())); } @After public void dispose() { if(shapeFileDataStore != null) { shapeFileDataStore.dispose(); } } @Test public void testFeatureCollection() throws IOException { SimpleFeatureSource featureSource = DataUtilities.source(new SimpleFeature[] { feature }); checkTiles(featureSource); } @Test public void testShapeFile() throws Exception { SimpleFeatureSource fs = shapeFileDataStore.getFeatureSource(featureType.getTypeName()); checkTiles(fs); } private static void checkTiles(SimpleFeatureSource featureSource) { Style style = createPointStyle(); BufferedImage untiled = renderImage(featureSource, 100, 100, new Rectangle2D.Double(5, 5, 10, 10), style, Collections.emptyMap()); BufferedImage tile1 = renderImage(featureSource, 50, 100, new Rectangle2D.Double(5, 5, 5, 10), style, Collections.emptyMap()); BufferedImage tile2 = renderImage(featureSource, 50, 100, new Rectangle2D.Double(10, 5, 5, 10), style, Collections.emptyMap()); assertEqualsImage(untiled.getSubimage(0, 0, 50, 100), tile1); assertEqualsImage(untiled.getSubimage(50, 0, 50, 100), tile2); } private static void assertEqualsImage(BufferedImage expected, BufferedImage actual) { assertEquals(expected.getWidth(), actual.getWidth()); assertEquals(expected.getHeight(), actual.getHeight()); for (int y = 0; y < expected.getHeight(); ++y) { for (int x = 0; x < expected.getWidth(); ++x) { int expectedRgb = expected.getRGB(x, y); int actualRgb = actual.getRGB(x, y); assertEquals("[" + y + ", " + x + "]", new Color(expectedRgb), new Color(actualRgb)); } } } private static BufferedImage renderImage(SimpleFeatureSource featureSource, int width, int height, Rectangle2D mapArea, Style style, Map renderingHints) { BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); Graphics2D g = (Graphics2D) image.getGraphics(); g.setColor(Color.WHITE); g.fillRect(0, 0, width, height); MapContent mapContent = new MapContent(); MapViewport viewport = mapContent.getViewport(); viewport.setBounds(new ReferencedEnvelope(mapArea, DefaultGeographicCRS.WGS84)); viewport.setScreenArea(new Rectangle(width, height)); mapContent.addLayer(new FeatureLayer(featureSource, style)); StreamingRenderer renderer = new StreamingRenderer(); renderer.setRendererHints(renderingHints); renderer.setMapContent(mapContent); renderer.paint(g, viewport.getScreenArea(), viewport.getBounds()); return image; } private static Style createPointStyle() { StyleFactory sf = CommonFactoryFinder.getStyleFactory(); URL iconUrl = ScreenMapShapefileTest.class.getResource("icon.png"); ExternalGraphic icon = sf.createExternalGraphic(iconUrl, "image/png"); Graphic graphic = sf.createGraphic(new ExternalGraphic[] { icon }, null, null, null, null, null); PointSymbolizer symbolizer = sf.createPointSymbolizer(graphic, "the_geom"); Rule rule = sf.createRule(); rule.symbolizers().add(symbolizer); FeatureTypeStyle fts = sf.createFeatureTypeStyle(); fts.rules().add(rule); Style style = sf.createStyle(); style.featureTypeStyles().add(fts); return style; } @Test public void testOffsetLabel() throws IOException { SimpleFeatureSource fs = shapeFileDataStore.getFeatureSource(featureType.getTypeName()); Style style = createLabelOffsetStyle(); Map renderingHints = new HashMap<>(); BufferedImage image = renderImage(fs, 200, 200, new Rectangle2D.Double(15, 0, 25, 10), style, renderingHints); assertEquals(0, countNonBlankPixels(image)); renderingHints.put(StreamingRenderer.RENDERING_BUFFER, 100); image = renderImage(fs, 200, 200, new Rectangle2D.Double(15, 0, 25, 10), style, renderingHints); assertTrue(countNonBlankPixels(image) > 0); } private static Style createLabelOffsetStyle() { StyleBuilder sb = new StyleBuilder(); PointPlacement pp = sb.createPointPlacement(0.5, 0.5, 50, 0, 0); TextSymbolizer ts = sb.createTextSymbolizer(); ts.setFont(sb.createFont("Bitstream Vera Sans", 20)); ts.setLabel(sb.getFilterFactory().literal("name")); ts.setLabelPlacement(pp); ts.getOptions().put("partials", "true"); return sb.createStyle(ts); } protected int countNonBlankPixels(BufferedImage image) { int pixelsDiffer = 0; for (int y = 0; y < image.getHeight(); y++) { for (int x = 0; x < image.getWidth(); x++) { if (image.getRGB(x, y) != Color.WHITE.getRGB()) { ++pixelsDiffer; } } } return pixelsDiffer; } }