码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • 从零开始学GeoServer源码十三(GeoServer生成的矢量切片缺失问题)


    快速导航

    从零开始学GeoServer源码一(开篇)
    从零开始学GeoServer源码二(搭建开发环境)
    从零开始学GeoServer源码三(断点应该打在哪?)
    从零开始学GeoServer源码四(自定义插件或拓展数据源)
    从零开始学GeoServer源码五(切片原理及自定义插件支持wms、wmts、tms)
    从零开始学GeoServer源码六(如何打包发布?)
    从零开始学GeoServer源码七(如何注册服务并发布3dtiles和cesium的地形terrain?)
    从零开始学GeoServer源码八(内存溢出?Out of Memory Error ?)
    从零开始学GeoServer源码九(如何集成Cesium以实现预览3dtiles和terrain服务?)
    从零开始学GeoServer源码十(如何修改菜单项以整合我们的功能?)
    从零开始学GeoServer源码十一(如何解决No Multipart-config for Servlet错误)
    从零开始学GeoServer源码十二(GeoServer中的切片规则)
    从零开始学GeoServer源码十三(GeoServer生成的矢量切片缺失问题)

    目录

    • 快速导航
    • 前言
    • 1.现象
    • 2.切片流程
    • 3.产生问题的原因
    • 4.修改默认采样因子
    • 5.修改BoundingBox
    • 6.总结

    前言

      GeoServer 生成的矢量切片存在缺失,这个问题是在我将矢量切片存储到 MongoDB 的过程中发现并确认的,其实在写渲染矢量切片的那一篇博文openlayers百万级和千万级数据量的矢量切片在渲染过程中的技术难点解析时,我就曾经产生过疑问,为什么已经提前切好片了,访问的时候还会去切片?今天终于可以解答这个问题了,且听我细细道来。

    1.现象

      同一图层,坐标系是EPSG:4326,当我对第1级进行 png 切片时,会产生8块切片,而当我将格式调整为 pbf,即 vector-tile 时,只会产生一块切片。
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

    2.切片流程

      上面我们介绍了现象,那会造成什么样的影响呢?对使用来说不会造成很大的影响,只不过就是访问切片很慢很慢,有种切片白切了的感觉。试想一下,明天要给客户演示,今天就开始切片了,结果到了明天一看,切片缺失了,给客户演示的时候,还是现切,这得益于 GeoServer 的自动切片机制,所以客户体验将会非常非常差。
      那是什么原因造成的这种现象呢?那就需要调试代码了。于是我们发现了切片的流程,以第1级为例。
    png切片流程:

    1. 先采样出来一个大图(只构造了一个GetMap请求)
    2. 然后将该大图裁成8块小图
    3. 依次存储后结束

    pbf切片流程:

    1. 先采样第1块pbf切片(只构造了一个GetMap请求)
    2. 直接存储
    3. 结束切片

      于是这里就存在问题了。因为 pbf 不能像 png 那样,可以直接裁切成几个小块的瓦片。因此正确的流程应该是构造出来8个 GetMap 请求,产生出来8个 pbf 瓦片才对。

    3.产生问题的原因

      于是就产生了一个问题:为什么切 pbf 时只构造了一个 GetMap 请求?
      通过调试代码发现,GeoServer 在切片时有个参数叫 meta-tiling factor ,翻译过来叫切片因子,默认是4✖4,当我们把4✖4改成1✖1时,就会产生8个 GetMap 请求了。
      现在我们就可以回答上面的那个问题了,因为第1级是2行4列,即8块切片,而默认采样时是4✖4,即16块采一次,完全满足8块的要求,因此,采一次就可以了。但是这是 png 采样用的因子,我们现在是 pbf ,因此不能再这样采样了,所以强制改成1✖1即可.

    这一块的代码在gwc-core1.19.jar中,类名为org.geowebcache.storage.TileRangeIterator,方法名为nextMetaGridLocation

    在这里插入图片描述

    4.修改默认采样因子

      找到 GeoServerTileLayer 中的 getMetaTilingFactors 修改即可。
    在这里插入图片描述

    5.修改BoundingBox

      解决了请求次数的问题之后,我们又发现了一个新的问题,即这8个请求每个请求的BoundingBox 都是【-180,-90,180,90】,显然是不对的,不过幸运的是,tile 对象的 xyz 值是对的。于是我们可以根据 xyz 的值来反算经纬度范围。
      我们来看下切片调用的函数 GeoServerTileLayer.getMetatilingReponse 中的执行过程:

    1. createMetaTile //创建瓦片元数据对象
    2. dispatchGetMap // 构造 GetMap 请求
    3. metaTile.setWebMap// 将 GetMap 结果赋值给瓦片元数据对象
    4. setupCachingStrategy //更新切片策略
    5. saveTiles //保存瓦片

      于是我们就需要在 dispatchGetMap 时根据行列号重新计算瓦片对应的经纬度范围,不会计算的同学可以去看我们之前讲过的从零开始学GeoServer源码五(切片原理及自定义插件支持wms、wmts、tms),我们这里直接上代码:
    在这里插入图片描述

    private void modifyBboxOfVectorTileLayer(ConveyorTile tile, String format, BoundingBox bbox) {
        if(format.contains("vector-tile")){
            long[] xyz=tile.getStorageObject().getXYZ();
            long x=xyz[0];
            long y=xyz[1];
            long z=xyz[2];
            if(tile.getGridSetId().equals("EPSG:4326")){
                int row_numberOfTiles=(int)Math.pow(2,z);
                int col_numberOfTiles=2*row_numberOfTiles;
                //每一列或每一行的跨度
                double resX = MBTilesFileUserDefine.WORLD_ENVELOPE.getSpan(0) / (double) col_numberOfTiles;
                double resY =MBTilesFileUserDefine.WORLD_ENVELOPE.getSpan(1) / (double) row_numberOfTiles;
                // 该坐标系经度和纬度的最小值
                double offsetX = MBTilesFileUserDefine.WORLD_ENVELOPE.getMinimum(0);
                double offsetY = MBTilesFileUserDefine.WORLD_ENVELOPE.getMinimum(1);
                double minLon=offsetX+(double)x*resX;
                double maxLon=offsetX+(double)(x+1)*resX;
                double minLat=offsetY+(double)y*resY;
                double maxLat=offsetY+(double)(y+1)*resY;
                bbox.setMinX(minLon);
                bbox.setMaxX(maxLon);
                bbox.setMinY(minLat);
                bbox.setMaxY(maxLat);
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

    6.总结

      本文通过跟踪 GeoServer 中切片的生成过程,对比了普通瓦片和矢量瓦片,即 png 和 pbf 的生成过程,发现了 GeoServer 中生成矢量瓦片时缺失数据的 bug ,并通过分析切片过程,修改切片因子,将这一 bug 进行了修复,希望对后来者有所帮助,回见~

  • 相关阅读:
    【Qt控件之QTableWidget】使用及技巧
    R语言:因子分析 factor analysis
    sublime text 显示空格
    RabbitMQ简介及在Linux中安装部署(yum)
    Linux 利用inotify和rsync服务实现数据实时同步
    FRP内网穿透
    考察软件开发公司的能力
    牛客刷SQL---2
    基于Linux和C++的socket编程示例(TCP)
    史上最全-常见正则表达式集合
  • 原文地址:https://blog.csdn.net/xiangshangdemayi/article/details/133700765
  • 最新文章
  • 攻防演习之三天拿下官网站群
    数据安全治理学习——前期安全规划和安全管理体系建设
    企业安全 | 企业内一次钓鱼演练准备过程
    内网渗透测试 | Kerberos协议及其部分攻击手法
    0day的产生 | 不懂代码的"代码审计"
    安装scrcpy-client模块av模块异常,环境问题解决方案
    leetcode hot100【LeetCode 279. 完全平方数】java实现
    OpenWrt下安装Mosquitto
    AnatoMask论文汇总
    【AI日记】24.11.01 LangChain、openai api和github copilot
  • 热门文章
  • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
    奉劝各位学弟学妹们,该打造你的技术影响力了!
    五年了,我在 CSDN 的两个一百万。
    Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
    面试官都震惊,你这网络基础可以啊!
    你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
    心情不好的时候,用 Python 画棵樱花树送给自己吧
    通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
    13 万字 C 语言从入门到精通保姆级教程2021 年版
    10行代码集2000张美女图,Python爬虫120例,再上征途
Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
正则表达式工具 cron表达式工具 密码生成工具

京公网安备 11010502049817号