zoukankan      html  css  js  c++  java
  • 使用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的操作,虽然进行了微调,但是在页面上是不会有明显的偏移的。

  • 相关阅读:
    Python 多线程学习(转)
    自己使用python webob,paste.deploy,wsgi总结
    Python中*args 和**kwargs的用法
    python 数字和字符串转换问题
    python socket编程
    深入解读Quartz的原理
    解决get方法传递URL参数中文乱码和解决tomcat下中文乱码问题
    Tomcat的Manager显示403 Access Denied
    mysql5.6 linux下安装笔记
    Quartz应用与集群原理分析
  • 原文地址:https://www.cnblogs.com/jyybeam/p/11126481.html
Copyright © 2011-2022 走看看