private BufferedImage requestImage(MercatorTextureTile tile, String mimeType) throws URISyntaxException { String pathBase = tile.getPath().substring(0, tile.getPath().lastIndexOf(".")); String suffix = WWIO.makeSuffixForMimeType(mimeType); String path = pathBase + suffix; URL url = WorldWind.getDataFileStore().findFile(path, false); if (url == null) // image is not local return null; if (WWIO.isFileOutOfDate(url, tile.getLevel().getExpiryTime())) { // The file has expired. Delete it. WorldWind.getDataFileStore().removeFile(url); String message = Logging.getMessage("generic.DataFileExpired", url); Logging.logger().fine(message); } else { try { File imageFile = new File(url.toURI()); BufferedImage image = ImageIO.read(imageFile); if (image == null) { String message = Logging.getMessage("generic.ImageReadFailed", imageFile); throw new RuntimeException(message); } this.levels.unmarkResourceAbsent(tile); return image; } catch (IOException e) { // Assume that something's wrong with the file and delete it. gov.nasa.worldwind.WorldWind.getDataFileStore().removeFile(url); this.levels.markResourceAbsent(tile); String message = Logging.getMessage("generic.DeletedCorruptDataFile", url); Logging.logger().info(message); } } return null; }
private void addTileOrDescendants(DrawContext dc, MercatorTextureTile tile) { if (this.meetsRenderCriteria(dc, tile)) { this.addTile(dc, tile); return; } // The incoming tile does not meet the rendering criteria, so it must be subdivided and those // subdivisions tested against the criteria. // All tiles that meet the selection criteria are drawn, but some of those tiles will not have // textures associated with them either because their texture isn't loaded yet or because they // are finer grain than the layer has textures for. In these cases the tiles use the texture of // the closest ancestor that has a texture loaded. This ancestor is called the // currentResourceTile. // A texture transform is applied during rendering to align the sector's texture coordinates // with the // appropriate region of the ancestor's texture. MercatorTextureTile ancestorResource = null; try { // TODO: Revise this to reflect that the parent layer is only requested while the algorithm // continues // to search for the layer matching the criteria. // At this point the tile does not meet the render criteria but it may have its texture in // memory. // If so, register this tile as the resource tile. If not, then this tile will be the next // level // below a tile with texture in memory. So to provide progressive resolution increase, add // this tile // to the draw list. That will cause the tile to be drawn using its parent tile's texture, and // it will // cause it's texture to be requested. At some future call to this method the tile's texture // will be in // memory, it will not meet the render criteria, but will serve as the parent to a tile that // goes // through this same process as this method recurses. The result of all this is that a tile // isn't rendered // with its own texture unless all its parents have their textures loaded. In addition to // causing // progressive resolution increase, this ensures that the parents are available as the user // zooms out, and // therefore the layer remains visible until the user is zoomed out to the point the layer is // no longer // active. if (tile.isTextureInMemory(dc.getTextureCache()) || tile.getLevelNumber() == 0) { ancestorResource = this.currentResourceTile; this.currentResourceTile = tile; } else if (!tile.getLevel().isEmpty()) { // this.addTile(dc, tile); // return; // Issue a request for the parent before descending to the children. if (tile.getLevelNumber() < this.levels.getNumLevels()) { // Request only tiles with data associated at this level if (!this.levels.isResourceAbsent(tile)) this.requestTexture(dc, tile); } } MercatorTextureTile[] subTiles = tile.createSubTiles(this.levels.getLevel(tile.getLevelNumber() + 1)); for (MercatorTextureTile child : subTiles) { if (this.isTileVisible(dc, child)) this.addTileOrDescendants(dc, child); } } finally { if (ancestorResource != null) // Pop this tile as the currentResource ancestor this.currentResourceTile = ancestorResource; } }