Cesiumlab提供了两种地形切片方式,一种是散列文件,一种是sqlite数据库形式。
散列文件数量往往巨大,拷贝和发布需要耗费较长的时间,因此选用sqlite形式,该方案需要自己写服务发布。本人试着用Node.js+Koa2写了一个地形发布服务。
根据帮助文件,sqlite数据库包括infos表和blocks表两种,infos表主要存储了layer.json文件,blocks表则存储了terrain文件。为了提高查询效率,blocks表根据层级划分为了不同的表。如果一个块的索引为x、y、z,如果 z < 10,那么表名是blocks,否则表名为“blocks_” + tostring(z) + “_” + tostring(x / 512) + “_” + tostring(y / 512) 。
服务发布方法如下:
const path = require('path');
const Koa = require('koa');
const app = new Koa();
const serve = require('koa-static');
const router = require('koa-router')();
const SqliteDB = require('./src/js/sqlite.js').SqliteDB;
// 静态文件
const home = serve(path.join(__dirname) + '/src/');
app.use(home);
// 引入sqlite数据库
var file = "./src/data/dem.pak";
var sqliteDB = new SqliteDB(file);
// 查询layer.json文件,由于查询需要时间,所以使用Promise形式,否则会加载失败
function layerQuery() {
let querySql = 'select layerjson from infos where type = "terrain"';
return new Promise((resolve, reject) => {
sqliteDB.queryData(querySql, (obj) => {
if (obj.length > 0) {
let layerBuf = obj[0].layerjson;
// 需要把Buffer转为字符串,否则无法读取
resolve(layerBuf.toString('utf-8'));
} else {
reject('查询结果为空!');
}
})
});
}
// 查询地形文件
function blockQuery(x, y, z) {
let tableName = z < 10 ? 'blocks' : `blocks_${z.toString()}_${Math.floor(x/512).toString()}_${Math.floor(y/512).toString()}`;
let querySql = `select tile from ${tableName} where x=${x} and y=${y} and z=${z}`;
return new Promise((resolve, reject) => {
sqliteDB.queryData(querySql, (obj) => {
if (obj.length > 0) {
let layerBuf = obj[0].tile;
// 地形文件不需要转格式
resolve(layerBuf);
} else {
reject('查询结果为空!');
}
})
});
}
// 添加路由
router.get('/dem', '/dem/layer.json', async(ctx) => {
await layerQuery().then(res =>
ctx.body = res
).catch(rej =>
ctx.body = rej
);
});
router.get('/dem', '/dem/:z/:x/:y.terrain', async(ctx) => {
await blockQuery(ctx.params.x, ctx.params.y, ctx.params.z).then(res => {
ctx.body = res
}).catch(rej =>
ctx.body = rej
);
});
// 加载路由中间件
app.use(router.routes());
app.listen(3000);
效果如下图所示: