import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
-import java.util.ArrayList;
+import java.util.HashSet;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
private boolean _normalTrack = true;
/** Flag set when any tiles had to be downloaded (rather than just loaded locally) */
private boolean _hadToDownload = false;
+ /** Count the number of tiles downloaded and cached */
+ private int _numCached = 0;
/** Flag to check whether this function is currently running or not */
private boolean _running = false;
*/
public void run()
{
- // Compile list of tiles to get
- ArrayList<SrtmTile> tileList = new ArrayList<SrtmTile>();
boolean hasZeroAltitudePoints = false;
boolean hasNonZeroAltitudePoints = false;
// First, loop to see what kind of points we have
}
// Now loop again to extract the required tiles
+ HashSet<SrtmTile> tileSet = new HashSet<SrtmTile>();
for (int i = 0; i < _track.getNumPoints(); i++)
{
// Consider points which don't have altitudes or have zero values
if (!_track.getPoint(i).hasAltitude()
|| (overwriteZeros && _track.getPoint(i).getAltitude().getValue() == 0))
{
- SrtmTile tile = new SrtmTile(_track.getPoint(i));
- boolean alreadyGot = false;
- for (int t = 0; t < tileList.size(); t++)
- {
- if (tileList.get(t).equals(tile)) {
- alreadyGot = true;
- }
- }
- if (!alreadyGot) {tileList.add(tile);}
+ tileSet.add(new SrtmTile(_track.getPoint(i)));
}
}
- lookupValues(tileList, overwriteZeros);
+ lookupValues(tileSet, overwriteZeros);
// Finished
_running = false;
// Show tip if lots of online lookups were necessary
if (_hadToDownload) {
_app.showTip(TipManager.Tip_DownloadSrtm);
}
+ else if (_numCached > 0) {
+ showConfirmMessage(_numCached);
+ }
}
/**
* Lookup the values from SRTM data
- * @param inTileList list of tiles to get
+ * @param inTileSet set of tiles to get
* @param inOverwriteZeros true to overwrite zero altitude values
*/
- private void lookupValues(ArrayList<SrtmTile> inTileList, boolean inOverwriteZeros)
+ private void lookupValues(HashSet<SrtmTile> inTileSet, boolean inOverwriteZeros)
{
UndoLookupSrtm undo = new UndoLookupSrtm(_app.getTrackInfo());
int numAltitudesFound = 0;
+ TileFinder tileFinder = new TileFinder();
+ String errorMessage = null;
+ final int numTiles = inTileSet.size();
+
// Update progress bar
if (_progress != null)
{
- _progress.setMaximum(inTileList.size());
+ _progress.setMaximum(numTiles);
_progress.setValue(0);
}
- String errorMessage = null;
- // Get urls for each tile
- URL[] urls = TileFinder.getUrls(inTileList);
- for (int t=0; t<inTileList.size() && !_progress.isCancelled(); t++)
+ int currentTileIndex = 0;
+ _numCached = 0;
+ for (SrtmTile tile : inTileSet)
{
- if (urls[t] != null)
+ URL url = tileFinder.getUrl(tile);
+ if (url != null)
{
- SrtmTile tile = inTileList.get(t);
try
{
// Set progress
- _progress.setValue(t);
+ _progress.setValue(currentTileIndex++);
final int ARRLENGTH = 1201 * 1201;
int[] heights = new int[ARRLENGTH];
// Open zipinputstream on url and check size
- ZipInputStream inStream = getStreamToHgtFile(urls[t]);
+ ZipInputStream inStream = getStreamToSrtmData(url);
boolean entryOk = false;
if (inStream != null)
{
if (entryOk)
{
- // Loop over all points in track, try to apply altitude from array
- for (int p = 0; p < _track.getNumPoints(); p++)
- {
- DataPoint point = _track.getPoint(p);
- if (!point.hasAltitude()
- || (inOverwriteZeros && point.getAltitude().getValue() == 0))
- {
- if (new SrtmTile(point).equals(tile))
- {
- double x = (point.getLongitude().getDouble() - tile.getLongitude()) * 1200;
- double y = 1201 - (point.getLatitude().getDouble() - tile.getLatitude()) * 1200;
- int idx1 = ((int)y)*1201 + (int)x;
- try
- {
- int[] fouralts = {heights[idx1], heights[idx1+1], heights[idx1-1201], heights[idx1-1200]};
- int numVoids = (fouralts[0]==VOID_VAL?1:0) + (fouralts[1]==VOID_VAL?1:0)
- + (fouralts[2]==VOID_VAL?1:0) + (fouralts[3]==VOID_VAL?1:0);
- // if (numVoids > 0) System.out.println(numVoids + " voids found");
- double altitude = 0.0;
- switch (numVoids)
- {
- case 0: altitude = bilinearInterpolate(fouralts, x, y); break;
- case 1: altitude = bilinearInterpolate(fixVoid(fouralts), x, y); break;
- case 2:
- case 3: altitude = averageNonVoid(fouralts); break;
- default: altitude = VOID_VAL;
- }
- // Special case for terrain tracks, don't interpolate voids yet
- if (!_normalTrack && numVoids > 0) {
- altitude = VOID_VAL;
- }
- if (altitude != VOID_VAL)
- {
- point.setFieldValue(Field.ALTITUDE, ""+altitude, false);
- // depending on settings, this value may have been added as feet, we need to force metres
- point.getAltitude().reset(new Altitude((int)altitude, UnitSetLibrary.UNITS_METRES));
- numAltitudesFound++;
- }
- }
- catch (ArrayIndexOutOfBoundsException obe) {
- // System.err.println("lat=" + point.getLatitude().getDouble() + ", x=" + x + ", y=" + y + ", idx=" + idx1);
- }
- }
- }
- }
+ numAltitudesFound += applySrtmTileToWholeTrack(tile, heights, inOverwriteZeros);
}
}
- catch (IOException ioe) {errorMessage = ioe.getClass().getName() + " - " + ioe.getMessage();
+ catch (IOException ioe) {
+ errorMessage = ioe.getClass().getName() + " - " + ioe.getMessage();
}
}
}
else if (errorMessage != null) {
_app.showErrorMessageNoLookup(getNameKey(), errorMessage);
}
- else if (inTileList.size() > 0) {
+ else if (numTiles > 0) {
_app.showErrorMessage(getNameKey(), "error.lookupsrtm.nonefound");
}
else {
* @param inUrl URL for online resource
* @return ZipInputStream either on the local file or on the downloaded zip file
*/
- private ZipInputStream getStreamToHgtFile(URL inUrl)
+ private ZipInputStream getStreamToSrtmData(URL inUrl)
+ throws IOException
+ {
+ ZipInputStream localData = null;
+ try {
+ localData = getStreamToLocalHgtFile(inUrl);
+ }
+ catch (IOException ioe) {
+ localData = null;
+ }
+ if (localData != null)
+ {
+ return localData;
+ }
+ // try to download to cache
+ TileDownloader cacher = new TileDownloader();
+ TileDownloader.Result result = cacher.downloadTile(inUrl);
+ // System.out.println("Result: " + result);
+ if (result == TileDownloader.Result.DOWNLOADED)
+ {
+ _numCached++;
+ return getStreamToLocalHgtFile(inUrl);
+ }
+ // If we don't have a cache, we may be able to download it temporarily
+ if (result != TileDownloader.Result.DOWNLOAD_FAILED)
+ {
+ _hadToDownload = true;
+ return new ZipInputStream(inUrl.openStream());
+ }
+ // everything failed
+ return null;
+ }
+
+ /**
+ * Get the SRTM file from the local cache, if available
+ * @param inUrl URL for online resource
+ * @return ZipInputStream on the local file or null if not there
+ */
+ private ZipInputStream getStreamToLocalHgtFile(URL inUrl)
throws IOException
{
String diskCachePath = Config.getConfigString(Config.KEY_DISK_CACHE);
}
}
}
- // System.out.println("Lookup: Trying online: " + inUrl.toString());
- _hadToDownload = true;
- // MAYBE: Only download if we're in online mode?
- return new ZipInputStream(inUrl.openStream());
+ return null;
+ }
+
+ /**
+ * Given the height data read in from file, apply the given tile to all points
+ * in the track with missing altitude
+ * @param inTile tile being applied
+ * @param inHeights height data read in from file
+ * @param inOverwriteZeros true to overwrite zero altitude values
+ * @return number of altitudes found
+ */
+ private int applySrtmTileToWholeTrack(SrtmTile inTile, int[] inHeights, boolean inOverwriteZeros)
+ {
+ int numAltitudesFound = 0;
+ // Loop over all points in track, try to apply altitude from array
+ for (int p = 0; p < _track.getNumPoints(); p++)
+ {
+ DataPoint point = _track.getPoint(p);
+ if (!point.hasAltitude()
+ || (inOverwriteZeros && point.getAltitude().getValue() == 0))
+ {
+ if (new SrtmTile(point).equals(inTile))
+ {
+ double x = (point.getLongitude().getDouble() - inTile.getLongitude()) * 1200;
+ double y = 1201 - (point.getLatitude().getDouble() - inTile.getLatitude()) * 1200;
+ int idx1 = ((int)y)*1201 + (int)x;
+ try
+ {
+ int[] fouralts = {inHeights[idx1], inHeights[idx1+1], inHeights[idx1-1201], inHeights[idx1-1200]};
+ int numVoids = (fouralts[0]==VOID_VAL?1:0) + (fouralts[1]==VOID_VAL?1:0)
+ + (fouralts[2]==VOID_VAL?1:0) + (fouralts[3]==VOID_VAL?1:0);
+ // if (numVoids > 0) System.out.println(numVoids + " voids found");
+ double altitude = 0.0;
+ switch (numVoids)
+ {
+ case 0: altitude = bilinearInterpolate(fouralts, x, y); break;
+ case 1: altitude = bilinearInterpolate(fixVoid(fouralts), x, y); break;
+ case 2:
+ case 3: altitude = averageNonVoid(fouralts); break;
+ default: altitude = VOID_VAL;
+ }
+ // Special case for terrain tracks, don't interpolate voids yet
+ if (!_normalTrack && numVoids > 0) {
+ altitude = VOID_VAL;
+ }
+ if (altitude != VOID_VAL)
+ {
+ point.setFieldValue(Field.ALTITUDE, ""+altitude, false);
+ // depending on settings, this value may have been added as feet, we need to force metres
+ point.getAltitude().reset(new Altitude((int)altitude, UnitSetLibrary.UNITS_METRES));
+ numAltitudesFound++;
+ }
+ }
+ catch (ArrayIndexOutOfBoundsException obe) {
+ // System.err.println("lat=" + point.getLatitude().getDouble() + ", x=" + x + ", y=" + y + ", idx=" + idx1);
+ }
+ }
+ }
+ }
+ return numAltitudesFound;
}
/**
{
return _running;
}
+
+ private void showConfirmMessage(int numDownloaded)
+ {
+ if (numDownloaded == 1)
+ {
+ JOptionPane.showMessageDialog(_parentFrame, I18nManager.getTextWithNumber("confirm.downloadsrtm.1", numDownloaded),
+ I18nManager.getText(getNameKey()), JOptionPane.INFORMATION_MESSAGE);
+ }
+ else if (numDownloaded > 1)
+ {
+ JOptionPane.showMessageDialog(_parentFrame, I18nManager.getTextWithNumber("confirm.downloadsrtm", numDownloaded),
+ I18nManager.getText(getNameKey()), JOptionPane.INFORMATION_MESSAGE);
+ }
+ }
}