在网上查询了很久,找了很多百度瓦片地图下载文章,但是并没有我想要如何下载百度地图操作的文章教程。通过同事指点加自我摸索理解,总结如下关于下载百度瓦片地图制作的教程。
我们下载某个地区的地图,首先我们需要获取 图块坐标;
百度地图API在展示地图时是将整个地图图片切割成若干图块来显示的,当地图初始化或是地图级别、中心点位置发生变化时,地图API会根据当前像素坐标计算出视野内需要的图块坐标(也叫图块编号),从而加载对应的图块用以显示地图。
百度地图的图块坐标原点与平面坐标一致,从原点向右上方开始编号为0, 0:
如何知道某个位置的图块坐标呢?通过如下公式计算即可(这里为向下取整):
图块坐标 =|像素坐标 ÷ 256|
256实际上是每个图块的宽度和高度,我们用像素坐标除以这个数就知道图块坐标了。还以天安门为例,在第4级下天安门所在的图块编号为:3, 1,而在第18级下,图块编号为:50617, 18851
如何获取百度图块坐标?
打开百度开发平台:http://lbsyun.baidu.com/jsdemo.htm?a#i7_1
将如下代码放入编辑器运行:
<html>
<head>
<meta charset="utf-8"/>
<title>地图坐标概念title>
<script src="http://api.map.baidu.com/api?v=1.2">script>
head>
<body>
<div id="map_container" style="width:500px;height:320px;">div>
<script>
var map =new BMap.Map('map_container', {defaultCursor: 'default'});
map.centerAndZoom(new BMap.Point(116.404, 39.915), 11);
var TILE_SIZE =256;
map.addEventListener('click', function(e){
var info =new BMap.InfoWindow('', {width: 260});
var projection =this.getMapType().getProjection();
var lngLat = e.point;
var lngLatStr ="经纬度:"+ lngLat.lng +", "+ lngLat.lat;
var worldCoordinate = projection.lngLatToPoint(lngLat);
var worldCoordStr ="
平面坐标:"+ worldCoordinate.x +", "+ worldCoordinate.y;
var pixelCoordinate =new BMap.Pixel(Math.floor(worldCoordinate.x * Math.pow(2, this.getZoom() -18)),
Math.floor(worldCoordinate.y * Math.pow(2, this.getZoom() -18)));
var pixelCoordStr ="
像素坐标:"+ pixelCoordinate.x +", "+ pixelCoordinate.y;
var tileCoordinate =new BMap.Pixel(Math.floor(pixelCoordinate.x /256),
Math.floor(pixelCoordinate.y /256));
var tileCoordStr ="
图块坐标:"+ tileCoordinate.x +", "+ tileCoordinate.y;
var viewportCoordinate = map.pointToPixel(lngLat);
var viewportCoordStr ="
可视区域坐标:"+ viewportCoordinate.x +", "+ viewportCoordinate.y;
var overlayCoordinate = map.pointToOverlayPixel(lngLat);
var overlayCoordStr ="
覆盖物坐标:"+ overlayCoordinate.x +", "+ overlayCoordinate.y;
info.setContent(lngLatStr + worldCoordStr + pixelCoordStr + tileCoordStr +
viewportCoordStr + overlayCoordStr);
map.openInfoWindow(info, lngLat);
});
script>
body>
html>
运行出来之后点击地图上会出现如图:
如此可以轻松地获取图块坐标信息。
如何下载百度瓦片?
通过上述可以轻松获取到地域图块坐标范围值。
提供如下Java代码下载瓦片图片:
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
/**
*
* 参考资料:
* 国内主要地图瓦片坐标系定义及计算原理
* 百度地图根据经纬度计算瓦片行列号
*
*/
public class R implements Runnable {
static int succeed = 0;
static int error = 0;
static int finishedThread = 0;
static long endTime = 0;
static String sPath = "http://online1.map.bdimg.com/onlinelabel/?qt=tile&x=%d&y=%d&z=%d&styles=pl&udt=20150924&scaler=1";
/**
* z : 层级
* xstart : x的开始值
* xend : x的最大值
* ystart : y的开始值
* yend : y的最大值
* threads : 几个线程开始下载地图
*/
int z=11, xstart = 407,xend = 409,ystart = 113,yend = 116,threads = 1;
//下载瓦片地图存放地址
String dir = "";
//是否覆盖之前下载的图片
boolean overwrite = false;
Map map = Maps.newHashMap();
public R(Map map) {
this.map = map;
}
public static void main(String[] args) {
final Map map = Maps.newHashMap();
/*Lists.newArrayList(args).forEach(s -> {
String k = s.split("=")[0];
String v = s.split("=")[1];
map.put(k, v);
});*/
List list = Lists.newArrayList(args);
for(String str : list){
String k = str.split("=")[0];
String v = str.split("=")[1];
map.put(k, v);
}
new R(map).run();
}
public void run() {
ExecutorService exec = Executors.newCachedThreadPool();
Set set = Sets.newHashSet();
int total = (xend - xstart) * (yend - ystart);
int split = total / threads;
int count = 0;
for(int i=xstart;i<=xend;i++) {
for(int j=ystart;jnew Point(i, j));
if(++count % split == 0) {
exec.execute(new DownloadThread(set));
set = Sets.newHashSet();
}
}
}
if(set.size()>0) {
exec.execute(new DownloadThread(set));
}
long t = System.currentTimeMillis();
while (finishedThread < threads) {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
}
System.out.println("耗时 " + (System.currentTimeMillis() - t) / 1000 + "s 成功 " + succeed + " 失败 " + error + " ok="+finishedThread+" total = "+total);
}
exec.shutdown();
System.out.println("完成 共耗时 " + (endTime - t) / 1000 + "s 成功 " + succeed + " 失败 " + error + " ok="+finishedThread+" total = "+total);
}
class DownloadThread extends Thread {
Set set;
public DownloadThread(Set set) {
this.set = set;
}
public void run() {
System.out.println(getName() + " started, task size = " + set.size());
File base = new File(dir, z + "");
for(Point point : set) {
int x = point.x;
int y = point.y;
File path = new File(base, x + "");
if (!path.exists()) {
path.mkdirs();
}
File file = new File(path, y + ".jpg");
if (!file.exists() || overwrite) {
String url = String.format(sPath, x, y, z);
boolean b = save(url, file);
if (b) {
succeed++;
System.out.println(file.getAbsolutePath());
} else {
error++;
}
}
}
System.out.println(getName()+" finished");
finishedThread++;
endTime = System.currentTimeMillis();
}
byte[] b = new byte[4096];
int s = 0;
boolean save(String path, File file) {
InputStream is = null;
OutputStream os = null;
try {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.connect();
is = conn.getInputStream();
os = new FileOutputStream(file);
while ((s = is.read(b)) != -1) {
os.write(b, 0, s);
}
return true;
} catch (Exception e) {
return false;
} finally {
if (os != null) {
try {
os.flush();
os.close();
} catch (Exception e) {
}
}
if (is != null) {
try {
is.close();
} catch (Exception e) {
}
}
}
}
}
static class Point {
int x, y;
Point(int x,int y){
this.x = x;
this.y = y;
}
}
}
通过上述java代码,修改其中参数值,百度瓦片地图下载到指定路径下。