4.01WorldWindAndroid載入TileImage切片解析
阿新 • • 發佈:2018-12-24
重點類:
TileSufaceImage
public void setLevelSet(LevelSet levelSet) {
if (levelSet == null) {
throw new IllegalArgumentException(
Logger.logMessage(Logger.ERROR, "TiledSurfaceImage", "setLevelSet", "missingLevelSet"));
}
this.levelSet = levelSet;
this.invalidateTiles();
}
public void setTileFactory (TileFactory tileFactory) {
this.tileFactory = tileFactory;
this.invalidateTiles();
}
@Override
protected void doRender(RenderContext rc) {
if (rc.terrain.getSector().isEmpty()) {
return; // no terrain surface to render on
}
this.determineActiveProgram(rc);
this.assembleTiles(rc);
this.activeProgram = null; // clear the active program to avoid leaking render resources
this.ancestorTile = null; // clear the ancestor tile and texture
this.ancestorTexture = null;
}
protected void assembleTiles(RenderContext rc) {
// TODO
// The need to create Tiles with a defined image source couples the need to determine a tile's visibility with
// he need to know its image source. Decoupling the two would mean we only need to know the image source when
// the texture is actually requested Could the tile-based operations done here be implicit on level/row/column,
// or use transient pooled tile objects not tied to an image source?
if (this.topLevelTiles.isEmpty()) {
this.createTopLevelTiles();
}
for (int idx = 0, len = this.topLevelTiles.size(); idx < len; idx++) {
this.addTileOrDescendants(rc, (ImageTile) this.topLevelTiles.get(idx));
}
}
protected void createTopLevelTiles() {
Level firstLevel = this.levelSet.firstLevel();
if (firstLevel != null) {
Tile.assembleTilesForLevel(firstLevel, this.tileFactory, this.topLevelTiles);
}
}
protected void addTileOrDescendants(RenderContext rc, ImageTile tile) {
if (!tile.intersectsSector(this.levelSet.sector) || !tile.intersectsFrustum(rc, rc.frustum)) {
return; // ignore the tile and its descendants if it's not needed or not visible
}
if (tile.level.isLastLevel() || !tile.mustSubdivide(rc, this.detailControl)) {
this.addTile(rc, tile);
return; // use the tile if it does not need to be subdivided
}
ImageTile currentAncestorTile = this.ancestorTile;
Texture currentAncestorTexture = this.ancestorTexture;
ImageSource tileImageSource = tile.getImageSource();
if (tileImageSource != null) { // tile has an image source; its level is not empty
Texture tileTexture = rc.getTexture(tileImageSource);
if (tileTexture != null) { // tile has a texture; use it as a fallback tile for descendants
this.ancestorTile = tile;
this.ancestorTexture = tileTexture;
}
}
for (Tile child : tile.subdivideToCache(this.tileFactory, this.tileCache, 4)) { // each tile has a cached size of 1
this.addTileOrDescendants(rc, (ImageTile) child); // recursively process the tile's children
}
this.ancestorTile = currentAncestorTile; // restore the last fallback tile, even if it was null
this.ancestorTexture = currentAncestorTexture;
}
protected void addTile(RenderContext rc, ImageTile tile) {
ImageSource imageSource = tile.getImageSource();
if (imageSource == null) {
return; // no image source indicates an empty level or an image missing from the tiled data store
}
Texture texture = rc.getTexture(imageSource); // try to get the texture from the cache
if (texture == null) {
texture = rc.retrieveTexture(imageSource, this.imageOptions); // puts retrieved textures in the cache
}
if (texture != null) { // use the tile's own texture
Pool<DrawableSurfaceTexture> pool = rc.getDrawablePool(DrawableSurfaceTexture.class);
Drawable drawable = DrawableSurfaceTexture.obtain(pool).set(this.activeProgram, tile.sector, texture, texture.getTexCoordTransform());
rc.offerSurfaceDrawable(drawable, 0 /*z-order*/);
} else if (this.ancestorTile != null) { // use the ancestor tile's texture, transformed to fill the tile sector
this.ancestorTexCoordMatrix.set(this.ancestorTexture.getTexCoordTransform());
this.ancestorTexCoordMatrix.multiplyByTileTransform(tile.sector, this.ancestorTile.sector);
Pool<DrawableSurfaceTexture> pool = rc.getDrawablePool(DrawableSurfaceTexture.class);
Drawable drawable = DrawableSurfaceTexture.obtain(pool).set(this.activeProgram, tile.sector, this.ancestorTexture, this.ancestorTexCoordMatrix);
rc.offerSurfaceDrawable(drawable, 0 /*z-order*/);
}
}
Tile:
public static Collection<Tile> assembleTilesForLevel(Level level, TileFactory tileFactory, Collection<Tile> result) {
if (level == null) {
throw new IllegalArgumentException(
Logger.logMessage(Logger.ERROR, "Tile", "assembleTilesForLevel", "missingLevel"));
}
if (tileFactory == null) {
throw new IllegalArgumentException(
Logger.logMessage(Logger.ERROR, "Tile", "assembleTilesForLevel", "missingTileFactory"));
}
if (result == null) {
throw new IllegalArgumentException(
Logger.logMessage(Logger.ERROR, "Tile", "assembleTilesForLevel", "missingResult"));
}
Sector sector = level.parent.sector;
double tileDelta = level.tileDelta;
int firstRow = Tile.computeRow(tileDelta, sector.minLatitude());
int lastRow = Tile.computeLastRow(tileDelta, sector.maxLatitude());
int firstCol = Tile.computeColumn(tileDelta, sector.minLongitude());
int lastCol = Tile.computeLastColumn(tileDelta, sector.maxLongitude());
double firstRowLat = -90 + firstRow * tileDelta;
double firstRowLon = -180 + firstCol * tileDelta;
double lat = firstRowLat;
double lon;
for (int row = firstRow; row <= lastRow; row++) {
lon = firstRowLon;
for (int col = firstCol; col <= lastCol; col++) {
Sector tileSector = new Sector(lat, lon, tileDelta, tileDelta);
result.add(tileFactory.createTile(tileSector, level, row, col));
lon += tileDelta;
}
lat += tileDelta;
}
return result;
}
LevelSet
public LevelSet(LevelSetConfig config) {
if (config == null) {
throw new IllegalArgumentException(
Logger.logMessage(Logger.ERROR, "LevelSet", "constructor", "missingConfig"));
}
if (config.sector == null) {
throw new IllegalArgumentException(
Logger.logMessage(Logger.ERROR, "LevelSet", "constructor", "missingSector"));
}
if (config.firstLevelDelta <= 0) {
throw new IllegalArgumentException(
Logger.logMessage(Logger.ERROR, "LevelSet", "constructor", "invalidTileDelta"));
}
if (config.numLevels < 0) {
throw new IllegalArgumentException(
Logger.logMessage(Logger.ERROR, "LevelSet", "constructor", "invalidNumLevels"));
}
if (config.tileWidth < 1 || config.tileHeight < 1) {
throw new IllegalArgumentException(
Logger.logMessage(Logger.ERROR, "LevelSet", "constructor", "invalidWidthOrHeight"));
}
this.sector.set(config.sector);
this.firstLevelDelta = config.firstLevelDelta;
this.tileWidth = config.tileWidth;
this.tileHeight = config.tileHeight;
this.levels = new Level[config.numLevels];
this.assembleLevels();
}
protected void assembleLevels() {
for (int i = 0, len = this.levels.length; i < len; i++) {
double n = Math.pow(2, i);
double delta = firstLevelDelta / n;
this.levels[i] = new Level(this, i, delta);
}
}
TileFactory:
public interface TileFactory {
/**
* Returns a tile for a specified sector, level within a {@link LevelSet}, and row and column within that level.
*
* @param sector the sector spanned by the tile
* @param level the level at which the tile lies within a LevelSet
* @param row the row within the specified level
* @param column the column within the specified level
*
* @return a tile constructed with the specified arguments
*
* @throws IllegalArgumentException if either the sector or the level is null
*/
Tile createTile(Sector sector, Level level, int row, int column);
}