栅格瓦片转mongodb离线部署

栅格瓦片转mongodb离线部署

前提

​ 上一篇博客中讲到了如何将TMS标准的瓦片转换成mbtiles格式发布服务,但是在现实环境中,使用的切图工具或者切图的人并没有按照标准切图。有的人切片为ArcServer切片或者GeoWebCache切片。这样的话上篇博客的方法就不能适用了。那么本篇博客就讲述上篇解决不了的切片。

实现思路

​ 使用NoSQL(这里指Mongodb)对瓦片的png图片进行入库存储,通过x,y,z来关联对应的图片,然后通过Nodejs查询得到图片的二进制写到页面中。完成展示瓦片的功能

准备工作
  1. 切好的瓦片(我这里是ArcServer切片)
  2. Python(我使用的版本:3.6.2)
  3. NodeJS(我使用的版本:8.11.3)
  4. Mongodb(我使用的版本:4.0.4)
工具安装

这里的Python,NodeJS,Mongodb 可以按照网上的教程安装,这里我就不再赘述了

步骤
  1. 下载栅格瓦片地图
    瓦片目录

    瓦片目录

  2. 编写脚本,将瓦片存入Mongodb库中,这里基于瓦片的图都比较小,就以二进制存到库中,不使用GridFS

    下面的脚本只是我自己要用的,不能满足所有情况,如果自己有特殊需求,可以对代码进行修改。大概思路就是:

    1. 循环遍历切片文件夹中的所有切片
    2. 将读取到的切片转成二进制并存储到库中
from pymongo import MongoClient
import os
from bson import binary


class file2db(object):
    def __init__(self, database, setname, level):
        mongodb_url = 'localhost'
        mongodb_port = 27017
        conn = MongoClient(mongodb_url, mongodb_port)
        db = conn[database]
        self.my_set = db[setname]
        self.max_level = level

    def read_png_file(self, root_path):
        # 遍历文件形成dict
        # D:\Tomcat 8.5\webapps\Layers\_alllayers
        _files = []
        if os.path.exists(root_path):
            list = os.listdir(root_path)
            for i in range(0, len(list)):
                path = os.path.join(root_path, list[i])
                if os.path.isdir(path):
                    _files.extend(self.read_png_file(path))
                if os.path.isfile(path):
                    _files.extend(path)
                    # get column
                    file_name = os.path.basename(path).split('.')[0]
                    file_type = os.path.basename(path).split('.')[1]
                    dir_path = os.path.dirname(path).split('\\')
                    # get row
                    row_name = dir_path[len(dir_path) - 1]
                    # get zoom level
                    zoom_name = dir_path[len(dir_path) - 2]
                    # insert mongodb
                    if file_type == 'png':
                        self.insert_file(zoom_name, row_name, file_name, path)
            return _files
        else:
            return None

    def insert_file(self, zoom, row, column, path):
        # 将data 存到mongo中
        level = zoom[1:]
        if int(level) <= self.max_level:
            png_list = self.my_set.find({"x": row, "y": column, "z": zoom})
            if png_list.count() == 0:
                print('zoom:%s row:%s fileName:%s path:%s ' % (zoom, row, column, path))
                file = open(path, mode='rb')
                content = binary.Binary(file.read())
                self.my_set.insert({"x": row, "y": column, "z": zoom, "img": content})
                file.close()
            else:
                print('this file is exist')
        else:
            print('this zoom greater than max level')


if __name__ == '__main__':
    file2db = file2db('png', 'layer', 13)
    file2db.read_png_file('D:\Tomcat 8.5\webapps\Layers\_alllayers')

执行完毕后库中的数据

库字段

  1. 给数据创建索引
png.layer.createIndex({x:1,y:1,z:1})
--创建完成后可以用explain看看有没有使用索引
  1. 编写node脚本,发布服务

    这里只是简单的写了一下,node我也是边用边学的,如果已经是对node写服务端很熟悉的大佬这段就可以过滤掉了。如果跟我一样也是刚接触的话可以看一下。具体思路:

    1. 连接mongo,查询数据
    2. 写一个接口用于前端调用得到瓦片图

    这里node需要安装的组件有:mongoose,express

新建一个node项目如下:

服务目录

db.js内容:

'use strict';
var mongoose = require('mongoose'),
    DB_URL = 'mongodb://localhost:27017/png';

/**
* 连接
*/
mongoose.connect(DB_URL);

/**
* 连接成功
*/
mongoose.connection.on('connected', function () {    
    console.log('Mongoose connection open to ' + DB_URL);  
});    

