WebGIS:前端:给出地理范围计算出地图瓦片的行列号
目录
前端代码实现
根据xml配置文件计算出行列号
1、xml配置文件信息样例
2、代码实现
运用到的知识
该文档是根据本人做的项目进行的总结,可能存在知识不准确,仅做参考;
前端代码实现
根据提供一个瓦片服务地址,解析服务的元数据,获取到范围,根据范围,计算出行列号
根据xml配置文件计算出行列号
1、xml配置文件信息样例
2、代码实现
1、解析xml数据为json格式的数据,借助插件x2js
2、本例中,只做了3857和4326坐标系的支持;请求用axios进行请求
3、因为文档中的比例尺分母使用的是米,所以4236中,如果没有提供level时,将度数转为米进行匹配层级信息的
4、4326坐标系的地球半径取值为:6371004;3857坐标系的地球半径取值为:6378137;
import X2JS from 'x2js';// 1、请求配置文件路径,获取元数据,通过插件x2js解析xml数据为json格式
let url = 'http://xxxxx';
axios.get(url).then((res) => {if (res.status != 200) {alert('请检查您的配置文件路径');return false;}var x2js = new X2JS();var json = x2js.xml2js(res.data);getColRowLevel({data:json,dpi:90.714});
});// 2、 根据获取的元数据,获取行列号和层级
const getColRowLevel = (json) => {let { data, dpi, level } = json;let Contents = data.Capabilities.Contents;let TileMatrixSet = Contents.TileMatrixSet;// 元数据中的crs坐标系let SupportedCRS = TileMatrixSet.SupportedCRS.__text || TileMatrixSet.SupportedCRS;// 默认crs是3857//默认dpi为90.714,dpi一般为90.714或者96;如果不确定dpi请咨询提供服务的后台dpi = dpi ? Number(dpi) : 90.714;level = level ? Number(level) : null;if (SupportedCRS.toLowerCase().includes('epsg::4326')) {// 4326return colRowLevel4326(Contents, dpi, level);} else {// 3857return colRowLevel3857(Contents, dpi, level);}
};const colRowLevel4326 = (Contents, dpi, level) => {let Layer = Contents.Layer;// 服务范围,如果给指定范围,则去掉下面四行,直接let extentObj = {minX,minY,maxX,maxY}let WGS84BoundingBox = Layer.WGS84BoundingBox;let LowerCorner = WGS84BoundingBox.LowerCorner.__text;let UpperCorner = WGS84BoundingBox.UpperCorner.__text;let extentObj = getExtent4326(LowerCorner, UpperCorner);let { minX, maxX, minY, maxY } = extentObj;let canvasWidth = 1000;let tileSize = 256;let realTileWidthDegree = (maxX - minX) / (canvasWidth / tileSize);let realTileWidthMeter = (realTileWidthDegree / 180) * (Math.PI * 6371004);let resolutions = realTileWidthMeter / tileSize;let scaleDenominator = resolutions / (0.0254 / dpi);// // Identifier ScaleDenominator TileHeight TopLeftCornerlet TileMatrixSet = Contents.TileMatrixSet;let TileMatrixArr = TileMatrixSet.TileMatrix;// 当前比例尺最接近的对象let curScaleObj = getScaleInfo(TileMatrixArr,scaleDenominator,level);if (curScaleObj) {// Identifier ScaleDenominator TileWidth TopLeftCornerlet { ScaleDenominator, TopLeftCorner, Identifier, TileWidth } = curScaleObj;Identifier = Identifier.__text;ScaleDenominator = eToNumber(ScaleDenominator);let originObj = TopLeftCorner.split(' ');let originX = originObj[1];let originY = originObj[0];var resolution = (((0.0254 / dpi) * ScaleDenominator) / (Math.PI * 6371004)) * 180;let minCol = Math.floor(Math.abs(originX - minX) / (resolution * tileSize));let minRow = Math.floor(Math.abs(originY - maxY) / (resolution * tileSize));let maxCol = Math.ceil(Math.abs(originX - maxX) / (resolution * tileSize));let maxRow = Math.ceil(Math.abs(originY - minY) / (resolution * tileSize));return {minCol,minRow,maxCol,maxRow,level: Identifier};}return false;
};const colRowLevel3857 = (Contents, dpi, level) => {let Layer = Contents.Layer;// 服务范围,如果给指定范围,则去掉下面四行,直接let extentObj = {minX,minY,maxX,maxY}let WGS84BoundingBox = Layer.WGS84BoundingBox;let LowerCorner = WGS84BoundingBox.LowerCorner.__text;let UpperCorner = WGS84BoundingBox.UpperCorner.__text;let extentObj = getExtent3857(LowerCorner, UpperCorner);let { minX, maxX, minY, maxY } = extentObj;let canvasWidth = 1000;let tileSize = 256;let realTileWidth = (maxX - minX) / (canvasWidth / tileSize);let resolutions = realTileWidth / tileSize;let scaleDenominator = resolutions / (0.0254 / dpi);// Identifier ScaleDenominator TileHeight TopLeftCornerlet TileMatrixSet = Contents.TileMatrixSet;let TileMatrixArr = TileMatrixSet.TileMatrix;// 当前比例尺最接近的对象let curScaleObj = getScaleInfo(TileMatrixArr,scaleDenominator,level);if (curScaleObj) {// Identifier ScaleDenominator TileWidth TopLeftCornerlet { ScaleDenominator, TopLeftCorner, Identifier, TileWidth } = curScaleObj;Identifier = Identifier.__text;ScaleDenominator = eToNumber(ScaleDenominator);let originObj = getOrigin(TopLeftCorner);let originX = originObj.x;let originY = originObj.y;let resolution = (0.0254 / dpi) * ScaleDenominator;let minCol = Math.floor(Math.abs(originX - minX) / (resolution * tileSize));let minRow = Math.floor(Math.abs(originY - maxY) / (resolution * tileSize));let maxCol = Math.ceil(Math.abs(originX - maxX) / (resolution * tileSize));let maxRow = Math.ceil(Math.abs(originY - minY) / (resolution * tileSize));return {minCol,minRow,maxCol,maxRow,level: Identifier};}return false;
};// 得到当前比例尺信息
const getScaleInfo = (TileMatrixArr,scaleDenominator,level)=>{let curScaleObj = null;let neastScaleD = undefined;if (level) {curScaleObj = TileMatrixArr.find((item) => item.Identifier.__text == level);}if (!curScaleObj) {TileMatrixArr.forEach((item) => {let ScaleDenominator = eToNumber(item.ScaleDenominator);let dist = Math.abs(scaleDenominator - ScaleDenominator);if (neastScaleD == undefined) {neastScaleD = dist;curScaleObj = item;} else if (dist < neastScaleD) {neastScaleD = dist;curScaleObj = item;}});}return curScaleObj;
}// 得到origin
const getOrigin = (TopLeftCorner) => {let arr = TopLeftCorner.split(' ');return { x: eToNumber(arr[0]), y: eToNumber(arr[1]) };
};
// 将自然计数转化为数字
const eToNumber = (eNum) => {eNum = (eNum + '').toLowerCase();if (eNum.includes('e')) {let arr = eNum.split('e');return Number(arr[0]) * Math.pow(10, arr[1]);}return Number(eNum);
};// 得到范围的坐标点
const getExtent3857 = (LowerCorner, UpperCorner) => {let lowerArr = LowerCorner.split(' ');let upperArr = UpperCorner.split(' ');let min = WGS84ToMercator({ lng: lowerArr[0], lat: lowerArr[1] });let max = WGS84ToMercator({ lng: upperArr[0], lat: upperArr[1] });return {minX: min.lng,minY: min.lat,maxX: max.lng,maxY: max.lat};
};
const getExtent4326 = (LowerCorner, UpperCorner) => {let lowerArr = LowerCorner.split(' ');let upperArr = UpperCorner.split(' ');return {minX: lowerArr[0],minY: lowerArr[1],maxX: upperArr[0],maxY: upperArr[1]};
};
运用到的知识
1、像素和米的换算
1英寸 = 2.54厘米 = 0.0254米
1英寸 = 96像素
所以:1像素 = (0.0254/dpi)米
dpi一般取值96或者90.714,dpi的值不确定的话,需要咨询提供瓦片服务的人
2、分辨率的计算
分辨率 = (0.0254/dpi)*比例尺分母;