Fuyi Atlas

I have a dream too !

  • 开源技术赋予我们站在巨人的肩膀上做到更高更强的可能,我想通过开源技术来构建一个地理信息的世界,愿给地理信息数据带来更多的使用价值。

  • 既然都说人类活动所接触、产生的信息80%以上都与地理空间位置有关,那么这些空间数据就应该很容易的被使用,而不是仅被围困在专业领域内,不是吗?


  • 如果你想要拥有从未有过的东西,那就去做你从未做过的事!

矢量金字塔技术研究

前言 在图像切片时代,多层次模型依靠的是影响金字塔。得益于影像栅格数据分辨率的特点,基于影像金字塔可以较好的实现多分辨率模型。但是在矢量切片时代中,就无法直接从影像金字塔技术获利了,因为矢量数据不具有分辨率这个特性,而是采用矢量金字塔技术来实现多层次、多尺度模型。 影像金字塔(分层) 影像金字塔技术通过影像重采样方法,建立一系列不同分辨率的影像图层,每个图层分割存储,并建立相应的空间索引机制,从而提高缩放浏览影像时的显示速度。如下图所示的影像金字塔,底部是影像的原始最高分辨率的表示,为512×512图像分辨率,越往上的影像的分辨率越小,分别为256×256,128×128,顶部是影像金字塔的最低分辨率的图像64×64,因此这个影像金字塔共有4层,即4个等级的分辨率。显然影像的图像分辨率越高,影像金字塔的等级越多。 从给出的定义与图示来看,好像与我们目前使用的瓦片地图有一定的差别。是的,这是因为影像金字塔负责的内容仅仅是构建多分辨率层次,也就是每一层都是对应完整数据范围的一块数据,也就是我们常说的分层(栅格数据是均衡的,可以通过分辨率来作为尺度描述,所以多分辨率层级也就对应着多尺度层级)。 瓦片金字塔(分块) 节选自《高性能影像数据瓦片化关键技术研究-刘世永-2016》 要实现现如今使用的瓦片地图模型,还需要瓦片金字塔配合完成。 瓦片金字塔模型是当前应用最广的多层次地图数据组织模型,通过瓦片金字塔模型,前端在进行放大和缩小操作时,可以有效地减少数据读取的空间查询时间。通过只加载可视区域范围内的瓦片,可以减少数据加载量,降低网络传输压力,提高前端的数据可视化速度。 也就是说,瓦片金字塔实在影像金字塔的基础上,基于特定规格大小对每层影像进行切割。此操作也就是对应着我们常说的分块。 数据原始分辨率并不是标准化的,分层结果即不够标准化,也不够细致。所以在此基础上再次分片,既是减少了数据量使得传输与加载效率提升,同时也是给出了标准,兼容性更好。 瓦片金字塔的主要原理为:基于某个特定的地图投影坐标系(常规是Web墨卡托),将曲面的地球投影到二维平面,而后将该二维平面进行多尺度地划分,即相当于制作了多个不同分辨率层级的数字地图。各层级对应相应编码,层级越高地图所对应的分辨率越高;而后对每一层级的全球空间范围地图按照某种空间划分方法进行格网划分,划分成若干行和列的固定尺寸的正方形栅格图片,这些切分出来的规整的单个格网单元称为瓦片,各层级的划分方法都是相同的。 瓦片划分方法需满足以下条件: 每个层级下的所有瓦片可以无缝拼合成一张全球空间范围的世界地图 每个瓦片都有唯一编码,根据编码可以解算该瓦片对应的空间范围 在某一层级下给定一坐标点可以根据其空间坐标解算其所在瓦片的编号 每一层级瓦片对应一层金字塔分层,所有层级的瓦片便构成了整个瓦片金字塔模型。每一层中的瓦片划分方法一般采用均匀四分的划分方法,即以赤道和中央经线的交点为初始中心,不断地对地图进行四分,直到每个格网的大小为tilesize * tilesize为止,其中tilesize表示单个瓦片的边长。基于此种划分方法,第0层金字塔(金字塔顶层)用一个瓦片就能表示整张世界地图,第1层要用4^z个瓦片来表示整个世界地图,z为当前瓦片的金字塔层级。 瓦片投影坐标系 瓦片金字塔模型中的投影坐标系可以有多种,目前最广泛采用的是Web Mercator投影,它是Mercator投影的一种变体。 瓦片坐标系 所有瓦片的编码都是基于瓦片坐标系下进行的,瓦片坐标系的原点一般都在左上角或者左下角,TMS规范中是在左下角(GeoWebCache遵循该规范),但是现有的Google、Mapnik切片系统都是选用左上角作为原点,本文主要以原点在左上角的瓦片坐标系进行说明。 瓦片的编码方式如下图所示,层级用z表示,瓦片经线方向(指瓦片经度发生变化的方法,即东西向,东向为正)上编号为x,纬线方向(指瓦片维度发生变化的方向,即南北向,南向为正)上编号为y,因此每一个瓦片都可以通过一个三维元组(x,y,z)来唯一描述。 总的来说,如今我们所说的影像(栅格)金字塔大多指代的是影像金字塔与瓦片金字塔的结合体或是瓦片金字塔(默认含有分层),而不是单独指代分层或者单独指代分块。 矢量金字塔 影像金字塔是为栅格数据服务的,也是图像切片时代的核心产物。但是到了矢量切片时代后,由于矢量数据并不具备分辨率的特性,且矢量数据不同于栅格数据,它有着疏密不一致、分布不均与的特点,所以无法直接利用影像金字塔技术。不过瓦片金字塔是基于分层金字塔的基础上构建的,所以对数据类型并没有要求,在矢量切片中是可以直接复用的。总而言之,在矢量切片时代中,需要一个符合矢量数据特点的分层模型,作为矢量数据源与瓦片金字塔之间沟通的桥梁。同时考虑到应用上的兼容性,所以最终基于金字塔理论之上进行分层模型的定义,谓之:矢量金字塔。 对于矢量数据的分层,将使用比例尺作为尺度描述,建立一系列不同比例尺的分层。不同于栅格金字塔的多分辨率层级,矢量数据金字塔没有分辨率的概念,但是不同层级之间的数据详尽程度也是不同的。随着比例尺的由小到大,矢量要素也变得越来越详细;而随着比例尺由大到小,矢量要素也将变得精简与概化,以符合人们的使用要求。 总而言之,矢量金字塔的的目的就是解决在小比例尺下大数据量(或高密度区域)矢量数据聚集度高、要素重叠和显示速度慢的问题。(其实就是矢量数据的制图综合问题,矢量金字塔不过是其中的一个解而已) 注:我们此处所谈矢量金字塔,只是矢量数据分层金字塔,只是分层。 矢量分层 为了达成人们的使用要求,则需要对数据进行处理,以符合给定比例尺级别下保持相应的详尽程度。 与栅格数据不同,矢量数据通常都具有空间特征与属性信息。空间特征体现在数据的空间坐标系、空间分布以及几何特征;属性信息则是数据实体相关的一些信息。那么矢量数据的空间特征与属性信息则可作为分层的依据,首要对数据的属性信息进行处理,而后再基于空间特征进行处理。 属性分类分级 对于数据的属性特征处理主要是对属性信息进行分类和分级两种情况。分类是根据属性信息划分类别;分级即根据属性信息按照其重要程度划分不同的级别,并且赋予不同的权重值。 空间特征处理 基于空间特征的处理则就多种多样了,比如可以基于数据的分布(密度)抽稀、基于周长或面积进行选取、基于几何形状进行简化。在处理的同时,还需要是实际情况考虑是否维持数据的拓扑关系。 总而言之,可将上述的分层处理方法抽象为两种: 选取(Filter):属性分类分级,基于密度、周长、面积的处理都属于选取 简化(Simplify):基于空间几何形状的处理属于简化 当然,上述两种只是最基础的分层处理方法,后续还可以有更多处理方法,比如合并、融合、夸大等。但我想来,如果能够比较合理的完成上述两个操作,应该也是达到了基本可用层次。 不同行业的数据具有着不同的重点或侧重点,分层不仅需要结合矢量数据模型的特点,还需要结合行业背景与应用场景综合考虑。 此处再借用公谨(遥想公瑾当年)的一句描述进行佐证: 所谓的矢量金字塔模型,即基于制图综合的知识,分别设置海量数据在不同zoom下是否显示,是否简化,是否融合的一种策略,当动态提取切片时,根据这个策略选择数据,实际捞取的数据就非常少,有效解决了矢量切片不能解决数据太密集集中的问题。 矢量金字塔 → 矢量数据的多尺度表达 → 矢量数据的自动制图综合(保证综合前后要素内部及要素之间的拓扑关系是矢量地图正确显示的基本需求 😯) 注:此处所述分层,并不是比例尺等级。而是在不同比例尺层级下,矢量数据的详尽程度。而分层处理,即为通过一定的手段来控制数据的详尽程度。 技术实现 在技术实现上,目前我看到的都是以瓦片金字塔结构为基础,叠加分层处理手段的方式实现的。因为瓦片金字塔是在分层金字塔的基础之上,而分层可分为两个部分: 尺度分级定义 → 一系列的比例尺等级 分层分级处理(综合算子) → 一系列的处理算子(如:Filter、Simplify) OGC TileMatrixSet 定义 而尺度分级定义不论是在分层金字塔还是瓦片金字塔中都是一致的,也就是将分层分级处理(综合算子)剥离出来单独实现,在最终的瓦片生产流程中,接入瓦片金字塔即可。 GeoWebCache 实现 瓦片金字塔结构 public class GridSet { private String name; // 投影坐标系 private SRS srs; // 瓦片宽, such as 256 private int tileWidth; // 瓦片高, such as 256 private int tileHeight; /** * Whether the y-coordinate of {@link #tileOrigin()} is at the top (true) or at the bottom * (false) */ protected boolean yBaseToggle = false; /** * By default the coordinates are {x,y}, this flag reverses the output for WMTS getcapabilities */ private boolean yCoordinateFirst = false; private boolean scaleWarning = false; // 将坐标参考系统 (CRS) 单位转换为米的系数 // 也就是说,这个参数表示的是给定的CRS中一个单元转换为米的系数。换句话说,也就是在指定的CRS中,一个单元表示多少米。 // 目前常用的就两种投影,一是以米为单位的(即metersPerUnit为1);其次是以度为单位的经纬度投影(metersPerUnit表示为1度代表多少米,即:360/赤道周长,不同CRS使用不同的椭球体,所以其赤道周长也会存在一定差异。) private double metersPerUnit; // 像素大小, 通常给定0....

May 3, 2024 · 2 min · Fuyi

关于矢量瓦片技术支持前端渲染带来的思考

前言 书接上回,此前提到地图瓦片切片技术的发展。矢量切片技术将瓦片的渲染由服务端迁移到客户端,此操作带来的影响力不可谓不大,基于此,完全可以随心所欲的定义地图的表达。那么在实际的应用当中,当渲染从服务端迁移后客户端后,是否会带来一些其他的问题? 超20M的瓦片数据 此事发生在2023年,当时我们的技术组合是:空间数据库+GeoServer(vector tile plugin)+ Mapbox GL JS,基于此提供矢量瓦片服务。某一天,在某位心细如发的大佬的察觉下,突然发现提供的地图服务在层级为10级时,出现一个大小大于20M的瓦片,顿感惊人。经过多次核对后,确定在该份数据下,GeoServer在小比例尺下(约莫10级往下)生产的大部分瓦片尺寸都比较大,而数据密度越大的地方尤其严重。最终,我们认为:是由于GeoServer没有提供矢量分层抽稀简化的能力,所以导致在小比例尺+高密度的双重叠加下,瓦片大小暴增。 在一段时间后,为了快速处理该问题,我曾提出。可以基于目前配图的思想(解析配图文件),在服务端去往数据库读取数据的时候便进行数据过滤(其实就是分层分级),避免大量不需要的数据经查询、传输、编码再传输带来的影响。比如我们按照口径进行约定,在13级往下,只显示大于xx口径的数据的数据,那么此时所有小于该口径的数据都不需要被传递 但我们前端配图人员提出一个说法:说如果你这般处理,那么意味着配图的时候数据就不是完整的,我无法自行选择数据,不同的项目需求也不尽相同,灵活性自然大打折扣。同时,也就意味着该项配置与瓦片缓存是绑定的,一旦存在配图项的变更,便意味着此前缓存均是失效的。 配图的边界 时至今日,已过半年。目前想来,这里确定存在这么几个问题: 到底什么是配图,配图配的又是什么? 数据发布过程中,配图应该处于什么阶段? 对于什么是配图,我目前还给不出一个十分恰当的回答,因为此前确定没有做过这方面的内容。但私以为狭义情况下,地图的符号化过程应该称之为配图。配图内容如下: 要素符号化 文字标注 那么分层显示控制能力(属性分级)是否应该归属到配图中呢?在图像切片时代中,想来配图都是提前确定好的,而且受益于影像金字塔自带多层次分辨率的能力,所以在配图中压根不需要考虑分级问题(假定数据都是栅格数据)。但是矢量数据并没有分辨率的说法,所以无法从影像金字塔模型获利。在面对大数据量或高密度区域的情况时,需自行处理分级问题。 对于矢量数据来说,在矢量瓦片技术出现之前,所有瓦片都是在服务端渲染,那么属性分级控制也是在服务端进行的。而在矢量瓦片技术出现之后,完全可以直接在客户端实现属性分层控制了。且目前开源GIS技术方案大多都选择:GeoServer+Mapbox,但在实际使用中感觉GeoServer并不理会什么属性分级和空间特征简化,而是一股脑的将数据丢给客户端,客户端自己筛选。 从结果来看,好像在应用上确实是行得通的。实际上确实如此,或许大多数公司都是这样做的吧。但是我认为这是有问题的,这就好像是得益于矢量瓦片渲染能力后移的特点,服务端将原本应该自己管控的数据一股脑的丢到了客户端,由客户端自行控制。 那么问题来了,数据的分层分级控制权到底应该给谁,是瓦片生产端还是客户端呢? 我认为应该优先厘清整个生产流程,明确各节点能力边界 数据的分类、分层肯定是在最前面,且分类、分层与金字塔分层息息相关。且应该形成公知,瓦片的生产段与应用的客户端都应该清晰的知道【数据分层分级控制策略 → 矢量金字塔分层规则定义】 其次是矢量数据的发布,此中应该完整的实现矢量数据分层,即形成矢量金字塔结构【矢量金字塔模型实现】 因矢量瓦片技术带来的配图后置,数据的符号化在此处完成【地图符号化】 其次,可以想一下数据分层控制权限归属到客户端后会带来什么样的影响: 在大数据量或高密度区域的情况下,小比例尺级别瓦片尺寸可能爆炸 计算资源、存储资源(缓存)占用增多 对带宽要求高,移动端的话流量嗖嗖的跑 客户端性能下降 所以我认为,数据控制能力应该归属于瓦片生产端,客户端可以支持分层控制能力,但其对于数据的控制只能在全局统计的分类、分层策略所提供的范围内活动。也就是说客户端可以实现的分层范围时全局规定的范围的子集。 对于目前在配图中进行全局数据的分层分级行为,我认为是矢量瓦片技术带来的配图动作后置产生的影响。同时在GeoServer + Mapbox 客户端控制数据操作的长期影响下,给后来人一种错觉便是数据控制也变更到客户端控制。 论GeoServer的正确使用? 最近在自己实现一个矢量瓦片服务,由于自己目前只会写Java,所以不得不对GeoServer进行借鉴,所以就进一步的研究了GeoServer的源码。 GeoServer可以看作是GeoTools,GeoWebCache以及OGC API Implement的结合体。其中,GeoWebCache提供了金字塔结构的定义和缓存能力;GeoTools提供了空间数据相关的定义和操作。在本次研究后,我确定我需要向GeoServer道歉。在此前的描述中,我认为GeoServer是没有提供数据分层和空间简化的能力的,但是我错了。 我拉取的是GeoServer的2.22.x分支,应为这个版本用的比较多,相对而言更具有代表性,所以没有选择最新版本。 空间简化能力 也就是说,在GeoServer vector tile的生产过程中,已经集成了Simplify功能。 还有一个情况,其实GeoServer Vector Tile Plugin采用的矢量瓦片编码器(java-vector-tile)中其实也提供了Simplify的功能,只不过默认是关闭的。 数据分层(属性分级) GeoServer的vector tile实现中,居然是尝试从Style(SLD)中获取到Filter的信息,用以减少数据的检索(数据库中的Filter比Java基于内存的Filter更高效),同时还提供了一个将Mapbox style转换为SLD的拓展模块。 看到这里的我很激动,感觉找到了知己一般,哈哈哈。 在明白真相之后的我,只能是感叹GeoServer的历史包袱太重了,但应该被敬佩。 而此时再次回头看我之前提出解析配图文件的想法,发现这种做法也是有问题的。 矢量瓦片技术出现,实现了一套瓦片数据可以有N种配图方案 矢量瓦片技术完美的分离了数据与渲染,边界清晰 所以,基于配图剥离属性分级的方式不就又将渲染与数据耦合起来,配图也就会和缓存绑定了,也就是一种配图方案一套瓦片数据了(若一旦涉及到分级部分的变化),自然是有问题的。 结论 综上所述,私以为: 在矢量切片技术下,数据当有数据本身的分层规则,不应该依赖于配图,也不应该由配图来定义。 分层控制当属于数据控制权限,应该归属于瓦片的生产端控制 在矢量瓦片时代,配图就是地图符号化的过程,对应矢量切片技术下,渲染后移到客户端的部分 全局分层分级策略应该是首先定义的,且应该形成公知的形态。服务端的数据控制应当严格遵循该策略,客户端可控分层范围时该策略的子集 参考 GeoServer Branch 2....

May 3, 2024 · 1 min · Fuyi

切片技术发展

前言 本文80%内容节选自:《WebGIS数据不切片或是时代必然》,后在其基础上添加了部分内容。 数据切片是解决大规模大体积地理数据在Web前端轻量化传输和显示的关键技术,是每一个开发者几乎每天都在使用的技术,有时候将服务端底图切成xyz图片,有时候将大影像数据切成xyz图片,也有时候将矢量数据切成xyz的矢量切片。 数据切片起源–图像切片时代(WMS → WMTS,服务端渲染+预处理) Web上古时代,人们浏览在线地图,一般是服务器端将页面地图要显示的地理范围内的地理数据都查询出来,然后在服务端按照专题地图的配置样式,渲染成地图图片,再返回客户端浏览,这个时代诞生的OGC标准就是WMS(Web Map Service)服务,该服务一直沿用至今。 类似WMS这种服务存在很多致命的缺点:由于地理范围的不可控,获取范围内的数据不可控,数据有时候会很大,数据通常在数据库中,IO和网络传输就耗时很严重;服务端获取数据后会进行数据渲染成地图图片,占用大量CPU资源;克服一系列的困难终于成图传输给前端浏览。可以想象,这个过程如此艰难,用户可能等的花儿都开了。 为了解决这个痛点,谷歌地图开创性提出了基于Web墨卡托投影,预先在服务端全量渲染,然后按照地图不同的显示级别(金字塔原理),切成了xyz的图片。 该技术成为Web2.0时代使用最广泛的技术,成为WebGIS标准,诞生了一系列如基于工业标准的TMS服务,基于OGC规范的WMTS服务。很快,百度地图,高德地图、天地图都使用该技术原理建设了自己的切片地图服务。广大GIS从业者也开始了“项目一启动,先把底图切”的套路。 基于该技术原理,对大的影像数据如几十G的GeoTiff数据也进行了切片,形成影像底图给客户端使用。 这个时期的开源GIS主要技术是基于GeoServer的WMS、WFS、TMS、WMTS服务。 核心技术:Web墨卡托投影、栅格金字塔 数据切片发展–矢量切片时代(WMTS,客户端渲染+预处理) 虽然基于XYZ的图片切片技术很成功,但是也存在不少问题: 全图预切耗时长:通常切图zoom级别从0到20,通过金字塔原理图可知,上一级别的一张图片,下一级别会裂变成4张,级别越大,图片越多,同时地理范围越大,图片也越多,图片多了,切图耗时就很长,资源无论是基础底图切片还是影像底图切片都要耗时漫长。 资源要求高:需要庞大的服务端渲染和切图的计算资源,满足分布式渲染、切图、存储需求。 存储冗余:原始矢量和栅格数据,同时冗余存储了数据切片,存储压力大,数据切片转储IO压力大。ArcGIS为了提升转储性能,开创了离散性切片和紧凑型切片两个格式,紧凑型切片在转储时性能较高。 数据更新不及时:由于切图耗时长,通常很少会定期更新地图切片数据,导致数据显示落后于实际生活现状,不能很好的服务用户。 地图千篇一律:这个时期项目最常采用的是天地图地图服务,不管啥项目,不管什么地区,似乎地图都长一个样子。甲方可能审美疲惫了,他们希望底图能是定制化的,能不能暗黑一点?科幻一点? 既然存在问题,自然有人想解决问题,从15年左右,Mapbox受够了传统地图显示风格了,它提出了MVT矢量切片技术,该技术一经推出就大受欢迎,开启了WebGIS底图定制化时代。 很显然,矢量切片和图像切片最大的区别就是:渲染从服务端迁移到客户端了,换句话说,服务端减负了,带来的好处也是不言而喻: 资源要求降低:服务器资源要求可见性降低,渲染很耗资源的。 数据更新比较及时:如果数据更新,简单更新下局部变更地区的数据的矢量切片即可,由于不用全图渲染,耗时极大减少,数据的有效性极大提高。 存储冗余降低:采用MbTiles的设计规范,将数据和序号索引剥离,复用重复区域数据,极大降低切片数据量。但是数据冗余还是存在的。 地图不再千篇一律:渲染是客户端的,那么甲方各种优秀的创意都能得到释放了,配置大屏的感觉已经是很容易的事情了。各行各业的地图五彩斑斓各有千秋,地图设计者们的春天来了。高德、百度跟的很快,目前也都提供矢量切片底图定制化服务了 这个时期的开源GIS主要技术是基于GeoServer的矢量切片服务,基于Mapbox的底图切图工具tippecanoe等。这个时期,3D GIS蓬勃发展,诞生了3DTiles、I3S等3D切片ogc规范,并大量在工程中使用。 矢量切片解决了不少问题,但仍遗留问题是:全图预切耗时长,切片数据冗余占用存储空间。这个问题同样也是栅格切片、3D切片共同的问题。于是有人问,能不能数据不切片?也就不存在预切耗时长,切片数据冗余的问题了?答案是肯定的。 核心技术:矢量金字塔,MVT 正所谓尾大不掉,虽然已经出现了矢量切片技术,但是整体的工艺流程还是在预切路线。这可能和矢量切片解决的问题相关,因为矢量切片解决的是渲染的问题,可以更自由的进行渲染了,而且只需要提供一份切片数据即可。 数据切片方向–动态切片时代(WMTS,客户端渲染) 那么上一个阶段遗留的问题还有什么:预处理,也就是不管怎么样,我先切数据 笔者(原文作者:遥想公瑾当年)曾经大量使用PostGIS+并行计算+动态矢量切片技术实现动态业务数据的快速前端矢量呈现,PostGIS是目前开源架构里唯一能支持动态矢量切片的数据技术。 动态切片技术不再预先切图,也不会有大量切片的文件存储,将切片技术诞生以来所遗留的问题都一次清空。由于通常数据量很大,动态矢量切片技术基本上数据不出库,而由数据库汇总组织数据并直接生成切片结果出去,后台几乎啥也不做,时空数据库的地位越来越重要。 这是一个崭新的时代,预示着数据不切片时代的来临,毕竟矢量和栅格不切片技术理论上还是比较成熟的,未来3DTiles这些3D切片理论也会逐渐成熟的。 核心技术:动态矢量切片+矢量金字塔+MVT 在这里我想要补充一下上面的示意图,这里不是说动态矢量切片技术只能应用在数据库中,前文中也提到当前开源架构中PostGIS是唯一能支持动态矢量切片的数据技术。这里是基于传统矢量切片技术与PostGIS的动态矢量切片技术的对比,更多的是想表达流程的变化(预切 → 动态,以及切片产生的位置),以及流程变化带来的性能提升和相关影响;还有就是原文作者认为的后续的发展方向,Based on spatial database。 关于动态矢量切片技术 动态矢量切片技术可以说是传统矢量切片的动态应用(更广义的可以认为:是可以按需动态生成的,具备多层次模型,且每个层次包含适当选取及简化的数据的切片技术)。强调不再预切,而是按需生成,且应该同时满足可以快速显示的要求。 按需动态生成(与数据源是链接着的或是可链接的,即可达成随时可访问),不做预切 多层次结构(如:矢量金字塔) 数据选取与简化 MVT支持 从发展进程上面看,技术的升级是为了解决此前存在的痛点问题。动态矢量切片技术是为了解决预切耗时,且会产生大量的瓦片存储(预切),数据越大,产生的瓦片越多。 从实际的应用上看,此前的矢量切片技术我更愿意将之称为传统矢量切片技术,用以与矢量切片做一定的区分。传统矢量切片技术还是走的预处理的路子,产生的是静态矢量瓦片数据,即在流程上是无法做到快速更新的。与之对应的便是动态实时生产的路线,可称为动态矢量瓦片技术。私以为,两者更大的区别在于矢量瓦片生产的思路,也就是是否需要预切。 所以,动态矢量切片技术可以有各种各样的实现,而PostGIS中的动态矢量瓦片技术便是其中的一种。且到目前,GeoServer同样实现了动态矢量瓦片技术(只不过其历史包袱过重 🫡)。 值得注意的是,基于数据库的动态矢量切片有一个很大的特点:缩短了切片的传导路径(也就是所谓的数据不出库,出库即为切片)。 参考 WebGIS数据不切片或是时代必然 PostGIS动态矢量切片(原理+实现)

May 3, 2024 · 1 min · Fuyi

微天气 终篇

起源 天气小程序产生于2022年年初,目的是用于验证自己是否有进入全栈开发(仅前后端)的能力。 受新冠疫情影响,2022年的春节是在杭州过的。还记得当时附近好几个地方都被划为了高风险,对整个区进行了管控。如果选择回家的话,得到将是14天的隔离,还不确定能否回来上班。因此便没有回去了。好在所在的区域情况并没有那么的严重,还是可以去买菜的。领了消费券,再加上公司发的年货,也没有想象中的那么糟糕。 所以,既然没有回去,又有十来天的时间,总得做点什么东西才行,对吧 🙄! 2022年,是我工作的第四个年头。受多方面的信息影响,我也想看看验证自己是否有进入全栈开发(仅前后端)的能力。 历程 拂衣天气,又名微天气。 一个集地理信息与天气预报为一体的天气预报类小程序,界面精美,使用便捷。【致敬:和风天气】! 💡 主要是有人给我说拂衣天气,听着还以为是卖衣服的。so,我就想着换个名字,就有了微天气。但是由于微信认证的原因,所以有些地方还是拂衣天气。现在细细想来,好像也没有什么关系,那就先这样吧 🙄 该项目从2022年1月12号正式启动,于2022年3月19日发布一阶段最终版本(1.1.9),总体耗时2个月零7天。从内容完整度以及界面友好程度来说,我给自己70分。 此前实在是没有经验,也没有相关的习惯,天气小程序开发过程中并没有编写相关的文档。所以在小程序开发完成之后,本来计划是将拂衣天气完整的开发过程通过文章的方式记录下来,并将该项目开源出去,甚至还想将该项目提交给和风天气。但最后的结果就是:文章就完成了四篇,也就是一个开头,没啥实际内容。@time 2022年8月16日 好的,现在时间来到2023年12月,我又有点时间了,因为我离职了(不是被裁)。这次的目标是完善文档,修复发现的一些BUG,然后新增一些内容,最终将该小程序开源,并贡献给和风天气。 接下来,让我来回忆一下每个阶段的详细内容 🤔 项目初始 为什么会想到做一个天气小程序呢? 嗯,首先我是一个做服务端开发的GIS开发工程师。在当时刚结束一个小程序的开发工作,觉得小程序这个东西还挺有意思。同时受到周边各种信息的影响,也想试一试写点前端的内容,最好是可以方便发布的那种,也算是自己的作品不是。为什么会选择天气类别,好像是当时刷网页还是什么,看到一个人分享自己做了一个天气机器人,然后给女朋友推天气信息。so, 🫣 所以,我当时就想做一个天气类别的小程序,以此进行全栈开发能力的试炼。我想这会是一个微信小程序、是一个可以正常使用的小程序,以Java进行服务端开发,以Mapbox实现天气数据可视化。 本阶段事务分为了三个阶段,分别是:调研、学习、实现 调研 天气小程序什么最重要?当然是天气数据最为重要,所以首要内容便是确定天气数据的来源。其次便是确定本次天气小程序的技术实现构成。 天气数据 天气数据需要是真实的、可用的。那么可以通过网络中提供的天气API进行获取。 通过一定的检索后,我选定了两个天气平台,分别是:和风天气、心知天气。 高德天气:大平台,但是目前服务类目比较少 彩云天气:免费接口几乎没有,收费又太贵 心知天气 心知天气试用版与开发者版开发产品几乎等同,且开发者版收费也不贵。最为关键的是,支持以经纬度方式进行天气查询。 和风天气 几乎可以免费使用其提供的所有 API,且同样支持经纬度方式进行天气查询。 对比了这两者,发现至少都需要注册为开发者之后,才可以较好的使用其服务。且两者的开发者认证均需要实名。 关于天气API的选择,我最终选择了和风天气,倒不是因为它可以免费使用。其实,刚开始的时候我更倾向于使用心知天气,因为它还可以直接查昨天的天气(和风对于历史天气的查询比较麻烦)。但是和风天气首页结合了地图进行可视化,而且还提供有APP可以使用(方便参考)。再加上,我想了想,其实我并没有迫切的需要知道昨天的天气情况。 🙄 💡 其实最重要的原因在于:我先注册了心知天气(需要审核),过了半天后再去注册了和风天气(需要审核),但是最先通过审核的是和风天气(耗时大概也就半天左右,我是在春节期间注册的啊)。 技术实现构成 这里存在一个遗憾,小程序原生并不支持使用如mapbox这样的第三方地图框架,初始想法是通过webview的方式使用mapbox,但是遗憾的是,webview并不对个人类型的小程序开放使用。 所以,退而求其次,选择腾讯地图(及其提供的样式)实现地图浏览。 服务端程序则使用Java语言开发,天气数据是经过服务端代理的方式形成内部的数据接口,并非是小程序直接调用和风的接口 最终将服务端程序部署到阿里云 学习 我是一个后端开发工程师,我不怎么会写页面,我特别的讨厌写CSS。我也没有接触过前端开发和微信小程序开发,所以需要提前储备一下相关知识。 前端知识 我并没有想要精通前端技术,但是我需要比较体系的了解一下前端技术,方便进行小程序开发。所以我在B站找了两门前端视频学习(粗略的刷了一遍) 尚硅谷Web前端零基础入门HTML5+CSS3基础教程丨初学者从入门到精通 千锋web前端开发项目教程_1000集完全零基础入门HTML5+CSS3+JS到精通 微信小程序知识 其实就看官方文档就足够了,不过心虚的我还是在极客时间找了门课。最终发现:就官方文档就足够了,因为我并不需要很深入的东西 实现 在有一定准备后,就开始进入实现环节了。 在这里有一个大问题就是UI设计问题,我看和风天气APP就挺好看的,有天气有地图,身为GIS开发的我就很喜欢。又发现无论是和风天气官方,还是其他天气小程序应用,基本都没有携带地图的。 所以,我当即决定参考和风天气官方APP界面,做一个类似的天气小程序。当然,我做的这个小程序就是奔着开源,同时将作为作品分享给和风天气,才想着如此操作的。请务必慎重 🤔 在经过简单的设计过后,于2022年1月18日正式进行开发,2022年3月19日发布一阶段最终版本1.1.9。 文档补充 今天偷的懒,明天都会让你加倍还回来。此前一是没意识,二是认为没必要,三还是太懒,所以并没有同步编写文档。 现在计划将拂衣天气开发的完整过程通过文章的方式记录下来,下面是我对该整体内容的编写计划: 但是,我又要开始说但是了。打工人还是打工人! 天气小程序于2022年4月前就已经完成了开发,直至到今天(2022年8月16日)也就才完成了三篇文章,不得不说拖延症是真的严重。天气小程序只是一个应用,就目前的投入收益来说,不应该把过多的时间放在小程序上面。在加上距离开发已经过去了4个月,开发之时并没有进行文档产出,所以现在才进行复盘则是相当于重新实现了一遍。就目前来看,核心的行政区划数据合并已基本完成,所以,后面将暂停小程序相关内容,变更为GIS基础与计算机基础的学习。 💡 对的,停更说明。 死灰复燃 打工是不可能打工的,只要我不打工,我就有时间了 🙄...

March 14, 2024 · 1 min · Fuyi

微天气 小程序发布记录

前言 服务端部署:由于并没有建立全链路的自动化部署,目前还需要到云服务器上进行环境制作(数据库,Nginx),并拉取后端服务进行部署 小程序发布:需要先完成服务端部署,保证应用正常可用 服务端部署 数据库安装与数据初始化 最开始的时候,我是直接将在操作系统上面安装数据库,后面发现迁移的时候还是不方便,即使我可以放弃数据库中的数据,但是还是需要重新创建数据表结构。 所以,在这一次中,我编写了一个Dockerfile脚本,使用一个空数据库作为模板,构建了postgis镜像。基于此,我可以实现快速的迁移与部署。由于这是一个实验性质的小程序,所以数据资产并不是十分重要(并不是说不安全,而是我可以丢弃),所以我可以安心的使用docker技术。在初始化postgis容器的时候,会同步释放模板以创建数据库。这将会带来一个问题是:如果重新创建容器,那么将会得到一个全新的数据库。当然你可以把数据库的data目录映射到宿主机上,应该可以解决这个问题。 docker build -t registry.cn-hangzhou.aliyuncs.com/fuyi-atlas/micro-weather-postgis:12-3.4 . 最后,我在本地完成该镜像的制作后,将其推送到我的阿里云镜像仓库中,便于后续使用。你可以注册一个阿里云账户去免费启用个人版的镜像仓库,也可以直接使用dockerhub。 docker push registry.cn-hangzhou.aliyuncs.com/fuyi-atlas/micro-weather-postgis:latest 应用部署 于本地完成镜像制作,并推送到阿里云镜像仓库中。 为了更方便的进行部署,我编写了docker compose脚本,用于将数据库与应用服务端程序一并启动。目前程序中有一个海报分享的功能,该功能实现中需要一些额外的中文字体的支持,所以需要将此部分中文字体放置到宿主机的某个目录下,并在环境变量中指定该目录,脚本中会将该目录映射该到容器内的/usr/share/fonts目录下 对于图片访问,还是延续此前的实现,即在服务器端生成分享海报,存储到本地(指服务器磁盘),而后通过Nginx代理访问。由于目前的服务器我是与他人共用,同时还需要配置域名证书,所以暂时没有将Nginx的部署同步放置到docker compose脚本中。 💡 由于部署中需要提供部分敏感信息,比如:小程序的密钥、天气应用的key、docker镜像仓库地址。我将所有信息以环境变量的方式进行占位,通过docker compose的环境变量进行替换,即.env文件 小程序发布 小程序端的发布就比较简单了 先将base_url更换为正式环境的地址(我没有提交此部分代码,你可以自己更改) 本次调试没有问题后,就可以上传代码,即提交为体验版本 而后使用体验版本测试没有问题,就可以提交审核 审核通过后,就可以发布了 总体来看,本次发布很顺利,审核在十分钟就通过了。

March 13, 2024 · 1 min · Fuyi

微天气 Github Action镜像自动构建与推送

前言 这里暂不作过多的操作,还是保持与此前一致。即通过Github Action完成Docker Image的build与push,目标仓库为阿里云容器镜像服务实例(个人版)registry.cn-hangzhou.aliyuncs.com 那么一共分为三个部分: Dockerfile编写 阿里云容器镜像服务配置 Github Action Dockerfile编写 jdk17 gradle FROM gradle:jdk17-alpine AS build # 设置语言,支持中文 ENV LANG C.UTF-8 COPY --chown=gradle:gradle . /opt/gradle/src WORKDIR /opt/gradle/src RUN gradle clean build -x test --no-daemon FROM eclipse-temurin:17-jdk-jammy COPY --from=build /opt/gradle/src/build/libs/*.jar /usr/app/ WORKDIR /usr/app/ RUN sh -c 'touch micro-weather-backend-1.0.0-RELEASE.jar' ENTRYPOINT ["java", "-jar", "micro-weather-backend-1.0.0-RELEASE.jar"] Github Action 先在阿里云镜像服务中创建命名空间 创建仓库(可选,因为可以自动创建) 编写Github Action脚本 name: Micro Weather Service Image Build And Push CI on: push: branches: - 'main' jobs: docker: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v2 # setup-qemu 如果您想使用 QEMU 添加仿真支持以便能够针对更多平台进行构建,则 action 会很有用 - name: Set up QEMU uses: docker/setup-qemu-action@v1 # setup-buildx-action 将默认使用docker-container 构建器驱动程序创建和引导构建器。非必需 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v1 - name: Login to Aliyun DockerHub uses: docker/login-action@v1 with: registry: ${{secrets....

March 13, 2024 · 1 min · Fuyi

微天气—行政区划数据(二)

前言 此前提到微天气应用程序需要使用到行政区划数据,不过上一章所使用的数据来源于网络,或多或少都可以考虑一下是否还有其他获取的方式,所以也就有了本文的内容。 在这里,将基于全国1:100万基础地理信息数据进行行政区划数据的提取。本文用于记录使用程序实现全国1:100万基础地理信息数据合并的全过程。 当然,本文产生的最重要原因其实并不是受到微天气的启发,更多的是个人想试一试能不能用。 数据说明 全国1:100万公众版基础地理信息数据(2021)覆盖全国陆地范围和包括台湾岛、海南岛、钓鱼岛、南海诸岛在内的主要岛屿及其临近海域,共77幅1:100万图幅,该数据集整体现势性为2019年。数据采用2000国家大地坐标系,1985国家高程基准,经纬度坐标。 为满足广大社会群众对地理信息数据资源的需求,经自然资源部授权,全国地理信息资源目录服务系统提供全国1:100万全图层要素免费下载的服务。下载数据采用1:100万标准图幅分发,内容包括水系、居民地及设施、交通、管线、境界与政区、地貌与土质、植被、地名及注记9个数据集,且保存要素间空间关系和相关属性信息。 💡 提供下载的是矢量数据,不是最终地图,与符号化后的地图再可视化表达上存在一定差异。用户利用此数据编制地图,应当严格执行《地图管理条例》有关规定;编制的地图如需向社会公开的,还应当依法履行地图审核程序。 成果规格 分幅编号及范围 1:100万公众版基础地理信息数据(2021)的图幅总数为77幅,分幅数据按照GB/T 13989-2012《国家基本比例尺地形图分幅和编号》执行。空间存储单元为6°(经差)×4°(纬差)。 坐标系统 平面坐标系: 2000国家大地坐标系。 高程基准:1985国家高程基准。 地图投影:分幅数据采用地理坐标,坐标单位为度。 几何精度 更新后地物点对于附近野外控制点的平面位置和高程中误差符合下表的要求,以两倍中误差值为最大误差。 地物点误差 最小 最大 平面位置 100 500 高程 50 200 现势性 1:100万地形数据现势性与更新使用的数据源的现势性一致,数据整体现势性达到2019年。 成果数据组织 全国1:100万公众版地形数据(2021)内容包括水系、居民地及设施、交通、管线、境界与政区、地貌与土质、植被、地名及注记9个数据集。 数据分层的命名采用四个字符,第一个字符代表数据分类,第二三个字符是数据内容的缩写,第四个字符代表几何类型。 目标 实现分图层合并(处理图幅合并时接边问题) 水系(暂缓) 交通(暂缓) 境界与政区(国、省、市、县) 地名及注记 根据合并后的行政区划与地名注记,制作行政区划数据库 数据库使用PostgreSQL(PostGIS) 设计 图层解析程序 Java程序, 使用GDAL 读取GDB 逻辑 根据《国家基本比例尺地形图分幅和编号》规定可知网格范围,通过网格范围动态生成对应网格的分幅编号,并以该编号进行数据检索。如果命中则根据成果数据组织规格以及相关标准对数据进行解析,如果未命中则跳过,直至网格扫描完毕。 经度:72~138(E),43~53(11) 纬度:0~56(N),A~N(14) 即,网格范围:[43,53] x [A,N] 数据的处理流程可使用责任链模式进行,后续也方便加入其他的处理流程。即,整体的执行框架为策略模式+责任链模式。为统一策略选择模型,在此提出图层定义(LayerDefinition)的概念。 LayerDefinition由如下几个关键要素组成: 图层数据源(LayerSource) driver:驱动,参考java.sql.UnWrapper实现 instance name catalog: schema: table: commonDefinitionKey :常规定义缓存的key fieldDefinitionKey :字段定义缓存的key featureCarrierKey :要素载体缓存的key origin:数据来源(分幅文件路径) scale:比例尺(如:1000000,表示1:1000000) sourceSpatialRef:源坐标系(表现形式可为标准ID、PROJ Text、WKT Text) sinkSpatialRef:目标坐标系(表现形式可为标准ID、PROJ Text、WKT Text) featureCode:要素分类码,对应成果数据组织中的要素分类(如:C、B) name:图层命名,也是图层分类码 layerCode:图层分类码 release:释放格式(比如:WMTS、Shapefile、GDB…) 描述字符为:比例尺:源坐标系:目标坐标系:要素分类码:图层名称:释放格式,在描述字符串中,坐标系仅使用标准ID表示...

October 16, 2023 · 2 min · Fuyi

微天气—行政区划数据(一)

前言 微天气程序中存在如下几个功能需要使用到行政区划数据: 城市列表,需要支持城市搜索 根据经纬度获区域(城市)的天气数据 地图坐标拾取并获取所处区域(城市)信息,同时获取天气数据 对于城市的天气数据,不使用和风天气的城市列表,而是自行维护,通过空间位置(经纬度)进行关联。对于城市位置的定义,本可以选择如行政中心或市中心,但我没有这样的数据,就直接用城市区划范围的中心点代替。不准确不重要,过程已经满足了,且后续是可以替换的。 其实完全可以使用官方提供的城市数据和GeoAPI覆盖这些功能,但既然我是做GIS开发的,而且手里也有可以用作研究学习的数据,为啥不用呢。 今天突然发现,其实我可以爬一下和风的数据,这样就可以拿到城市选择的经纬度数据了 @time 2023.10.10 About 行政区划解析程序,输入shape文件,写入Postgresql. 大体完整的四级行政区划数据组织 github link: fuyi-district-parse 数据情况 数据原源于网络,由于时间久远,我已经忘记了是如何获取到的 名词解释 省级行政区 中国的一级行政区,或称国家一级行政区或省级行政区,是指直属中央政府管辖的行政区划,在历史上曾有不同的称呼。如:省、自治区、直辖市、特别行政区。 地级行政区 地级行政区即“地区级别行政区”,是现行中华人民共和国行政区划中常规的第二级行政区划单位,包括地级市、地区、盟、自治州等。地级行政区隶属于省、自治区、直辖市等省级行政区之下;下辖若干个县、区、县级市、旗等县级行政区。作为特例,东莞市、中山市、嘉峪关市、儋州市等四个地级市下辖街道办事处与乡镇,不辖县、区,因此也称作“直筒子(地级)市”。地级行政区的级别为正厅级,所以非正厅级的省直辖的行政区划不算作地级行政区,例如:湖北省辖的仙桃市、天门市、潜江市;河南省辖的济源市等等。直辖市下辖的区,虽然是正厅级,但未列入地级行政区的统计。 县级行政区 县为中华人民共和国行政区划单位之一,县级行政区指行政地位与“县”相同的行政区划单位的总称,其管辖乡级行政区。为乡、镇的上一级行政区划单位。中华人民共和国成立后,随着行政督察区名称的变更,除各直辖市均隶属于专区(行政督察专区)、地区或地级行政区,现除各直辖市、海南省直管县外均为地级行政区的下一级行政区。 按省、县、乡三级行政区划制度划分,县级行政区属于第二级行政区,为直辖市的下级行政区划单位。 按省、地、县、乡四级行政区划制度划分,县级行政区属于第三级行政区,属于省、自治区所辖地级行政区的下级行政区划单位。 乡级行政区 乡,中华人民共和国现行基层行政区划单位,区划层次介于县与村之间。“乡”为县、县级市下的主要行政区划类型之一。中国行政区划史上,“乡”一直为县的行政区划单元,因此现行处同一层次的区划单位归入乡级行政区。中国自改革开放以来,由于城市的快速扩张,行政区划制度出现了大的变革。1980年代以后“乡改镇”、“乡改街道”的现象越来越普遍。 在乡级行政区划中,乡(包括镇)设有一级人民政府,属于基层政权;乡的行政区划单位为村(含民族村)。但很多乡设有社区,乡的区划单位设置与镇、街道看不出实质性差异。 目的 解析所有数据文件,实现最终入库 使用GeoTools实现 数据库表结构: 行政区划信息(district_info) id:自增Id(bigserial) name:行政区划名称 grade:行政区划等级(省级行政区:1, 地级行政区:2, 县级行政区:3,) code:行政区代码 center_point:中心点(geometry::point) bounds:行政区边界(geometry) 注: 数据入库前审查,保证行政区代码唯一 使用grade区分省、市、县、乡镇 对于省、市、县code列,统一进行前6位截取(不满6位字符所在数据,直接丢弃),对于乡镇则统一进行前9位进行截取(不满9位字符所在数据,直接丢弃) 省级行政区 存在错乱数据,可以使用行政区代码识别(adcode) 地级行政区 存在错乱数据,可以使用行政区代码识别(code),需要截取前6位 县级行政区 存在错乱数据,可以使用行政区代码识别(code),需要截取前6位 乡级行政区 成果 记录数:46652 点数据为各个行政区中心点 数据表 PostGIS CREATE EXTENSION IF NOT EXISTS postgis WITH SCHEMA public; 行政区划 -- -- Name: district_info_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres -- CREATE SEQUENCE public....

October 10, 2023 · 6 min · Fuyi

如何构建一个矢量瓦片服务

前言 关于矢量瓦片(节选) 地图瓦片技术是在线地图服务常用的瓦片技术,瓦片就是地图瓦片的具体存储形态,提前切好的瓦片可以大大提高在线地图的访问效率。 栅格瓦片 以图片为介质的栅格瓦片使得在线地图得以迅速普及,优势在于显示效率高、方便传输。但是,随着地图的移动化和应用的逐渐深入,栅格瓦片占用带宽和存储都较大,不利于地图在移动设备的应用。 矢量瓦片 矢量瓦片的产生弥补了栅格瓦片的不足。矢量瓦片数据以矢量形式存在。矢量瓦片体积下,可高度压缩,占用的存储空间比栅格瓦片要小上千倍。数据传输体量小,地图更新的代价小 常见的矢量瓦片制作工具(节选) 目前开源的矢量切片工具还是非常多的,列出一些主流的阐述下: 基于GeoServer的矢量切片插件,适合熟悉GeoServer的用户,操作还比较简单,缺点是切片的行列号与一般的XYZ编号不同不容易单独部署。 基于tippecanoe的矢量切片工具方案,该工具提供了很多高级功能在数据定制化上有很强的优势,但只能部署在Linux,并不是跨平台,只能读取geojson文件,不能直连数据库,不是很好,如果有幸您是c++开发大神,可以改下库的编译绑定平台,使其支持windows,再更改下数据源底层,使其能支持空间数据库,那么该工具会有更多的应用空间。 基于PostGIS的矢量切片方案,该方案在熟悉PostGIS的用户中应该很受欢迎,优势是支持动态矢量切片,有PG社区的系统级加成。 总的来说,工具虽然很多,但是没有一款可以说覆盖一切场景的,具体应用还是看场景的,比如前两个方案都是做底图数据时比较有用,都是静态矢量切片方案,geoserver能直连数据库,tippecanoe有强数据定制性要求,那么如果用户侧重点是简单点的话geoserver够了,用户侧重点是希望对数据做很多高级过滤什么的操作用tippecanoe,但步骤麻烦点。这些矢量切片工具仅仅在处理很久不变的数据,就是切一次用很久的数据,如果数据频繁变化,这种静态数据切片工具就很不好用了。 与其他方案相比,PostGIS方案的好处主要有两大点: 资源开销低:空间数据一般存空间数据库中,传统工具会先从数据库中捞数据,这个数据通常很大,网络开销和服务器端内存都要很大,查询慢计算慢是肯定的。而PostGIS是在数据库中把数据处理完,只把结果传给后台转前台,可以很方便的使用数据库的索引,并行计算等,优化查询和处理速度。 动态矢量切片,数据时效性高:每当根据xyz请求时,数据库会动态查询范围内数据,裁剪简化并输出pbf格式的二进制数据出去,在数据变化频繁的场景下,可以保证用户看到的是最新的数据。 💡 GeoServer、Tippecanoe 皆为静态矢量切片方案,需提前准备切片数据,并进行持久化(GeoServer也可以在使用时进行切片,同时进行持久化)。PostGIS支持动态矢量切片方案,即实时计算生成切片,且不进行切片的持久化。 为什么要自己写一个服务 于我个人而言,我目前仅接触和使用到了GeoServer,且对其中的实现细节并不太清楚,所以想通过参考模仿的方式实现一个示例服务。其次,还想测试在没有如GeoWebcache此类的瓦片缓存的情况下,服务的性能如何。综上所述,其实也就是为了如下这几方面的目的: 学习,了解其中的实现细节 更好的适配 比如说,WMTS服务很明确存在缓存,WMS性能又不够好。如果使用WMTS服务确实可以提升服务的性能,但是对于源数据存在编辑的场景下,缓存问题还是会让人头疼。 那么是否存在动态的矢量瓦片服务?既能解决缓存的问题,同时还没有太大的性能问题。 你或许会提到基于PostGIS的动态矢量瓦片服务,但是有些历史的原因,短时间内没有变法变更数据库。当然也可以基于类如CDC这样的功能进行缓存的更新,但其实还是会存在缓存的问题,只是说可以通过一些手段降低缓存问题出现的概率,并无法从根本上解决问题 所以,基于此,既然PostGIS可以实现动态矢量瓦片服务,我们自然也可以。公瑾大佬曾发文说过,当下地图服务去服务化、数据不切片基本上已经是必然的趋势,那么我为什么还要去做一个服务化的东西。大概就是下面这几个原因了: 数据库技术,在某些特定的因素下,短时间内无法切换到PostGIS 数据量级 性能容忍度 小厂,我不思进取 🙄 后续知识储备 矢量瓦片标准 参见:矢量瓦片标准 在这里贴几个关键点(对于目前使用上来说): 文件格式 矢量瓦片文件采用Google Protocol Buffers进行编码。Google Protocol Buffers是一种兼容多语言、多平台、易扩展的数据序列化格式。 投影和范围 矢量瓦片表示的是投影在正方形区块上的数据。矢量瓦片不应该包含范围和投影信息。解码方被假定知道矢量瓦片的范围和投影信息。 Web Mercator是默认的投影方式,Google tile scheme是默认的瓦片编号方式。两者一起完成了与任意范围、任意精度的地理区域的一一对应,例如https://example.com/17/65535/43602.mvt。 矢量瓦片可以用来表示任意投影方式、任意瓦片编号方案的数据。 内部结构 图层 每块矢量瓦片应该至少包含一个图层。每个图层应该至少包含一个要素。 几何图形编码 矢量瓦片中的几何数据被定义为屏幕坐标系。瓦片的左上角(显示默认如此)是坐标系的原点。X轴向右为正,Y轴向下为正。几何图形中的坐标必须为整数。 矢量瓦片服务构建 在这里,我选择抄GeoServer的作业。众所周知,PostGIS是开源的,那为什么没有选择抄PostGIS的作业呢? 当下水平不够 想快速验证想法 想基于GeoServer做二次开发,或者说是基于现存的地图服务相关的实现,集各家之大成,合并成一个组在功能上可自由搭配的、较高性能服务端组件 接着说当前的事情。要实现一个动态矢量瓦片服务,我们需要先分析一下实现内容,在此先做出如下拆解: 动态矢量瓦片服务可以理解为没有瓦片缓存的,实时生成的矢量瓦片服务,所以核心还是矢量瓦片服务(@time 20210503: 动态矢量瓦片技术是相对矢量瓦片技术提出的,而矢量瓦片技术的大规模应用还是以预切为主,所以动态矢量瓦片要解决的是不再预切动态生成,同时避免一下子生成大规模瓦片文件的问题) 矢量瓦片服务也就是根据调用端传递的参数,从数据源获取对应的数据,并将其转换为矢量瓦片格式,最终返回给调用端 这里选择瓦片坐标作为检索参数,可以便于服务降级(缓存)和性能优化(瓦片坐标值相对来说更加准确和可固定,且便于降维) 需要实现瓦片坐标系到数据源坐标系下数据范围的相互转换 需要实现数据源的范围查询 需要实现矢量数据到矢量瓦片的编解码 那么大体的实现路径可归结于如下所示: 其中的核心要点总结如下:...

May 23, 2023 · 5 min · Fuyi

GeoServer开发环境搭建

前言 本文用于记录GeoServer开发环境的搭建过程 通过GeoServer发布计划可以看到,在2.23.x版本开始,会移除对jdk1.8的支持。那么当前我们会选择2.22.x版本进行研究 环境 JAVA:1.8或11 Maven Git Action 获取源码 git clone git://github.com/geoserver/geoserver.git geoserver # or git clone https://github.com/geoserver/geoserver.git geoserver 代码库结构 Each branch has the following structure: build - release and continuous integration scripts doc - sources for the user and developer guides src - java sources for GeoServer itself data - a variety of GeoServer data directories / configurations 切换到2.22.x分支 # 查看分支 git branch -av # 切换分支 git checkout -b 2....

March 9, 2023 · 2 min · Fuyi