// ********************************************************************** // // <copyright> // // BBN Technologies // 10 Moulton Street // Cambridge, MA 02138 // (617) 873-8000 // // Copyright (C) BBNT Solutions LLC. All rights reserved. // // </copyright> // ********************************************************************** // // $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/dataAccess/image/ImageTile.java,v $ // $RCSfile: ImageTile.java,v $ // $Revision: 1.5 $ // $Date: 2009/01/21 01:24:42 $ // $Author: dietrick $ // // ********************************************************************** package com.bbn.openmap.dataAccess.image; import java.awt.Color; import java.awt.Image; import java.awt.geom.Point2D; import java.awt.image.BufferedImage; import java.io.Serializable; import com.bbn.openmap.omGraphics.OMGraphic; import com.bbn.openmap.omGraphics.OMScalingRaster; import com.bbn.openmap.proj.Projection; import com.bbn.openmap.util.cacheHandler.CacheHandler; import com.bbn.openmap.util.cacheHandler.CacheObject; /** * This is an extension to OMRaster that automatically scales itself to match * the current projection. It is only lat/lon based, and takes the coordinates * of the upper left and lower right corners of the image. It does straight * scaling - it does not force the image projection to match the map projection! * So, your mileage may vary - you have to understand the projection of the * image, and know how it fits the projection type of the map. Of course, at * larger scales, it might not matter so much. * * This class was inspired by, and created from parts of the ImageLayer * submission from Adrian Lumsden@sss, on 25-Jan-2002. Used the scaling and * trimming code from that submission. That code was also developed with * assistance from Steve McDonald at SiliconSpaceships.com. * * @see com.bbn.openmap.omGraphics.OMRaster * @see com.bbn.openmap.omGraphics.OMRasterObject */ public class ImageTile extends OMScalingRaster implements Serializable { protected ImageReader imageDecoder; protected CacheHandler cache; /** * Construct a blank OMRaster, to be filled in with set calls. Make sure you * set either a source image or ImageDecoder that knows how to get the * image. */ public ImageTile() { super(); } // //////////////////////////////////// IMAGEICON /** * Create an OMRaster, Lat/Lon placement with an ImageIcon. * * @param ullat latitude of the top of the image. * @param ullon longitude of the left side of the image. * @param lrlat latitude of the bottom of the image. * @param lrlon longitude of the right side of the image. * @param imageDecoder ImageReader for Image. * @param cache CacheHandler holding cached images. */ public ImageTile(double ullat, double ullon, double lrlat, double lrlon, ImageReader imageDecoder, CacheHandler cache) { super(); setRenderType(OMGraphic.RENDERTYPE_LATLON); setColorModel(COLORMODEL_IMAGEICON); lat = ullat; lon = ullon; lat2 = lrlat; lon2 = lrlon; this.imageDecoder = imageDecoder; this.cache = cache; } /** * Create an OMRaster, Lat/Lon placement with an ImageIcon. * * @param ullat latitude of the top of the image. * @param ullon longitude of the left side of the image. * @param lrlat latitude of the bottom of the image. * @param lrlon longitude of the right side of the image. * @param image BufferedImage used for the image. */ public ImageTile(double ullat, double ullon, double lrlat, double lrlon, BufferedImage image) { super(ullat, ullon, lrlat, lrlon, image); } protected Boolean realSelection = null; public static Color DEFAULT_NON_CLEAR_FILL_PAINT = new Color(200, 200, 200, 100); public void setSelected(boolean setting) { if (realSelection != null) { realSelection = Boolean.valueOf(setting); if (setting) { displayPaint = getSelectPaint(); } else { displayPaint = getLinePaint(); } } else { super.setSelected(setting); } } /** * Checking to see of the image needs to be updated for the projection * parameters, namely scale. * * @param proj current projection * @return true if the image scale, as projected, isn't being shrunk down * too much, and the image should be displayed. */ protected boolean shouldFetchForProjection(Projection proj) { Point2D anchor1 = new Point2D.Double(lat, lon); Point2D anchor2 = new Point2D.Double(lat2, lon2); float imageScale = com.bbn.openmap.proj.ProjMath.getScale(anchor1, anchor2, proj); float scaleRatio = Cache.DEFAULT_SCALE_RATIO; // Something somewhat // reasonable, a default. if (cache instanceof Cache) { scaleRatio = ((Cache) cache).getCutoffScaleRatio(); } return (imageScale * scaleRatio) <= proj.getScale(); } /** * Called from within generate. * * @param proj current projection. * @return false if the rest of generate() should be skipped, if the image * doesn't need to be formed for the current projection. */ protected boolean updateImageForProjection(Projection proj) { // point1 and point2 are not yet set for a changed projection position(proj); if (imageDecoder != null) { if (!isOnMap(proj)) { setNeedToRegenerate(true); return false; } // Check the scale against the cache to see if we should do // anything. if (shouldFetchForProjection(proj)) { if (realSelection == null) { if (getFillPaint() == com.bbn.openmap.omGraphics.OMColor.clear) { setFillPaint(DEFAULT_NON_CLEAR_FILL_PAINT); } realSelection = Boolean.valueOf(selected); } selected = true; setShape(); setNeedToRegenerate(false); return false; } else if (realSelection != null) { if (getFillPaint() == DEFAULT_NON_CLEAR_FILL_PAINT) { setFillPaint(com.bbn.openmap.omGraphics.OMColor.clear); } setFillPaint(com.bbn.openmap.omGraphics.OMColor.clear); selected = realSelection.booleanValue(); realSelection = null; } if (bitmap == null) { if (cache != null) { setImage((Image) cache.get(imageDecoder)); } else { setImage(imageDecoder.getBufferedImage()); } } } return true; } public boolean regenerate(Projection p) { return generate(p); } public ImageReader getImageDecoder() { return imageDecoder; } public void setImageDecoder(ImageReader imageDecoder) { this.imageDecoder = imageDecoder; } public static class Cache extends CacheHandler { public final static float DEFAULT_SCALE_RATIO = 5f; protected float cutoffScaleRatio = DEFAULT_SCALE_RATIO; public Cache() { super(10); } public Cache(int maxSize) { super(maxSize); } public void setCutoffScaleRatio(float scale) { cutoffScaleRatio = scale; } public float getCutoffScaleRatio() { return cutoffScaleRatio; } /** * Returns a CacheObject that will be loaded into the cache. The key * should be an ImageDecoder, and the object in the cache object will be * the BufferedImage that will get inserted into the ImageTile. */ public CacheObject load(Object key) { try { if (key instanceof ImageReader) { // URL imageURL = PropUtils.getResourceOrFileOrURL(key); // // FileCacheImageInputStream fciis = new // FileCacheImageInputStream(imageURL.openStream(), null); // BufferedImage fileImage = ImageIO.read(fciis); BufferedImage fileImage = ((ImageReader) key).getBufferedImage(); return new CacheObject(key, fileImage); } } catch (Exception e) { } // Catch errors return null; } } }