forked from NASAWorldWind/WorldWindJava
-
Notifications
You must be signed in to change notification settings - Fork 17
Closed
Labels
enhancementNew feature or requestNew feature or request
Milestone
Description
MercatorTiledImageLayer is a modified copy-paste of BasicTailedImageLayer extended from AbstractLayer, but it can simply extend BasicTailedImageLayer and override several methods. This allow to maintain reusable logic in BasicTailedImageLayer and avoid future bugs.
There is also a copy-pasted MercatorTextureTile cache logic instead of using the cache build in parent TextureTile class.
And one improvement - MercatorUrlBuilder transforms col, row and level into usual x, y, z parameters by inversing row numbering and allowing to make offset of first zoom level to have first level consists of e.g. 8 tiles instead of 1.
To solve this issues just refactor several classes...
- MercatorTiledImageLayer:
public class MercatorTiledImageLayer extends BasicTiledImageLayer {
protected String name;
private static LevelSet makeLevels(String name, int numLevels, int tileSize, String formatSuffix, MercatorTileUrlBuilder buider) {
double delta = Angle.POS360.degrees / (1 << buider.getFirstLevelOffset());
AVList params = new AVListImpl();
params.setValue(AVKey.SECTOR, new MercatorSector(-1.0, 1.0, Angle.NEG180, Angle.POS180));
params.setValue(AVKey.LEVEL_ZERO_TILE_DELTA, new LatLon(Angle.fromDegrees(delta / 2), Angle.fromDegrees(delta)));
params.setValue(AVKey.NUM_LEVELS, numLevels - buider.getFirstLevelOffset());
params.setValue(AVKey.FORMAT_SUFFIX, formatSuffix);
params.setValue(AVKey.TILE_WIDTH, tileSize);
params.setValue(AVKey.TILE_HEIGHT, tileSize);
params.setValue(AVKey.DATASET_NAME, "*");
params.setValue(AVKey.DATA_CACHE_NAME, "Earth/Mercator/" + name);
params.setValue(AVKey.TILE_URL_BUILDER, buider);
return new LevelSet(params);
}
public MercatorTiledImageLayer(String name, int numLevels, int tileSize, boolean overlay, String formatSuffix, MercatorTileUrlBuilder builder) {
this(makeLevels(name, numLevels, tileSize, formatSuffix, builder), name);
setUseTransparentTextures(overlay);
}
public MercatorTiledImageLayer(LevelSet levelSet, String name) {
super(levelSet);
this.name = name;
this.detailHintOrigin = 1.5;
}
@Override
public String toString() {
return name;
}
@Override
protected 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 WorldWind 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<>(nLatTiles * nLonTiles);
double deltaLat = dLat.degrees / 90;
double d1 = sector.getMinLatPercent() + deltaLat * firstRow;
for (int row = firstRow; row <= lastRow; row++) {
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;
}
}
@Override
protected boolean needToSplit(DrawContext dc, Sector sector, Level level) {
double texelSize = level.getTexelSize() * dc.getGlobe().getRadius();
double pixelSize = dc.getView().computePixelSizeAtDistance(sector.distanceTo(dc, dc.getView().getEyePoint()));
return texelSize > pixelSize * this.getDetailFactor();
}
@Override
protected DownloadPostProcessor createDownloadPostProcessor(TextureTile tile) {
return new MercatorDownloadPostProcessor((MercatorTextureTile) tile, this);
}
private static class MercatorDownloadPostProcessor extends DownloadPostProcessor {
MercatorDownloadPostProcessor(MercatorTextureTile tile, MercatorTiledImageLayer layer) {
super(tile, layer);
}
@Override
protected BufferedImage transformPixels() {
// Make parent transformations
BufferedImage image = super.transformPixels();
// Read image from buffer
if(image == null) {
try {
image = ImageIO.read(new ByteArrayInputStream(this.getRetriever().getBuffer().array()));
} catch (IOException ignored) {
return null;
}
}
// Transform mercator tile to equirectangular projection
if(image != null) {
int type = image.getType();
if (type == BufferedImage.TYPE_CUSTOM) type = BufferedImage.TYPE_INT_RGB;
else if (type == BufferedImage.TYPE_BYTE_INDEXED) type = BufferedImage.TYPE_INT_ARGB;
BufferedImage trans = new BufferedImage(image.getWidth(), image.getHeight(), type);
double miny = ((MercatorSector) tile.getSector()).getMinLatPercent();
double maxy = ((MercatorSector) tile.getSector()).getMaxLatPercent();
for (int y = 0; y < image.getHeight(); y++) {
double sy = 1.0 - y / (double) (image.getHeight() - 1);
Angle lat = Angle.fromRadians(sy * tile.getSector().getDeltaLatRadians() + tile.getSector().getMinLatitude().radians);
double dy = 1.0 - (MercatorSector.gudermannianInverse(lat) - miny) / (maxy - miny);
dy = Math.max(0.0, Math.min(1.0, dy));
int iy = (int) (dy * (image.getHeight() - 1));
for (int x = 0; x < image.getWidth(); x++) {
trans.setRGB(x, y, image.getRGB(x, iy));
}
}
return trans;
} else {
return null;
}
}
}
}
- MercatorTextureTile:
public class MercatorTextureTile extends TextureTile {
MercatorTextureTile(MercatorSector mercatorSector, Level level, int row, int col) {
super(mercatorSector, level, row, col);
}
@Override
public TextureTile[] createSubTiles(Level nextLevel) {
if (nextLevel == null) {
String msg = Logging.getMessage("nullValue.LevelIsNull");
Logging.logger().severe(msg);
throw new IllegalArgumentException(msg);
}
MercatorSector sector = (MercatorSector) this.getSector();
double d0 = sector.getMinLatPercent();
double d2 = sector.getMaxLatPercent();
double d1 = d0 + (d2 - d0) / 2.0;
Angle t0 = sector.getMinLongitude();
Angle t2 = sector.getMaxLongitude();
Angle t1 = Angle.midAngle(t0, t2);
String nextLevelCacheName = nextLevel.getCacheName();
int nextLevelNum = nextLevel.getLevelNumber();
int northRow = 2 * this.getRow();
int southRow = northRow + 1;
int westCol = 2 * this.getColumn();
int eastCol = westCol + 1;
TextureTile[] subTiles = new TextureTile[4];
TextureTile subTile = this.getTileFromMemoryCache(new TileKey(nextLevelNum, northRow, westCol, nextLevelCacheName));
subTiles[0] = subTile != null ? subTile : new MercatorTextureTile(new MercatorSector(d0, d1, t0, t1), nextLevel, northRow, westCol);
subTile = this.getTileFromMemoryCache(new TileKey(nextLevelNum, northRow, eastCol, nextLevelCacheName));
subTiles[1] = subTile != null ? subTile : new MercatorTextureTile(new MercatorSector(d0, d1, t1, t2), nextLevel, northRow, eastCol);
subTile = this.getTileFromMemoryCache(new TileKey(nextLevelNum, southRow, westCol, nextLevelCacheName));
subTiles[2] = subTile != null ? subTile : new MercatorTextureTile(new MercatorSector(d1, d2, t0, t1), nextLevel, southRow, westCol);
subTile = this.getTileFromMemoryCache(new TileKey(nextLevelNum, southRow, eastCol, nextLevelCacheName));
subTiles[3] = subTile != null ? subTile : new MercatorTextureTile(new MercatorSector(d1, d2, t1, t2), nextLevel, southRow, eastCol);
return subTiles;
}
}
- MercatorTileUrlBuilder:
public abstract class MercatorTileUrlBuilder implements TileUrlBuilder {
private int firstLevelOffset;
public MercatorTileUrlBuilder setFirstLevelOffset(int firstLevelOffset) {
this.firstLevelOffset = firstLevelOffset;
return this;
}
public int getFirstLevelOffset() {
return firstLevelOffset;
}
@Override
public URL getURL(Tile tile, String imageFormat) throws MalformedURLException {
return getMercatorURL(tile.getColumn(), (1 << (tile.getLevelNumber() + firstLevelOffset)) - 1 - tile.getRow(), tile.getLevelNumber() + firstLevelOffset);
}
protected abstract URL getMercatorURL(int x, int y, int z) throws MalformedURLException;
}
Metadata
Metadata
Assignees
Labels
enhancementNew feature or requestNew feature or request