4.02WorldwindAndroid載入切片解析之請求的傳送
阿新 • • 發佈:2018-12-24
TileSurfaceImage類
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 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;
}
Tile類
public Tile[] subdivideToCache(TileFactory tileFactory, LruMemoryCache<String, Tile[]> cache, int cacheSize) {
if (tileFactory == null) {
throw new IllegalArgumentException(
Logger.logMessage(Logger.ERROR, "Tile", "subdivideToCache", "missingTileFactory"));
}
if (cache == null) {
throw new IllegalArgumentException(
Logger.logMessage(Logger.ERROR, "Tile", "subdivideToCache", "missingCache"));
}
Tile[] children = cache.get(this.tileKey);
if (children == null) {
children = this.subdivide(tileFactory);
if (children != null) {
cache.put(this.tileKey, children, cacheSize);
}
}
return children;
}
public Tile[] subdivide(TileFactory tileFactory) {
if (tileFactory == null) {
throw new IllegalArgumentException(
Logger.logMessage(Logger.ERROR, "Tile", "subdivide", "missingTileFactory"));
}
Level childLevel = this.level.nextLevel();
if (childLevel == null) {
return null;
}
Tile[] children = new Tile[4];
double latMin = this.sector.minLatitude();
double lonMin = this.sector.minLongitude();
double latMid = this.sector.centroidLatitude();
double lonMid = this.sector.centroidLongitude();
double childDelta = this.level.tileDelta * 0.5;
int childRow = 2 * this.row;
int childCol = 2 * this.column;
Sector childSector = new Sector(latMin, lonMin, childDelta, childDelta);
children[0] = tileFactory.createTile(childSector, childLevel, childRow, childCol); // Southwest
childRow = 2 * this.row;
childCol = 2 * this.column + 1;
childSector = new Sector(latMin, lonMid, childDelta, childDelta);
children[1] = tileFactory.createTile(childSector, childLevel, childRow, childCol); // Southeast
childRow = 2 * this.row + 1;
childCol = 2 * this.column;
childSector = new Sector(latMid, lonMin, childDelta, childDelta);
children[2] = tileFactory.createTile(childSector, childLevel, childRow, childCol); // Northwest
childRow = 2 * this.row + 1;
childCol = 2 * this.column + 1;
childSector = new Sector(latMid, lonMid, childDelta, childDelta);
children[3] = tileFactory.createTile(childSector, childLevel, childRow, childCol); // Northeast
return children;
}
這裡想說明問題是:
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
}
就是對當前的現實狀態進行判斷,以決定是否直接載入當前切片還是需要進一步切分,如果需要繼續劃分,就不載入,繼續向下切分子切片,並遞迴呼叫addTileOrDescendants,繼續判斷切片是否還需切分,如果不需要繼續切分,就addTile
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*/);
}
}
此時,就需要傳送請求來獲取對應的切片了!
RenderresourceCachelei
public Texture retrieveTexture(ImageSource imageSource, ImageOptions options) {
if (imageSource == null) {
return null; // a null image source corresponds to a null texture
}
// Bitmap image sources are already in memory, so a texture may be created and put into the cache immediately.
if (imageSource.isBitmap()) {
Texture texture = this.createTexture(imageSource, options, imageSource.asBitmap());
this.put(imageSource, texture, texture.getByteCount());
return texture;
}
// All other image sources must be retrieved from disk or network and must be retrieved on a separate thread.
// This includes bitmap factory image sources, since we cannot make any guarantees about what a bitmap factory
// implementation may do. First look for the image in the image retrieval cache, removing it and creating a
// corresponding texture if found.
Bitmap bitmap = this.imageRetrieverCache.remove(imageSource);
if (bitmap != null) {
Texture texture = this.createTexture(imageSource, options, bitmap);
this.put(imageSource, texture, texture.getByteCount());
return texture;
}
// The image must be retrieved on a separate thread. Request the image source and return null to indicate that
// the texture is not in memory. The image is added to the image retrieval cache upon successful retrieval. It's
// then expected that a subsequent render frame will result in another call to retrieveTexture, in which case
// the image will be found in the image retrieval cache.
if (imageSource.isUrl()) {
this.urlImageRetriever.retrieve(imageSource, options, this);
} else {
this.imageRetriever.retrieve(imageSource, options, this);
}
return null;
}
Retriever類:
public void retrieve(K key, O options, Callback<K, O, V> callback) {
if (key == null) {
throw new IllegalArgumentException(
Logger.logMessage(Logger.ERROR, "Retriever", "retrieve", "missingKey"));
}
if (callback == null) {
throw new IllegalArgumentException(
Logger.logMessage(Logger.ERROR, "Retriever", "retrieve", "missingCallback"));
}
AsyncTask<K, O, V> task = this.obtainAsyncTask(key, options, callback);
if (task == null) { // too many async tasks running, or a task for 'key' is already running
callback.retrievalRejected(this, key);
return;
}
try {
WorldWind.taskService().execute(task);
} catch (RejectedExecutionException ignored) { // singleton task service is full
this.recycleAsyncTask(task);
callback.retrievalRejected(this, key);
}
}