使用cesium中的scene.open中遇到的幾個問題


  有些服務是發在場景(scene)下的,超圖提供了一個很方便的方法:scene.open,這個方法會將場景中所有的圖層(無論是OSGB還是影像和地形)加載進來。同時這個方法會自帶一個自動地位功能,具體實現不深究。

  這個方法雖然很方便,省去了循環遍歷場景下圖層的代碼,但是也會因此導致出現一些問題。

  1、刪除圖層的問題

    使用scene.open的首要問題就是如何刪除圖層。因為這個方法會將場景下面的所有圖層一次性的加載進來,不需要我們單獨進行台南佳。那么這個方法的內部在加載圖層之初必然會進行判定,根據圖層的不同調用不同的方法進行圖層的疊加。目前我用到的圖層的不同類型有:

    a、OSGBLayer

      這個圖層是用來加載三維模型,目前還未單獨使用進行添加。不過推測單獨添加的方法應該如下:

1 var promise = scene.addS3MTilesLayerByScp('http://localhost:8090/iserver/services/3D-zj/rest/realspace/datas/zj/config', {name : 'base'});
2 promise.then(function(layer){
3     layer.visible = false;
4 });

      這個方法依舊是由超圖進行了封裝。

      刪除的方法如下:

1 scene.layers.remove(layerName)

      可見圖層是加載了Layers中,所以才能使用layers.remove移除圖層。

    b、ImageFileLayer

      影像文件圖層,用來加載影像,單獨加載方法如下:

 1 let imageryLayer = viewer.imageryLayers.addImageryProvider(imageryProvider);
 2         imageryLayer.getViewableRectangle().then(function (rectangle) {
 3             if(rectangle == undefined){
 4                 return;
 5             }else{
 6                 let cur_rectangle = viewer.camera.computeViewRectangle();   // 獲取當前視角邊界
 7                 let inter_rectangle = Cesium.Rectangle.intersection(cur_rectangle,rectangle);     // 取得當前視角邊界和影像圖層邊界的交集
 8                 // 若邊界的交集不存在,說明所加載的影像圖層不再視界范圍內,這時候需要使用飛入效果。否則不使用飛入效果
 9                 if(inter_rectangle == undefined || isNeedToFly(cur_rectangle)){
10                     viewer.camera.flyTo({
11                         destination: rectangle
12                     });
13                 }
14             }
15         },function(err){
16             throw "影響圖層疊加失敗,請聯系管理員"
17          })
18         viewer.imageryLayers.add(imageryLayer);

 

      刪除方法:

viewer.imageryLayers.remove(item, false)

    c、TerrainFileLayer

      地形圖層,單獨添加方法如下:

1 let terrainProvider = new Cesium.CesiumTerrainProvider({url:path});
2 viewer.terrainProvider = terrainProvider;

      刪除方法目前感覺不理想,前端所作的效果不好。因為目前只能加載一個地形數據,如果你想動態的添加兩地的地形數據,比如北京和河北,移除北京的地形圖層保留河北地形圖層,前端是做不到的。因為刪除地形圖層的時候相當於重新把橢球賦給當前球體,這樣整個地球的地形圖層也就沒有了,也就不存在保留某個地區的地形數據。如果想要做到靈活的添加移除任意一個地形圖層的話,應該是需要修改配置文件,具體可聯系超圖客服。刪除的方法如下:

1 viewer.terrainProvider = new window.Cesium.EllipsoidTerrainProvider({});

    這樣的話,使用scene.open添加的話,我們不需要做的太多,主要在於刪除的時候分清楚圖層的類型,然后根據圖層的類型進行刪除就好了。

 

  2、獲取整個場景的矩形范圍以及飛行效果失效

    scene.open作用在於添加圖層、自動定位到場景的位置,但是我很費勁的是,為什么官網沒有這個方法的介紹,而且為什么不把自動定位關閉將視角返回,讓用戶自己去定位呢?

    還是首先去獲取矩形范圍。我發現在api文檔中,有將矩形范圍轉換成視角的方法,但是卻唯獨沒有將視角轉換成矩形范圍的方法。所以想要獲取使用scene.open的矩形范圍的話,只能通過一個方法(也或許我沒有在找到這樣的方法):對所有的圖層進行遍歷,獲取所有圖層的范圍,然后取其並集。代碼如下:

  1 /**
  2  * 將三維場景中圖層的配置文件進行解析,得到其bounds;
  3  * @param data
  4  * @returns {{east: number, south: number, north: number, west: number}}
  5  */
  6 export function transFormXML(data){
  7     let Cesium = window.Cesium;
  8     // 獲取bounds中的字符串
  9     let startIndex = data.indexOf("<sml:Bounds>");
 10     let endIndex = data.indexOf("</sml:Bounds>");
 11     let str_position = data.substring(startIndex + 12,endIndex);
 12     // 分別獲取左上右下的坐標(角度)
 13     let left_startIndex = str_position.indexOf("<sml:Left>");
 14     let left_endIndex = str_position.indexOf("</sml:Left>");
 15     let top_startIndex = str_position.indexOf("<sml:Top>");
 16     let top_endIndex = str_position.indexOf("</sml:Top>");
 17     let right_startIndex = str_position.indexOf("<sml:Right>");
 18     let right_endIndex = str_position.indexOf("</sml:Right>");
 19     let bottom_startIndex = str_position.indexOf("<sml:Bottom>");
 20     let bottom_endIndex = str_position.indexOf("</sml:Bottom>");
 21     let west = parseFloat(str_position.substring(left_startIndex + 10,left_endIndex));
 22     let north = parseFloat(str_position.substring(top_startIndex + 9,top_endIndex));
 23     let east = parseFloat(str_position.substring(right_startIndex + 11,right_endIndex));
 24     let south = parseFloat(str_position.substring(bottom_startIndex + 12,bottom_endIndex));
 25     return Cesium.Rectangle.fromDegrees(west, south, east, north);  // 將數據轉換為rectangle對象
 26 }
 27 
 28 
 29         Cesium.loadJson(url + "/datas.json").then(function(datas){
 30                 let arr_text = [];
 31                 for(let i = 0;i < datas.length; i++){
 32                     // 獲取數據集配置文件
 33                     Cesium.loadText(url + "/datas/" + datas[i].name + "/config").then(function(data){
 34                         let obj_position = transFormXML(data);  // 對獲取的數據集配置文件進行解析得到矩形范圍
 35                         arr_text.push(obj_position);
 36                     },function(err){
 37                         console.log(err);
 38                     })
 39                 }
 40 
 41                 // 由於循環異步存在,會導致在arr_text還未獲取到時就對其進行操作。故需要使用間歇調用
 42                 let timer = setInterval(function(){
 43                     if(arr_text.length == datas.length){
 44                         clearInterval(timer);   // 停止間歇調用
 45                         // 使用reduce方法進行遍歷,對所有的矩形范圍取並集
 46                         let max_rectangle = arr_text.reduce((max,item) => {
 47                             if(isNaN(item.east) || isNaN(item.west) || isNaN(item.south)|| isNaN(item.north)){
 48                                 return max;
 49                             }else{
 50                                 return Cesium.Rectangle.union(max, item);   // 對兩個矩形范圍取並集
 51                             }
 52                         })
 53                         // 設置視角飛行
 54                         let cur_rectangle = viewer.camera.computeViewRectangle();   // 獲取當前視角邊界
 55                         let inter_rectangle = Cesium.Rectangle.intersection(cur_rectangle,max_rectangle);     // 取得當前視角邊界和影像圖層邊界的交集
 56                         if(inter_rectangle == undefined || isNeedToFly(cur_rectangle)) {
 57                             scene.camera.flyTo({
 58                                 destination: new Cesium.Cartesian3.fromDegrees(cameraPosition.longitude, cameraPosition.latitude, cameraPosition.altitude),
 59                                 orientation: {
 60                                     heading: heading,
 61                                     pitch: tilt,
 62                                     roll: 0
 63                                 },
 64                             });
 65                         }else{
 66                             let cur_heading = viewer.scene.camera.heading;  // 獲取當前時間的俯仰角
 67                             let cur_pitch = viewer.scene.camera.pitch;  // 獲取當前視角的方位角
 68                             let cur_roll = viewer.scene.camera.roll;    // 獲取當前視角的旋轉角
 69                             let cur_position = viewer.scene.camera.position.clone();    // 獲取當前視角的e欸之
 70                             cur_position.z += 1;    // 由於使用scene.open 的時候,使用flyto中的數據相同的時候,會發生位置相同,scene.open內置的視角定位會發生作用,所以需要稍微修改值。
 71                             scene.camera.flyTo({
 72                                 destination: cur_position,
 73                                 orientation: {
 74                                     heading: cur_heading,
 75                                     pitch: cur_pitch,
 76                                     roll: cur_roll
 77                                 },
 78                                 duration: 0.1
 79                             })
 80                         }
 81                         try {
 82                             let promise = scene.open(url);
 83                             Cesium.when(promise, function (layers) { 97                             })
 98                         }catch(e){
 99                             message.error(e.message);
100                         }
101                     }
102                 },10)
103             },function(err){
104                 console.log(err);
105             })

    具體流程就是異步獲取配置文件,得到所有的數據集信息,然后對這個數據集進行遍歷,得到數據集的配置文件,解析配置文件中的位置信息,得到矩形范圍轉換成cesium中的矩形對象rectangle,然后將所有的矩形對象取並集。

    第70行處的代碼是因為scene.open的自帶的定位功能,可能會使得flyTo失效。具體的場景是:當當前視角與加載的圖層的矩形范圍存在交集,則視角不變(包括經緯度,高度,俯仰角等均不變)。但是卻會出現一個問題,如果兩次flyTo定位的視角都是一樣的,那么視角就不會進行flyTo的動作,而是會定位到配置文件中的位置處。后來發現如果對視角進行一個微弱的數值改變,使其與上次的數值有不同,則可以正常進行flyTo。經測試,可以對Cartesian3的z坐標進行加1的操作,雖然進行了微調,但是在頁面上是不會有明顯的偏移的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM