/*
* This file is part of JGrasstools (http://www.jgrasstools.org)
* (C) HydroloGIS - www.hydrologis.com
*
* JGrasstools is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.jgrasstools.gears.modules.r.tmsgenerator;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.net.URL;
import javax.imageio.ImageIO;
import org.geotools.geometry.jts.JTS;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.geotools.referencing.crs.DefaultGeographicCRS;
import org.jgrasstools.gears.io.vectorreader.OmsVectorReader;
import org.jgrasstools.gears.libs.monitor.IJGTProgressMonitor;
import org.jgrasstools.gears.libs.monitor.LogProgressMonitor;
import org.jgrasstools.gears.utils.CrsUtilities;
import org.jgrasstools.gears.utils.files.FileUtilities;
import org.opengis.referencing.crs.CoordinateReferenceSystem;
import org.opengis.referencing.operation.MathTransform;
import com.vividsolutions.jts.geom.Coordinate;
public class OpenstreetmapImageCreator {
private static final String EPSG_MERCATOR = "EPSG:3857";
private String inServiceUrl;
private int zoomLevel;
private ReferencedEnvelope mercatorBounds;
private IJGTProgressMonitor pm;
private File outFile;
/**
* @param inServiceUrl The OSM tile service to use (XXX, YYY, ZZZ will be substituted by tile indexes and zoom level).
* @param zoomLevel The zoom level to use.
* @param inBounds The area to consider in 3875.
* @param pm The progress monitor.
* @return the image.
* @throws Exception
*/
public OpenstreetmapImageCreator( String inServiceUrl, int zoomLevel, ReferencedEnvelope mercatorBounds, File outFile,
IJGTProgressMonitor pm ) {
this.inServiceUrl = inServiceUrl;
this.zoomLevel = zoomLevel;
this.mercatorBounds = mercatorBounds;
this.outFile = outFile;
this.pm = pm;
}
public void generate() throws Exception {
CoordinateReferenceSystem mercatorCrs = CrsUtilities.getCrsFromEpsg(EPSG_MERCATOR, null);
CoordinateReferenceSystem latLongCrs = DefaultGeographicCRS.WGS84;
ReferencedEnvelope llBounds = mercatorBounds.transform(latLongCrs, true);
double w = llBounds.getMinX();
double e = llBounds.getMaxX();
double s = llBounds.getMinY();
double n = llBounds.getMaxY();
int[] ulTileNumber = getTileXY(n, w, zoomLevel);
int[] lrTileNumber = getTileXY(s, e, zoomLevel);
int startXTile = ulTileNumber[0];
int startYTile = ulTileNumber[1];
int endXTile = lrTileNumber[0];
int endYTile = lrTileNumber[1];
BoundingBox bbUL = tile2boundingBox(startXTile, startYTile, zoomLevel);
double imageW = bbUL.west;
double imageN = bbUL.north;
BoundingBox bbLR = tile2boundingBox(endXTile, endYTile, zoomLevel);
double imageS = bbLR.south;
double imageE = bbLR.east;
int tileCols = endXTile - startXTile + 1;
int tileRows = endYTile - startYTile + 1;
int tileSize = 256;
int height = tileRows * tileSize;
int width = tileCols * tileSize;
BufferedImage outImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = (Graphics2D) outImage.getGraphics();
pm.beginTask("Generating tiles at zoom level: " + zoomLevel + " with tiles: " + tileCols + "x" + tileRows,
(endXTile - startXTile + 1));
int runningX = 0;
for( int x = startXTile; x <= endXTile; x++ ) {
int runningY = 0;
for( int y = startYTile; y <= endYTile; y++ ) {
// int[] tmsNUms = getTileXY(y, x, zoomLevel);
String tmp = inServiceUrl.replaceFirst("ZZZ", String.valueOf(zoomLevel));
tmp = tmp.replaceFirst("XXX", String.valueOf(x));
tmp = tmp.replaceFirst("YYY", String.valueOf(y));
URL url = new URL(tmp);
try {
BufferedImage tileImage = ImageIO.read(url);
g2d.drawImage(tileImage, null, runningX, runningY);
} catch (Exception ex) {
pm.errorMessage("Unable to get image: " + tmp);
}
runningY += tileSize;
}
runningX += tileSize;
pm.worked(1);
}
pm.done();
g2d.dispose();
String nameL = outFile.getName().toLowerCase();
if (nameL.endsWith("png")) {
ImageIO.write(outImage, "png", outFile);
} else if (nameL.endsWith("jpg")) {
ImageIO.write(outImage, "jpg", outFile);
} else if (nameL.endsWith("tiff")) {
ImageIO.write(outImage, "tiff", outFile);
}
MathTransform transform = CRS.findMathTransform(latLongCrs, mercatorCrs);
Coordinate llES = new Coordinate(imageE, imageS);
Coordinate llWN = new Coordinate(imageW, imageN);
Coordinate osmES = JTS.transform(llES, null, transform);
Coordinate osmWN = JTS.transform(llWN, null, transform);
// create tfw
double dx = (osmES.x - osmWN.x) / width;
double dy = (osmWN.y - osmES.y) / height;
StringBuilder sb = new StringBuilder();
sb.append(dx).append("\n");
sb.append("0.00000000").append("\n");
sb.append("0.00000000").append("\n");
sb.append(-dy).append("\n");
sb.append(osmWN.x).append("\n");
sb.append(osmWN.y).append("\n");
String fileName = FileUtilities.getNameWithoutExtention(outFile);
File folder = outFile.getParentFile();
File tfwFile = new File(folder, fileName + ".tfw");
FileUtilities.writeFile(sb.toString(), tfwFile);
// create prj
File prjFile = new File(folder, fileName + ".prj");
FileUtilities.writeFile(mercatorCrs.toWKT(), prjFile);
}
private static int[] getTileXY( final double lat, final double lon, final int zoom ) {
int xtile = (int) Math.floor((lon + 180) / 360 * (1 << zoom));
int ytile = (int) Math.floor(
(1 - Math.log(Math.tan(Math.toRadians(lat)) + 1 / Math.cos(Math.toRadians(lat))) / Math.PI) / 2 * (1 << zoom));
if (xtile < 0)
xtile = 0;
if (xtile >= (1 << zoom))
xtile = ((1 << zoom) - 1);
if (ytile < 0)
ytile = 0;
if (ytile >= (1 << zoom))
ytile = ((1 << zoom) - 1);
return new int[]{xtile, ytile};
}
private class BoundingBox {
double north;
double south;
double east;
double west;
}
private BoundingBox tile2boundingBox( final int x, final int y, final int zoom ) {
BoundingBox bb = new BoundingBox();
bb.north = tile2lat(y, zoom);
bb.south = tile2lat(y + 1, zoom);
bb.west = tile2lon(x, zoom);
bb.east = tile2lon(x + 1, zoom);
return bb;
}
private static double tile2lon( int x, int z ) {
return x / Math.pow(2.0, z) * 360.0 - 180.0;
}
private static double tile2lat( int y, int z ) {
double n = Math.PI - (2.0 * Math.PI * y) / Math.pow(2.0, z);
return Math.toDegrees(Math.atan(Math.sinh(n)));
}
public static void main( String[] args ) throws Exception {
String outFile = "/home/hydrologis/Dropbox/hydrologis/lavori/2015_05_bim_sarcamincio/shape_3857/image_output/osm15.png";
String bounds = "/home/hydrologis/Dropbox/hydrologis/lavori/2015_05_bim_sarcamincio/shape_3857/area.shp";
String inServiceUrl = "http://a.tile.opencyclemap.org/cycle/ZZZ/XXX/YYY.png";
// String inServiceUrl = "http://a.tile.openstreetmap.org/ZZZ/XXX/YYY.png";
ReferencedEnvelope env = OmsVectorReader.readVector(bounds).getBounds();
OpenstreetmapImageCreator c = new OpenstreetmapImageCreator(inServiceUrl, 15, env, new File(outFile),
new LogProgressMonitor());
c.generate();
}
}