WebGIS:前端:给出地理范围计算出地图瓦片的行列号

news2024/9/21 5:37:35

目录

前端代码实现

根据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')) {
        // 4326
        return colRowLevel4326(Contents, dpi, level);
    } else {
        // 3857
        return 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  TopLeftCorner
    let TileMatrixSet = Contents.TileMatrixSet;
    let TileMatrixArr = TileMatrixSet.TileMatrix;
    // 当前比例尺最接近的对象
    let curScaleObj = getScaleInfo(TileMatrixArr,scaleDenominator,level);
    
    if (curScaleObj) {
        // Identifier  ScaleDenominator TileWidth  TopLeftCorner
        let { 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  TopLeftCorner
    let TileMatrixSet = Contents.TileMatrixSet;
    let TileMatrixArr = TileMatrixSet.TileMatrix;
    // 当前比例尺最接近的对象
    let curScaleObj = getScaleInfo(TileMatrixArr,scaleDenominator,level);

    if (curScaleObj) {
        // Identifier  ScaleDenominator TileWidth  TopLeftCorner
        let { 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)*比例尺分母;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/440897.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Linux】Linux入门手册

入门Linux Linux的目录结构Linux的远程操作Xshell 软件Xftp 软件 Linux 基础命令vi 和 vimLinux中的用户管理Linux中的组管理Linux中的权限管理文件或者目录中的三种权限修改文件或者目录的权限使用数字的方式修改文件或者目录的权限 Linux中的帮助命令Linux目录相关命令Linux查…

关于数制及其转换

关于数制及其转换 从1除以10谈起 十进制计算 1 10 0.1 商是有限小数 用二进制计算 是无限循环小数&#xff1a; 1 1010 0.00011001100110011…… 1/10 是无法用二进制小数精确表示的。十进制小数转换成二进制有可能无限循环。 十进制数0.1转换成二进制为0.00011000…

C++程序设计—类与对象

目录 1、类和对象的概念 2、面向对象程序设计的特点 3、类和对象的区别 4、成员运行算符 &#xff08;1&#xff09;&#xff08;.&#xff09;点运算符 &#xff08;2&#xff09;&#xff08;->&#xff09;箭头运算符 5、类的声明形式 &#xff08;1&#xff09;…

DataBinding 大坑总结(网上我暂时搜不到解决方法)

在使用多Module中使用DataBinding会引发一些奇怪的问题&#xff0c;最近好好的腾出时间来折腾这些奇怪的问题&#xff1a; 1&#xff1a;如果当Module启动DataBinding重启AS启动报错的话&#xff0c;就启用允许多行代码 android { defaultConfig {multiDexEnabled true} } de…

设计模式:UML中的类图(6种关系)

一.UML图介绍 统一建模语言是用来设计软件的可视化建模语言。它的特点是简单、统一、图形化、能表达软件设计中的动态与静态信息。 UML 从目标系统的不同角度出发&#xff0c;定义了用例图、类图、对象图、状态图、活动图、时序图、协作图、构件图、部署图等 9 种图。 二.类图…

apkanalyzer-classpath.jar 中没有.class 文件

apkanalyzer-classpath.jar 中没有.class 文件&#xff0c;apkanalyzer-classpath.jar 包目录下&#xff0c;只有 MANIFEST.MF 文件&#xff0c;如下截图&#xff1a; 而 apkanalyzer.jar 下&#xff0c;有很多 class 文件&#xff0c;其中&#xff0c;BinaryXmlParser.class 就…

P80-MySQL

//启动mysql&#xff0c;我的名字是mysql80 net start mysql80//我的端口号为3307 mysql -hlocalhost -P3307 -uroot -p一、课程介绍 什么是数据库? 数据库&#xff1a;DataBase&#xff08;DB&#xff09;&#xff0c;是存储和管理数据的仓库。

ChatGPT账号被封怎么办?进来看看解决办法

部分内容整理自网络&#xff0c;侵删 最近有很多同学说自己的chatgpt账号被封了。仔细研究了一下大部分被封账号&#xff0c;发现主要有这些个原因&#xff1a; 1&#xff0c;被封的账号可能是用程序批量注册的&#xff0c;也就是一台机器用一个IP在短时间内注册了大量的账号 …

JSON Web Tokens (JWT) — the only explanation you will ever need

本文摘抄自 Ariel Weinberger 博客 JSON Web Tokens (JWT) — the only explanation you will ever need | by Ariel Weinberger | Medium JSON Web Tokens (JWT) — the only explanation you will ever need JSON Web Tokens are changing the world for the better. Acting …

java程序员学前端-Vue2篇

Vue 2 1. Vue 基础 1) 环境准备 安装脚手架 npm install -g vue/cli-g 参数表示全局安装&#xff0c;这样在任意目录都可以使用 vue 脚本创建项目 创建项目 vue ui使用图形向导来创建 vue 项目&#xff0c;如下图&#xff0c;输入项目名 选择手动配置项目 添加 vue rou…

【Vue基础】element快速入门

一、知识点整理 1、安装Element UI组件库&#xff0c;在当前目录下&#xff0c;在命令行执行指令&#xff1a; npm install element -ui2.15.3 如果无法安装&#xff0c;执行以下指令&#xff1a; npm install --legacy-peer-deps element-ui --save 2、引入Element组件库 …

IT项目管理画图题【太原理工大学】

期末复习汇总&#xff0c;点这里&#xff01;https://blog.csdn.net/m0_52861684/category_12095266.html?spm1001.2014.3001.5482 也不知道让画啥&#xff0c;随便猜一下吧。我觉得大概率是让画双代号网络图了&#xff0c;不是网络图我倒立&#xff0c;呃...还是算了吧&#…

氢原子光谱、类氢原子光谱和类氢离子光谱

一、氢原子光谱 &#xff08;1&#xff09;万分之五的差值 在文章“原子的波尔模型、能量量子化、光电效应、光谱实验、量子态、角动量”的第3.3节角动量量子化中&#xff0c;通过公式联立获得得里德伯常数要比经验获得的相差万分之五。 当然这时候有人会想是不是实验测得不准…

设计模式:创建者模式 - 适配器模式

文章目录 1.概述2.结构3.类适配器模式4.对象适配器模式5.应用场景6.JDK源码解析 - Reader 与 InputStream 1.概述 如果去欧洲国家去旅游的话&#xff0c;他们的插座如下图最左边&#xff0c;是欧洲标准。而我们使用的插头如下图最右边的。因此我们的笔记本电脑&#xff0c;手机…

中国人民大学与加拿大女王大学金融硕士——每一份投入和努力其实都有回声

有付出&#xff0c;就会有收获&#xff1b;有努力&#xff0c;就会有回报。当你愿意走出舒适区投入到再学习上&#xff0c;当你为了提升自身而努力后&#xff0c;你终将收获属于你的美好。在金融领域在职读研的我们&#xff0c;待拿到中国人民大学与加拿大女王大学金融硕士毕业…

zabbix配置钉钉机器人告警

1.在钉钉上创建一个钉钉群组 2.在群组中添加一个机器人 3.配置zabbix server调用钉钉接口的代码(使用python) 查看是否有python环境 python --version 找到zabbix 的AlertScriptsPath目录路径 cat /etc/zabbix/zabbix_server.conf|grep AlertScriptsPath 将调用钉钉接口的py…

51单片机(80951系列)引脚功能说明

一 AT89C51引脚图 1.0 中断 1.0.1 中断源 AT89C51一共有5个中断源 &#xff08;1&#xff09;&#xff1a;外部中断0&#xff0c;外部中断请求信号由引脚输入&#xff0c;低电平或下降沿有效&#xff0c;中断请求标志位IE0。 &#xff08;2&#xff09;&#xff1a;外部中断1…

Hive-hive核心面试范围题目整理(数据倾斜、外部表内部表、分区分桶、行转列等)

1 hive的优缺点 优点 SQL减少MR的开发难度使用于实时性不高的数据分析场合优势处理大数据自定义函数 缺点 Hql表达能力优先&#xff1a;迭代式算法&#xff1f; 处理延迟效率较低&#xff0c;小数据的时候&#xff0c;不如传统数据库 2 对hive的了解 优点本质&#xff1…

pymysql详解——通过Python连接Mysql数据库

pymysql详解——通过Python连接Mysql数据库 pymysql是可用于连接mysql数据库&#xff0c;且能够提供mysql与python窗口交互创立通道的工具库。可以通过创建引擎&#xff0c;建立游标直接通过python编程实现mysql数据库操作。在开发和分析可形成线性脚本。是广泛使用的库。 连…

计算机组成原理——第七章输入输出系统(上)

如若来世再相见&#xff0c;半点朱唇尽我尝 文章目录 7.1.1 输入输出系统和IO控制方式7.1.2 外部设备7.2 IO接口7.3.1 程序查询方式流程图 7.1.1 输入输出系统和IO控制方式 i/O接口是一个电子部件&#xff0c;会被集成与主板中&#xff0c;而I/O设备则是你看得见摸得着的那些设…