深入浅出学习切片LOD——ArcGIS server模拟缓存切片(影像快显)

一、第一次实践

原理

        免切片实现影像服务的模拟切片,主要原理是接收前端传过来的xyz(行列层级)以及切片方案,计算出该请求的切片的四至经纬度信息,通过mapserver的exportImage接口,传入每个模拟切片的四至经纬度信息得到图片返回。好似前端请求了http://xxx/mapserver/z/y/x,后台返回给前端一张图片(切片),让客户端无感知的就像是请求了缓存切片。

        而这问题的关键在于获取目标图片的四至经纬度信息。怎么计算?

        首先,咱们需要知道细节层次模型LOD。LOD技术即Levels of Detail的简称,意为多细节层次(百度解释的描述会越描越黑)。实际上就是世界地图展示的时候想看某个细节,那么就需要缩放(因为屏幕大小不会变),但缩放不能直接把整个图缩放,数据细节太大,放不下。那只需要把感兴趣的细节部分数据返回给客户拼接到一起,查看不同级别就返回不同级别的图片。

        这里模拟切片,第0级是一张图片,经度从-180到180,纬度从-90到90。流行方式是以左上角(-180,90)为坐标原点(origin),计算每个片的最小经纬度,最大经纬度(xmin,ymin,xmax,ymax)。

         如计算第1级的四张瓦片中的右上角,直观答案是经度0到180,纬度0到90。这个数据从公式中如何计算得来呢?如上图中x,y的计算方式:最小经度xmin(0)= 原点的经度(-180)+偏移量(偏移的瓦片数量(1)*第一级瓦片宽度(以角度为单位,也就是180)),这样就可以算出每个瓦片的最小最大经纬度。

        上图中用的resolution*256是什么意思,这是为了理解常说的切片方案中的参数,其中256是一张瓦片的宽度(256px像素),经过反算得出来的参数结果与天地图常用的切片方案一致。0级的resolution是0.703125,每个层级的resolution是上一层级的½。

lodinfos: [{ 'level': 0, 'resolution': 0.703125, 'scale': 295497598.570834 },{ 'level': 1, 'resolution': 0.3515625, 'scale': 147748799.285417 },{ 'level': 2, 'resolution': 0.17578125, 'scale': 73874399.6427087 },{ 'level': 3, 'resolution': 0.087890625, 'scale': 36937199.8213544 },{ 'level': 4, 'resolution': 0.0439453125, 'scale': 18468599.9106772 },{ 'level': 5, 'resolution': 0.02197265625, 'scale': 9234299.95533859 },{ 'level': 6, 'resolution': 0.010986328125, 'scale': 4617149.97766929 },...]

获得了这些参数信息,再输入/z/y/x,我们就获得了层级/行/列,通过公式便可计算出图片四至。这里有第一个坑,每个正方形瓦片的经度和纬度的边长是不一样的,宽(经度)是长(纬度)的两倍,可以结合第0级正方形理解,经度总共是360度,纬度总共是180度。

var lt_x = -180 + col * lodinfos[level].resolution * tilecols;
var lt_y = 90 - row * lodinfos[level].resolution * tilerows / 2;
var rb_x = -180  + (col + 1) * lodinfos[level].resolution * tilecols;
var rb_y = 90 - (row + 1) * lodinfos[level].resolution * tilerows / 2;

貌似大功告成,写了个本地服务测试两个切片结果,拉出来检验一下:用ArcGIS的切片服务看看

https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/2/1/2

         两个图片的最小经度和最大经度值是一样的,但纬度差异很大。一开始我以为是公式错误,或者切片方案的问题,实际上这里是投影的问题。从一开始我的计算方案就是以地理坐标的经纬度计算的,瓦片切分下来就是正轴墨卡托投影,而ArcGIS server使用的是横轴墨卡托投影(关于投影可以看看这个一文了解地图投影 - 知乎),所以两者并不对等,当细节级别更高时两者的结果就相差十万八千里了。

二、第二次实践

思路

        既然知道了原因,那么我们可以直接计算投影坐标下的四至,而不是经纬度四至。需要先获取0级的四至,即全球基准四至,然后每一级都可以通过上一级二分来计算。这里的基准四至可以从切片方案中获取也可以从ArcGIS服务中获取

      let deltX = (xmax -xmin)/Math.pow(2,level); //level级别的瓦片宽度 0级一张图,1级两张图let deltY = (ymax -ymin)/Math.pow(2,level); //level级别的瓦片高度 0级一张图,1级两张图let lt_x = xmin + col * deltX ;let lt_y = ymax - row * deltY ;let rb_x = xmin + (col + 1) * deltX ;let rb_y = ymax - (row + 1) * deltY ;

