UNPKG

geotile_sdk

Version:

A tile sdk for Cloud Optimised Geotiff and shapefile

292 lines (258 loc) 8.94 kB
/* * @Description: 将当前瓦片请求以及横向相关区域加入orderList(快队列), 立即处理orderList中的瓦片请求, 调用map.js获取瓦片 * @Author: luojun1 * @Date: 2021-10-21 17:25:12 * @LastEditTime: 2021-12-10 11:46:07 */ var util = require('util') var map = require('./map') var Cache = require('./regionCache') // 当前正在处理的请求数量 var requestNum = 0 // 一次获取 pad_width×pad_width个瓦片 var padWidth = 2 /** **order类, 某一瓦片相关的order请求和瓦片数据*****/ class Order { constructor (key, regionNode) { this.key = key this.PaddingRegion = regionNode // 所属的regionNode this.request_recall = [] // 请求此瓦片的回调函数 this.tile_ = undefined // 请求得到的瓦片(暂存) this.BigTile_ = undefined // 请求得到的大瓦片,当有请求时,才提取出小瓦片 this.offsetX = 0 this.offsetY = 0 } sendTile (recall) { if (this.tile_) { recall(null, this.tile_) } else if (this.BigTile_) { // var start1 = new Date().getTime() map.getBlock(this.BigTile_, this.offsetX, this.offsetY, 256, 256, (err, tile) => { // var processTime1 = new Date().getTime() // console.log('###resize:', processTime1 - start1) if (err) { console.error('###getBlock:', err) } // 将瓦片喂给orderList tile.encode('png', function (err, PngTile) { // var processTime2 = new Date().getTime() // console.log('###encode:', processTime2 - processTime1) this.tile_ = PngTile this.BigTile_ = undefined recall(err, this.tile_) }) }) } requestNum-- // preload() } // 来了新的请求,先检查瓦片是否就绪,如未就绪,加入等待队列,如已就绪,直接返回 request (recall) { requestNum++ if (!this.tile_ && !this.BigTile_) { this.request_recall.push(recall) } else { this.sendTile(recall) } } // 瓦片获取成功后,放到order里暂存; 如有等待队列,再喂给等待队列 // 喂小瓦片256*256 feed256Tile (tile) { this.tile_ = tile while (this.request_recall.length) { var recall = this.request_recall.pop() this.sendTile(recall) } } // 喂大瓦片512*512 feed512Tile (tile, offsetX, offsetY) { this.BigTile_ = tile this.offsetX = offsetX this.offsetY = offsetY while (this.request_recall.length) { var recall = this.request_recall.pop() this.sendTile(recall) } } } /** orderList, 快队列, 存放瓦片order, 即刻获取瓦片,hashmap便于快速查找, 全局对象***/ // key: xml_uuid_z_x_y" // value: Order var orderList = new Map() function pushOrders (paddingRegion, Z, xmlUUID, regionNode) { for (var x = paddingRegion[0]; x < paddingRegion[1]; x++) { for (var y = paddingRegion[2]; y < paddingRegion[3]; y++) { var key = util.format('%s_%d_%d_%d', xmlUUID, Z, x, y) if (!orderList.has(key)) orderList.set(key, new Order(key, regionNode)) // console.log('pushOrders:', key) } } } function closeOrder (x, y, z, xmlUUID) { var key = util.format('%s_%d_%d_%d', xmlUUID, z, x, y) if (orderList.has(key)) { if (orderList.get(key).tile_) { delete this.tile_ } orderList.delete(key) } } function cancelOrder (x, y, z, xmlUUID, err) { var key = util.format('%s_%d_%d_%d', xmlUUID, z, x, y) if (orderList.has(key)) { orderList.get(key).feed256Tile(err, []) orderList.delete(key) } } function cancelOrders (paddingRegion, z, xmlUUID, err) { for (var x = paddingRegion[0]; x < paddingRegion[1]; x++) { for (var y = paddingRegion[2]; y < paddingRegion[3]; y++) { cancelOrder(x, y, z, xmlUUID, err) } } } function checkOrder (x, y, z, xmlUUID, sendRecall) { var key = util.format('%s_%d_%d_%d', xmlUUID, z, x, y) if (orderList.has(key)) { Cache.updateRegion(orderList.get(key).PaddingRegion) if (sendRecall) orderList.get(key).request(sendRecall) console.log('###request: got', key) return true } else { console.log('###request: not', key) return false } } function feedSmallTile (x, y, z, xmlUUID, tile) { var key = util.format('%s_%d_%d_%d', xmlUUID, z, x, y) if (orderList.has(key)) { orderList.get(key).feed256Tile(tile) } } function feed512Tile (paddingRegion, z, xmlUUID, BigTile) { for (var x = paddingRegion[0]; x < paddingRegion[1]; x++) { for (var y = paddingRegion[2]; y < paddingRegion[3]; y++) { var key = util.format('%s_%d_%d_%d', xmlUUID, z, x, y) if (orderList.has(key)) { orderList.get(key).feed512Tile(BigTile, 256 * (x - paddingRegion[0]), 256 * (y - paddingRegion[2])) } } } } function pushOrder (paddingRegion, X, Y, Z, xmlUUID, regionNode, sendRecall) { pushOrders(paddingRegion, Z, xmlUUID, regionNode) // 添加触发瓦片的请求回调 var key = util.format('%s_%d_%d_%d', xmlUUID, Z, X, Y) if (orderList.has(key)) orderList.get(key).request(sendRecall) } // orderList // 根据瓦片请求,添加预加载任务 function addPreloadingTask (x, y, z, xmlUUID) { if (z > 19) { return } // 计算低级别瓦片的范围 region z+1 let lowRegion = [x * 2, x * 2 + 2, y * 2, y * 2 + 2] let lowLevel = Number(z) + 1 // 检查生成的低级别瓦片是否已经存在于orderList if (!checkOrder(lowRegion[0], lowRegion[2], lowLevel, xmlUUID)) { Cache.addVerticalRegion(lowRegion, lowLevel, xmlUUID) } } function hasRegion (Region, Z, xmlUUID, mRegion) { for (var x = Region[0]; x < Region[1]; x++) { for (var y = Region[2]; y < Region[3]; y++) { var key = util.format('%s_%d_%d_%d', xmlUUID, Z, x, y) if (orderList.has(key)) { mRegion = orderList.get(key).PaddingRegion return true } } } mRegion = null return false } // 周期循环,最多10次: 0.1s执行一次低级别瓦片预加载功能, 执行完判断是否闲时,如是,继续执行预加载 function timeLoop () { setTimeout(function () { // 预加载低]级别瓦片 // console.log('requestNum:', requestNum) if (requestNum <= 0) { let err = Cache.preloadVerticalRegion((Region, z, xmlUUID) => { Cache.checkRegionCache(cancelOrders) // 完善判断条件,避免重复插入region到cache let _ if (!hasRegion(Region, z, xmlUUID, _)) { let regionNode = Cache.addRegion(Region, z, xmlUUID) pushOrders(Region, z, xmlUUID, regionNode) // 提取padding_region瓦片 var start = new Date().getTime() map.fetchTiles(Region, z, xmlUUID, (err, BigTile) => { if (err) { // 如果获取失败,则取消相关的order,并返回err console.error('###fetchTiles failed') cancelOrders(Region, z, xmlUUID, err) } else { var processTime = new Date().getTime() console.log('###preload big tile:', processTime - start) feed512Tile(Region, z, xmlUUID, BigTile) } }) } else { console.log('<<<hasRegion') } }) if (err) { // console.log('>>>>pop end') return } timeLoop() } }, 10) } // 外部接口 function preload () { if (requestNum <= 0) { timeLoop() } } // 外部接口 function OrderTile (x, y, z, xmlUUID, sendRecall) { // 纵向扩大提取范围(预加载低级别瓦片) addPreloadingTask(x, y, z, xmlUUID) // 检查orderList中是否依旧包含此order,如包含,则无需再请求 if (checkOrder(x, y, z, xmlUUID, sendRecall)) { return } // 横向扩大提取范围 var paddingRegion = [ padWidth * Math.floor(x / padWidth), padWidth * Math.floor(x / padWidth) + padWidth, padWidth * Math.floor(y / padWidth), padWidth * Math.floor(y / padWidth) + padWidth] // 将要提取的范围存入orderList(订单列表),并调用回调函数发送 Cache.checkRegionCache(cancelOrders) let regionNode if (!hasRegion(paddingRegion, z, xmlUUID, regionNode)) { regionNode = Cache.addRegion(paddingRegion, z, xmlUUID) } // var regionNode = Cache.addRegion(paddingRegion, z, xmlUUID) pushOrder(paddingRegion, x, y, z, xmlUUID, regionNode, sendRecall) // 提取padding_region瓦片 var start = new Date().getTime() map.fetchTiles(paddingRegion, z, xmlUUID, (err, BigTile) => { var processTime = new Date().getTime() console.log('###fetch big tile:', processTime - start) if (err) { // 如果获取失败,则取消相关的order,并返回err console.error('###fetchTiles failed') cancelOrders(paddingRegion, z, xmlUUID, err) } else { feed512Tile(paddingRegion, z, xmlUUID, BigTile) } }) } module.exports = { OrderTile, preload }