Cesium巨坑之当聚簇遇上billboard

Cesium自带了聚簇对象,对于点实体,允许开发者仅仅定义聚簇的一些基本属性则自动完成点聚簇并显示聚合的点个数,在cesium的官方示例沙盘中有聚簇效果:
在这里插入图片描述

所以在项目中使用这个特性加载数量有限的实体,但是在加载过程中发现一个严重问题,若原始数据有它自己的billboard属性,并且cluster也有它自己的billboard属性,它们各自不相同,当第一次添加完实体后,所有的实体entity并不会聚簇,而是分散地加载在场景中,只有重新加载一遍,才会聚簇。
在这里插入图片描述
刷新以后效果:
在这里插入图片描述
但是我希望第一次加载就是带聚簇的效果。

程序现有的逻辑过程如下:
1.定义一个customdatasource,添加到场景中,在viewer.datasources.add()的promise回调函数中定义cluster属性并添加其eventlister;
2.当场景移动到对应位置,刷新数据后向该customdatasource中一个一个地添加实体,并设置实体显示billboard

然而每当第一次添加完数据场景就显示不加聚簇的效果,这并不是我们希望的结果。

实际解决方法是:
必须在添加实体时设置该实体billboard的width和height。
在这里插入图片描述

查看cesium官方文档,其中清楚地说明width和height并不是必选项,在属性说明中甚至标明如果没有设置,则使用默认值的字样。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这样看来,这是一个cesium的bug,该bug直接导致出现后面一段痛苦的调错经历。

下面来记录下整个bug发现过程:
1.出现上面问题后,我首先查看两次刷新过程的区别,很快定位第一次刷新(不带聚簇)的过程在添加完实体后没有进入cluster的eventlistener监听事件,而第二次刷新(带聚簇)进了该监听事件:
在这里插入图片描述
2.接下来思考为什么第一次没有进入该事件,将断点打到监听事件内部,然后查看第二次进入事件的调用堆栈:
在这里插入图片描述
3.通过分析,发现其中entitycluster类的方法非常可疑,应该是该方法一个条件(如下图标注部分)没有满足导致没有调用该事件:
在这里插入图片描述
4.如上图所示,numPoints在第一次刷新时为1,而minimumClusterSize为2(这是我们自己设置的),所以第一次没有进入该代码片段,那么问题来了:为什么第一次刷新时numpoints值为1,而第二次刷新大于1?,顺着这个思路往上推,看到上面代码中一开始设置numpoints值为1,只是在一个循环中累加了该值:
在这里插入图片描述
5.所以实际是neighborLength值为0导致的:
在这里插入图片描述
6.为什么值为0,继续往上看,发现neighborlength是neighbors数组的长度,而后者是通过bbox计算出来的,但是该值在第一次刷新时各属性都为NAN,第二次刷新正常:
在这里插入图片描述
7.为什么bbox各属性第一次刷新全部为不正常数字,显然是赋值失败,F11进入bbox的赋值函数getBoundingBox内部,发现原因是item的width和height属性为undefined导致:
在这里插入图片描述
在这里插入图片描述
8.那么item是什么东东,继续往上看代码,item是point的collection属性,而point是points数组的元素:
在这里插入图片描述
9.points是什么?往上看,发现points在一开始定义为空数组,而在getScreenSpacePositions中被赋值了:
在这里插入图片描述
10.进入getScreenSpacePositions函数内部看到points如何被赋值的,其中的collection属性就是传入的第一个参数,而第一个参数是billboardCollection
在这里插入图片描述
在这里插入图片描述
11.billboardCollection是entityCluster的billboardcollection属性:
在这里插入图片描述
12.这里查看该集合发现这个集合就是我们在初始化entity时输入的billboard,通过其中一个billboard的image属性可以证明:
在这里插入图片描述
13.所以这里问题就在于:当第一次刷新时,如果我们不手动设置单个entity的width和height,此时的单个billboard的width和height为undefined,所以导致后面计算bbox出问题,然后计算neighborlength出问题,导致不进入addcluster函数,所以也就不会调用对应的监听。

看源码entity的billboard初始化函数,发现其实所谓width、height默认值其实就是undefined,而不是实际的数值:
在这里插入图片描述
在这里插入图片描述
所以不能指望有什么默认值,需要的话还是要自己设置。

通过这次事件,发现entitycluster的createDeclutterCallback的方法是个有用的函数,在entitycluster创建时和每次更新后都会调用该回调函数,cesium应该是在这里面完成了点聚簇算法:
在这里插入图片描述

cesium还是一个相当棒的开源api,以后得空还是乐意多研究下这里面的算法。有意思有意思。

该问题已经在github的cesium项目中上报,希望cesium团队越做越好,让更多人能免费使用这个优秀的框架:)
https://github.com/AnalyticalGraphicsInc/cesium/issues/8060

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章