再拉出来看看结果

        怎么回事???为什么还是不一样???

        原来是取错数值了,我取原图的四至的时候使用了initial extent计算的,这个范围是超出了图本身的范围full extent,所以在计算的时候有偏差(initial不是正方形也有影响)。

        更新使用fullextent参数试试12层级的图片,大体上接近了,还有少许经度差异,可以再深入研究研究。

三、最终实践

正解

        第二次实践是自作聪明了。因为切片方案定义的就是以原点为起点,加偏移量去计算值。使用二分法必然不符合他原始的切片(尽管上面看起来只有微小差距,到了13级也是天差万别...)规则,纯属搞笑**行为。老老实实使用原点+切片方案计算偏移:

      const resolution = 156543.03392800014; //0级resolution(一张图)const originX = -2.0037508342787E7;const originY = 2.0037508342787E7;const delta = resolution*256/Math.pow(2,level);let lt_x = originX + col * delta ;let lt_y = originY - row * delta ;let rb_x = originX + (col + 1) * delta ;let rb_y = originY - (row + 1) * delta ;

检验:

鸣金收兵!

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

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

相关文章

Spark01

Spark01 一. Spark概述二. Spark环境部署 - Local三. Spark环境部署 - Standalone1. Standalone集群概述2. Standalone环境部署3. 测试环境 四. Spark环境部署 - Standalone-HA1. 安装部署Zookeeper1. 下载2. zookeeper安装3. 配置StandAlone-HA集群 五. Spark On YARN -- 重点…

ESP32S3在VScode中使用USB口调试

ESP32S3在VScode中使用USB口调试 安装USB驱动修改工程的配置文件launch.jsonsettings.json 启动GDB Server 安装USB驱动 在powershell中输入下面指令: Invoke-WebRequest https://dl.espressif.com/dl/idf-env/idf-env.exe -OutFile .\idf-env.exe; .\idf-env.exe…

js实现抽奖效果

<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>随机抽奖</title> </head> <body>…

锂电池寿命预测 | Matlab基于GRU门控循环单元的锂电池寿命预测

目录 预测效果基本介绍程序设计参考资料 预测效果 基本介绍 锂电池寿命预测 | Matlab基于GRU门控循环单元的锂电池寿命预测 Matlab基于GRU的锂电池剩余寿命预测 基于GRU的锂电池剩余寿命预测&#xff08;单变量&#xff09; 运行环境Matlab2020及以上 锂电池的剩余寿命预测是…

W11安装WSL2 ubuntu 攻略

W11安装WSL2 ubuntu 攻略 最近换了新电脑重新安装一遍wsl2&#xff0c;记录一下方便以后使用。 打开控制面板&#xff0c;选择程序 —— 启用或关闭Windows功能&#xff0c;勾选 适用于Linux的Windows子系统还有虚拟机平台选项&#xff0c;修改后需要重启 wsl2版本 wsl --se…

Rust腐蚀服务器清档多教程

Rust腐蚀服务器清档多教程 大家好我是艾西&#xff0c;一个做服务器租用的网络架构师。上期教了大家怎么搭建服务器以及安装插件等那么随着大家自己架设服或是玩耍的时间肯定会有小伙伴想要去新增开区数量或是把原本的服务器进行一些调整等&#xff0c;那么今天主要聊的就是怎…

如何在Windows 10中启用和使用上帝模式,这里有详细步骤

序言 上帝模式&#xff08;God Mode&#xff09;是一个特殊的文件夹&#xff0c;只在一个窗口中显示所有可用的操作设置。它可以节省搜索命令的时间&#xff0c;而无需知道通过“开始”菜单或“控制面板”查找命令的步骤。上帝模式默认情况下是隐藏的&#xff0c;所以我们需要…

类和对象-封装-设计案例1-立方体类

#include<bits/stdc.h> using namespace std; class Cube{public://设置长void setL(int l){m_Ll;} //获取长int getL(){return m_L;}//设置宽 void setW(int w){m_Ww;}//获取宽 int getW(){return m_W;}//设置高 void setH(int h){m_Hh;}//获取高int getH(){return m_H;…

线程池 ThreadPoolExecutor 配置参数详解

