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

src.gov.nasa.worldwind.layers.placename.PlaceNameLayerBulkDownloader Maven / Gradle / Ivy

Go to download

World Wind is a collection of components that interactively display 3D geographic information within Java applications or applets.

There is a newer version: 2.0.0-986
Show 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.placename;

import gov.nasa.worldwind.WorldWind;
import gov.nasa.worldwind.cache.FileStore;
import gov.nasa.worldwind.event.*;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.retrieve.*;
import gov.nasa.worldwind.util.Logging;

import java.net.URL;
import java.nio.ByteBuffer;
import java.util.*;

/**
 * Downloads placenames not currently available in the World Wind file cache or a specified {@link FileStore}. The class
 * derives from {@link Thread} and is meant to operate in its own thread.
 * 

* The sector and resolution associated with the downloader are specified during construction and are final. * * @author tag * @version $Id: PlaceNameLayerBulkDownloader.java 1171 2013-02-11 21:45:02Z dcollins $ */ public class PlaceNameLayerBulkDownloader extends BulkRetrievalThread { protected static final long AVG_TILE_SIZE = 8 * 1024; protected int MAX_TILE_COUNT_PER_REGION = 200; protected final PlaceNameLayer layer; protected ArrayList missingTiles; protected long pollDelay = RETRIEVAL_SERVICE_POLL_DELAY; /** * Constructs a downloader to retrieve placenames not currently available in the World Wind file cache. *

* The thread returned is not started during construction, the caller must start the thread. * * @param layer the layer for which to download placenames. * @param sector the sector to download data for. This value is final. * @param resolution the target resolution, provided in radians of latitude per texel. This value is final. * @param listener an optional retrieval listener. May be null. * * @throws IllegalArgumentException if either the layer or sector are null, or the resolution is less than zero. */ public PlaceNameLayerBulkDownloader(PlaceNameLayer layer, Sector sector, double resolution, BulkRetrievalListener listener) { // Arguments checked in parent constructor //resolution is compared to the maxDsiatnce value in each placenameservice super(layer, sector, resolution, layer.getDataFileStore(), listener); this.layer = layer; } /** * Constructs a downloader to retrieve placenames not currently available in a specified file store and places it * there. *

* The thread returned is not started during construction, the caller must start the thread. * * @param layer the layer for which to download placenames. * @param sector the sector to download data for. This value is final. * @param resolution the target resolution, provided in radians of latitude per texel. This value is final. * @param fileStore the file store in which to place the downloaded elevations. * @param listener an optional retrieval listener. May be null. * * @throws IllegalArgumentException if either the layer, the sector or file store are null, or the resolution is * less than zero. */ public PlaceNameLayerBulkDownloader(PlaceNameLayer layer, Sector sector, double resolution, FileStore fileStore, BulkRetrievalListener listener) { // Arguments checked in parent constructor //resolution is compared to the maxDsiatnce value in each placenameservice super(layer, sector, resolution, fileStore, listener); this.layer = layer; } public void run() { try { // Cycle though placenameservices and find missing tiles this.missingTiles = new ArrayList(); ArrayList allMissingTiles = this.getMissingTilesInSector(this.sector); this.progress.setTotalCount(allMissingTiles.size()); // Submit missing tiles requests at 10 sec intervals while (allMissingTiles.size() > 0) { transferMissingTiles(allMissingTiles, missingTiles, MAX_TILE_COUNT_PER_REGION); while (missingTiles.size() > 0) { submitMissingTilesRequests(); if (missingTiles.size() > 0) Thread.sleep(this.pollDelay); } } } catch (InterruptedException e) { String message = Logging.getMessage("generic.BulkRetrievalInterrupted", layer.getName()); Logging.logger().log(java.util.logging.Level.WARNING, message, e); } catch (Exception e) { String message = Logging.getMessage("generic.ExceptionDuringBulkRetrieval", layer.getName()); Logging.logger().severe(message); throw new RuntimeException(message); } } protected void transferMissingTiles(ArrayList source, ArrayList destination, int maxCount) { int i = 0; while (i < maxCount && source.size() > 0) { destination.add(source.remove(0)); i++; } } protected synchronized void submitMissingTilesRequests() throws InterruptedException { RetrievalService rs = WorldWind.getRetrievalService(); int i = 0; while (this.missingTiles.size() > i && rs.isAvailable()) { Thread.sleep(1); // generates InterruptedException if thread has been interrupted PlaceNameLayer.Tile tile = this.missingTiles.get(i); if (this.isTileLocalOrAbsent(tile)) { // No need to request that tile anymore this.missingTiles.remove(i); } else { this.layer.downloadTile(tile, new BulkDownloadPostProcessor(this.layer, tile, this.fileStore)); i++; } } } protected class BulkDownloadPostProcessor extends PlaceNameLayer.DownloadPostProcessor { public BulkDownloadPostProcessor(PlaceNameLayer layer, PlaceNameLayer.Tile tile, FileStore fileStore) { super(layer, tile, fileStore); } public ByteBuffer run(Retriever retriever) { ByteBuffer buffer = super.run(retriever); if (retriever.getState().equals(Retriever.RETRIEVER_STATE_SUCCESSFUL)) removeRetrievedTile(this.tile); if (hasRetrievalListeners()) callRetrievalListeners(retriever, this.tile); return buffer; } } protected void callRetrievalListeners(Retriever retriever, PlaceNameLayer.Tile tile) { String eventType = (retriever.getState().equals(Retriever.RETRIEVER_STATE_SUCCESSFUL)) ? BulkRetrievalEvent.RETRIEVAL_SUCCEEDED : BulkRetrievalEvent.RETRIEVAL_FAILED; super.callRetrievalListeners(new BulkRetrievalEvent(this.layer, eventType, tile.getFileCachePath())); } protected synchronized void removeRetrievedTile(PlaceNameLayer.Tile tile) { this.missingTiles.remove(tile); this.progress.setCurrentCount(this.progress.getCurrentCount() + 1); this.progress.setCurrentSize(this.progress.getCurrentSize() + AVG_TILE_SIZE); this.progress.setLastUpdateTime(System.currentTimeMillis()); // Estimate total size this.progress.setTotalSize( this.progress.getCurrentSize() / this.progress.getCurrentCount() * this.progress.getTotalCount()); } protected long getEstimatedMissingDataSize() { int tileCount; try { tileCount = this.getMissingTilesCountEstimate(sector, resolution); } catch (Exception e) { String message = Logging.getMessage("generic.ExceptionDuringDataSizeEstimate", this.getName()); Logging.logger().severe(message); throw new RuntimeException(message); } return tileCount * AVG_TILE_SIZE; } protected int getMissingTilesCountEstimate(Sector sector, double resolution) { int tileCount = 0; int serviceCount = this.layer.getPlaceNameServiceSet().getServiceCount(); for (int i = 0; i < serviceCount; i++) { int serviceTileCount = 0; PlaceNameService service = this.layer.getPlaceNameServiceSet().getService(i); if (service.getMaxDisplayDistance() > resolution) { PlaceNameLayer.NavigationTile navTile = this.layer.navTiles.get(i); // drill down into tiles to find bottom level navTiles visible List list = this.navTilesVisible(navTile, sector); for (PlaceNameLayer.NavigationTile nt : list) { serviceTileCount += this.estimateNumberTilesinSector(nt, sector); } } tileCount += serviceTileCount; } return tileCount; } protected ArrayList getMissingTilesInSector(Sector sector) throws InterruptedException { ArrayList allMissingTiles = new ArrayList(); int serviceCount = this.layer.getPlaceNameServiceSet().getServiceCount(); for (int i = 0; i < serviceCount; i++) { PlaceNameService service = this.layer.getPlaceNameServiceSet().getService(i); if (service.getMaxDisplayDistance() > this.resolution) { // get tiles in sector ArrayList baseTiles = new ArrayList(); PlaceNameLayer.NavigationTile navTile = this.layer.navTiles.get(i); // drill down into tiles to find bottom level navTiles visible List list = this.navTilesVisible(navTile, sector); for (PlaceNameLayer.NavigationTile nt : list) { baseTiles.addAll(nt.getTiles()); } for (PlaceNameLayer.Tile tile : baseTiles) { if ((tile.getSector().intersects(sector)) && (!this.isTileLocalOrAbsent(tile))) allMissingTiles.add(tile); } } } return allMissingTiles; } protected List navTilesVisible(PlaceNameLayer.NavigationTile tile, Sector sector) { ArrayList navList = new ArrayList(); if (tile.navSector.intersects(sector)) { if (tile.level > 0 && !tile.hasSubTiles()) tile.buildSubNavTiles(); if (tile.hasSubTiles()) { for (PlaceNameLayer.NavigationTile nav : tile.subNavTiles) { navList.addAll(this.navTilesVisible(nav, sector)); } } else //at bottom level navigation tile { navList.add(tile); } } return navList; } protected int estimateNumberTilesinSector(PlaceNameLayer.NavigationTile tile, Sector searchSector) { final Angle dLat = tile.placeNameService.getTileDelta().getLatitude(); final Angle dLon = tile.placeNameService.getTileDelta().getLongitude(); // Determine the row and column offset from the global tiling origin for the southwest tile corner int firstRow = PlaceNameLayer.Tile.computeRow(dLat, tile.navSector.getMinLatitude()); int firstCol = PlaceNameLayer.Tile.computeColumn(dLon, tile.navSector.getMinLongitude()); int lastRow = PlaceNameLayer.Tile.computeRow(dLat, tile.navSector.getMaxLatitude().subtract(dLat)); int lastCol = PlaceNameLayer.Tile.computeColumn(dLon, tile.navSector.getMaxLongitude().subtract(dLon)); int tileCount = 0; Angle p1 = PlaceNameLayer.Tile.computeRowLatitude(firstRow, dLat); boolean needToCheckDisk = true; for (int row = 0; row <= lastRow - firstRow; row++) { Angle p2; p2 = p1.add(dLat); Angle t1 = PlaceNameLayer.Tile.computeColumnLongitude(firstCol, dLon); for (int col = 0; col <= lastCol - firstCol; col++) { Angle t2; t2 = t1.add(dLon); Sector tileSector = new Sector(p1, p2, t1, t2); if (tileSector.intersects(searchSector)) { if (needToCheckDisk) { //now check if on disk String filePath = tile.placeNameService.createFileCachePathFromTile(row + firstRow, col + firstCol); final java.net.URL tileURL = this.fileStore.findFile(filePath, false); if (tileURL == null) needToCheckDisk = false; //looked and found nothing else return 0; //found one, assume rest are there } tileCount++; } t1 = t2; } p1 = p2; } return tileCount; } protected boolean isTileLocalOrAbsent(PlaceNameLayer.Tile tile) { if (tile.getPlaceNameService().isResourceAbsent( tile.getPlaceNameService().getTileNumber(tile.row, tile.column))) return true; // tile is absent URL url = this.fileStore.findFile(tile.getFileCachePath(), false); return url != null; // tile is already in cache } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy