-
Notifications
You must be signed in to change notification settings - Fork 125
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add MercatorTiledImageLayer support.
- Loading branch information
1 parent
0dacfec
commit 06ee66c
Showing
7 changed files
with
296 additions
and
3 deletions.
There are no files selected for viewing
144 changes: 144 additions & 0 deletions
144
worldwind/src/main/java/gov/nasa/worldwind/layer/mercator/MercatorImageTile.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
package gov.nasa.worldwind.layer.mercator; | ||
|
||
import android.graphics.Bitmap; | ||
|
||
import java.util.Collection; | ||
|
||
import gov.nasa.worldwind.render.ImageTile; | ||
import gov.nasa.worldwind.util.DownloadPostprocessor; | ||
import gov.nasa.worldwind.util.Level; | ||
import gov.nasa.worldwind.util.LevelSet; | ||
import gov.nasa.worldwind.util.Logger; | ||
import gov.nasa.worldwind.util.Tile; | ||
import gov.nasa.worldwind.util.TileFactory; | ||
|
||
class MercatorImageTile extends ImageTile implements DownloadPostprocessor<Bitmap> { | ||
|
||
/** | ||
* Constructs a tile with a specified sector, level, row and column. | ||
* | ||
* @param sector the sector spanned by the tile | ||
* @param level the tile's level in a {@link LevelSet} | ||
* @param row the tile's row within the specified level | ||
* @param column the tile's column within the specified level | ||
*/ | ||
MercatorImageTile(MercatorSector sector, Level level, int row, int column) { | ||
super(sector, level, row, column); | ||
} | ||
|
||
/** | ||
* Creates all Mercator tiles for a specified level within a {@link LevelSet}. | ||
* | ||
* @param level the level to create the tiles for | ||
* @param tileFactory the tile factory to use for creating tiles. | ||
* @param result an pre-allocated Collection in which to store the results | ||
*/ | ||
static void assembleMercatorTilesForLevel(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")); | ||
} | ||
|
||
// NOTE LevelSet.sector is final Sector attribute and thus can not be cast to MercatorSector! | ||
MercatorSector sector = MercatorSector.fromSector(level.parent.sector); | ||
double dLat = level.tileDelta / 2; | ||
double dLon = level.tileDelta; | ||
|
||
int firstRow = Tile.computeRow(dLat, sector.minLatitude()); | ||
int lastRow = Tile.computeLastRow(dLat, sector.maxLatitude()); | ||
int firstCol = Tile.computeColumn(dLon, sector.minLongitude()); | ||
int lastCol = Tile.computeLastColumn(dLon, sector.maxLongitude()); | ||
|
||
double deltaLat = dLat / 90; | ||
double d1 = sector.minLatPercent() + deltaLat * firstRow; | ||
for (int row = firstRow; row <= lastRow; row++) { | ||
double d2 = d1 + deltaLat; | ||
double t1 = sector.minLongitude() + (firstCol * dLon); | ||
for (int col = firstCol; col <= lastCol; col++) { | ||
double t2; | ||
t2 = t1 + dLon; | ||
result.add(tileFactory.createTile(MercatorSector.fromDegrees(d1, d2, t1, t2), level, row, col)); | ||
t1 = t2; | ||
} | ||
d1 = d2; | ||
} | ||
} | ||
|
||
/** | ||
* Returns the four children formed by subdividing this tile. This tile's sector is subdivided into four quadrants | ||
* as follows: Southwest; Southeast; Northwest; Northeast. A new tile is then constructed for each quadrant and | ||
* configured with the next level within this tile's LevelSet and its corresponding row and column within that | ||
* level. This returns null if this tile's level is the last level within its {@link LevelSet}. | ||
* | ||
* @param tileFactory the tile factory to use to create the children | ||
* | ||
* @return an array containing the four child tiles, or null if this tile's level is the last level | ||
*/ | ||
@Override | ||
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; | ||
} | ||
|
||
MercatorSector sector = (MercatorSector) this.sector; | ||
|
||
double d0 = sector.minLatPercent(); | ||
double d2 = sector.maxLatPercent(); | ||
double d1 = d0 + (d2 - d0) / 2.0; | ||
|
||
double t0 = sector.minLongitude(); | ||
double t2 = sector.maxLongitude(); | ||
double t1 = 0.5 * (t0 + t2); | ||
|
||
int northRow = 2 * this.row; | ||
int southRow = northRow + 1; | ||
int westCol = 2 * this.column; | ||
int eastCol = westCol + 1; | ||
|
||
Tile[] children = new Tile[4]; | ||
children[0] = tileFactory.createTile(MercatorSector.fromDegrees(d0, d1, t0, t1), childLevel, northRow, westCol); | ||
children[1] = tileFactory.createTile(MercatorSector.fromDegrees(d0, d1, t1, t2), childLevel, northRow, eastCol); | ||
children[2] = tileFactory.createTile(MercatorSector.fromDegrees(d1, d2, t0, t1), childLevel, southRow, westCol); | ||
children[3] = tileFactory.createTile(MercatorSector.fromDegrees(d1, d2, t1, t2), childLevel, southRow, eastCol); | ||
|
||
return children; | ||
} | ||
|
||
@Override | ||
public Bitmap process(Bitmap resource) { | ||
// Re-project mercator tile to equirectangular | ||
int[] pixels = new int[resource.getWidth() * resource.getHeight()]; | ||
int[] result = new int[resource.getWidth() * resource.getHeight()]; | ||
resource.getPixels(pixels, 0, resource.getWidth(), 0, 0, resource.getWidth(), resource.getHeight()); | ||
double miny = ((MercatorSector) sector).minLatPercent(); | ||
double maxy = ((MercatorSector) sector).maxLatPercent(); | ||
for (int y = 0; y < resource.getHeight(); y++) { | ||
double sy = 1.0 - y / (double) (resource.getHeight() - 1); | ||
double lat = sy * (sector.maxLatitude() - sector.minLatitude()) + sector.minLatitude(); | ||
double dy = 1.0 - (MercatorSector.gudermannianInverse(lat) - miny) / (maxy - miny); | ||
dy = Math.max(0.0, Math.min(1.0, dy)); | ||
int iy = (int) (dy * (resource.getHeight() - 1)); | ||
for (int x = 0; x < resource.getWidth(); x++) { | ||
result[x + y * resource.getWidth()] = pixels[x + iy * resource.getWidth()]; | ||
} | ||
} | ||
return Bitmap.createBitmap(result, resource.getWidth(), resource.getHeight(), resource.getConfig()); | ||
} | ||
|
||
} |
47 changes: 47 additions & 0 deletions
47
worldwind/src/main/java/gov/nasa/worldwind/layer/mercator/MercatorSector.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package gov.nasa.worldwind.layer.mercator; | ||
|
||
import gov.nasa.worldwind.geom.Sector; | ||
|
||
public class MercatorSector extends Sector { | ||
|
||
private final double minLatPercent, maxLatPercent; | ||
|
||
private MercatorSector(double minLatPercent, double maxLatPercent, | ||
double minLongitude, double maxLongitude) { | ||
this.minLatPercent = minLatPercent; | ||
this.maxLatPercent = maxLatPercent; | ||
this.minLatitude = gudermannian(minLatPercent); | ||
this.maxLatitude = gudermannian(maxLatPercent); | ||
this.minLongitude = minLongitude; | ||
this.maxLongitude = maxLongitude; | ||
} | ||
|
||
public static MercatorSector fromDegrees(double minLatPercent, double maxLatPercent, | ||
double minLongitude, double maxLongitude) { | ||
return new MercatorSector(minLatPercent, maxLatPercent, minLongitude, maxLongitude); | ||
} | ||
|
||
static MercatorSector fromSector(Sector sector) { | ||
return new MercatorSector(gudermannianInverse(sector.minLatitude()), | ||
gudermannianInverse(sector.maxLatitude()), | ||
sector.minLongitude(), sector.maxLongitude()); | ||
} | ||
|
||
static double gudermannianInverse(double latitude) { | ||
return Math.log(Math.tan(Math.PI / 4.0 + Math.toRadians(latitude) / 2.0)) / Math.PI; | ||
} | ||
|
||
private static double gudermannian(double percent) { | ||
return Math.toDegrees(Math.atan(Math.sinh(percent * Math.PI))); | ||
} | ||
|
||
double minLatPercent() { | ||
return minLatPercent; | ||
} | ||
|
||
double maxLatPercent() | ||
{ | ||
return maxLatPercent; | ||
} | ||
|
||
} |
44 changes: 44 additions & 0 deletions
44
worldwind/src/main/java/gov/nasa/worldwind/layer/mercator/MercatorTiledImageLayer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
package gov.nasa.worldwind.layer.mercator; | ||
|
||
import gov.nasa.worldwind.WorldWind; | ||
import gov.nasa.worldwind.geom.Sector; | ||
import gov.nasa.worldwind.layer.RenderableLayer; | ||
import gov.nasa.worldwind.render.ImageOptions; | ||
import gov.nasa.worldwind.render.ImageSource; | ||
import gov.nasa.worldwind.util.Level; | ||
import gov.nasa.worldwind.util.LevelSet; | ||
import gov.nasa.worldwind.util.Tile; | ||
import gov.nasa.worldwind.util.TileFactory; | ||
|
||
public abstract class MercatorTiledImageLayer extends RenderableLayer implements TileFactory { | ||
|
||
private static final double FULL_SPHERE = 360; | ||
|
||
private final int firstLevelOffset; | ||
|
||
public MercatorTiledImageLayer(String name, int numLevels, int firstLevelOffset, int tileSize, boolean overlay) { | ||
super(name); | ||
this.setPickEnabled(false); | ||
this.firstLevelOffset = firstLevelOffset; | ||
|
||
MercatorTiledSurfaceImage surfaceImage = new MercatorTiledSurfaceImage(); | ||
surfaceImage.setLevelSet(new LevelSet( | ||
MercatorSector.fromDegrees(-1.0, 1.0, - FULL_SPHERE / 2, FULL_SPHERE / 2), | ||
FULL_SPHERE / (1 << firstLevelOffset), numLevels - firstLevelOffset, tileSize, tileSize)); | ||
surfaceImage.setTileFactory(this); | ||
if(!overlay) { | ||
surfaceImage.setImageOptions(new ImageOptions(WorldWind.RGB_565)); // reduce memory usage by using a 16-bit configuration with no alpha | ||
} | ||
this.addRenderable(surfaceImage); | ||
} | ||
|
||
@Override | ||
public Tile createTile(Sector sector, Level level, int row, int column) { | ||
MercatorImageTile tile = new MercatorImageTile((MercatorSector) sector, level, row, column); | ||
tile.setImageSource(ImageSource.fromUrl(getImageSourceUrl(column, (1 << (level.levelNumber + firstLevelOffset)) - 1 - row, level.levelNumber + firstLevelOffset), tile)); | ||
return tile; | ||
} | ||
|
||
protected abstract String getImageSourceUrl(int x, int y, int z); | ||
|
||
} |
16 changes: 16 additions & 0 deletions
16
worldwind/src/main/java/gov/nasa/worldwind/layer/mercator/MercatorTiledSurfaceImage.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
package gov.nasa.worldwind.layer.mercator; | ||
|
||
import gov.nasa.worldwind.shape.TiledSurfaceImage; | ||
import gov.nasa.worldwind.util.Level; | ||
|
||
public class MercatorTiledSurfaceImage extends TiledSurfaceImage { | ||
|
||
@Override | ||
protected void createTopLevelTiles() { | ||
Level firstLevel = this.levelSet.firstLevel(); | ||
if (firstLevel != null) { | ||
MercatorImageTile.assembleMercatorTilesForLevel(firstLevel, this.tileFactory, this.topLevelTiles); | ||
} | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 14 additions & 0 deletions
14
worldwind/src/main/java/gov/nasa/worldwind/util/DownloadPostprocessor.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package gov.nasa.worldwind.util; | ||
|
||
/** | ||
* Interface for resource download post-processing | ||
*/ | ||
public interface DownloadPostprocessor<T> { | ||
/** | ||
* Process resource according to specified algorithm implementation | ||
* | ||
* @param resource original resource | ||
* @return processed resource | ||
*/ | ||
T process(T resource); | ||
} |