/*******************************************************************************
* Copyright 2012 Geoscience Australia
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
******************************************************************************/
package au.gov.ga.earthsci.worldwind.common.terrain;
import gov.nasa.worldwind.WorldWind;
import gov.nasa.worldwind.avlist.AVKey;
import gov.nasa.worldwind.avlist.AVList;
import gov.nasa.worldwind.avlist.AVListImpl;
import gov.nasa.worldwind.util.BufferWrapper;
import gov.nasa.worldwind.util.Logging;
import gov.nasa.worldwind.util.Tile;
import gov.nasa.worldwind.util.TileKey;
import gov.nasa.worldwind.util.TileUrlBuilder;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URL;
import org.w3c.dom.Element;
import au.gov.ga.earthsci.worldwind.common.util.AVKeyMore;
import au.gov.ga.earthsci.worldwind.common.util.IOUtil;
import au.gov.ga.earthsci.worldwind.common.util.URLUtil;
import au.gov.ga.earthsci.worldwind.common.util.Util;
/**
* Elevation model that retrieves its elevation data from elevation tiles stored
* in a directory in the local file system.
*
* @author Michael de Hoog (michael.dehoog@ga.gov.au)
*/
public class FileElevationModel extends BoundedBasicElevationModel
{
public FileElevationModel(Element domElement, AVList params)
{
super(getBasicElevationModelConfigParams(domElement, createURLBuilderParam(params)));
}
protected static AVList createURLBuilderParam(AVList params)
{
if (params == null)
{
params = new AVListImpl();
}
URL context = (URL) params.getValue(AVKeyMore.CONTEXT_URL);
params.setValue(AVKey.TILE_URL_BUILDER, new FileURLBuilder(context));
return params;
}
/**
* TileUrlBuilder implementation that creates file:// URLs pointing to
* elevation tiles stored locally.
*
* @author Michael de Hoog
*/
protected static class FileURLBuilder implements TileUrlBuilder
{
private URL context;
public FileURLBuilder(URL context)
{
this.context = context;
}
@Override
public URL getURL(Tile tile, String imageFormat) throws MalformedURLException
{
return Util.getLocalTileURL(tile.getLevel().getService(), tile.getLevel().getDataset(),
tile.getLevelNumber(), tile.getRow(), tile.getColumn(), context, imageFormat, "bil");
}
}
protected String getImageFormat()
{
AVList params = (AVList) getValue(AVKey.CONSTRUCTION_PARAMETERS);
if (params != null)
{
return params.getStringValue(AVKey.IMAGE_FORMAT);
}
return null;
}
@Override
protected void requestTile(TileKey key)
{
if (WorldWind.getTaskService().isFull())
{
return;
}
if (this.getLevels().isResourceAbsent(key))
{
return;
}
RequestTask request = new RequestTask(key, this);
WorldWind.getTaskService().addTask(request);
}
@Override
protected BufferWrapper readElevations(URL url) throws IOException
{
//overridden to handle unzipping the file if required
if (!URLUtil.isForResourceWithExtension(url, "zip"))
{
return super.readElevations(url);
}
try
{
return IOUtil.readByteBuffer(url, this.getElevationDataType(), this.getElevationDataByteOrder());
}
catch (java.io.IOException e)
{
Logging.logger().log(java.util.logging.Level.SEVERE, "ElevationModel.ExceptionReadingElevationFile", url.toString());
throw e;
}
}
/**
* This {@link RequestTask} creates elevation tile requests passing the
* image format returned by the getImageFormat() function. It also skips
* calling the downloadElevations() function, as the tiles are stored
* locally and don't need to be downloaded.
*
* @author Michael de Hoog
*/
protected static class RequestTask implements Runnable
{
protected final FileElevationModel elevationModel;
protected final TileKey tileKey;
protected RequestTask(TileKey tileKey, FileElevationModel elevationModel)
{
this.elevationModel = elevationModel;
this.tileKey = tileKey;
}
@Override
public final void run()
{
//modified to load tiles directly from ResourceURL instead of checking
//cache and downloading non-existant tiles
try
{
// check to ensure load is still needed
if (elevationModel.areElevationsInMemory(tileKey))
{
return;
}
ElevationTile tile = elevationModel.createTile(tileKey);
final URL url = tile.getResourceURL(elevationModel.getImageFormat());
if (url != null && elevationModel.loadElevations(tile, url))
{
elevationModel.getLevels().unmarkResourceAbsent(tile);
elevationModel.firePropertyChange(AVKey.ELEVATION_MODEL, null, this);
}
else
{
elevationModel.getLevels().markResourceAbsent(tile);
}
}
catch (IOException e)
{
String msg = Logging.getMessage("ElevationModel.ExceptionRequestingElevations", tileKey.toString());
Logging.logger().log(java.util.logging.Level.FINE, msg, e);
}
}
@Override
public final boolean equals(Object o)
{
if (this == o)
{
return true;
}
if (o == null || getClass() != o.getClass())
{
return false;
}
final RequestTask that = (RequestTask) o;
if (this.tileKey != null ? !this.tileKey.equals(that.tileKey) : that.tileKey != null)
{
return false;
}
return true;
}
@Override
public final int hashCode()
{
return (this.tileKey != null ? this.tileKey.hashCode() : 0);
}
@Override
public final String toString()
{
return this.tileKey.toString();
}
}
}