WorldWindAndroid对于TileImage的加载默认是按照等经纬差的正切片加载的,经圈范围-180--180,纬圈范围-90--90,所以,经纬方向上的切片规格为2X1!
为了能够加载经纬差之比为2:1的切片服务,需要将加载正切片的方式进行一定的处理,才能正确加载本服务!
1、第一级切片的范围重设置
Sector sector1 = new Sector(sector.minLatitude(), sector.minLongitude() * 2 + 180, sector.deltaLatitude(), sector.deltaLongitude() * 2);
纬度起点不变,但经度上要偏移原来的2倍,同时纬度差不变,经度差要变为原来的2倍,对应经纬差为2:1的切片。
2、顶级切片之下做子切片
此时不能像顶级切片一样设置,因为子切片是在上一级切片的基础上得到的,将一张父切片等分为四分,此时获得的子切片的起点经纬度是正确的,不能再将经度偏移2倍,而只需要将经差设为2倍即可。
Tile类
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(level.levelNumber>0){
sector1 = new Sector(sector.minLatitude(), sector.minLongitude() , sector.deltaLatitude(), sector.deltaLongitude() * 2);
tile = new ImageTile(sector1, level, row, column);
}
3、切片服务的起点在左上角(-180,90),而WorldWindAndroid中为左下角(-180,-90),所以,行数上略作变换
int row1 = (int) Math.pow(2, (level.levelNumber + 2)) - 1 - row;
最后,得到完整的加载类TiandituVecLayer 如下:
import gov.nasa.worldwind.WorldWind;
import gov.nasa.worldwind.geom.Sector;
import gov.nasa.worldwind.render.ImageOptions;
import gov.nasa.worldwind.render.ImageSource;
import gov.nasa.worldwind.render.ImageTile;
import gov.nasa.worldwind.shape.TiledSurfaceImage;
import gov.nasa.worldwind.util.Level;
import gov.nasa.worldwind.util.LevelSet;
import gov.nasa.worldwind.util.LevelSetConfig;
import gov.nasa.worldwind.util.Logger;
import gov.nasa.worldwind.util.Tile;
import gov.nasa.worldwind.util.TileFactory;
/**
* Created by Lenovo on 2018/4/1.
*/
public class TiandituVecLayer extends RenderableLayer implements TileFactory {
//protected TileFactory tiandituTileFactory;
String urlAddress = "";
public TiandituVecLayer() {
this("http://t0.tianditu.com/DataServer");
}
public TiandituVecLayer(String serviceAddress) {
if (serviceAddress == null) {
throw new IllegalArgumentException(
Logger.logMessage(Logger.ERROR, "BlueMarbleLandsatLayer", "constructor", "missingServiceAddress"));
}
urlAddress = serviceAddress;
//tiandituTileFactory = new WmtsTileFactory();
// Configure this layer's level set to capture the entire globe at 15m resolution.
double metersPerPixel = 15;
double radiansPerPixel = metersPerPixel / WorldWind.WGS84_SEMI_MAJOR_AXIS;
LevelSetConfig levelsConfig = new LevelSetConfig(null, 45, 16, 512, 256);
//levelsConfig.numLevels = levelsConfig.numLevelsForResolution(radiansPerPixel);
this.setDisplayName("TiandituSat");
this.setPickEnabled(false);
TiledSurfaceImage surfaceImage = new TiledSurfaceImage();
surfaceImage.setLevelSet(new LevelSet(levelsConfig));
surfaceImage.setTileFactory(this);
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) {
Sector sector1 = new Sector(sector.minLatitude(), sector.minLongitude() * 2 + 180, sector.deltaLatitude(), sector.deltaLongitude() * 2);
ImageTile tile = new ImageTile(sector1, level, row, column);
if(level.levelNumber>0){
sector1 = new Sector(sector.minLatitude(), sector.minLongitude() , sector.deltaLatitude(), sector.deltaLongitude() * 2);
tile = new ImageTile(sector1, level, row, column);
}
//urlAddress= "http://t0.tianditu.com/DataServer";
//String urlString = urlAddress;//this.urlForTile(level.levelNumber, row, column);
int row1 = (int) Math.pow(2, (level.levelNumber + 2)) - 1 - row;//计算行列和jishu
int col1 = column;
/*if(col1> Math.pow(2, (level.levelNumber + 2))-1){
return null;
}*/
/* if(column%2!=0){
return null;
}else{
col1 = column/2;
}*/
int level1 = level.levelNumber + 2;
String serverURL = urlAddress.replaceFirst("0", String.valueOf((int) (Math.random() * 8)));//由于服务器端采用了集群技术,http://tile0/同http://tile7/取的是同一图片
//瓦片URL串
String urlString = serverURL + "?T=vec_w&x="+col1+"&y="+row1+"&l="+level1;
if (urlString != null) {
tile.setImageSource(ImageSource.fromUrl(urlString));
}
return tile;
}
}
不过,由于投影的问题,加载的地图与worldwind的坐标系是不完全匹配的,所以,也只能通过这一过程来充分认识WorldWindAndroid加载切片的内在逻辑了!