// 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; } }