/**
* 连接异常
*/
mongoose.connection.on('error',function (err) {    
    console.log('Mongoose connection error: ' + err);  
});    

/**
* 连接断开
*/
mongoose.connection.on('disconnected', function () {    
    console.log('Mongoose connection disconnected');  
});    

module.exports = mongoose;

layer.js内容:

'use strict';
var mongoose = require('./db'),
    Schema = mongoose.Schema;

var GGSchema = new Schema({          
    x : { type: String },                    //行
    y: {type: String},                        //列
    z: {type: String},                        //层级
    img : { type: Buffer},                       //图片二进制
});

module.exports = mongoose.model('layer',GGSchema,'layer');

map-server.js内容:

'use strict';
var express = require('express');
var mylayer = require("./layer");
var app = express();

// 获取图片
app.get('/getimage/',function(req, res) {
    var x = req.query.x
    var y = req.query.y
    var z = req.query.z
    console.log(req.originalUrl)
    var whereStr = {"x":x,"y":y,"z":z};
    mylayer.findOne(whereStr,function(err, doc){
        if(err){
            console.log("Error: "+err)
        }else{
            let img = null 
            if(doc){
                if(doc.img){
                    img = doc.img
                }
            }
            if(img){
                res.writeHead('200', {'Content-Type': 'image/png'});    //写http头部信息
                res.end(img,'binary'); 
            }else{
                res.status(404);
                res.end()
            }

        }
    })

})
var server = app.listen(8081, function () {

    var host = server.address().address
    var port = server.address().port

    console.log("应用实例,访问地址为 http://%s:%s", host, port)

})

  1. 使用OL预览效果

    这里我的切片是ArcgisServer切片,如果是其他切片(geowebcache等)只要更改加载算法就行

//初始化XYZsource
var source  = new ol.source.XYZ({
    tileUrlFunction : function (xyz, obj1, obj2) {
        var z = xyz[0];
        var x = Math.abs(xyz[1]);
        var y = Math.abs(xyz[2]) - 1;
        var x = 'C' + padLeft(8, x.toString(16)).toUpperCase();
        var y = 'R' + padLeft(8, y.toString(16)).toUpperCase();
        var z = 'L' + padLeft(2, z);
        var url = 'http://localhost:8081/getimage?x=' + y + '&y=' + x + '&z=' + z ;
        return url;
    }
});
      
//ArcgisServer切片加载算法
function padLeft(num, val) {
    return (new Array(num).join('0') + val).slice(-num);
}

最后的效果:

预览效果

总结
  1. 如果切片比较多,导入数据库的速度会受影响,可以考虑换成多线程进行处理
  2. 上面的效果是在我自己的开发机器上展现的。单机情况下,这个速度还是可以的。感觉做集群部署将请求进行分发,速度应该还能提高。
最后

以上的代码和脚本均已上传到github库中。

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 13
    评论
栅格瓦片和矢量瓦片是两种不同类型的地图切片,它们在数据存储和呈现方式上存在一些区别。 1. 数据结构: - 栅格瓦片栅格瓦片使用像素网格的形式来存储地图数据,每个瓦片都是一个固定大小的图像,其中包含了地图上的像素值信息。栅格瓦片通常用于卫星图像、航空影像等需要精确的图像表达的地图数据。 - 矢量瓦片:矢量瓦片使用矢量数据来存储地图信息,每个瓦片包含了线、面、点等地理要素的几何形状和属性。矢量瓦片可以根据需要进行渲染和符号化,具有更高的灵活性和可定制性。 2. 数据大小: - 栅格瓦片:由于栅格瓦片是基于像素的图像数据,因此它们的文件大小通常比矢量瓦片要大。这是因为栅格瓦片需要存储每个像素的颜色值和其他属性信息。 - 矢量瓦片:矢量数据可以使用压缩算法来减小文件大小,因此相对于栅格瓦片,矢量瓦片的文件大小通常较小。 3. 渲染和样式: - 栅格瓦片:由于栅格瓦片是预先渲染的图像,因此它们的样式和细节在生成时就已经确定,无法进行动态修改。如果需要更改地图样式或添加交互元素,需要重新生成新的栅格瓦片。 - 矢量瓦片:矢量瓦片可以根据需要进行渲染和样式修改,可以实现动态更新和交互。这使得矢量瓦片在需要实时交互和自定义地图样式的应用中更加灵活。 综上所述,栅格瓦片适用于需要精确图像表达的场景,而矢量瓦片则更适用于需要灵活性和可定制性的应用。选择使用哪种类型的瓦片取决于具体的地图需求和应用场景。
评论 13
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值