All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gov.nasa.worldwind.layers.SurfaceImageLayer Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2012 United States Government as represented by the Administrator of the
 * National Aeronautics and Space Administration.
 * All Rights Reserved.
 */
package gov.nasa.worldwind.layers;

import gov.nasa.worldwind.avlist.*;
import gov.nasa.worldwind.data.*;
import gov.nasa.worldwind.exception.WWRuntimeException;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.render.*;
import gov.nasa.worldwind.util.*;

import javax.imageio.ImageIO;
import java.awt.image.*;
import java.io.*;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * Displays a collection of local images on the globe.
 * 

* Note: The view input handlers detect surface images rather than the terrain as the top picked object in {@link * gov.nasa.worldwind.event.SelectEvent}s and will not respond to the user's attempts at navigation when the cursor is * over the image. If this is not the desired behavior, disable picking for the layer containing the surface image. * * @author tag * @version $Id: SurfaceImageLayer.java 1171 2013-02-11 21:45:02Z dcollins $ */ public class SurfaceImageLayer extends RenderableLayer { protected ImageTiler imageTiler = new ImageTiler(); protected ConcurrentHashMap> imageTable = new ConcurrentHashMap>(); protected BasicDataRasterReaderFactory factory = new BasicDataRasterReaderFactory(); @Override public void dispose() { super.dispose(); this.imageTable.clear(); } /** * Add an image to the collection, reprojecting it to geographic (latitude & longitude) coordinates if necessary. * The image's location is determined from metadata files co-located with the image file. The number, names and * contents of these files are governed by the type of the specified image. Location metadata must be available. *

* If projection information is available and reprojection of the image's projection type is supported, the image * will be reprojected to geographic coordinates. If projection information is not available then it's assumed that * the image is already in geographic projection. *

* Only reprojection from UTM is currently provided. * * @param imagePath the path to the image file. * * @throws IllegalArgumentException if the image path is null. * @throws IOException if an error occurs reading the image file. * @throws IllegalStateException if an error occurs while reprojecting or otherwise processing the image. * @throws WWRuntimeException if the image type is unsupported. */ public void addImage(final String imagePath) throws IOException { DataRaster raster = this.openDataRaster(imagePath, null); final BufferedImage image = this.getBufferedImage(raster); if (null != raster && image != null) { addImage(imagePath, image, raster.getSector()); } else { String message = Logging.getMessage("generic.ImageReadFailed", imagePath); Logging.logger().severe(message); throw new WWRuntimeException(message); } } protected BufferedImage getBufferedImage(DataRaster raster) { if (null == raster) return null; if (raster instanceof GDALDataRaster) { AVList params = new AVListImpl(); params.setValue(AVKey.WIDTH, raster.getWidth()); params.setValue(AVKey.HEIGHT, raster.getHeight()); params.setValue(AVKey.SECTOR, raster.getSector()); raster = raster.getSubRaster(params); } if (raster instanceof BufferedImageRaster) { return ((BufferedImageRaster) raster).getBufferedImage(); } if (raster instanceof BufferWrapperRaster) { return ImageUtil.visualize((BufferWrapperRaster) raster); } return null; } protected DataRaster openDataRaster(Object src, AVList params) throws IllegalArgumentException, WWRuntimeException { if (src == null) { String message = Logging.getMessage("nullValue.ImageSource"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } final File rasterFile = WWIO.getFileForLocalAddress(src); if (null == rasterFile || !rasterFile.exists()) { String message = Logging.getMessage("generic.FileNotFound", src); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (null == params) params = new AVListImpl(); DataRaster raster; try { DataRasterReader reader = factory.findReaderFor(rasterFile, params); DataRaster[] rasters = reader.read(rasterFile, params); if (null == rasters || rasters.length == 0 || null == rasters[0]) { String message = Logging.getMessage("generic.ImageReadFailed", src); Logging.logger().severe(message); throw new WWRuntimeException(message); } raster = rasters[0]; if (raster.getSector() == null && params.hasKey(AVKey.SECTOR)) { Object o = params.getValue(AVKey.SECTOR); if (null != o && o instanceof Sector) { Sector sector = (Sector) o; if (raster instanceof GDALDataRaster) ((GDALDataRaster) raster).setSector(sector); else raster.setValue(AVKey.SECTOR, sector); } } if (raster.getSector() == null) { String reason = Logging.getMessage("nullValue.SpatialReferenceIsNull"); String message = Logging.getMessage("generic.ImageReadFailed", src + ":" + reason); Logging.logger().severe(message); throw new WWRuntimeException(message); } } catch (WWRuntimeException wwre) { throw wwre; } catch (Throwable t) { String reason = WWUtil.extractExceptionReason(t); String message = Logging.getMessage("generic.ImageReadFailed", reason); Logging.logger().severe(message); throw new WWRuntimeException(message); } return raster; } /** * Add an image to the collection and specify its coverage. The image is assumed to be in geographic projection * (latitude & longitude). * * @param imagePath the path to the image file. * @param sector the geographic location of the image. * * @throws IllegalArgumentException if the image path or sector is null. * @throws IOException if an error occurs reading the image file. * @throws WWRuntimeException if the image type is unsupported. */ @SuppressWarnings({"UnusedDeclaration"}) public void addImage(String imagePath, Sector sector) throws IOException, WWRuntimeException { AVList params = new AVListImpl(); if (null != sector) params.setValue(AVKey.SECTOR, sector); DataRaster raster = this.openDataRaster(imagePath, params); final BufferedImage image = this.getBufferedImage(raster); if (null != raster && image != null) { Sector rasterSector = raster.getSector(); rasterSector = (null == rasterSector) ? sector : rasterSector; addImage(imagePath, image, rasterSector); } else { String message = Logging.getMessage("generic.ImageReadFailed", imagePath); Logging.logger().severe(message); throw new WWRuntimeException(message); } } /** * Add a {@link BufferedImage} to the collection at an explicitly specified location. The image is assumed to be in * geographic projection (latitude & longitude). * * @param name a unique name to associate with the image so that it can be subsequently referred to without having * to keep a reference to the image itself. Use this name in calls to {@link #removeImage(String)}. * @param image the image to add. * @param sector the geographic location of the image. * * @throws IllegalArgumentException if the image path or sector is null. * @throws WWRuntimeException if the image type is unsupported. */ public void addImage(String name, BufferedImage image, Sector sector) { if (name == null) { String message = Logging.getMessage("nullValue.NameIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (image == null) { String message = Logging.getMessage("nullValue.ImageSource"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (sector == null) { String message = Logging.getMessage("nullValue.SectorIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (this.imageTable.contains(name)) this.removeImage(name); final ArrayList surfaceImages = new ArrayList(); this.imageTable.put(name, surfaceImages); this.imageTiler.tileImage(image, sector, new ImageTiler.ImageTilerListener() { public void newTile(BufferedImage tileImage, Sector tileSector) { try { File tempFile = File.createTempFile("wwj-", ".png"); tempFile.deleteOnExit(); ImageIO.write(tileImage, "png", tempFile); SurfaceImage si = new SurfaceImage(tempFile.getPath(), tileSector); surfaceImages.add(si); si.setOpacity(SurfaceImageLayer.this.getOpacity()); SurfaceImageLayer.this.addRenderable(si); } catch (IOException e) { String message = Logging.getMessage("generic.ImageReadFailed"); Logging.logger().severe(message); } } public void newTile(BufferedImage tileImage, List corners) { } }); } /** * Add an image to the collection at an explicitly specified location. The image is assumed to be in geographic * projection (latitude & longitude). * * @param imagePath the path to the image file. * @param corners the geographic location of the image's corners, specified in order of lower-left, lower-right, * upper-right, upper-left. * * @throws IllegalArgumentException if the image path or sector is null. * @throws IOException if an error occurs reading the image file. * @throws WWRuntimeException if the image type is unsupported. */ public void addImage(String imagePath, List corners) throws IOException, WWRuntimeException { AVList params = new AVListImpl(); if (null != corners) { Sector sector = Sector.boundingSector(corners); params.setValue(AVKey.SECTOR, sector); } DataRaster raster = this.openDataRaster(imagePath, params); final BufferedImage image = this.getBufferedImage(raster); if (null != raster && image != null) { this.addImage(imagePath, image, corners); } else { String message = Logging.getMessage("generic.ImageReadFailed", imagePath); Logging.logger().severe(message); throw new WWRuntimeException(message); } } /** * Add a {@link BufferedImage} to the collection at an explicitly specified location. The image is assumed to be in * geographic projection (latitude & longitude). * * @param name a unique name to associate with the image so that it can be subsequently referred to without * having to keep a reference to the image itself. Use this name in calls to {@link * #removeImage(String)}. * @param image the image to add. * @param corners the geographic location of the image's corners, specified in order of lower-left, lower-right, * upper-right, upper-left. * * @throws IllegalArgumentException if the image path is null, the corners list is null, contains null values or * fewer than four locations. * @throws WWRuntimeException if the image type is unsupported. */ public void addImage(String name, BufferedImage image, List corners) { if (name == null) { String message = Logging.getMessage("nullValue.NameIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (image == null) { String message = Logging.getMessage("nullValue.ImageSource"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (corners == null) { String message = Logging.getMessage("nullValue.LocationsListIsNull"); Logging.logger().severe(message); throw new IllegalArgumentException(message); } if (this.imageTable.contains(name)) this.removeImage(name); final ArrayList surfaceImages = new ArrayList(); this.imageTable.put(name, surfaceImages); this.imageTiler.tileImage(image, corners, new ImageTiler.ImageTilerListener() { public void newTile(BufferedImage tileImage, Sector tileSector) { } public void newTile(BufferedImage tileImage, List corners) { SurfaceImage si = new SurfaceImage(tileImage, corners); surfaceImages.add(si); si.setOpacity(SurfaceImageLayer.this.getOpacity()); SurfaceImageLayer.this.addRenderable(si); } }); } public void removeImage(String imagePath) { ArrayList images = this.imageTable.get(imagePath); if (images == null) return; this.imageTable.remove(imagePath); for (SurfaceImage si : images) { if (si != null) this.removeRenderable(si); } } @Override public void setOpacity(double opacity) { super.setOpacity(opacity); for (Map.Entry> entry : this.imageTable.entrySet()) { for (SurfaceImage si : entry.getValue()) { if (si != null) si.setOpacity(opacity); } } } @SuppressWarnings({"UnusedDeclaration"}) public int getNumImages() { int count = 0; for (ArrayList images : this.imageTable.values()) { count += images.size(); } return count; } /** * Create an image for the portion of this layer lying within a specified sector. The image is created at a * specified aspect ratio within a canvas of a specified size. * * @param sector the sector of interest. * @param canvasWidth the width of the canvas. * @param canvasHeight the height of the canvas. * @param aspectRatio the aspect ratio, width/height, of the window. If the aspect ratio is greater or equal to * one, the full width of the canvas is used for the image; the height used is proportional to * the inverse of the aspect ratio. If the aspect ratio is less than one, the full height of the * canvas is used, and the width used is proportional to the aspect ratio. * @param image if non-null, a {@link BufferedImage} in which to place the image. If null, a new buffered * image of type {@link BufferedImage#TYPE_INT_RGB} is created. The image must be the width and * height specified in the canvasWidth and canvasHeight arguments. * * @return image the assembelled image, of size indicated by the canvasWidth and * canvasHeight. If the specified aspect ratio is one, all pixels contain values. If the aspect * ratio is greater than one, a full-width segment along the top of the canvas is blank. If the aspect ratio * is less than one, a full-height segment along the right side of the canvase is blank. If the * image argument was non-null, that buffered image is returned. * * @see ImageUtil#mergeImage(Sector, Sector, double, BufferedImage, BufferedImage) */ @SuppressWarnings({"UnusedDeclaration"}) public BufferedImage composeImageForSector(Sector sector, int canvasWidth, int canvasHeight, double aspectRatio, BufferedImage image) { if (sector == null) { String message = Logging.getMessage("nullValue.SectorIsNull"); Logging.logger().severe(message); throw new IllegalStateException(message); } if (!this.getRenderables().iterator().hasNext()) { Logging.logger().severe(Logging.getMessage("generic.NoImagesAvailable")); return null; } if (image == null) image = new BufferedImage(canvasWidth, canvasHeight, BufferedImage.TYPE_INT_RGB); for (Renderable r : this.getRenderables()) { SurfaceImage si = (SurfaceImage) r; if (si.getImageSource() == null) continue; BufferedImage sourceImage = null; try { if (si.getImageSource() instanceof String) sourceImage = ImageIO.read(new File((String) si.getImageSource())); else sourceImage = (BufferedImage) si.getImageSource(); } catch (IOException e) { Logging.logger().severe(Logging.getMessage("generic.ExceptionAttemptingToReadImageFile", sourceImage)); return null; } ImageUtil.mergeImage(sector, si.getSector(), aspectRatio, sourceImage, image); } return image; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy