为何 Google S2 geometry 产生错误Check failed: si <= kMaxSiTi
最近在学习Google开源的S2 Geometry库,在学习和使用的过程中,由于理解上的不到位,一个BUG困扰了我将近一周的时间,今天来跟大家分享一下,如果你碰巧也碰到了这个问题,那太好了,真希望能帮到你,那我会很开心,错误的地方,还望指正。
S2算法填充曲线采用的是Hilbert Curve,代码中默认使用的lKMaxCellLevel = 30
(在s2coords.h中),由于我不需要使用这么高的精度,所以我选用了lKMaxCellLevel = 12
,然后我进行编译,编译通过,在使用经纬度构造S2CellId
的对象时,并没有报错,代码如下:
S2CellId cell_id(S2LatLng::FromDegrees(lat_degrees, lng_degrees));
构造并没有报错,当然可能得到的S2CellID
对象是不符合他应有的数据结构的。
当我通过地图块的id
值(数据类型:unsigned long long
)来构造S2CellId
的对象,然后返回id
值对应的经纬度时,却出现了如下的报错信息:
我的id
值转经纬度的主要代码片度如下:
S2CellId cellId(id);
R2Point point;
S2LatLng latlng;
latlng = cellId.ToLatLng();
lat = latlng.lat().degrees();
lon = latlng.lng().degrees();
一般说来,我从经纬度获得地图块的id
值,然后再从地图块的id
值获得经纬度,应该会得到和我输入的经纬度一样的结果,但是这里不但得不到正确的结果,反而还会产生上面的报错信息,我根据报错信息中的提示找到了s2coords.h
中对应的代码:
inline double SiTitoST(unsigned int si){
S2_DCHECK_LE(si, kMaxSiTi);
return (1.0 / kMaxSiTi) * si;
}
报错就是因为S2_DCHECK_LE(si, kMaxSiTi)
这一句,报错产生的原因就是,因为si > kMaxSiTi
,如果你已经了解过了Hilbert Curve的原理,那么就应该就知道,si
应该对应的就是平面划分为栅格之后在s方向上的第i个栅格,对于level为12的划分精度,面的边长应该是
s
i
d
e
=
2
12
−
1
side = 2^{12} - 1
side=212−1正常情况下来说si <= side
,所以一定是从经纬度构造S2CellId
的时候出错了,我在这里折腾了四五天总算找到了一个解决方法(也许这就是S2正确的使用方法吧),依然使用lKMaxCellLevel = 30
的默认值,从经纬度求id
值的代码修改如下:
S2CellId cell_id(S2LatLng::FromDegrees(lat_degrees, lng_degrees));
id = cell_id.parent(12).id();
这里我还是按照默认的lKMaxCellLevel = 30
来划分地图,但是在我需要获得id
值的时候,我使用了cell_id.parent(12).id()
这个函数,将parent(int)
的值设为12,这样我就获得了当前经纬度在level=12
时对应的id
值了。当我将上述方法获得的id
值用到上述求取经纬度的代码中时,原先报的错误不在出现了。然后也得到了我需要的结果了!
如果您有更好的方法,请不吝赐教!