1. 程式人生 > >4.02WorldWindAndroid載入天地圖線上非正切片地圖

4.02WorldWindAndroid載入天地圖線上非正切片地圖

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載入切片的內在邏輯了!