java计算经纬度距离_数据源与存储计算

53c2b16223becce66bac6b612c3a50d2.png

导读

阅读完此文,你会了解:

1、互联网地图的坐标投影;
2、互联网地图数据源是如何组织的;
3、3D 地图如何计算瓦片 ID;
4、数据源处理有哪些优化方案

坐标系及投影

地理坐标系一般是指由经度、纬度和高度组成的坐标系,能够标示地球上的任何一个位置。地理坐标系是三维的,我们要在地图或者屏幕上显示就需要转化为二维,这就是投影。常用的投影有 EPSG: 4326,以及 EPSG:3857 墨卡托投影。

EPSG: 4326 是 WGS84 坐标系,是球面坐标,水平线是等纬度线,垂直线是等经度线,单位是度。零经度线称为本初子午线,通过英国格林尼治的经线,西负东正。零纬度线为赤道,南负北正。下图是一张 WGS84 坐标系的展开的二维世界地图,常见于使用 GeoJSON 数据源的场景,但这并不是我们在互联网上常见到地图的投影。

1792fc3f2fd5bb8ba17f70bf964172d8.png

互联网上常见的地图,皆是以墨卡托投影为原型的变体。

墨卡托投影是由荷兰地图学家墨卡托(Mercator)在 1569 年创拟,设想地球被围在一个中空的圆柱里,赤道与圆柱相切,再假想地球中心有一盏灯,把球面上的图形投影到圆柱体上,再把圆柱体展开,这就是一幅标准纬线为零度(即赤道)的“墨卡托投影”绘制出的世界地图。(以上来自百科)

518f3dd2d107d1f16701a98c58e2be7a.png
墨卡托投影

互联网使用的墨卡托投影,又称 Web 墨卡托(EPSG:3785),最早由 Google 提出,基于墨卡托投影把 WGS84 坐标系投影到正方形,公式如下,投影完纬度在[-85°, 85°]之间,x 轴和 y 轴的取值范围均在 [-20037508.3427892,20037508.3427892]。

393974d25e89fd2d2f0351b45a925f72.png
Web 墨卡托投影计算

代码可参考:

Leaflet 的 Web 墨卡托转换​github.com
var 

除此以外,国内常用的坐标系还有火星坐标系、百度坐标系。

附赠常用地图坐标系的相互坐标转换:

常用WGS84、GCJ02、BD09地图坐标系的相互坐标转换_Java_sinat_41838539的博客-CSDN博客​blog.csdn.net
20f018945bd971505737bf86fb13faa3.png

知道了要使用的投影和坐标系,下一步就是要了解需要什么样的数据源。

数据源结构

互联网常见的数据源使用的是瓦片金字塔模型,是一种多分辨率层次模型,从瓦片金字塔的底层到顶层,分辨率越来越低,但表示的地理范围不变(以上来自百科)。这么做的好处是,可以在不同的地图层级,显示不同的地理细节。经过投影为平面的世界地图,在不同地图的缩放等级,通过金字塔的切割方式将数据源进行切割和索引,从而更好的控制展示的细节。

4e0fbc242c2b315b0ee45cc297ffaef2.png
瓦片金字塔组织结构示意

了解了数据源的组织结构,接下来就是要和相机、场景联系起来,计算当前视窗需要加载的瓦片索引。

瓦片数据源加载

由于 3D 地图中相机位置和角度都会影响视窗范围,所以计算时需要考虑到相机视锥及相机坐标与旋转。

  1. 首先通过相机视锥与 XOZ 平面的交点算出视窗的梯形范围,也是可视区域。
  2. 进而算出梯形包围盒范围。
  3. 根据包围盒范围的坐标,推算四个角的金字塔瓦片,得出瓦片金字塔包围盒范围。
  4. 根据瓦片金字塔包围盒计算当前视窗瓦片的索引。

e0e3dc9ccf2c9307e7972213d3efc012.png
瓦片边界计算示意

175c90d66106294dfc8484cb6f958b03.gif
调试模式看相机视窗与瓦片加载关系

根据当前地图层级,视窗范围,以及视窗大小,就可以推断当前需要加载的栅格瓦片的x,y,z。

相机视锥与平面相交的计算可参考如下:

