/*
* 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 static org.jgrasstools.gears.libs.modules.JGTConstants.RASTERPROCESSING;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import org.geotools.geometry.jts.JTS;
import org.geotools.geometry.jts.ReferencedEnvelope;
import org.geotools.referencing.CRS;
import org.jgrasstools.gears.libs.exceptions.ModelsIOException;
import org.jgrasstools.gears.libs.modules.JGTConstants;
import org.jgrasstools.gears.libs.modules.JGTModel;
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 static org.jgrasstools.gears.modules.r.tmsgenerator.OmsOnlineTilesDownloader.*;
import com.vividsolutions.jts.geom.Coordinate;
import com.vividsolutions.jts.geom.Envelope;
import oms3.annotations.Author;
import oms3.annotations.Description;
import oms3.annotations.Documentation;
import oms3.annotations.Execute;
import oms3.annotations.In;
import oms3.annotations.Keywords;
import oms3.annotations.Label;
import oms3.annotations.License;
import oms3.annotations.Name;
import oms3.annotations.Status;
import oms3.annotations.UI;
@Description(OMSONLINETILESDOWNLOADER_DESCRIPTION)
@Documentation(OMSONLINETILESDOWNLOADER_DOCUMENTATION)
@Author(name = OMSONLINETILESDOWNLOADER_AUTHORNAMES, contact = OMSONLINETILESDOWNLOADER_AUTHORCONTACTS)
@Keywords(OMSONLINETILESDOWNLOADER_KEYWORDS)
@Label(OMSONLINETILESDOWNLOADER_LABEL)
@Name(OMSONLINETILESDOWNLOADER_NAME)
@Status(OMSONLINETILESDOWNLOADER_STATUS)
@License(OMSONLINETILESDOWNLOADER_LICENSE)
@UI(OMSONLINETILESDOWNLOADER_UI)
public class OmsOnlineTilesDownloader extends JGTModel {
@Description(OMSONLINETILESDOWNLOADER_inServiceUrl_DESCRIPTION)
@In
public String inServiceUrl = null;
@Description(OMSONLINETILESDOWNLOADER_pType_DESCRIPTION)
@In
public int pType = 0;
@Description(OMSONLINETILESDOWNLOADER_pName_DESCRIPTION)
@In
public String pName = "tmstiles";
@Description(OMSONLINETILESDOWNLOADER_pMinzoom_DESCRIPTION)
@In
public Integer pMinzoom = null;
@Description(OMSONLINETILESDOWNLOADER_pMaxzoom_DESCRIPTION)
@In
public Integer pMaxzoom = null;
@Description(OMSONLINETILESDOWNLOADER_pNorth_DESCRIPTION)
@UI(JGTConstants.PROCESS_NORTH_UI_HINT)
@In
public Double pNorth = null;
@Description(OMSONLINETILESDOWNLOADER_pSouth_DESCRIPTION)
@UI(JGTConstants.PROCESS_SOUTH_UI_HINT)
@In
public Double pSouth = null;
@Description(OMSONLINETILESDOWNLOADER_pWest_DESCRIPTION)
@UI(JGTConstants.PROCESS_WEST_UI_HINT)
@In
public Double pWest = null;
@Description(OMSONLINETILESDOWNLOADER_pEast_DESCRIPTION)
@UI(JGTConstants.PROCESS_EAST_UI_HINT)
@In
public Double pEast = null;
@Description(OMSONLINETILESDOWNLOADER_pEpsg_DESCRIPTION)
@UI(JGTConstants.CRS_UI_HINT)
@In
public String pEpsg;
@Description(OMSONLINETILESDOWNLOADER_doLenient_DESCRIPTION)
@In
public boolean doLenient = true;
@Description(OMSONLINETILESDOWNLOADER_inPath_DESCRIPTION)
@In
public String inPath;
public static final String OMSONLINETILESDOWNLOADER_DESCRIPTION = "Module for the downloading of map tiles.";
public static final String OMSONLINETILESDOWNLOADER_DOCUMENTATION = "";
public static final String OMSONLINETILESDOWNLOADER_KEYWORDS = "Raster, Vector, TMS, Tiles";
public static final String OMSONLINETILESDOWNLOADER_LABEL = RASTERPROCESSING;
public static final String OMSONLINETILESDOWNLOADER_NAME = "tmsdownloader";
public static final int OMSONLINETILESDOWNLOADER_STATUS = 10;
public static final String OMSONLINETILESDOWNLOADER_LICENSE = "General Public License Version 3 (GPLv3)";
public static final String OMSONLINETILESDOWNLOADER_AUTHORNAMES = "Andrea Antonello";
public static final String OMSONLINETILESDOWNLOADER_AUTHORCONTACTS = "http://www.hydrologis.com";
public static final String OMSONLINETILESDOWNLOADER_UI = "hide";
public static final String OMSONLINETILESDOWNLOADER_inServiceUrl_DESCRIPTION = "An optional online tile service to include (XXX, YYY, ZZZ will be substituted by tile indexes and zoom level).";
public static final String OMSONLINETILESDOWNLOADER_pType_DESCRIPTION = "The type of tile source (0 = TMS, 1 = google).";
public static final String OMSONLINETILESDOWNLOADER_pName_DESCRIPTION = "A name of the tile source.";
public static final String OMSONLINETILESDOWNLOADER_pMinzoom_DESCRIPTION = "The min zoom for which to generate tiles.";
public static final String OMSONLINETILESDOWNLOADER_pMaxzoom_DESCRIPTION = "The max zoom for which to generate tiles.";
public static final String OMSONLINETILESDOWNLOADER_pNorth_DESCRIPTION = "The north bound of the region to consider.";
public static final String OMSONLINETILESDOWNLOADER_pSouth_DESCRIPTION = "The south bound of the region to consider.";
public static final String OMSONLINETILESDOWNLOADER_pWest_DESCRIPTION = "The west bound of the region to consider.";
public static final String OMSONLINETILESDOWNLOADER_pEast_DESCRIPTION = "The east bound of the region to consider.";
public static final String OMSONLINETILESDOWNLOADER_pEpsg_DESCRIPTION = "The coordinate reference system of the bound coordinates (ex. EPSG:4328).";
public static final String OMSONLINETILESDOWNLOADER_doLenient_DESCRIPTION = "Switch that set to true allows for some error due to different datums. If set to false, it won't reproject without Bursa Wolf parameters.";
public static final String OMSONLINETILESDOWNLOADER_inPath_DESCRIPTION = "The folder inside which to create the tiles.";
private boolean doDryrun = false;
private static final String EPSG_MERCATOR = "EPSG:3857";
private static final String EPSG_LATLONG = "EPSG:4326";
@Execute
public void process() throws Exception {
checkNull(inPath, inServiceUrl, pEpsg, pMinzoom, pMaxzoom, pWest, pEast, pSouth, pNorth);
CoordinateReferenceSystem boundsCrs = CrsUtilities.getCrsFromEpsg(pEpsg, null);
CoordinateReferenceSystem mercatorCrs = CrsUtilities.getCrsFromEpsg(EPSG_MERCATOR, null);
CoordinateReferenceSystem latLongCrs = CrsUtilities.getCrsFromEpsg(EPSG_LATLONG, null);
ReferencedEnvelope inBounds = new ReferencedEnvelope(pWest, pEast, pSouth, pNorth, boundsCrs);
MathTransform in2MercatorTransform = CRS.findMathTransform(boundsCrs, mercatorCrs);
Envelope mercatorEnvelope = JTS.transform(inBounds, in2MercatorTransform);
ReferencedEnvelope mercatorBounds = new ReferencedEnvelope(mercatorEnvelope, mercatorCrs);
MathTransform transform = CRS.findMathTransform(boundsCrs, latLongCrs);
Envelope latLongBounds = JTS.transform(inBounds, transform);
Coordinate latLongCentre = latLongBounds.centre();
File inFolder = new File(inPath);
File baseFolder = new File(inFolder, pName);
double w = latLongBounds.getMinX();
double s = latLongBounds.getMinY();
double e = latLongBounds.getMaxX();
double n = latLongBounds.getMaxY();
GlobalMercator mercator = new GlobalMercator();
for( int z = pMinzoom; z <= pMaxzoom; z++ ) {
// get ul and lr tile number in GOOGLE tiles
int[] llTileXY = mercator.GoogleTile(s, w, z);
int[] urTileXY = mercator.GoogleTile(n, e, z);
int startXTile = Math.min(llTileXY[0], urTileXY[0]);
int endXTile = Math.max(llTileXY[0], urTileXY[0]);
int startYTile = Math.min(llTileXY[1], urTileXY[1]);
int endYTile = Math.max(llTileXY[1], urTileXY[1]);
int tileNum = 0;
ReferencedEnvelope levelBounds = new ReferencedEnvelope();
pm.beginTask("Generating tiles at zoom level: " + z, (endXTile - startXTile + 1));
for( int i = startXTile; i <= endXTile; i++ ) {
for( int j = startYTile; j <= endYTile; j++ ) {
tileNum++;
double[] bounds = mercator.TileLatLonBounds(i, j, z);
double west = bounds[0];
double south = bounds[1];
double east = bounds[2];
double north = bounds[3];
ReferencedEnvelope tmpBounds = new ReferencedEnvelope(west, east, south, north, latLongCrs);
levelBounds.expandToInclude(tmpBounds);
if (!doDryrun) {
int[] onlineTileNumbers = {i, j};
int[] fileNameTileNumbers = {i, j};
// switch( pType ) {
// case 1:
// need to convert in TMS format
int[] tmsNUms = mercator.TMSTileFromGoogleTile(i, j, z);
fileNameTileNumbers = tmsNUms;
// break;
// case 0:
// default:
// break;
// }
File imageFolder = new File(baseFolder, z + "/" + fileNameTileNumbers[0]);
if (!imageFolder.exists()) {
if (!imageFolder.mkdirs()) {
throw new ModelsIOException("Unable to create folder:" + imageFolder, this);
}
}
File imageFile = new File(imageFolder, fileNameTileNumbers[1] + ".png");
if (imageFile.exists()) {
continue;
}
String tmp = inServiceUrl.replaceFirst("ZZZ", String.valueOf(z));
tmp = tmp.replaceFirst("XXX", String.valueOf(onlineTileNumbers[0]));
tmp = tmp.replaceFirst("YYY", String.valueOf(onlineTileNumbers[1]));
// System.out.println(tmp);
URL url = new URL(tmp);
InputStream imgStream = null;
OutputStream out = null;
try {
imgStream = url.openStream();
out = new FileOutputStream(imageFile);
int read = 0;
byte[] bytes = new byte[1024];
while( (read = imgStream.read(bytes)) != -1 ) {
out.write(bytes, 0, read);
}
} catch (Exception ex) {
pm.errorMessage("Unable to get image: " + tmp);
} finally {
if (imgStream != null)
imgStream.close();
if (out != null) {
out.flush();
out.close();
}
}
}
}
pm.worked(1);
}
pm.done();
pm.message("Zoom level: " + z + " has " + tileNum + " tiles.");
pm.message("Boundary covered at Zoom level: " + z + ": " + levelBounds);
pm.message("Total boundary wanted: " + mercatorBounds);
}
StringBuilder properties = new StringBuilder();
properties.append("url=").append(pName).append("/ZZZ/XXX/YYY.png\n");
properties.append("minzoom=").append(pMinzoom).append("\n");
properties.append("maxzoom=").append(pMaxzoom).append("\n");
properties.append("center=").append(latLongCentre.x).append(" ").append(latLongCentre.y).append("\n");
properties.append("type=tms").append("\n");
File propFile = new File(inFolder, pName + ".mapurl");
FileUtilities.writeFile(properties.toString(), propFile);
}
}