📄 mercatortiledimagelayer.java
字号:
/*
Copyright (C) 2001, 2009 United States Government
as represented by the Administrator of the
National Aeronautics and Space Administration.
All Rights Reserved.
*/
package gov.nasa.worldwind.layers.Mercator;
import com.sun.opengl.util.j2d.TextRenderer;
import gov.nasa.worldwind.*;
import gov.nasa.worldwind.geom.*;
import gov.nasa.worldwind.globes.Globe;
import gov.nasa.worldwind.layers.AbstractLayer;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.retrieve.*;
import gov.nasa.worldwind.util.*;
import javax.imageio.ImageIO;
import javax.media.opengl.GL;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.io.*;
import java.net.*;
import java.nio.ByteBuffer;
import java.util.*;
import java.util.concurrent.PriorityBlockingQueue;
/**
* TiledImageLayer modified 2009-02-03 to add support for Mercator projections.
*
* @author tag
* @version $Id: MercatorTiledImageLayer.java 10925 2009-05-06 22:22:50Z dcollins $
*/
public abstract class MercatorTiledImageLayer extends AbstractLayer
{
// Infrastructure
private static final LevelComparer levelComparer = new LevelComparer();
private final LevelSet levels;
private ArrayList<MercatorTextureTile> topLevels;
private boolean forceLevelZeroLoads = false;
private boolean levelZeroLoaded = false;
private boolean retainLevelZeroTiles = false;
private String tileCountName;
private double splitScale = 0.9; // TODO: Make configurable
private boolean useMipMaps = false;
private ArrayList<String> supportedImageFormats = new ArrayList<String>();
// Diagnostic flags
private boolean showImageTileOutlines = false;
private boolean drawTileBoundaries = false;
private boolean useTransparentTextures = false;
private boolean drawTileIDs = false;
private boolean drawBoundingVolumes = false;
// Stuff computed each frame
private ArrayList<MercatorTextureTile> currentTiles = new ArrayList<MercatorTextureTile>();
private MercatorTextureTile currentResourceTile;
private Vec4 referencePoint;
private boolean atMaxResolution = false;
private PriorityBlockingQueue<Runnable> requestQ = new PriorityBlockingQueue<Runnable>(
200);
abstract protected void requestTexture(DrawContext dc,
MercatorTextureTile tile);
abstract protected void forceTextureLoad(MercatorTextureTile tile);
public MercatorTiledImageLayer(LevelSet levelSet)
{
if (levelSet == null)
{
String message = Logging.getMessage("nullValue.LevelSetIsNull");
Logging.logger().severe(message);
throw new IllegalArgumentException(message);
}
this.levels = new LevelSet(levelSet); // the caller's levelSet may change internally, so we copy it.
this.createTopLevelTiles();
this.setPickEnabled(false); // textures are assumed to be terrain unless specifically indicated otherwise.
this.tileCountName = this.getName() + " Tiles";
}
@Override
public void setName(String name)
{
super.setName(name);
this.tileCountName = this.getName() + " Tiles";
}
public boolean isUseTransparentTextures()
{
return this.useTransparentTextures;
}
public void setUseTransparentTextures(boolean useTransparentTextures)
{
this.useTransparentTextures = useTransparentTextures;
}
public boolean isForceLevelZeroLoads()
{
return this.forceLevelZeroLoads;
}
public void setForceLevelZeroLoads(boolean forceLevelZeroLoads)
{
this.forceLevelZeroLoads = forceLevelZeroLoads;
}
public boolean isRetainLevelZeroTiles()
{
return retainLevelZeroTiles;
}
public void setRetainLevelZeroTiles(boolean retainLevelZeroTiles)
{
this.retainLevelZeroTiles = retainLevelZeroTiles;
}
public boolean isDrawTileIDs()
{
return drawTileIDs;
}
public void setDrawTileIDs(boolean drawTileIDs)
{
this.drawTileIDs = drawTileIDs;
}
public boolean isDrawTileBoundaries()
{
return drawTileBoundaries;
}
public void setDrawTileBoundaries(boolean drawTileBoundaries)
{
this.drawTileBoundaries = drawTileBoundaries;
}
public boolean isShowImageTileOutlines()
{
return showImageTileOutlines;
}
public void setShowImageTileOutlines(boolean showImageTileOutlines)
{
this.showImageTileOutlines = showImageTileOutlines;
}
public boolean isDrawBoundingVolumes()
{
return drawBoundingVolumes;
}
public void setDrawBoundingVolumes(boolean drawBoundingVolumes)
{
this.drawBoundingVolumes = drawBoundingVolumes;
}
protected LevelSet getLevels()
{
return levels;
}
protected void setSplitScale(double splitScale)
{
this.splitScale = splitScale;
}
protected PriorityBlockingQueue<Runnable> getRequestQ()
{
return requestQ;
}
public boolean isMultiResolution()
{
return this.getLevels() != null && this.getLevels().getNumLevels() > 1;
}
public boolean isAtMaxResolution()
{
return this.atMaxResolution;
}
public boolean isUseMipMaps()
{
return useMipMaps;
}
public void setUseMipMaps(boolean useMipMaps)
{
this.useMipMaps = useMipMaps;
}
private void createTopLevelTiles()
{
MercatorSector sector = (MercatorSector) this.levels.getSector();
Level level = levels.getFirstLevel();
Angle dLat = level.getTileDelta().getLatitude();
Angle dLon = level.getTileDelta().getLongitude();
Angle latOrigin = this.levels.getTileOrigin().getLatitude();
Angle lonOrigin = this.levels.getTileOrigin().getLongitude();
// Determine the row and column offset from the common World Wind global tiling origin.
int firstRow = Tile.computeRow(dLat, sector.getMinLatitude(), latOrigin);
int firstCol = Tile.computeColumn(dLon, sector.getMinLongitude(), lonOrigin);
int lastRow = Tile.computeRow(dLat, sector.getMaxLatitude(), latOrigin);
int lastCol = Tile.computeColumn(dLon, sector.getMaxLongitude(), lonOrigin);
int nLatTiles = lastRow - firstRow + 1;
int nLonTiles = lastCol - firstCol + 1;
this.topLevels = new ArrayList<MercatorTextureTile>(nLatTiles
* nLonTiles);
//Angle p1 = Tile.computeRowLatitude(firstRow, dLat);
double deltaLat = dLat.degrees / 90;
double d1 = -1.0 + deltaLat * firstRow;
for (int row = firstRow; row <= lastRow; row++)
{
//Angle p2;
//p2 = p1.add(dLat);
double d2 = d1 + deltaLat;
Angle t1 = Tile.computeColumnLongitude(firstCol, dLon, lonOrigin);
for (int col = firstCol; col <= lastCol; col++)
{
Angle t2;
t2 = t1.add(dLon);
this.topLevels.add(new MercatorTextureTile(new MercatorSector(
d1, d2, t1, t2), level, row, col));
t1 = t2;
}
d1 = d2;
}
}
private void loadAllTopLevelTextures(DrawContext dc)
{
for (MercatorTextureTile tile : this.topLevels)
{
if (!tile.isTextureInMemory(dc.getTextureCache()))
this.forceTextureLoad(tile);
}
this.levelZeroLoaded = true;
}
// ============== Tile Assembly ======================= //
// ============== Tile Assembly ======================= //
// ============== Tile Assembly ======================= //
private void assembleTiles(DrawContext dc)
{
this.currentTiles.clear();
for (MercatorTextureTile tile : this.topLevels)
{
if (this.isTileVisible(dc, tile))
{
this.currentResourceTile = null;
this.addTileOrDescendants(dc, tile);
}
}
}
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;
}
}
private void addTile(DrawContext dc, MercatorTextureTile tile)
{
tile.setFallbackTile(null);
if (tile.isTextureInMemory(dc.getTextureCache()))
{
// System.out.printf("Sector %s, min = %f, max = %f\n", tile.getSector(),
// dc.getGlobe().getMinElevation(tile.getSector()), dc.getGlobe().getMaxElevation(tile.getSector()));
this.addTileToCurrent(tile);
return;
}
// Level 0 loads may be forced
if (tile.getLevelNumber() == 0 && this.forceLevelZeroLoads
&& !tile.isTextureInMemory(dc.getTextureCache()))
{
this.forceTextureLoad(tile);
if (tile.isTextureInMemory(dc.getTextureCache()))
{
this.addTileToCurrent(tile);
return;
}
}
// Tile's texture isn't available, so request it
if (tile.getLevelNumber() < this.levels.getNumLevels())
{
// Request only tiles with data associated at this level
if (!this.levels.isResourceAbsent(tile))
this.requestTexture(dc, tile);
}
// Set up to use the currentResource tile's texture
if (this.currentResourceTile != null)
{
if (this.currentResourceTile.getLevelNumber() == 0
&& this.forceLevelZeroLoads
&& !this.currentResourceTile.isTextureInMemory(dc
.getTextureCache())
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -