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

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