tiledrasterproducer.java
来自「world wind java sdk 源码」· Java 代码 · 共 965 行 · 第 1/3 页
JAVA
965 行
/* Copyright (C) 2001, 2008 United States Government as represented by
the Administrator of the National Aeronautics and Space Administration.
All Rights Reserved.
*/
package gov.nasa.worldwind.data;
import gov.nasa.worldwind.*;
import gov.nasa.worldwind.avlist.*;
import gov.nasa.worldwind.cache.*;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.util.*;
/**
* @author dcollins
* @version $Id: TiledRasterProducer.java 8329 2009-01-05 21:29:51Z dcollins $
*/
public abstract class TiledRasterProducer extends AbstractDataStoreProducer
{
private static final long DEFAULT_TILED_RASTER_PRODUCER_CACHE_SIZE = 300000000L; // ~300 megabytes
private static final int DEFAULT_TILED_RASTER_PRODUCER_LARGE_DATASET_THRESHOLD = 3000; // 3000 pixels
private static final int DEFAULT_WRITE_THREAD_POOL_SIZE = 2;
private static final int DEFAULT_TILE_WIDTH_AND_HEIGHT = 512;
private static final int DEFAULT_SINGLE_LEVEL_TILE_WIDTH_AND_HEIGHT = 512;
private static final double DEFAULT_LEVEL_ZERO_TILE_DELTA = 36d;
// List of source data rasters.
private java.util.List<DataRaster> dataRasterList = new java.util.ArrayList<DataRaster>();
// Data raster caching.
private MemoryCache rasterCache;
// Concurrent processing helper objects.
private final java.util.concurrent.ExecutorService tileWriteService;
private final java.util.concurrent.Semaphore tileWriteSemaphore;
private final Object fileLock = new Object();
// Progress counters.
private int tile;
private int tileCount;
public TiledRasterProducer(MemoryCache cache, int writeThreadPoolSize)
{
if (cache == null)
{
String message = Logging.getMessage("nullValue.CacheIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
if (writeThreadPoolSize < 1)
{
String message = Logging.getMessage("generic.ArgumentOutOfRange", "writeThreadPoolSize < 1");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.rasterCache = cache;
this.tileWriteService = this.createDefaultTileWriteService(writeThreadPoolSize);
this.tileWriteSemaphore = new java.util.concurrent.Semaphore(writeThreadPoolSize, true);
}
public TiledRasterProducer()
{
this(createDefaultCache(), DEFAULT_WRITE_THREAD_POOL_SIZE);
}
// TODO: this describes the file types the producer will read. Make that more clear in the method name.
public String getDataSourceDescription()
{
DataRasterReader[] readers = this.getDataRasterReaders();
if (readers == null || readers.length < 1)
return "";
// Collect all the unique format suffixes available in all readers. If a reader does not publish any
// format suffixes, then collect it's description.
java.util.Set<String> suffixSet = new java.util.TreeSet<String>();
java.util.Set<String> descriptionSet = new java.util.TreeSet<String>();
for (DataRasterReader reader : readers)
{
String description = reader.getDescription();
String[] names = reader.getSuffixes();
if (names != null && names.length > 0)
suffixSet.addAll(java.util.Arrays.asList(names));
else
descriptionSet.add(description);
}
// Create a string representaiton of the format suffixes (or description if no suffixes are available) for
// all readers.
StringBuilder sb = new StringBuilder();
for (String suffix : suffixSet)
{
if (sb.length() > 0)
sb.append(", ");
sb.append("*.").append(suffix);
}
for (String description : descriptionSet)
{
if (sb.length() > 0)
sb.append(", ");
sb.append(description);
}
return sb.toString();
}
public void removeProductionState()
{
java.io.File installLocation = this.installLocationFor(this.getStoreParameters());
if (installLocation == null || !installLocation.exists())
{
String message = "Install location is null or does not exist";
Logging.logger().warning(message);
return;
}
try
{
WWIO.deleteDirectory(installLocation);
}
catch (Exception e)
{
String message = "Exception while removing install location";
Logging.logger().log(java.util.logging.Level.SEVERE, message, e);
}
}
protected abstract DataRaster createDataRaster(int width, int height, Sector sector, AVList params);
protected abstract DataRasterReader[] getDataRasterReaders();
protected abstract DataRasterWriter[] getDataRasterWriters();
protected MemoryCache getCache()
{
return this.rasterCache;
}
protected java.util.concurrent.ExecutorService getTileWriteService()
{
return this.tileWriteService;
}
protected java.util.concurrent.Semaphore getTileWriteSemaphore()
{
return this.tileWriteSemaphore;
}
protected void doStartProduction(AVList parameters) throws Exception
{
// Copy production parameters to prevent changes to caller's reference.
AVList productionParams = parameters.copy();
this.initProductionParameters(productionParams);
// Assemble the source data rasters.
this.assembleDataRasters();
// Initialize the level set parameters, and create the level set.
this.initLevelSetParameters(productionParams);
LevelSet levelSet = new LevelSet(productionParams);
// Install the each tiles of the LevelSet.
this.installLevelSet(levelSet, productionParams);
// Wait for concurrent tasks to complete.
this.waitForInstallTileTasks();
// Clear the raster cache.
this.getCache().clear();
// Install the data descriptor for this tiled raster set.
this.installDataDescriptor(productionParams);
}
protected String validateProductionParameters(AVList parameters)
{
StringBuilder sb = new StringBuilder();
Object o = parameters.getValue(AVKey.FILE_STORE_LOCATION);
if (o == null || !(o instanceof String) || ((String) o).length() < 1)
sb.append((sb.length() > 0 ? ", " : "")).append(Logging.getMessage("term.fileStoreLocation"));
o = parameters.getValue(AVKey.DATA_CACHE_NAME);
if (o == null || !(o instanceof String) || ((String) o).length() == 0)
sb.append((sb.length() > 0 ? ", " : "")).append(Logging.getMessage("term.fileStoreFolder"));
o = parameters.getValue(AVKey.DATASET_NAME);
if (o == null || !(o instanceof String) || ((String) o).length() < 1)
sb.append((sb.length() > 0 ? ", " : "")).append(Logging.getMessage("term.datasetName"));
if (sb.length() == 0)
return null;
return Logging.getMessage("DataStoreProducer.InvalidDataStoreParamters", sb.toString());
}
protected java.io.File installLocationFor(AVList params)
{
String fileStoreLocation = params.getStringValue(AVKey.FILE_STORE_LOCATION);
String dataCacheName = params.getStringValue(AVKey.DATA_CACHE_NAME);
if (fileStoreLocation == null || dataCacheName == null)
return null;
String path = appendPathPart(fileStoreLocation, dataCacheName);
if (path == null || path.length() < 1)
return null;
return new java.io.File(path);
}
//**************************************************************//
//******************** LevelSet Assembly *********************//
//**************************************************************//
protected void initProductionParameters(AVList params)
{
// Used by subclasses to specify default production parameters.
}
protected void initLevelSetParameters(AVList params)
{
int largeThreshold = Configuration.getIntegerValue(AVKey.TILED_RASTER_PRODUCER_LARGE_DATASET_THRESHOLD,
DEFAULT_TILED_RASTER_PRODUCER_LARGE_DATASET_THRESHOLD);
boolean isDataSetLarge = this.isDataSetLarge(this.dataRasterList, largeThreshold);
Sector sector = (Sector) params.getValue(AVKey.SECTOR);
if (sector == null)
{
// Compute a sector that bounds the data rasters. Make sure the sector does not exceed the limits of
// latitude and longitude.
sector = this.computeBoundingSector(this.dataRasterList);
if (sector != null)
sector = sector.intersection(Sector.FULL_SPHERE);
params.setValue(AVKey.SECTOR, sector);
}
Integer tileWidth = (Integer) params.getValue(AVKey.TILE_WIDTH);
if (tileWidth == null)
{
tileWidth = isDataSetLarge ? DEFAULT_TILE_WIDTH_AND_HEIGHT : DEFAULT_SINGLE_LEVEL_TILE_WIDTH_AND_HEIGHT;
params.setValue(AVKey.TILE_WIDTH, tileWidth);
}
Integer tileHeight = (Integer) params.getValue(AVKey.TILE_HEIGHT);
if (tileHeight == null)
{
tileHeight = isDataSetLarge ? DEFAULT_TILE_WIDTH_AND_HEIGHT : DEFAULT_SINGLE_LEVEL_TILE_WIDTH_AND_HEIGHT;
params.setValue(AVKey.TILE_HEIGHT, tileHeight);
}
LatLon rasterTileDelta = this.computeRasterTileDelta(tileWidth, tileHeight, this.dataRasterList);
LatLon desiredLevelZeroDelta = this.computeDesiredTileDelta(sector);
Integer numLevels = (Integer) params.getValue(AVKey.NUM_LEVELS);
if (numLevels == null)
{
// If the data set is large, then use compute a number of levels for the full pyramid. Otherwise use a
// single level.
numLevels = isDataSetLarge ? this.computeNumLevels(desiredLevelZeroDelta, rasterTileDelta) : 1;
params.setValue(AVKey.NUM_LEVELS, numLevels);
}
Integer numEmptyLevels = (Integer) params.getValue(AVKey.NUM_EMPTY_LEVELS);
if (numEmptyLevels == null)
{
numEmptyLevels = 0;
params.setValue(AVKey.NUM_EMPTY_LEVELS, numEmptyLevels);
}
LatLon levelZeroTileDelta = (LatLon) params.getValue(AVKey.LEVEL_ZERO_TILE_DELTA);
if (levelZeroTileDelta == null)
{
double scale = Math.pow(2d, numLevels - 1);
levelZeroTileDelta = LatLon.fromDegrees(
scale * rasterTileDelta.getLatitude().degrees,
scale * rasterTileDelta.getLongitude().degrees);
params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, levelZeroTileDelta);
}
LatLon tileOrigin = (LatLon) params.getValue(AVKey.TILE_ORIGIN);
if (tileOrigin == null)
{
tileOrigin = new LatLon(sector.getMinLatitude(), sector.getMinLongitude());
params.setValue(AVKey.TILE_ORIGIN, tileOrigin);
}
// If the default or caller-specified values define a level set that does not fit in the limits of latitude
// and longitude, then we re-define the level set parameters using values known to fit in those limits.
if (!this.isWithinLatLonLimits(sector, levelZeroTileDelta, tileOrigin))
{
String message = "TiledRasterProducer: native tiling is outside lat/lon limits. Falling back to default tiling.";
Logging.logger().warning(message);
levelZeroTileDelta = LatLon.fromDegrees(DEFAULT_LEVEL_ZERO_TILE_DELTA, DEFAULT_LEVEL_ZERO_TILE_DELTA);
params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, levelZeroTileDelta);
tileOrigin = new LatLon(Angle.NEG90, Angle.NEG180);
params.setValue(AVKey.TILE_ORIGIN, tileOrigin);
numLevels = this.computeNumLevels(levelZeroTileDelta, rasterTileDelta);
params.setValue(AVKey.NUM_LEVELS, numLevels);
int numLevelsNeeded = isDataSetLarge ? this.computeNumLevels(desiredLevelZeroDelta, rasterTileDelta) : 1;
numEmptyLevels = (numLevels > numLevelsNeeded) ? (numLevels - numLevelsNeeded) : 0;
params.setValue(AVKey.NUM_EMPTY_LEVELS, numEmptyLevels);
}
}
protected boolean isDataSetLarge(Iterable<? extends DataRaster> rasters, int largeThreshold)
{
Sector sector = this.computeBoundingSector(rasters);
LatLon pixelSize = this.computeSmallestPixelSize(rasters);
int sectorWidth = (int) Math.ceil(sector.getDeltaLonDegrees() / pixelSize.getLongitude().degrees);
int sectorHeight = (int) Math.ceil(sector.getDeltaLatDegrees() / pixelSize.getLatitude().degrees);
return (sectorWidth >= largeThreshold) || (sectorHeight >= largeThreshold);
}
protected boolean isWithinLatLonLimits(Sector sector, LatLon tileDelta, LatLon tileOrigin)
{
double minLat = Math.floor((sector.getMinLatitude().degrees - tileOrigin.getLatitude().degrees)
/ tileDelta.getLatitude().degrees);
minLat = tileOrigin.getLatitude().degrees + minLat * tileDelta.getLatitude().degrees;
double maxLat = Math.ceil((sector.getMaxLatitude().degrees - tileOrigin.getLatitude().degrees)
/ tileDelta.getLatitude().degrees);
maxLat = tileOrigin.getLatitude().degrees + maxLat * tileDelta.getLatitude().degrees;
double minLon = Math.floor((sector.getMinLongitude().degrees - tileOrigin.getLongitude().degrees)
/ tileDelta.getLongitude().degrees);
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?