背景
地圖功能是每個系統必備的功能之一,通常可以使用百度地圖和高德地圖來實作線上地圖展示。
但是将展示的地圖下載下傳到本地則是一件有挑戰的事情。
運作環境
mac系統
java 1.8
其中标注的坐标原始資料是百度坐标,是以代碼中進行了轉換。
參考代碼
需求
某一天上司找我,說客戶提出需要将系統裡的線上地圖下載下傳到本地浏覽。利用搜尋引擎,找到一些思路,
前端思路: 線上地圖是canvas繪制的,可以将canvas轉圖檔存儲到本地。
後端思路: 高德和百度均提供靜态地圖接口,但是存在尺寸限制、标注限制。是以需要程式自己切割下載下傳,拼接地圖。
作為一名java後端開發,當然是選擇後端解決方案。
這裡先說下我的需求:我需要一份地圖,是杭州濱江地區的,地圖需要标注一些位置。這些位置超過10個。是以無法直接使用高德地圖接口下載下傳。
實作過程
以高德地圖為例,
首先請注冊高德開發者,申請密鑰,如此才可以調用接口
public final static String uurl = "http://restapi.amap.com/v3/staticmap?zoom=16&size=1024*1024&scale=1";// 高德地圖api
key = "你的密鑰";
解釋下這個接口的參數。
zoom 地圖的縮放比。
size 地圖的尺寸
scale 地圖清晰度 1表示非高清。2表示高清。如果設定值為2 則 zoom将自動成為17 size将變成 2048
由于下載下傳高清地圖,非常慢,以及記憶體容易溢出,是以這裡修改非高清的參數。
直接想要結果的,可以下載下傳一份代碼,自己跑一次
這裡先解釋下思路:
1、經緯度切割。 先确定你需要下載下傳地圖的經緯度範圍。需要2個點即可。
地圖左上角、地圖右下角。
例如這裡我的坐标是杭州濱江區。
String top = "120.123754,30.232441";
String end = "120.243745,30.141632";
你需要決定将你的地圖切割成多少塊。
這裡我設定步長是
// 按照0.01為步長,循環計算出所需獲得的圖檔中心位置坐标
int countX = (int) ((ex - sx) / 0.010999);// 如果ex - sx = 0,說明隻有一列
int countY = (int) ((sy - ey) / 0.00955);// 如果sy - ey = 0,說明隻有一行
其中0.010999 表示 橫向的地圖中心距離 0.00955 表示豎向的地圖中心距離。
這2個值 不能随意修改。和縮放比、清晰度存在關聯。
2、下載下傳地圖
設定了步長後即可運作程式,下載下傳地圖碎片。下載下傳有可能失敗,請多次執行,直到數目完整。
3、橫向切割圖檔
下載下傳的地圖碎片,多數情況存在重疊部分,是以需要切割。切割的規則是 第一張圖檔保持完整,從第二張圖檔開始切割重疊的部分,隻保留不重疊的圖檔。是以需要确定起點是關鍵。
for (int i = 1, j = 0; i <= allPng; i++) {
System.out.println("正在截取");
if (i == (j * count[1] + 1)) {
cutImage(path + "/getMaps/" + i + ".png", path + "/cuttedMaps/" + i + ".png", 0, 0, 1024, 1024);
j++;
} else {
cutImage(path + "/getMaps/" + i + ".png", path + "/cuttedMaps/" + i + ".png", 1024 - 1024, 0, 1024,
1024);
}
}
上圖中的 1024-1024 表示計算切割的起點位置。
這個重疊值如何确定,拿 1.png和2.png 對比确定。在打開ps工具手動數數偏差。 如果你重疊的像素是10 則這裡應當是 10
這裡因為我給的步長十分精确,重疊為0 是以切割的起點位置從0開始。
3、豎向切割
和橫向是同理的。需要人工通過ps确定 重疊的像素是多少.
橫向是比較第一張和第二張圖檔,但是豎向則需要 比較 第一列的第一張和 第二列的第一張圖檔。
System.out.println("開始對圖檔進行第二次截取...");
File f1 = new File(path + File.separator+"mergedMaps");
String[] mergedImgs = f1.list();
for (int i = 1; i <= mergedImgs.length; i++) {
if (i != mergedImgs.length) {
cutImage(path + File.separator+"mergedMaps"+File.separator + i + ".png", path + "/cutteddMaps/" + i + ".png", 0, 0,
(count[1] - 1) * 1024 + 1024, 1024);
} else {
cutImage(path + File.separator+"mergedMaps"+File.separator + i + ".png", path + "/cutteddMaps/" + i + ".png", 0, 0,
(count[1] - 1) * 1024 + 1024, 1024);
}
}
4、合成
正确設定步長、橫豎的切割起點,即可正确拼接出想要的圖檔了。
下載下傳圖檔可能不完整,可以重複多次執行,
以下是程式執行的效果。由于是16的縮放比,是以圖是很大的。大小是 28MB

image.png
問題
1、拼接的圖檔,出現錯位?
重疊值錯誤。請重新設定。
2、圖檔沒有重疊?
步長太大,請重新設定。
3、标注不完整,破碎
這個問題非常常見,本人也卡在這裡。主要原因是标注的點,正好處于分割線上,然後分割線存在重疊部分,切割的時候導緻标注不完整。
這裡解決方案主要是,不斷改變步長,確定地圖水準恰好無縫可以拼接。也就是0重疊,但是線條吻合。傳說中的完美分割,本人采用的就是該方案。
另外一個就是 ,位于标注上的點,坐标進行偏移,確定位于重疊的右側。這樣不會被切割。也需要多次人工嘗試。
4、高清版本
高清版本的參數和非高清的差異較大。主要是確定是 高清版本的地圖碎片尺寸是固定的 2048
而非高清的是 1024 是以需要注意修改參數。
5、切割和合并提示檔案不存在
下載下傳的地圖不完整,多次運作程式即可。因為高德的該接口似乎很奇怪,經常會失敗。
代碼下載下傳
提供2份代碼
濱江高清版本
稍後釋出,