《开发语言-Java》 线程池 ThreadPoolExecutor 参数详解 一、引言二、主要内容2.1 核心构造函数2.2 核心线程数2.3 最大线程数2.4 空闲线程存活时间2.5 keepAliveTime 的时间单位2.6 核心线程在空闲时的回收策略2.7 工作队列2.8 线程工厂2.9 拒绝策略 三、总结 一、引言 提到 …

《QT实用小工具·三十一》基于QT开发的访客管理平台demo2

1、概述 源码放在文章末尾 该项目为访客管理平台demo&#xff0c;包含主界面、系统设置、警情查询、调试帮助、用户退出功能。 项目部分代码如下&#xff1a; #pragma execution_character_set("utf-8")#include "frmmain.h" #include "ui_frmmain…

js调用html页面需要隐藏某个按钮

&#x1f3c6;本文收录于「Bug调优」专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收藏&&…

Qt日志使用

QsLog使用 这篇讲qt的日志还是比较好的&#xff0c;可以在自己的函数里面配置这个日志框架实现自己所需的功能。 我接触的项目里面&#xff0c;假如有个函数功能执行错误了&#xff0c;我希望可以快速定位到这个错误&#xff0c;这个时候就需要到了日志&#xff0c;我咨询了有经…

Python测试转岗网络安全测试,挑战年薪30W+

有许多人问我安全测试前景怎么样&#xff1f; 目前&#xff0c;网络安全市场可大致分为17大安全领域、59个细分领域。不同领域大类核心技术相距甚远&#xff0c;因此绝大多数企业都选择专注于几个细分市场上。产品终端使用者主要以政企、军队、运营商、金融、医疗、教育、交通…

【技巧】PPT文件如何添加公司LOGO?

在工作上&#xff0c;我们经常要给PPT文件添加上公司的logo&#xff0c;如果一页一页添加不但耗时耗力&#xff0c;还容易有遗漏。那怎样快速给PPT添加logo呢&#xff1f;不清楚的小伙伴一起来看看如何吧&#xff01; 操作步骤&#xff1a; 1.打开PPT文件&#xff0c;点击菜单…

【DM8】ODBC

官网下载ODBC https://www.unixodbc.org/ 上传到linux系统中 /mnt下 [rootstudy ~]#cd /mnt [rootstudy mnt]# tar -zxvf unixODBC-2.3.12.tar.gz [rootstudy mnt]# cd unixODBC-2.3.12/ [rootstudy unixODBC-2.3.12]# ./configure 注意&#xff1a;若是报以上错 则是gcc未安…

【C语言】【数据结构】项目实践——贪吃蛇游戏(超详细)

前言 本篇博客我们来实现一个小游戏项目——贪吃蛇&#xff0c;相信肯定很多人都玩过&#xff0c;那么整个贪吃蛇是怎么实现出来的那&#xff0c;这个项目用到了很多方面的知识&#xff1a;C语言函数、枚举、结构体、动态内存管理、预处理指令、链表、Win32 API等。我们就通过这…

JAVA 集合框架(一) Collection集合详解和常用方法

Java集合框架&#xff08;Java Collections Framework&#xff09;是一个强大的、高度灵活的数据结构库&#xff0c;它为Java应用程序提供了组织、存储和操作对象集合的标准方法。 集合类体系结构 接口类&#xff1a; Collection: 是单例集合类的顶层接口&#xff0c;包括Lis…

【MIT6.824】lab3 Fault-tolerant Key/Value Service 实现笔记

引言 lab3A的实验要求如下&#xff1a; Your first task is to implement a solution that works when there are no dropped messages, and no failed servers. You’ll need to add RPC-sending code to the Clerk Put/Append/Get methods in client.go, and implement Pu…

算法课程笔记——pair的使用

先思考&#xff0c;为什么 STL 中的容器和算法都是用的左闭右开区间&#xff1f; | | | 这样迭代器只需要支持和!(或者<或者)操作就可以方便的进行区间遍历了。 其它区间设置的话&#xff0c;要么得支持<操作&#xff0c;要么得在循环体内&#xff0c;操作之前进行!判定。…

牛客2024 【牛客赛文X】春招冲刺 ONT34 加油站【中等 贪心 C++、Java、Go、PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/a013a0691a0343aeb262ca1450d2fe4e 思路 贪心&#xff1a; 如果总的gas小于走完全程的cost&#xff0c;直接返回-1不需要再找了 如果确保了可以走完一圈之后&#xff0c;那么从index 0开始找&#xff0c; 当g…