/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2015, Open Source Geospatial Foundation (OSGeo)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation;
* version 2.1 of the License.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*/
package org.geotools.tile.util;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.util.Collection;
import java.util.logging.Logger;
import org.geotools.coverage.grid.GridCoverage2D;
import org.geotools.coverage.grid.GridCoverageFactory;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.map.DirectLayer;
import org.geotools.map.MapContent;
import org.geotools.map.MapViewport;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.geotools.renderer.lite.RendererUtilities;
import org.geotools.tile.Tile;
import org.geotools.tile.TileService;
import org.geotools.util.logging.Logging;
import org.opengis.referencing.FactoryException;
import org.opengis.referencing.operation.TransformException;
/**
* <p>
* TileLayer is a direct map layer that does the mosaicking work for tiles of a
* given tile service.
* </p>
*
* @author Ugo Taddei
* @since 12
* @source $URL:
* http://svn.osgeo.org/geotools/trunk/modules/unsupported/tile-client
* /src/main/java/org/geotools/tile/util/TileLayer.java $
*/
public class TileLayer extends DirectLayer {
private static final Logger LOGGER = Logging.getLogger(TileLayer.class
.getPackage().getName());
private static final GridCoverageFactory gridFactory = new GridCoverageFactory();
private TileService service;
/** Resolution in DPI */
private double resolution = 90;
private GridCoverage2D coverage;
public TileLayer(TileService service) {
super();
this.service = service;
}
public GridCoverage2D getCoverage() {
return this.coverage;
}
public ReferencedEnvelope getBounds() {
return new ReferencedEnvelope(-180, 180, -85, 85,
DefaultGeographicCRS.WGS84);
}
@Override
public void draw(Graphics2D graphics, MapContent map,
MapViewport theViewport) {
LOGGER.fine("Started drawing");
final MapViewport viewport = new MapViewport(theViewport);
final ReferencedEnvelope viewportExtent = viewport.getBounds();
int scale = calculateScale(viewportExtent, viewport.getScreenArea());
Collection<Tile> tiles = service.findTilesInExtent(viewportExtent,
scale, false, 128);
BufferedImage mosaickedImage = createImage(viewport.getScreenArea());
Graphics2D g2d = mosaickedImage.createGraphics();
long t = System.currentTimeMillis();
renderTiles(tiles, g2d, viewportExtent, viewport.getWorldToScreen());
// System.out.println("Sync: " + (System.currentTimeMillis() - t));
this.coverage = gridFactory.create("GridCoverage", mosaickedImage,
viewportExtent);
graphics.drawImage(mosaickedImage, 0, 0, null);
LOGGER.fine("Drawing done");
}
protected void renderTiles(Collection<Tile> tiles, Graphics2D g2d,
ReferencedEnvelope viewportExtent,
AffineTransform worldToImageTransform) {
g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
RenderingHints.VALUE_INTERPOLATION_BILINEAR);
double[] points = new double[4];
for (Tile tile : tiles) {
ReferencedEnvelope nativeTileEnvelope = tile.getExtent();
ReferencedEnvelope tileEnvViewport;
try {
tileEnvViewport = nativeTileEnvelope.transform(
viewportExtent.getCoordinateReferenceSystem(), true);
} catch (TransformException | FactoryException e) {
throw new RuntimeException(e);
}
points[0] = tileEnvViewport.getMinX();
points[3] = tileEnvViewport.getMinY();
points[2] = tileEnvViewport.getMaxX();
points[1] = tileEnvViewport.getMaxY();
worldToImageTransform.transform(points, 0, points, 0, 2);
renderTile(tile, g2d, points);
}
}
protected void renderTile(Tile tile, Graphics2D g2d, double[] points) {
BufferedImage img = getTileImage(tile);
g2d.drawImage(img, (int) points[0], (int) points[1],
(int) Math.ceil(points[2] - points[0]),
(int) Math.ceil(points[3] - points[1]), null);
}
protected BufferedImage getTileImage(Tile tile) {
return tile.getBufferedImage();
}
private int calculateScale(ReferencedEnvelope extent, Rectangle screenArea) {
int scale = 0;
try {
scale = (int) Math.round(RendererUtilities.calculateScale(extent,
screenArea.width, screenArea.height, this.resolution));
} catch (FactoryException | TransformException ex) {
throw new RuntimeException("Failed to calculate scale", ex);
}
return scale;
}
private BufferedImage createImage(Rectangle rectangle) {
return new BufferedImage(rectangle.width, rectangle.height,
BufferedImage.TYPE_INT_RGB);
}
}