/**

将 WebGL 坐标系 XOZ 平面划分为瓦片加载的网格,不同的层级划分的数量也不同,在z层 x、y 方向的瓦片数目为分别 pow(2, z - 1) 个,调整相机到瓦片 XOZ 平面的距离,就能按照不同的分辨率进行加载地图瓦片,加载完毕之后,将地图瓦片填充入不同的网格。

以左上角瓦片编号为 [0 ,0, z] 为例,根据 Web 墨卡托转换公式,对在z层级的任意经纬度latlng,计算它所在的瓦片编号x, y为:

const 

矢量瓦片的加载逻辑与栅格瓦片类似,只是不同数据源提供商,金字塔分割的方式略有不同,计算方式也因地制宜。

矢量瓦片数据源处理

请求来的栅格瓦片,一般用纹理贴图可以直接使用,但是矢量瓦片需要根据数据,前端生成图形。

我们使用的矢量瓦片数据源请求来的是二进制数据,首先需要根据与服务端协商的解析规则经过第一层数据解析,得到数据源中的陆地、海洋、功能面、道路、POI、道路名称、建筑面等地理信息。紧接着进入第二层数据处理,是将瓦片数据计算成用来渲染使用的顶点、面、法向和 UV。最后根据样式文件,生成材质纹理等,传给Tile,添加到 Layer 中,完成一次 Tile 的加载、解析、装配、渲染。

a384ac3afd1f1b73dd40f9bde15545fb.png
矢量数据处理流程

d69dcb0d26a32c5d2114d3e1877b74aa.png
单张矢量瓦片数解析道路、区域面示例(左视窗,右调试模式)

LRU Cache

在解析过程中,利用 LRU (最近最少使用)缓存机制,对 Tile 做了第一层缓存。在 Source 算出 Tile ID 后,会首先从 TileCache 中寻找 Tile,Tile 计算完成后,也会更新 TileCache。

class 

代码可以参考 Mapbox 的 TileCache:

https://github.com/mapbox/mapbox-gl-js/blob/master/src/source/tile_cache.js​github.com

Indexed DB

考虑到IndexedDB允许存储大数量,以及是本地化存储,数据处理中的第二层缓存,利用了 IndexedDB 的特性对瓦片中描述的信息数据做了本地化缓存。其中对数据的 level 值做了索引,以提高查询速度。

26a7c74c686e0f0d62192db1537a2443.png
IndexedDB 示例

我们的瓦片是数据场景下,一级数据是256张矢量瓦片,不使用IndexedDB的情况下,全部加载和渲染完需要6000ms,使用IndexedDB的情况下,时间缩减了一半。

Worker

由于一次性加载或处理大批量的瓦片,常常会对主线程造成阻塞,因此我们利用 Web Worker 技术对数据解析做了一层计算优化,旨在释放主线程压力。使用 Worker 的方法不在此赘述,在此分享一些使用 Worker 中的问题和心得:

1、Worker 适合做复杂数据计算,并不意味着适合做大数据量的数据计算,首先在数据通信上,就会浪费很多的时间。为了保证Worker 对通信内容的修改,不会影响到主线程,主线程与 Worker 之间的通信内容是拷贝关系,即是传值而不是传址(包括对象)。不过可以通过使用 ArrayBuffer 和转移数据的控制权,来提升通信速度,前提是主线程无法再次使用这些数据。此外,SharedArrayBuffers 因为是共享内存,也是解决大量数据通信问题的一个思路。

2、使用多 Worker 时,需要考虑每个 Worker 的负载情况分配工作,否则也可能会因为一个 Worker 负载过重导致解析处理慢的情况。因此我们简略做了一个Worker调度的模型,为了减少某个Worker单独处理多个复杂任务的概率。

7dd912fb771df729b66e13b1072b58f6.png
worker调度示意

下图为一个测试对比,同屏加载256张瓦片图,使用单个进程需要542ms,使用3个Worker的总计算时间为220ms,且主进程没有被影响。

0052bf65cccba05aa93ee249063f0edc.png

Web Assembly

与 Worker 技术不同的是,Web Assembly 解决的是 JS 计算速度慢的问题。在解析和装配的阶段,计算顶点和面是非常耗费时间和性能的部分。因此,这部分采用 Web Assembly 对数据处理做了提升。在此分享一些使用 Web Assembly 中的经验和心得。

1、WebAssembly 是一种可以使用非 JavaScript 编程语言编写代码并且能在浏览器上运行的技术方案,例如 C/C++、Rust、AssemblyScript 等。但不同语言所编写出来的 wasm 性能是不同的,最终我们选择性能好的 C++,使用 emscripten 作为编译工具,cpp- wasm-loader 用于加载 cpp 文件。

2、对于 wasm 的数据输入,最好采用类型化数组(TypedArray)的方式进行传入,这样在 wasm 中直接通过 string 类型,完成数据转换。也可以使用 emscripten::val 类来包装需要传递的数据值,但并不建议使用 val 用于内部逻辑计算,因为 val 类会通过 C++代码控制浏览器行为从而增加无意义的开销。

3、wasm 在返回数据时,如果返回数据是数组,可以采用内存视图(typed_memory_view)的方法进行传递,避免数据的二次拷贝,提升性能。

4b0550cf4fc1c0559c921431e7453c1b.png
瓦片解析效率对比

对于单个地图建筑所包含的顶点数,一般介于 10-100 个之间,因此生成 100 顶点的三角面属于常态。对于一个包含100个顶点图形来说,WASM 相对于 JS 平均提效 4.4 倍左右。

ca3877f0400a40af0af6227863db6840.png
三角面生成效率对比(不同点数)

对于一次性加载一屏的建筑物,大约 100 左右的图形数,每个图形以 100 个顶点为例,WASM 相对于 JS 平均提效 5.5 倍左右。

0ed33e84df84e29ec661d34a142d3c1e.png
三角面生成效率对比(不同面数)

f1afb7169d242a828202896dc3496a68.png
三角面生成效率对比

​最后的装配的数据以这样的层级排序渲染出来(铛铛铛铛):

0403a6dc87a1e1462cf7abe205ac0cad.png
地理信息渲染层级关系

请期待下一期:《地图交互与姿态控制》

往期回顾:

windyh:打造服务B端客户的酷炫3D地图可视化产品​zhuanlan.zhihu.com
85b5806da9c72e0d1c23fb57f7b1a0c6.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值