// License: GPL. For details, see LICENSE file.
package org.openstreetmap.josm.plugins.lakewalker;
import static org.openstreetmap.josm.tools.I18n.tr;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.math.BigDecimal;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Vector;
import javax.imageio.ImageIO;
import org.openstreetmap.josm.gui.progress.ProgressMonitor;
public class LakewalkerWMS {
private BufferedImage image;
private int imagex;
private int imagey;
// Vector to cache images in memory
private List<BufferedImage> images = new Vector<>();
// Hashmap to hold the mapping of cached images
private Map<String, Integer> imageindex = new HashMap<>();
private int resolution;
private int tilesize;
private String wmslayer;
public LakewalkerWMS(int resolution, int tilesize, String wmslayer) {
this.resolution = resolution;
this.tilesize = tilesize;
this.wmslayer = wmslayer;
}
public BufferedImage getTile(int x, int y, ProgressMonitor progressMonitor) throws LakewalkerException {
progressMonitor.beginTask(tr("Downloading image tile..."));
try {
String layer = "global_mosaic_base";
int[] bottom_left_xy = new int[2];
bottom_left_xy[0] = floor(x, this.tilesize);
bottom_left_xy[1] = floor(y, this.tilesize);
int[] top_right_xy = new int[2];
top_right_xy[0] = bottom_left_xy[0] + this.tilesize;
top_right_xy[1] = bottom_left_xy[1] + this.tilesize;
double[] topright_geo = xy_to_geo(top_right_xy[0], top_right_xy[1], this.resolution);
double[] bottomleft_geo = xy_to_geo(bottom_left_xy[0], bottom_left_xy[1], this.resolution);
String filename = this.wmslayer+"/landsat_"+this.resolution+"_"+this.tilesize+
"_xy_"+bottom_left_xy[0]+"_"+bottom_left_xy[1]+".png";
// The WMS server only understands decimal points using periods, so we need
// to convert to a locale that uses that to build the proper URL
NumberFormat nf = NumberFormat.getInstance(Locale.ENGLISH);
DecimalFormat df = (DecimalFormat) nf;
df.applyLocalizedPattern("0.000000");
String urlloc = "http://onearth.jpl.nasa.gov/wms.cgi?request=GetMap&layers="+layer+
"&styles="+wmslayer+"&srs=EPSG:4326&format=image/png"+
"&bbox="+df.format(bottomleft_geo[1])+","+df.format(bottomleft_geo[0])+
","+df.format(topright_geo[1])+","+df.format(topright_geo[0])+
"&width="+this.tilesize+"&height="+this.tilesize;
File file = new File(LakewalkerPlugin.getLakewalkerCacheDir(), filename);
// Calculate the hashmap key
String hashkey = Integer.toString(bottom_left_xy[0])+":"+Integer.toString(bottom_left_xy[1]);
// See if this image is already loaded
if (this.image != null) {
if (this.imagex != bottom_left_xy[0] || this.imagey != bottom_left_xy[1]) {
// Check if this image exists in the hashmap
if (this.imageindex.containsKey(hashkey)) {
// Store which image we have
this.imagex = bottom_left_xy[0];
this.imagey = bottom_left_xy[1];
// Retrieve from cache
this.image = this.images.get(this.imageindex.get(hashkey));
return this.image;
} else {
this.image = null;
}
} else {
return this.image;
}
}
try {
System.out.println("Looking for image in disk cache: "+filename);
// Read from a file
this.image = ImageIO.read(file);
this.images.add(this.image);
this.imageindex.put(hashkey, this.images.size()-1);
} catch (FileNotFoundException e) {
System.out.println("Could not find cached image, downloading.");
} catch (IOException e) {
System.out.println(e.getMessage());
} catch (Exception e) {
System.out.println(e.getMessage());
}
if (this.image == null) {
/**
* Try downloading the image
*/
try {
System.out.println("Downloading from "+urlloc);
// Read from a URL
URL url = new URL(urlloc);
this.image = ImageIO.read(url); // this can return null!
} catch (MalformedURLException e) {
System.out.println(e.getMessage());
} catch (IOException e) {
System.out.println(e.getMessage());
} catch (Exception e) {
System.out.println(e.getMessage());
}
if (this.image != null) {
this.images.add(this.image);
this.imageindex.put(hashkey, this.images.size()-1);
this.saveimage(file, this.image);
}
}
this.imagex = bottom_left_xy[0];
this.imagey = bottom_left_xy[1];
if (this.image == null) {
throw new LakewalkerException(tr("Could not acquire image"));
}
return this.image;
} finally {
progressMonitor.finishTask();
}
}
public void saveimage(File file, BufferedImage image) {
/**
* Save the image to the cache
*/
try {
ImageIO.write(image, "png", file);
System.out.println("Saved image to cache");
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
public int getPixel(int x, int y, ProgressMonitor progressMonitor) throws LakewalkerException {
// Get the previously shown text
BufferedImage image = null;
try {
image = this.getTile(x, y, progressMonitor);
} catch (LakewalkerException e) {
System.out.println(e.getMessage());
throw e;
}
int tx = floor(x, this.tilesize);
int ty = floor(y, this.tilesize);
int pixel_x = (x-tx);
int pixel_y = (this.tilesize-1)-(y-ty);
//System.out.println("("+x+","+y+") maps to ("+pixel_x+","+pixel_y+") by ("+tx+", "+ty+")");
int rgb = image.getRGB(pixel_x, pixel_y);
int pixel;
int r = (rgb >> 16) & 0xff;
int g = (rgb >> 8) & 0xff;
int b = (rgb >> 0) & 0xff;
pixel = (int) ((0.30 * r) + (0.59 * b) + (0.11 * g));
return pixel;
}
public int floor(int num, int precision) {
double dnum = num/(double) precision;
BigDecimal val = new BigDecimal(dnum);
val = val.setScale(0, BigDecimal.ROUND_FLOOR);
return val.intValue()*precision;
}
public double floor(double num) {
BigDecimal val = new BigDecimal(num);
val = val.setScale(0, BigDecimal.ROUND_FLOOR);
return val.doubleValue();
}
public double[] xy_to_geo(int x, int y, double resolution) {
double[] geo = new double[2];
geo[0] = y / resolution;
geo[1] = x / resolution;
return geo;
}
public int[] geo_to_xy(double lat, double lon, double resolution) {
int[] xy = new int[2];
xy[0] = (int) Math.floor(lon * resolution + 0.5);
xy[1] = (int) Math.floor(lat * resolution + 0.5);
return xy;
}
}