<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          自學(xué)HarmonyOS應(yīng)用開(kāi)發(fā)(52)- 地圖數(shù)據(jù)拼接和緩存

          上一篇文章中我們獲取了當(dāng)前位置所處的地圖瓦片并表示,本文介紹獲取更多的瓦片數(shù)據(jù)并進(jìn)行拼接的方法。動(dòng)作演示視頻如下:

          瓦片數(shù)據(jù)類

          我們假設(shè)顯示區(qū)域的中心是當(dāng)前位置,以這個(gè)位置為中心分別向上下左右擴(kuò)展地圖瓦片就可以鋪滿整個(gè)表示區(qū)域的地圖數(shù)據(jù)。為了方便管理,我們?cè)O(shè)計(jì)了瓦片數(shù)據(jù)類:

          public class Tile extends PixelMapHolder {    static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00208, "Tile");    int x = 0;    int y = 0;    int z = 0;    // 地圖來(lái)源    public enum MapSource {        GAODE_VECTOR, GAODE_ROAD, GAODE_SATELLITE    }
          public Tile(PixelMap pixelMap) { super(pixelMap); }
          public void setTileInfo(int tile_x, int tile_y, int zoom) { x = tile_x; y = tile_y; z = zoom; }
          public static Tile createTile(MapSource src, int tile_x, int tile_y, int zoom){ String urlString = String.format(getMapUrlString(src), tile_x, tile_y, zoom); PixelMap map = Tile.getImagePixmap(urlString); if(map != null) { Tile tile = new Tile(map); tile.setTileInfo(tile_x, tile_y, zoom); return tile; } else { //HiLog.info(LABEL,"createTile Fail: zoom=%{public}d,row=%{public}d,col=%{public}d", zoom, tile_y, tile_x); return null; } }
          public Size calculateOffset(double longitude, double latitude){ //獲取位圖尺寸 Size imageSize = getPixelMap().getImageInfo().size; //獲取當(dāng)前坐標(biāo)所處瓦片位置 int tile_x = getTileX(longitude, z); int tile_y = getTileY(latitude, z); //計(jì)算瓦片經(jīng)度范圍 double long_from = getTileLongitude(tile_x, z); double long_to = getTileLongitude(tile_x + 1, z); //計(jì)算玩片緯度范圍 double lat_from = getTileLatitude(tile_y, z); double lat_to = getTileLatitude(tile_y + 1, z); //計(jì)算Tile內(nèi)偏移量 int offset_x = (int)((longitude - long_from) / (long_to - long_from) * (imageSize.width)); int offset_y = (int)((latitude - lat_from) / (lat_to - lat_from) * (imageSize.height));
          offset_x -= (x - tile_x) * imageSize.width; offset_y -= (y - tile_y) * imageSize.height; //HiLog.info(LABEL,"calculateOffset: x=%{public}d,y=%{public}d,offset_x=%{public}d,offset_y=%{public}d", x, y, offset_x, offset_y); //HiLog.info(LABEL,"calculateOffset: x=%{public}d,y=%{public}d", x, y); return new Size(offset_x, offset_y); }
          public static String getMapUrlString(MapSource src){ // 高德地圖 - 矢量 final String GAODE_V_MAP_URL = "https://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=2&style=8&x=%d&y=%d&z=%d"; // 高德地圖 - 道路 final String GAODE_R_MAP_URL = "https://webst02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=2&style=8&x=%d&y=%d&z=%d"; // 高德地圖 - 衛(wèi)星 final String GAODE_S_MAP_URL = "https://webst01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=2&style=6&x=%d&y=%d&z=%d"; switch(src){ case GAODE_VECTOR: return GAODE_V_MAP_URL; case GAODE_ROAD: return GAODE_R_MAP_URL; case GAODE_SATELLITE: return GAODE_S_MAP_URL; default: return null; } }
          //https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames static int getTileX(double long_deg, int zoom){ int total_cols = (int)Math.pow(2, zoom); return (int)((long_deg + 180)/360 * total_cols); }
          static int getTileY(double lat_deg, int zoom){ double tan = Math.tan(Math.toRadians(lat_deg)); double asinh = Math.log(tan + Math.sqrt(tan * tan + 1)); return (int)((1.0 - asinh / Math.PI) * Math.pow(2, zoom - 1)); }
          static double getTileLongitude(int tile_x, int zoom){ return tile_x / Math.pow(2, zoom) * 360 - 180; }
          static double getTileLatitude(int tile_y, int zoom){ return Math.toDegrees(Math.atan(Math.sinh(Math.PI * (1 - 2 * tile_y / Math.pow(2, zoom))))); }
          /** * 獲取網(wǎng)絡(luò)中的ImagePixmap * @param urlString * @return */ static PixelMap getImagePixmap(String urlString) { try { URL url = new URL(urlString); URLConnection con = url.openConnection(); con.setConnectTimeout(500*1000); InputStream is = con.getInputStream(); ImageSource source = ImageSource.create(is, new ImageSource.SourceOptions()); ImageSource.DecodingOptions options = new ImageSource.DecodingOptions(); options.desiredSize = new Size(512,512); PixelMap pixelMap = source.createPixelmap(options); is.close(); return pixelMap; } catch (Exception e) { return null; } }}

          函數(shù)calculateOffset用于計(jì)算當(dāng)前瓦片和畫面中心之間的偏移量;getMapUrlString是一個(gè)工廠方法用于根據(jù)地圖數(shù)據(jù)源,瓦片位置和當(dāng)前的縮放級(jí)別生成瓦片數(shù)據(jù)。


          瓦片數(shù)據(jù)緩存

          如果每次都重新獲取地圖數(shù)據(jù)勢(shì)必拖慢表示速度,因此準(zhǔn)備了一個(gè)瓦片數(shù)據(jù)緩存類,用來(lái)保存已經(jīng)獲取的地圖數(shù)據(jù):

          public class TileMapData {    static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00207, "TileMapData");    Map<Long, Tile> mapData = new HashMap<Long, Tile>();
          void setData(int zoom, int tile_x, int tile_y, Tile tile){ //HiLog.info(LABEL, "TileMapData.setData!"); mapData.put(getKey(zoom, tile_x, tile_y), tile); }
          Tile getData(int zoom, int tile_x, int tile_y){ //HiLog.info(LABEL, "TileMapData.getData!"); Tile tile = mapData.get(getKey(zoom, tile_x, tile_y)); return tile; }
          void clear(){ mapData.clear(); }
          private Long getKey(int zoom, int tile_x, int tile_y){ return new Long((zoom << 50) + (tile_x << 20) + tile_y); }}

          代碼很簡(jiǎn)單,唯一的一個(gè)小技巧是根據(jù)縮放倍數(shù)和瓦片位置計(jì)算key值。


          獲取瓦片數(shù)據(jù)

          下面是通過(guò)x,y兩個(gè)方向循環(huán)獲取足以覆蓋整個(gè)表示區(qū)域的瓦片數(shù)據(jù)的代碼。如果需要的數(shù)據(jù)已經(jīng)存在則不再重新獲取;如果存在新獲取的地圖數(shù)據(jù),則觸發(fā)畫面更新。

          public void loadMapTile(boolean invalidate){    getContext().getGlobalTaskDispatcher(TaskPriority.DEFAULT).asyncDispatch(new Runnable() {        @Override        public void run() {            HiLog.info(LABEL, "TileMap.loadMapTile.run!");            int tileCol = Tile.getTileX(longitude, zoom);            int tileRow = Tile.getTileY(latitude, zoom);            boolean need_update = false;            for(int col = tileCol - 1; col <= tileCol + 1; col++) {                for (int row = tileRow - 1; row <= tileRow + 1; row++) {                    Tile tile = mapData.getData(zoom, col, row);                    if (tile == null) {                        //HiLog.info(LABEL,"loadMapTile: zoom=%{public}d,row=%{public}d,col=%{public}d", zoom, row, col);                        tile = Tile.createTile(mapSource, col, row, zoom);                        if(tile != null) {                            //HiLog.info(LABEL,"createTile Succefully!: zoom=%{public}d,row=%{public}d,col=%{public}d", zoom, row, col);                            mapData.setData(zoom, col, row, tile);                            need_update = true;                        }                    }                }            }            if(need_update || invalidate)            {                getContext().getUITaskDispatcher().asyncDispatch(new Runnable() {                    @Override                    public void run() {                        //HiLog.info(LABEL, "TileMap.loadMapTile.run.TileMap.this.invalidate!");                        TileMap.this.invalidate();                    }                });            }        }    });}


          顯示地圖數(shù)據(jù)

          以下是顯示地圖數(shù)據(jù)的代碼:

          @Overridepublic void onDraw(Component component, Canvas canvas) {    HiLog.info(LABEL, "TileMap.onDraw!");    int tileCol = Tile.getTileX(longitude, zoom);    int tileRow = Tile.getTileY(latitude, zoom);    boolean need_load = false;    for(int col = tileCol - 1; col <= tileCol + 1; col++){        for(int row = tileRow - 1; row <= tileRow + 1; row++){            Tile tile = mapData.getData(zoom, col, row);            if(tile != null) {                Size imageSize = tile.getPixelMap().getImageInfo().size;                Size offset = tile.calculateOffset(longitude, latitude);                canvas.drawPixelMapHolder(tile,                        getWidth() / 2 - offset.width,                        getHeight() / 2 - offset.height,                        new Paint());            }            else{                need_load = true;            }        }    }    if(need_load){        loadMapTile(false);    }}

          如果存在沒(méi)有準(zhǔn)備好的數(shù)據(jù),則觸發(fā)一次地圖數(shù)據(jù)獲取處理。


          參考代碼

          完整代碼可以從以下鏈接下載:

          https://github.com/xueweiguo/Harmony/tree/master/StopWatch


          參考資料

          Slippy map tilenames(包含各種轉(zhuǎn)換示例代碼):

          https://wiki.openstreetmap.org/wiki/Slippy_map_tilenames\

          董昱老師的TinyMap:

          https://gitee.com/dongyu1009/tiny-map-for-harmony-os/tree/master/tinymap


          作者著作介紹

          《實(shí)戰(zhàn)Python設(shè)計(jì)模式》是作者去年3月份出版的技術(shù)書籍,該書利用Python 的標(biāo)準(zhǔn)GUI 工具包tkinter,通過(guò)可執(zhí)行的示例對(duì)23 個(gè)設(shè)計(jì)模式逐個(gè)進(jìn)行說(shuō)明。這樣一方面可以使讀者了解真實(shí)的軟件開(kāi)發(fā)工作中每個(gè)設(shè)計(jì)模式的運(yùn)用場(chǎng)景和想要解決的問(wèn)題;另一方面通過(guò)對(duì)這些問(wèn)題的解決過(guò)程進(jìn)行說(shuō)明,讓讀者明白在編寫代碼時(shí)如何判斷使用設(shè)計(jì)模式的利弊,并合理運(yùn)用設(shè)計(jì)模式。

          對(duì)設(shè)計(jì)模式感興趣而且希望隨學(xué)隨用的讀者通過(guò)本書可以快速跨越從理解到運(yùn)用的門檻;希望學(xué)習(xí)Python GUI 編程的讀者可以將本書中的示例作為設(shè)計(jì)和開(kāi)發(fā)的參考;使用Python 語(yǔ)言進(jìn)行圖像分析、數(shù)據(jù)處理工作的讀者可以直接以本書中的示例為基礎(chǔ),迅速構(gòu)建自己的系統(tǒng)架構(gòu)。




          覺(jué)得本文有幫助?請(qǐng)分享給更多人。

          關(guān)注微信公眾號(hào)【面向?qū)ο笏伎肌枯p松學(xué)習(xí)每一天!

          面向?qū)ο箝_(kāi)發(fā),面向?qū)ο笏伎迹?/span>



          瀏覽 61
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  在线成人免费视频 | 免费看黄A级毛片成人片 | 第四色色五月 | 亚洲一级无码精品 | 天天干,一区二区 |