美文网首页开源GIS相关
为mapbox部署离线地图

为mapbox部署离线地图

作者: 上岸躲雨 | 来源:发表于2018-11-05 16:18 被阅读43次

看到一个博客 分析矢量地图切片技术,里面提到MBTiles文件。于是产生了想利用该文件格式部署离线地图想法,也是补充自己在使用mapbox地图数据来源这块短板。

使用mbtiles文件发布地图分为以下几步:

  1. 找到或制作合适的 mbtiles文件。osmlabopenmaptiles
    tippecanoe

  2. 将文件内的发布出去。mbview

以上的解决方案,都是网上搜集的方案。但是存在以下问题:

  • osm在国内数据质量不行,如缺少建筑数据。
  • 使用网上开源的发布程序,没找到自己称手的。

为了解决上面问题,打算自己写代码爬数据然后自己发布数据。

  1. 爬取四维图新的数据
import sqlite3
import requests
from  mbtiles.TileLnglatTransformGoogle import *
from mbtiles.TileLnglatTransformGaode import *
import time

#**创建表格接收数据**
def createDataTable(layerName):
   print(layerName)
   #链接sqlite数据库文件
   conn = sqlite3.connect('minedata.mbtiles')
   c = conn.cursor()
   print("Opened database successfully");
   table_name = layerName;
   sql = "SELECT count(*) FROM sqlite_master WHERE type='table' AND name='" + table_name + "';";
   cursor = c.execute(sql);
   dateArr = cursor.fetchall();
   tableCount = dateArr[0][0];
   if (tableCount > 0):
      print("已存在")
   else:
      print("不存在")
      createSql = "CREATE TABLE " + table_name + " (zoom_level integer, tile_column integer, tile_row integer, tile_data blob,primary key (zoom_level,tile_column,tile_row));"
      cursor.execute(createSql)
      conn.commit();
   print("Operation done successfully");
   cursor.close();
   conn.close()

#瓦片入库
def insert_image_db(z,x,y,image,layerName):
    sql_path = "minedata.mbtiles"
    conn = sqlite3.connect(sql_path, timeout=10)
    try:
        sql="INSERT INTO "+layerName+" (zoom_level, tile_column, tile_row, tile_data) VALUES (?,?,?,?);"
        conn.execute(sql,(z,x,y,image))
        conn.commit()
        conn.close()
    except IOError:
        print ("写入数据库失败")
        conn.close()

#请求瓦片
def downImg(z,x,y,url,layerName):
    url=url+str(z)+"/"+str(x)+"/"+str(y)+"?token=[your_key]&solu=2365";
    print(url)
    try:
        print("url")
        r = requests.get(url, timeout=30)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
        print(len(r.content))
        if(len(r.content)>0):
            img_blob=sqlite3.Binary(r.content);
            insert_image_db(z,x,y,img_blob,layerName);
            time.sleep(2);
    except Exception as e:
        print(e);



def downOneLayer(layerName,lnglatRange,startZ,lastZ):
    url="http://datahive.minedata.cn/data/"+layerName+"/"
    for zlevel in range(startZ,lastZ):
        print(zlevel)
        tilesRange = getTilesRange(lnglatRange, zlevel);
        print(tilesRange)
        minX = tilesRange[0];
        minY = tilesRange[3];
        maxX = tilesRange[2];
        maxY = tilesRange[1];
        print(tilesRange);
        print(minX, maxX);
        print(minY, maxY)
        tiles = [];
        for i in range(minX - 1, maxX + 1):
            for j in range(minY - 1, maxY + 1):
                tile = [i, j, zlevel];
                tiles.append(tile);
        for tile in tiles:
            downImg(tile[2], tile[0], tile[1],url,layerName)



#根据经纬度、层级计算瓦片号
def lnglatToTilesRange(lnglat,z):
    return lnglatToTile_gaode(lnglat[0],lnglat[1],z);

#获取瓦片范围
def getTilesRange(lnglatRange,z):
    # [minX,minY,maxX,maxY]
    return [ lnglatToTilesRange(lnglatRange[0],z)[0],lnglatToTilesRange(lnglatRange[0],z)[1],lnglatToTilesRange(lnglatRange[1],z)[0],lnglatToTilesRange(lnglatRange[1],z)[1]];



#layerName需要爬取的图层名,范围,开始层级,结束层级
def downTileLayer(layerName,minX,minY,maxX,maxY,startZ,lastZ):
   createDataTable(layerName);
   lnglatRange = [
      [minX, minY],  # [minX,minY]
      [maxX, maxY],  # [maxX,maxY]
   ];
   downOneLayer(layerName,lnglatRange,startZ,lastZ);


downTileLayer("Waterface",119.9635, 30.0841,120.3971, 30.4146,12,18)
  1. 发布图层数据
import sqlite3
from django.http import HttpResponse
#发布图层数据
def getXYZ(request,x,y,z,layerName):
    conn = sqlite3.connect('/home/yushi/PycharmProjects/superpower/simulation/view/minedata.mbtiles')
    c = conn.cursor()
    # z = 12;
    # x = 2885;
    # y = 2534;
    sql="SELECT * from "+layerName+" m WHERE m.zoom_level = " + str(
            z) + " AND m.tile_column = " + str(x) + " AND m.tile_row = " + str(y) + ""

    cursor = c.execute(sql)
    dateArr = cursor.fetchall();
    print(len(dateArr))
    print(sql)
    if (len(dateArr) > 0):
        pbfFile=dateArr[0][3];
        FileName=dateArr[0][2];
        cursor.close();
        conn.close();
        response = HttpResponse(pbfFile, content_type='application/octet-stream')
        response['Content-Disposition'] = "filename="+str(FileName)
        return response;
  1. mapbox添加图层,测试结果
//mapbox添加图层
       map.on('load', function () {
            map.addSource('minedata_source', {
                type: 'vector',
                    tiles:['http://192.168.25.44:8000/simulation/getXYZ/{z}/{x}/{y}'],
                    maxzoom: 22
            })
            map.addLayer( {
                "id": "83798d37c86f475985aa16353d0e269f",
                "maxzoom": 17.5,
                "source": "minedata_source",
                "layout": {
                    "visibility": "visible"
                },
                "source-layer": "Waterface",
                "paint": {
                    "fill-outline-color": "#e6120e",
                    "fill-color": "#e6120e",
                    "fill-antialias": true,
                    "fill-translate-anchor": "viewport"
                },
                "minzoom": 5.0,
                "type": "fill",
            })
Waterface图层效果

结果验证,效果还是比较满意,自己爬数据自己发布数据,终于mapbox使用上补上了数据这块。

相关文章

网友评论

    本文标题:为mapbox部署离线地图

    本文链接:https://www.haomeiwen.com/subject/kdbsxqtx.html