Skip to content

SDK

场景基础

场景事件

Javascript
//1.初始化事件句柄
var handler = new LSGlobe.ScreenSpaceEventHandler(viewer.scene.canvas);

//2.添加事件句柄鼠标操作类型
handler.setInputAction(function (movement){
    //movement.position当前的屏幕坐标
}, LSGlobe.ScreenSpaceEventType.LEFT_CLICK);
//LEFT_DOWN左键按下时触发
//LEFT_UP 左键弹起时触发
//LEFT_CLICK 左击时触发
//RIGHT_CLICK 右击时触发
//DOUBLE_CLICK 双击时触发
//MOUSE_MOVE 鼠标移动时触发

//3.事件销毁
Handler.destroy();

场景坐标转换

Javascript
//1.屏幕坐标转换和世界坐标相互转换

//屏幕坐标转世界坐标
var Pos=scene.pickGlobe(movement.position);
//movement.position 鼠标事件触发时返回的坐标

//世界坐标转屏幕坐标
var movement = LSGlobe.SceneTransforms.wgs84ToWindowCoordinates(scene, pos);
//scene 场景对象 pos世界坐标

//2.世界坐标和经纬度相互转换
//世界坐标转换为经纬度
var cartographic = LSGlobe.Cartographic.fromCartesian(Pos);
//Pos世界坐标对象
var currentClickLon = LSGlobe.Math.toDegrees(cartographic.longitude);
//经度
var currentClickLat = LSGlobe.Math.toDegrees(cartographic.latitude);
//纬度
var height= cartographic.height;
//高度

//经纬度换为世界坐标转
var ellipsoid=viewer.scene.globe.ellipsoid;
var cartographic=LSGlobe.Cartographic.fromDegrees(longitude,latitude,height);
//longitude经度 latitude维度 height高度
var cartesian3=ellipsoid.cartographicToCartesian(cartographic);

//3.经纬度弧度相互转换

//经纬度转弧度
LSGlobe.Math.toRadians(degrees)

//弧度转经纬度
LSGlobe.Math.toDegrees (radians)

素材

素材类型

目前 Wish3DEarth 支持的空间数据类型,如下表:

类型格式上传要求
实景三维osgb压缩成 zip 格式
人工模型obj、fbx、skpobj 需要将纹理等附属文件一并压缩成 zip 文件;skp 直接上传
矢量数据shp、kmlshp 需要将所有同名文件一并压缩成 zip 文件;kml 直接上传
影像数据tiftif 文件直接上传
地形数据tiftif 文件直接上传

素材管理

素材上传前端使用插件是 webuploader.js,数据的上传是分片上传的,上传前获取 MD5 码,上传完成后请求后台合并文件接口。数据的修改和删除均是利用 ajax 请求后台接口进行操作的。具体接口请查询 api 文档素材相关

素材预览

前提条件

注意事项:使用 sdk 开发的用户会出现数据加载时跨域,无法正常加载数据的情况.此时需要在加载数据之前,将要跨域的服务地址(ip 和 port),添加到后台管理系统菜单中的 系统管理设置白名单中

域名白名单

在加载数据之前我们需要获取素材的路径,通过请求素材信息接口返回的参数中取 extraJson 字段中的jsonPath(下面引用地方均指该参数)。

实景三维数据的预览

  1. 加载实景三维数据

    JavaScript
     var sTimeSeconds = new Date().getTime(); //防止缓存
     var url = jsonPath + "?" + sTimeSeconds; //dataGuid 数据的唯一标识
     try{
         var tileset = await LSGlobe.LSPageLOD.fromUrl(url, {
             shadows: LSGlobe.ShadowMode.DISABLED,
             //开启将耗性能
             // shadows属性值详解
             // LSGlobe.ShadowMode.ENABLED  即接受阴影也自己投影
             // LSGlobe.ShadowMode.DISABLED  即不接受投影也不自己投影
             // LSGlobe.ShadowMode.RECEIVE_ONLY 只接受阴影不自己投影
             // LSGlobe.ShadowMode.CAST_ONLY  不接受阴影只自己投影
             viewer: viewer
         });
         tileset.name = {
             "在加入到场景时添加一些字段来区分各种数据,预览时无需添加"
         }
         //倾斜模型对象加入到球中
         viewer.scene.pageLODLayers.add(tileset);
         //飞到倾斜模型的位置(可解决中心点不准问题)
         var oCenter = tileset.tileBoundingSphere.center;
         var cartesian3 = new LSGlobe.Cartesian3(oCenter.x, oCenter.y, oCenter.z);
         var cartographic = ellipsoid.cartesianToCartographic(cartesian3);
         var lat = LSGlobe.Math.toDegrees(cartographic.latitude);
         var lng = LSGlobe.Math.toDegrees(cartographic.longitude);
         var height = cartographic.height;
         viewer.camera.flyTo({
             destination: LSGlobe.Cartesian3.fromDegrees(lng, lat, height + 1500),
             duration: 1 //过渡时间,单位秒
         })
     } catch (error) {
         console.log(`Error loading LSPageLOD: ${error}`)
     }

人工三维数据的预览

与倾斜模型不同,倾斜模型一般是由无人机飞出来数据,经过建模软件处理最终生成带有坐标信息的瓦片文件,而人工三维数据通常不带坐标信息,需要我们自己指定好放人工三维数据的坐标,才能达到我们想要的效果。

人工三维数据最终加载有两种方式,是由数据转换环节决定的,目前 Wish3D Earth 统一把 obj 数据转换为 lmz 数据,skp 数据和 fbx 数据转为 3dtiles 数据。lmz 数据加载是等所有细节加载完成后再显示在场景中,适合体积小且简单的模型加载。3dtiles 数据加载是根据角度可视区域加载,因此不会因为数据过大导致阻塞假死现象出现,适合体积较大细节复杂的人工模型(体积小的效果媲美 lmz)。

  1. lmz 加载(obj 转换为 lmz)

    JavaScript
    //人工三维加载的位置信息可自己设置
    var position={x:120,y:30,z:0};
    var model = new LSGlobe.LSModelLOD({
        //dataGuid 数据的唯一标识
        url :jsonPath,
        shadows : LSGlobe.ShadowMode.ENABLED,
        // shadows属性值详解
        // LSGlobe.ShadowMode.ENABLED  即接受阴影也自己投影
        // LSGlobe.ShadowMode.DISABLED  即不接受投影也不自己投影
        // LSGlobe.ShadowMode.RECEIVE_ONLY 只接受阴影不自己投影
        // LSGlobe.ShadowMode.CAST_ONLY  不接受阴影只自己投影
        position : new LSGlobe.Cartesian3(position.x,position.y, position.z)
    });
    model.name={"在加入到场景时添加一些字段来区分各种数据,预览时无需添加"}
    //人工模型加入到球中
    viewer.scene.primitives.add(model);
    //飞到人工模型的位置
    viewer.camera.flyTo({
        destination : LSGlobe.Cartesian3.fromDegrees(position.x,position.y,position.z+120),
        orientation : {
            heading : LSGlobe.Math.toRadians(0.0),
            pitch : LSGlobe.Math.toRadians(-90.0),
            roll : 0.0
        },
        duration: 2
    });
  2. 3dtiles(skp 转换为 3dtiles)

    JavaScript
     const url = jsonPath; // dataGuid 数据地址也是数据的唯一标识
     try{
         var tileset = await LSGlobe.Cesium3DTileset.fromUrl(url, {
             maximumScreenSpaceError:0
         });
         //3dtiles加入到球中
         tileset.name={"在加入到场景时添加一些字段来区分各种数据,预览时无需添加"}
         viewer.scene.primitives.add(tileset);
         //飞到3dtiles模型的位置
         var boundingSphere = tileset.boundingSphere;
         viewer.camera.viewBoundingSphere(boundingSphere, new LSGlobe.HeadingPitchRange(0, -2.0, 0));
         viewer.camera.lookAtTransform(LSGlobe.Matrix4.IDENTITY);
     } catch(error){
         console.log(`Error loading tileset: ${error}`);
     }

矢量数据的预览

目前 Wish3D Earth 支持 shp 和 kml 数据加载。

  1. shp 加载,Wish3D Earth 已经支持大矢量数据加载,加载此类数据需要使用插件 VectorTileProvider.js。在页面中引用该插件,代码如下:

    HTML
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Hello World</title>
        <link href="LSGlobe/Widgets/widgets.css" type="text/css" rel="stylesheet" />
        <script src="Build/LSGlobe/LSGlobe.js"></script>
        <script src="Plugins/VectorTileProvider.js"></script>
    </head>
    <body>
    <div id="lsGlobe" class="fullSize"></div>
    <div id="loadingOverlay"><h1>Loading...</h1></div>
    <script>
        var viewer = new LSGlobe.Viewer('lsGlobe', {
            baseLayerPicker: false,
            sceneModePicker: false,
            fullscreenButton:false,
            guid:licenseCode,
            //许可码
            licenseUrl:lincenseUrl
            //许可服务地址
        });
        //token是当前用户的登录凭证
        LSGlobe.LSOnline.defaultAccessToken = token;
    </script>
    </body>
    </html>

    加载矢量代码如下:

    JavaScript
     try {
         oShpImageLayer = new LSGlobe.VectorTileProvider.fromUrl(jsonPath, {
             viewer: viewer
         });
         //设置矢量样式
         var oStyle = {
             styletyle: "default",
             color: "rgba(187, 187, 187,1)",//矢量的颜色
             lineType: LSGlobe.VectorTileLineType.SOLID,//边框类型
             lineWidth: 2,//边框宽度
             outline: false,//是否显示边框
             outlineColor: "#2196F3",//边框
             icon: "images/GEMarker/red-circle.png",//如果是矢量点,则用该图标路径
             textField: "NAME",//参照字段
             font: 'bold 14px sans-serif'//字体相关
         };
         var styles = new LSGlobe.VectorTileStyleCollection([new LSGlobe.VectorTileStyle(oStyle)]);
    
         /*
         var style = new LSGlobe.VectorTileStyle({
             color: LSGlobe.Color.fromRandom().toCssColorString(),
             classificationField: 'height',//参照字段
             classificationFieldValue: [301, 400]//对应字段的数值区间
         });
         */
         //正常显示样式
         oShpImageLayer.styles = styles;
         //选种样式
         oShpImageLayer.selectedStyles = styles;//最好和正常样式有区别这样才能体现选中效果
    
         viewer.imageryLayers.addImageryProvider(oShpImageLayer);
         oShpImageLayer.maximumLevel=30;
         var rect = oShpImageLayer._rectangle;
         viewer.camera.flyTo({
             destination: rect
         });
     } catch (error) {
         console.log(`Error loading vector tiles: ${error}`);
     }
  2. KML 加载

    JavaScript
    var options = {
        camera: viewer.scene.camera,
        canvas: viewer.scene.canvas,
        clampToGround: true
    };
    //dataGuid 数据的唯一标识
    var promise= LSGlobe.KmlDataSource.load(jsonPath,options);
    promise.then(function(dataSource){
        dataSource.name ={"在加入到场景时添加一些字段来区分各种数据,预览时无需添加"}
        //KML加载到球中
        viewer.dataSources.add(dataSource);
        //飞到KML数据的位置
        viewer.flyTo(dataSource);
    }).otherwise(function(error) {
        console.error("加载kml数据失败");
    });

影像数据的预览

  1. 载 lrc 文件影像(Wish3D Earth 中的谷歌影像、天地图影像均采用该接口)

    JavaScript
    var oLrcImgPath = "lrc/google-satellite.lrc";//lrc文件路径
    try{
         var oGoogleImg = await LSGlobe.LSImageryProvider.fromUrl(oLrcImgPath);
         oGoogleImg.name = "google";
         viewer.imageryLayers.addImageryProvider(oGoogleImg);
    }catch(error){
         console.log(`Error loading imagery: ${error}`);
    }
  2. 加载 tif 经过 earth 服务处理后的影像(Wish3D Earth 服务处理后的数据)

    JavaScript
    
    var imageryLayers = viewer.imageryLayers;
    var imageLayer = new LSGlobe.LSImageryProvider({
        "url": jsonPath
    })
    currentImageLayer = imageLayer;
    imageryLayers.addImageryProvider(imageLayer);
    imageLayer.readyPromise.then(function (flag) {
        var rect = imageLayer.rectangle;
        viewer.camera.flyTo({
            destination: rect
        });
    }).otherwise(function (error) {
        console.error(error)
    });
  3. 设置影像贴贴模型(模型指的是实景三维模型)

    Javascript
    
    //tilset:实景三维模型对象,oImgery:影像图层对象
    tilset.setOverlayImageLayer(oImgery);

地形数据的预览

JavaScript
var terrainLayers = viewer.terrainLayers;
try {
    var terrainLayer = await LSGlobe.LSTerrainProvider.fromUrl(jsonPath)
    terrainLayer.name = {
        "在加入到场景时添加一些字段来区分各种数据,预览时无需添加"
    }
    //地形加载到球中
    terrainLayers.addTerrainProvider(terrainLayer);
    var rect = terrainLayer.rectangle;
    //飞到地形数据的位置
    viewer.camera.flyTo({ destination: rect });
} catch (error) {
    console.log(`Error loading terrain: ${error}`);
}

场景

场景构建保存图层加载

  • 场景构建

场景是用数据构建成的,场景中可以添加多种数据(目前该平台支持:osgb、obj、skp、shp、kml、tif 影像、tif 地形等),每种数据也可添加多个,对于人工模型只上传一次即可在场景中添加多个相同的数据,用户可以使用自己添加的数据来构建自己想要的各种场景,除此之外还可以利用标绘功能进行点、线、面、单体化、压平、水面、裁剪,达到预期的效果。

场景数据结构

场景添加

进行场景构建之前需要先定义场景,由于场景的数据保存是以 json 的格式保存所以也可以人为的拼接一个和场景相关的 json 数据和定义场景关联起来,以达到场景构建时就拥有某些数据(该方法主要用于添加场景默认的底图)

保存场景的接口(既可以新增也可以更新,区别在于传参里面的 sceneId 数据库是否已存在,存在即更新,反之是新增)

//localhost:8000/wish3dearth/api/scene/v1.0.0/saveScene

其中dataJson需要注意,是 json 对象通过 JSON.stringify()方法转换而来的字符串,json 对象实例代码如下:

javascript
var oSubSceneData = {
  /*场景基本信息*/
  basicInfo: {
    sceneId: 'a3f13f9410d540818a45c84eb38dacbe', //场景id
    title: '我的场景', //场景名称
    keyWord: '', //场景开屏弹框
    coverImg: '', //缩略图部分路径
    logoImg: '', //场景Logo
    description: '', //场景标注
    sceneStatus: '1', //1:正式保存,2:临时保存,3:另存为
    viewPoint: {
      /*场景的默认视角的基本信息*/
      posx: -2764325.5750570972,
      posy: 4787969.484454991,
      posz: 3170427.8013527235,
      upx: 0.10971595179642417,
      upy: -0.2804932817046718,
      upz: 0.9535648529806184,
      directionx: 0.4685107860447898,
      directiony: -0.8315036975588643,
      directionz: -0.2984949652936043,
      viewImg: 'image/eca4f9ac49e84d26a0e2a5212480010b.jpg' //场景默认视角的缩略图
    }
  },
  /*该对象通过viewer.toJSON()获取,二次组合JSON*/
  scene: {
    VERSION: '1.6.534', //手动加入:js引擎版本号,LSGlobe.VERSION获取
    asset: {
      version: '1.0.0',
      date: '2019-12-18 17:06:36'
    },
    Tree: '', //手动加入:zTree节点数组,JSON.stringify(oLayerTree.transformToArray(oLayerTree.getNodes())),oLayerTree是zTree实例化对象
    scene: {
      properties: {
        minimumDisableDepthTestDistance: 0,
        shadows: true
      },
      /*人工模型图层*/
      layers: [],
      /*实景三维模型图层*/
      pageLODLayers: [],
      /*影像或shp矢量数据图层*/
      imageryLayers: [
        {
          show: true,
          name: 'LSGlobe/Build/LSGlobe/Assets/Textures/GlobalBkLayer.jpg',
          url: 'LSGlobe/Build/LSGlobe/Assets/Textures/GlobalBkLayer.jpg',
          tileWidth: 1024,
          tileHeight: 512,
          tilingScheme: {
            type: 'GeographicTilingScheme',
            numberOfLevelZeroTilesX: 1,
            numberOfLevelZeroTilesY: 1
          }
        },
        {
          type: 'LSLRCImageryProvider',
          show: true,
          name: 'google',
          url: earth_url + 'LSGlobe/lrc/google-satellite.lrc',
          tilingScheme: {
            type: 'WebMercatorTilingScheme',
            numberOfLevelZeroTilesX: 1,
            numberOfLevelZeroTilesY: 1
          }
        },
        {
          type: 'LSLRCImageryProvider',
          show: true,
          name: 'skyLandImage',
          url: earth_url + 'LSGlobe/lrc/skyLandMarker.lrc',
          tilingScheme: {
            type: 'GeographicTilingScheme',
            numberOfLevelZeroTilesX: 2,
            numberOfLevelZeroTilesY: 1
          }
        }
      ],
      /*矢量图层*/
      datasources: [],
      /*地形图层*/
      terrainLayers: [
        {
          type: 'LRPTerrainProvider',
          show: true,
          name: 'Terrain1800',
          url: 'http://e0.wish3d.com/servicedata/globalocean/globalocean.ltc'
        }
      ]
    }
  },
  fly: {
    sceneId: '4a8cbec3413417e58f227060e464c7c5',
    lines: [
      {
        id: '1730757e513417e310674b92267f33ad', //路径id
        title: '飞行路径', //路径名称
        /*关键视点数组*/
        points: [
          {
            id: '846f1897313417e3106751bdd54f5365', //视点id
            title: '视点', //视点名称
            /*视点视角的基本信息*/
            directionx: 0.4685107860447907,
            directiony: -0.8315036975588634,
            directionz: -0.29849496529360536,
            posx: -2764325.5750570996,
            posy: 4787969.48445499,
            posz: 3170427.8013527235,
            upx: 0.10971595179642323,
            upy: -0.28049328170467314,
            upz: 0.9535648529806181,

            timeInterval: 2, //视点的过渡时间,单位s

            viewImg:
              'temp/scene/4a8cbec3413417e58f227060e464c7c5/image/e5b067e5febe4df7a155f26d3515a0be.jpg' //视点的缩略图路径
          }
        ]
      }
    ]
  },
  splitscreen: {
    sceneId: '4a8cbec3413417e58f227060e464c7c5',
    screens: [
      {
        id: 'b5eedb0ad13417e4f4f44d7c3ca436cd' //...场景信息
      }
    ]
  },
  draw: {}, //drawDataSource.toGeoJson()获取
  monomer: {}, //monomerDataSource.toGeoJson()获取
  push: {}, //pushDataSource.toGeoJson()获取
  water: {}, //waterDataSource.toGeoJson()获取
  clip: {}, //cutDataSource.toGeoJson()获取
  drawDetail: {
    sceneId: '4a8cbec3413417e58f227060e464c7c5',
    /*点的附属信息*/
    points: [
      {
        id: '48305169713417e3109408c9e90242b1',
        title: '无标题',
        viewPoint: {
          /*视角视角信息*/
          posx: -2764325.5750570996,
          posy: 4787969.48445499,
          posz: 3170427.8013527235,
          upx: 0.1097159517963033,
          upy: -0.2804932817046312,
          upz: 0.9535648529806443,
          directionx: 0.4685107860447907,
          directiony: -0.8315036975588634,
          directionz: -0.29849496529360536,
          viewImg:
            'temp/scene/4a8cbec3413417e58f227060e464c7c5/image/05aaf15a88354e0793feea8bf5c5fefa.jpg'
        },
        text: {
          title: 'dfdf', //文本标题
          content: 'dffd' //文本内容
        },
        image: {
          title: 'dfdf', //图片标题
          pics: [
            {
              id: '306c7418d13417e31095a1f02edec708', //图片id
              path: 'temp/scene/4a8cbec3413417e58f227060e464c7c5/file/5ac7f5def6084bebb33632a05b3c4c4e.png' //图片路径
            }
          ]
        },
        video: [
          {
            id: '1b4a148a013417e31095edf386cff10a', //视频id
            title: 'fdf', //视频标题
            type: '2', //视频类型,1:本地上传 2:在线视频
            url: 'http:video.com'
          }
        ],
        panoramic: [
          {
            id: '311167ca313417e31096b4c4d3c9a345', //全景id
            title: '720', //全景标题
            url: 'http://720yun.com' //全景链接
          }
        ]
      }
    ]
  },
  deleteObj: {
    sceneId: 'a3f13f9410d540818a45c84eb38dacbe',
    images: [], //删除的图片路径
    videos: [], //删除的视频路径
    drawDetails: [] //删除的entity的id
  }
}

如果场景里面含有 shp 矢量数据,还要把对应的 shp 涂层的样式存储,接口如下:

其中注意参数styleJson,该参数是对应的 shp 矢量数据的 imageryProvider.styles.toJson()得到

//localhost:8000/wish3dearth/api/material/shp/v1.0.0/setStyle

场景基本信息获取

通过接口获取当前场景的基本信息,返回信息包含场景 id、名称、描述、缩略图、默认视角等信息,详情参照一下接口。

//localhost:8000/wish3dearth/api/scene/v1.0.0/getSceneJsonInfo

场景(相机)定位

从上一条获取到场景的默认视角字段,经过转换后得到视角信息, 然后利用以下方法飞行到默认位置。

JavaScript
//position direction up保存的视角信息
    viewer.camera.flyTo({
        destination :new LSGlobe.Cartesian3(position.x,position.y,position.z),
        orientation : {
            direction : new LSGlobe.Cartesian3(direction.x,direction.y,direction.z),
            up : new LSGlobe.Cartesian3(up.x,up.y,up.z)
        }
    });

场景删除

删除接口参照:

//localhost:8000/wish3dearth/api/scene/v1.0.0/deleteScene

场景图层加载

获取场景图层信息接口,参数jsonType=1如下:

//localhost:8000/wish3dearth/api/scene/v1.0.0/getSceneJsonInfo

返回参数 data 直接加载到场景中,方法如下:

Javascript
    //加载到场景
    viewer.fromJSON(data);
    //使用上面方法数据会自动加载到球上形成一个场景

    //在2.1.0版中viewer.fromJSON()方法已经不使用,但是为了快捷加载图层依然可以使用。 建议解析data里面图层路径分别进行素材加载,可以很好的做到逻辑上的可控和稳定

zTree 插件使用方法可以参照插件官网

data.Tree数据,树结构渲染(通过 <a href="http://www.treejs.cn/" target="_blank">zTree插件</a>渲染)
Javascript
    //初始化树
    $.fn.zTree.init($("#treeLayer"), {}, data.Tree);
  1. 场景中数据管理

    场景中一般有多个,多种类型的数据,我们需要对这些数据进行操作管理达到构建场景的目的。

    1.场景中的数据获取

    JavaScript
    //1).实景三维数据获取
    viewer.scene.pageLODLayers._pageLODs[1] //1是实景三维数据的索引
    //为了精确获取实景三维数据可使用根据数据id获取的方式获取,获取方法如下
    function getPageLODLayersById(primitiveid) {
        var aPrimitives = viewer.scene.pageLODLayers;
        var oPrimitive = "";
        for (var i = 0; i < aPrimitives._pageLODs.length; i++) {
            if ( !! aPrimitives._pageLODs[i].name) {
                if (aPrimitives._pageLODs[i].name.guid == primitiveid) {
                    oPrimitive = aPrimitives._pageLODs[i];
                    break;
                }
            }
        }
        return oPrimitive;
    }
    //2).人工三维数据获取
    viewer.scene.primitives._primitives[1] //1是人工三维数据的索引
    //精确获取参照实景三维数据获取方法
    //3).矢量数据获取
    viewer.dataSources._dataSources[1] //1是矢量数据的索引
    //精确获取参照实景三维数据获取方法
    //4).影像数据获取
    viewer.scene.imageryLayers._layers[1] //1影像数据的索引
    //精确获取参照实景三维数据获取方法
    //5).地形数据获取
    viewer.scene.terrainLayers._layers[1] //1是地形数据的索引
    //精确获取参照实景三维数据获取方法

    2.场景中的数据飞行

    JavaScript
    //1).实景三维数据飞行
        //tileset第一步获取的数据对象
        var oCenter=tileset.tileBoundingSphere.center;
        var cartesian3=new LSGlobe.Cartesian3(oCenter.x,oCenter.y,oCenter.z);
        var cartographic=ellipsoid.cartesianToCartographic(cartesian3);
    
        var lat=LSGlobe.Math.toDegrees(cartographic.latitude);
        var lng=LSGlobe.Math.toDegrees(cartographic.longitude);
        var height=cartographic.height;
        viewer.camera.flyTo({
            destination: LSGlobe.Cartesian3.fromDegrees(lng, lat, height + 1500),
            duration: 1
        })
    //2).人工三维数据飞行
        //tileset第一步获取的数据对象(lmz格式)
        var addpointStrs = tileset._position.split(',');
        viewer.camera.flyTo({
            destination : LSGlobe.Cartesian3.fromDegrees(addpointStrs[0],addpointStrs[1], addpointStrs[2]+120),
            orientation : {
                    heading : LSGlobe.Math.toRadians(0.0),
                    pitch : LSGlobe.Math.toRadians(-90.0),
                    roll : 0.0
            },
            duration: 2
        });
        //tileset第一步获取的数据对象(3tiles格式)
        var boundingSphere = tileset.boundingSphere;
        viewer.camera.viewBoundingSphere(boundingSphere, new LSGlobe.HeadingPitchRange(0, -2.0, 0));
        viewer.camera.lookAtTransform(LSGlobe.Matrix4.IDENTITY);
    //3).矢量数据飞行
        //datasource第一步获取的数据对象
        viewer.flyTo(datasource)
    //4).影像数据飞行
            //imageLayer第一步获取的数据对象
            var rect = imageLayer._imageryProvider.rectangle;
            viewer.camera.flyTo({
                destination: rect
            }, {duration: 3});
    
    //5).地形数据飞行
            //terrainLayer第一步获取的数据对象
            var rect = terrainLayer._imageryProvider.rectangle;
            viewer.camera.flyTo({
                destination: rect
            }, {duration: 3});

    3.场景中的数据显示隐藏

    JavaScript
    //1).实景三维数据显示隐藏
        //tileset第一步获取的数据对象
        tileset.show=false;
        //false 隐藏 true 显示
    //2).人工三维数据显示隐藏
        //参考实景三维数据显示隐藏
    //3).矢量数据显示隐藏
        //参考实景三维数据显示隐藏
    //4).影像数据显示隐藏
        //参考实景三维数据显示隐藏
    //5).地形数据显示隐藏
        //参考实景三维数据显示隐藏

    4.场景中的数据删除

    JavaScript
    //1).实景三维数据删除
        //tileset第一步获取的数据对象
        viewer.scene.pageLODLayers.remove(tileset)
    //2).人工三维数据删除
        //tileset第一步获取的数据对象
        viewer.scene.primitives.remove(tileset)
    //3).矢量数据删除
        //dataSources第一步获取的数据对象
        viewer.dataSources.remove(dataSources)
    //4).影像数据删除
        //imageLayer第一步获取的数据对象
        viewer.imageryLayers.remove(imageLayer)
    //5).地形数据删除
        //terainLayer第一步获取的数据对象
        viewer.imageryLayers.remove(terainLayer)

场景底图

加载在线影像

JavaScript
//1).google影像
var google = new LSGlobe.UrlTemplateImageryProvider({
    url: 'http://mt0.google.cn/vt/lyrs=s&hl=zh-CN&x={x}&y={y}&z={z}',
    tilingScheme: new LSGlobe.WebMercatorTilingScheme(),
    maximumLevel: 20,
    name: "google"
});
viewer.imageryLayers.addImageryProvider(google);
//2).天地图
var tianditu = new LSGlobe.WebMapTileServiceImageryProvider({
    url: "http://t0.tianditu.com/img_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=img&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=9dd6ff82e27b5411290191ae41776f6d",
    layer: "tdtBasicLayer",
    style: "default",
    format: "image/jpeg",
    tileMatrixSetID: "GoogleMapsCompatible",
    show: false
}) viewer.imageryLayers.addImageryProvider(tianditu);
//3).bingmap
var bing = new LSGlobe.BingMapsImageryProvider({
    url: 'https://dev.virtualearth.net',
    key: 'Ak1xFbfMYLAAsWU7cZMRyvDHY13HFN1PESWP98WJLoK49OQDb8HSeUjBV3MpC5Yf',
    //bingmap秘钥
    mapStyle: LSGlobe.BingMapsStyle.AERIAL
});
viewer.imageryLayers.addImageryProvider(bing);

加载 lrc 文件作为底图

JavaScript
var oLrcPath = "lrc文件路径";
try{
    var oLrc = await LSGlobe.LSImageryProvider.fromUrl(oLrcPath);
    viewer.imageryLayers.addImageryProvider(oLrc);
}catch (error) {
    console.log(`Error loading imagery: ${error}`);
}

设置图层的层级

JavaScript
//初始添加影像时设置层级
viewer.imageryLayers.addImageryProvider(bing, index);
//index影像图层的层级number类型,对lrp也适用
//设置某一个影像为最高层级
viewer.imageryLayers.raiseToTop(imageLayer)
//imageLayer获取的影像对象

设置在线 google 地形

JavaScript
//google地形为国外数据加载较慢
const url = 'http://assets02.agi.com/stk-terrain/v1/tilesets/world/tiles'
try {
    var terrainLayer = await LSGlobe.CesiumTerrainProvider.fromUrl(url, {
        requestWaterMask: true,
        requestVertexNormals: true
    });
    viewer.terrainLayers.addTerrainProvider(terrainLayer);
} catch (error) {
    console.log(`Error loading terrain: ${error}`);
}

飞行

飞行路径构建

  1. 添加一条飞行路径,即向场景 JSON,oSubSceneData.fly.lines 数组添加路径

    Javascript
    oSubSceneData.fly={
        "sceneId":"4a8cbec3413417e58f227060e464c7c5",
        "lines":[]
    }
    //添加一条飞行路径
    var line={
        "id":"1730757e513417e310674b92267f33ad",//路径id
        "title":"飞行路径",//路径名称
        /*关键视点数组*/
        "points":[]
    }
    oSubSceneData.fly.lines.push(line)
    //向飞行路径中添加当前视点
    var oPos=viewer.camera.postion;
    var oDir=viewer.camera.direction;
    var oUp=viewer.camera.up;
    
    line.points.push({
        "id": "846f1897313417e3106751bdd54f5365",
        //视点id
        "title": "视点",
        //视点名称
        /*视点视角的基本信息*/
        "posx": oPos.x,
        "posy": oPos.y,
        "posz": oPos.z,
        "directionx": oDir.x,
        "directiony": oDir.y,
        "directionz": oDir.z,
        "upx": oUp.x,
        "upy": oUp.y,
        "upz": oUp.z,
    
        "timeInterval": 2,
        //视点的过渡时间,单位s
        "viewImg": "temp/scene/4a8cbec3413417e58f227060e464c7c5/image/e5b067e5febe4df7a155f26d3515a0be.jpg" //视点的缩略图路径
    });
  2. 修改、删除某条飞行路径

    修改数飞行路径的名称和视点仅修改对应数组的信息,最后随场景保存接口一并提交

  3. 获取飞行路径

    根据场景 id 获取飞行路径

    //localhost:8000/wish3dearth/api/scene/v1.0.0/getSceneJsonInfo

  4. 生成视点缩略图,并上传该图片,同时修改对应视点的缩略图路径(标注缩略图获取方法相同)

    JavaScript
    //截取canvas方形图片
    var oOriginImg = $("#visibleImg");
    var canvasWidth = $("canvas").width();
    var canvasHeight = $("canvas").height();
    var sImg = getRenderer();
    oOriginImg.off("load");
    oOriginImg.attr("src", sImg);
    oOriginImg.attr("style", "width:" + canvasWidth + "px;height:" + canvasHeight + "px;");
    oOriginImg.off("load").load(function () {
        //原始尺寸
        var orinWidth = oOriginImg.width();
        var orinHeight = oOriginImg.height();
        //计算比例
        var fProportion = parseFloat(orinHeight / orinWidth);
        //现在尺寸
        var iCurrentWidth = orinWidth;
        var iCurrentheight = orinHeight;
        if (fProportion >= 1) {
            iCurrentWidth = parseInt(orinWidth * 0.6);
            iCurrentheight = iCurrentWidth;
        } else {
            iCurrentWidth = parseInt(orinHeight * 0.6);
            iCurrentheight = iCurrentWidth;
        }
        var left = parseInt(orinWidth / 2) - parseInt(iCurrentWidth / 2);
        var top = parseInt(orinHeight / 2) - parseInt(iCurrentheight / 2);
        var crop_canvas = document.createElement('canvas');
        crop_canvas.width = 150;
        crop_canvas.height = 150;
        crop_canvas.getContext('2d').drawImage(oOriginImg.get(0), left, top, iCurrentWidth, iCurrentheight, 0, 0, 150, 150);
        var imgUrl = crop_canvas.toDataURL("image/jpeg");
    });
    
    //注意:每添加一个飞行视点或者删除一个视点都需要更新一下对应该条飞行路径的视点的缩略图,并操作oSubSceneData.deleteObj.images数组
  5. 上传飞行视点的缩略图

    上传接口参照//localhost:8000/wish3dearth/api/scene/v1.0.0/uploadTempImg

飞行路径的预览

  1. 初始化一条飞行路径

    JavaScript
    var cameraTrackControls = new LSGlobe.LSCameraTrackControls(viewer.scene);
  2. 向飞行路径中添加视点信息

    JavaScript
    //向飞行路径中添加单个视点
    //pos,direction,up这些值是保存视点中的相机位置信息
    //timeDelta 保存视点中的timeInterval值
    cameraTrackControls.getAllKeys().push(
    {
        destination: new LSGlobe.Cartesian3(posx,posy,posz),
        orientation: {
            direction: new LSGlobe.Cartesian3(directionx,directiony,directionz),
            up: new LSGlobe.Cartesian3(upx,upy,upz)
        },
        time: timeDelta
    });
    //添加视点完成该飞行路径初始化完成
  3. 飞行路径的操作

    JavaScript
    //开始飞行路径的飞行或继续飞行路径的飞行
    cameraTrackControls.play();
    
    //暂停飞行路径的飞行,从暂停视点开始飞行
    cameraTrackControls.pause();
    
    //清除飞行路径并停止飞行路径的飞行
    cameraTrackControls.clear();
    
    //停止飞行路径的飞行,再次飞行从第一个视点飞行
    cameraTrackControls.stop()

标绘

标绘功能包含标绘点、标绘线、标绘面。这些标绘信息统一保存在一个 drawDataSource 对象中,保存时数据可转换为 json 文件,加载时获取到之前保存的 json,可以统一一次将各种标绘数据加载到场景中并与保存前的显示效果一致。

为了更好的绘制体验,标绘线面的绘制可以应用现在封装好的线面绘制插件来绘制。而标注的绘制需要在事件句柄中点击绘制添加

初始化标绘存储对象

JavaScript
var drawDataSource;
//标绘存储对象绘制的标绘要素(线或者面)会保存到该对象中
var promise = viewer.dataSources.add(new LSGlobe.GeoJsonDataSource("drawDataSource"));
promise.then(function(dataSource) {
    drawDataSource = dataSource;
}).otherwise(function(error) {

});

标绘绘制

绘制点

  1. 添加至场景

    JavaScript
    //第一步新加事件句柄
    var handler = new LSGlobe.ScreenSpaceEventHandler(viewer.scene.canvas);
    handler.setInputAction(function(movement) {
        //获取的坐标上添加标绘点,具体的坐标获取参照坐标转换
        var Pos = scene.pickGlobe(movement.position);
    },
    LSGlobe.ScreenSpaceEventType.LEFT_CLICK);
    
    //第二部将标注添加到球上
    //drawDataSource 保存标绘集合的对象,标绘初始化定义的
    var NewPoint = drawDataSource.entities.add({
        //标注的坐标 x,y,z 经度纬度和高度的值
        position: new LSGlobe.Cartesian3(Pos.x, Pos.y, Pos.z),
        label: {
            text: name,
            //标注文字描述
            font: "32px Microsoft YaHei",
            //标注文字大小、字体
            style: LSGlobe.LabelStyle.FILL_AND_OUTLINE,
            outlineWidth: 6,
            translucencyByDistance: new LSGlobe.NearFarScalar(1.5e2, 1.0, 1.5e5, 0.0),
            //根据告诉改变透明度
            horizontalOrigin: LSGlobe.HorizontalOrigin.LEFT,
            pixelOffset: new LSGlobe.Cartesian2(15, -15),
            disableDepthTestDistance: 0,
            //标注的遮挡距离设置为100则视角与标注的距离大于100米时会有遮挡
            scale: 0.5
        },
        billboard: {
            image: iconPath,
            //标注图标路径
            width: 64,
            height: 64,
            disableDepthTestDistance: 1000000000,
            //标注的遮挡距离设置为100则视角与标注的距离大于100米时会有遮挡
            scale: 0.5,
            translucencyByDistance: new LSGlobe.NearFarScalar(1.5e2, 1.0, 1.5e5, 0.0),
        },
        id: id,
        //标注唯一标识
        show: true //标绘点对象的true显示,false隐藏属性
    });
    
    NewPoint.properties.addProperty(des, description);
    //使用该方法加入单个自定义属性  des自定义属性名 description自定义属性值
    //NewPoint刚刚添加的标绘点对象
    NewPoint.properties = new LSGlobe.PropertyBag({
        des: description
    });
    //使用该方法加入多个自定义属性  des自定义属性名 description自定义属性值
    //NewPoint刚刚添加的标绘点对象
    //标绘点自定义属性中一般需要有标绘点的图片地址信息和相机位置信息 这些信息需要添加到自定义的属性中用于再次加载时使用
  2. 缩略图信息上传

    获取标绘点缩略图同飞行视点获取视点的缩略图一致。

  3. 标会点附属信息

    每个标绘点都可以挂载附属信息,分为文本、图片、视频、全景,在 Wish3DEarth 中称其为附属信息。在场景设置中,所有标会点的附属信息,均存储在 oSubSceneData.drawDetail.points 中(如需要其他标绘也可以挂载在不同属性中),

    JavaScript
    //附属信息容器
    oSubSceneData.drawDetail= {
        'sceneId': '场景ID',
        'points': []
    },
    //附属信息单个示例
    var oDrawDetail={
    'id': 'GUID',
    'title': '名称',
    'viewPoint': {
        /*标绘点的视角信息*/
        "posx": -2765417.479773966600000,
        "posy": 4789433.917735196000000,
        "posz": 3171073.033866435000000,
        "upx": 0.479484059578550,
        "upy": 0.042675029450645,
        "upz": 0.876512337888898,
        "directionx": 0.578378444536402,
        "directiony": -0.766548590616974,
        "directionz": -0.279072809708834,
        "viewImg": "scene/44446d72-0039-443a-bcb0-f20fbe25ca64/image/34546d72-0039-443a-bcb0-f20fbe25ca64.jpg"
    },
    /*文本附属信息*/
    text: {
        title: '标题',
        content: '内容'
    },
    /*图片附属信息*/
    image: {
        title: '标题',
        pics: [{
            'id': 'GUID',
            path: '图片地址'
        }]
    },
    /*视频附属信息*/
    video: [{
        'id': 'GUID',
        title: '',
        type: '视频类型(1;url, 2自定义上传)',
        url: '视频地址'
    }],
    /*全景附属信息*/
    panoramic: [{
        'id': 'GUID',
        title: '标题',
        url: '全景地址'
    }]
    
    }
  4. 附属信息-图片和视频(本地视频,非在线)上传

    上传接口参照//localhost:8000//wish3dearth/api/scene/v1.0.0/uploadTempFile

标绘线

Javascript
//获取线上点,>=2个点
var handler = new LSGlobe.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function(movement) {
    //获取的坐标上添加标绘点,具体的坐标获取参照坐标转换
    var Pos = scene.pickGlobe(movement.position);
},
LSGlobe.ScreenSpaceEventType.LEFT_CLICK);

//添加到场景中
drawDataSource.entities.add({
    //特殊字段该字段会保存下来,可以是字符串也可以是个对象
    name: "标绘线",
    //线的唯一标识会存储下来,再次加载也不改变,用于查找
    id: "1ab133f2-6a13-4575-a65a-aa2e9bbbc3ca",
    polyline: {
        //线点的集合
        positions: [{
            "x": -2762093.143122826,
            "y": 4700702.533345467,
            "z": 3299201.561099788
        },
        {
            "x": -2762049.697649547,
            "y": 4700739.367655585,
            "z": 3299182.502160778
        },
        {
            "x": -2762049.5886295093,
            "y": 4700739.656572349,
            "z": 3299182.139584659
        }],
        //线宽
        width: 2,
        //线的材质
        material: LSGlobe.Color.fromCssColorString("rgb(255,120,255)"),
        /*
        1.虚实线material: new LSGlobe.PolylineDashMaterialProperty({
            color:oMaterial,
            dashPattern:LSGlobe.LineType.SOLID//SOLID:实线,DASH:虚线,DOT:浮点,DASHDOT:-.-.-,DASHDOTDOT:-..-..
        })
        2.箭头:material: new LSGlobe.PolylineArrowMaterialProperty(LSGlobe.Color.PURPLE)
        3.边框线:material: new LSGlobe.PolylineOutlineMaterialProperty({
                    color: LSGlobe.Color.ORANGE,
                    outlineWidth: 2,
                    outlineColor: LSGlobe.Color.BLACK
                })
        4.发光线:material: new LSGlobe.PolylineGlowMaterialProperty({
                    glowPower: 0.2,
                    color: LSGlobe.Color.BLUE
                })
        */
        //空间线被遮挡部分样式,仅适用空间线
        depthFailMaterial: new LSGlobe.PolylineDashMaterialProperty({
                    color:LSGlobe.Color.fromCssColorString("rgba(0,186,255,0.5)")
                }),
        clampToGround: false,//是否贴地(空间线必须为false,贴地形、贴模型、贴地表模型必须为true)
        classificationType: undefined//TERRAIN:贴地表,CESIUM_3D_TILE:贴模型,BOTH贴模型贴地表,undefined:空间线
    }
});

标绘面

JavaScript
drawDataSource.entities.add({
    //特殊字段该字段会保存下来,可以是字符串也可以是个对象
    name: '标绘面',
    //面的唯一标识会存储下来,再次加载也不改变,用于查找
    id: id,
    polygon: {
        hierarchy: {
            //面的点集合
            positions: event.positions,
        },
        //面的材质
        material: LSGlobe.Color.fromCssColorString("rgb(0,186,255)"),
        //是否填充面
        fill: true,
        //是否显示面的外边框(仅空间面有效)
        outline: true,
        //面的外边框的材质
        outlineColor: LSGlobe.Color.fromCssColorString("rgb(0,186,255)"),
        //面的外边框的宽度(暂不支持非1)
        outlineWidth:1,
        //面的类型
        classificationType: LSGlobe.ClassificationType.BOTH,
        //LSGlobe.ClassificationType.BOTH           即可贴地又可贴模型
        //LSGlobe.ClassificationType.TERRAIN        仅贴地
        //LSGlobe.ClassificationType.CESIUM_3D_TILE 仅贴模型
        //undefined 空间面
        perPositionHeight:false//是否绝对高度(当设置非空间面时候一定要设置false,空间面一定要设置true)
    }
});

标绘要素获取

JavaScript
//id 绘制线面时加入的唯一标识
var entity = drawDataSource.entities.getById(id)

标绘显示隐藏

JavaScript
//entity获取到的标绘要素对象
entity.show=true;//true:显示,false:隐藏

标绘飞行

JavaScript
//entity获取到的标绘要素对象

//空间线面的飞行(发光线等都是空间线)
viewer.flyto(entity)

//特殊线面的飞行(贴地,贴模型)
//使用单体化的飞行方式飞行

标绘删除

JavaScript
//单个标绘线面删除
//id绘制时添加的唯一标识
drawDataSource.entities.removeById(id)

//删除drawDataSource对象中的所有标绘要素
drawDataSource.entities.removeAll();

标绘编辑

编辑标绘点

JavaScript
//entity
//markid是标注添加时的唯一标识
entity.billboard = new LSGlobe.BillboardGraphics({ //图标
    image: iconPath,//标注图标
    width: 64,
    height: 64,
    pixelOffset: new LSGlobe.Cartesian2(0, -13),
    //偏移量
    disableDepthTestDistance: 0,
    scale: 0.5,
    translucencyByDistance: new LSGlobe.NearFarScalar(1.5e2, 1.0, 1.5e5, 0.0),
});
//修改标注图标信息
entity.label = new LSGlobe.LabelGraphics({
    text: objEntity.name,
    //修改后的文字信息
    font: "64px Microsoft YaHei",//修改后的文字类型和大小
    fillColor: LSGlobe.Color.fromCssColorString('rgb(0,0,0)'),
    //文字填充颜色
    style: LSGlobe.LabelStyle.FILL_AND_OUTLINE,
    outlineWidth: 6,
    translucencyByDistance: new LSGlobe.NearFarScalar(1.5e2, 1.0, 1.5e5, 0.0),
    horizontalOrigin: LSGlobe.HorizontalOrigin.LEFT,
    pixelOffset: new LSGlobe.Cartesian2(15, -15),
    disableDepthTestDistance: 0,
    scale: 0.5//缩放
});
//修改标注位置信息(经纬度)
entity.position = new LSGlobe.Cartesian3.fromDegrees(position.x, position.y, position.z);
//修改标注文字信息
entity.label.text = new LSGlobe.ConstantProperty(objEntity.name);
//单独修改标注文字信息中的文本
entity.label.fillColor = LSGlobe.Color.fromCssColorString('rgb(255,255,255)');
//单独修改标注文字信息中的文本填充颜色

编辑标绘线

JavaScript

//编辑线的特殊字段
entity.name = '面标绘名称';
//编辑线宽度
entity.polyline.width = 10;
//编辑线材质(颜色)
entity.polyline.material = LSGlobe.Color.fromCssColorString('rgb(0,0,0)');
//编辑线的透明度
entity.polyline.material = LSGlobe.Color.fromCssColorString('rgb(0,0,0)').withAlpha('0.5')
//线的材质
/*
1.虚实线
entity.polyline.material = new LSGlobe.PolylineDashMaterialProperty({
    color: oMaterial,
    dashPattern: LSGlobe.LineType.SOLID //SOLID:实线,DASH:虚线,DOT:浮点,DASHDOT:-.-.-,DASHDOTDOT:-..-..
})
2.箭头:
entity.polyline.material = new LSGlobe.PolylineArrowMaterialProperty(LSGlobe.Color.PURPLE)
3.边框线:material: new LSGlobe.PolylineOutlineMaterialProperty({
    color: LSGlobe.Color.ORANGE,
    outlineWidth: 2,
    outlineColor: LSGlobe.Color.BLACK
})
4.发光线:
entity.polyline.material = new LSGlobe.PolylineGlowMaterialProperty({
    glowPower: 0.2,
    color: LSGlobe.Color.BLUE
})
*/
//编辑线的遮挡部分虚线属性
entity.polyline.depthFailMaterial = new LSGlobe.PolylineDashMaterialProperty({
    color: LSGlobe.Color.fromCssColorString('rgb(0,0,0)').withAlpha('0.5')
});
//是否贴地(空间线必须为false,贴地形、贴模型、贴地表模型必须为true)
entity.polyline.clampToGround = false;
entity.polyline.classificationType = undefined//TERRAIN:贴地表,CESIUM_3D_TILE:贴模型,BOTH贴模型贴地表,undefined:空间线

编辑标绘面

JavaScript
//编辑线的特殊字段
entity.name = '面标绘名称';
//编辑面的材质
entity.polygon.material = LSGlobe.Color.fromCssColorString('rgb(0,0,0)');
//编辑面的透明度
entity.polygon.material = LSGlobe.Color.fromCssColorString('rgb(0,0,0)').withAlpha('0.5');
//编辑面的外边框(特殊面不显示边框不能设置该属性)
entitie.polygon.outline = true / false;
//编辑面是否填充
entitie.polygon.fill = true / false;
//编辑面外边框材质(特殊面不显示边框不能设置该属性)
entitie.polygon.outlineColor = LSGlobe.Color.fromCssColorString('rgb(0,0,0)');
//编辑面外边框透明度(特殊面不显示边框不能设置该属性)
entitie.polygon.outlineColor = LSGlobe.Color.fromCssColorString('rgb(0,0,0)').withAlpha('0.5');

entitie.polygon.classificationType = LSGlobe.ClassificationType.BOTH;
//LSGlobe.ClassificationType.BOTH           即可贴地又可贴模型
//LSGlobe.ClassificationType.TERRAIN        仅贴地
//LSGlobe.ClassificationType.CESIUM_3D_TILE 仅贴模型
//undefined 空间面
entitie.polygon.perPositionHeight:false//是否绝对高度(当设置非空间面时候一定要设置false,空间面一定要设置true)

标绘存储

标绘的存储是以 json 格式保存的,直接赋值给 oSubSceneData.draw,然后随场景保存接口一并提交保存

JavaScript
oSubSceneData.draw = drawDataSource.toGeoJson()

标绘重载

标绘获取接口,参数 jsonType 为 2

//localhost:8000/wish3dearth/api/scene/v1.0.0/getSceneJsonInfo

JavaScript
var oGeoJson = result.data;
//result.data前面获取的标绘数据json
var promise = LSGlobe.GeoJsonDataSource.load(oGeoJson, {});
promise.then(function(dataSource) {
    //将数据再次加载到初始化存储标绘要素的对象中
    drawDataSource = dataSource;
    //添加到球中
    viewer.dataSources.add(dataSource);
}).otherwise(function(error) {
    console.log(error);
});

单体化

单体化原理:本质就是贴模型地表的标绘面,在默认 0.01 的透明度下,当鼠标移动到该面时候,改变面的材质的透明度为 1,当鼠标移出后透明度重新设置透明度为 0.01,从而实现高亮效果。

单体化绘制

JavaScript

//1).初始化单体化存储对象
var monomerDataSource;
var promise = viewer.dataSources.add(new LSGlobe.GeoJsonDataSource("monomerDataSource"));

promise.then(function(dataSource) {
   monomerDataSource = dataSource;
   monomerDataSource.name="monomerDataSource"
}).otherwise(function(error) {

});

//2).单体化绘制
monomerDataSource.entities.add({
   //特殊字段该字段会保存下来,可以是字符串也可以是个对象
   name: '单体化面',
   //面的唯一标识会存储下来,再次加载也不改变,用于查找
   id: id,
   polygon: {
       hierarchy: {
           //面的点集合
           positions: event.positions,
       },
       //面的材质
       material: LSGlobe.Color.fromCssColorString("rgb(0,186,255)").withAlpha('0.5');,
       //是否填充面
       fill: true,
       //是否显示面的外边框(仅空间面有效)
       outline: false,
       //面的类型
       classificationType: LSGlobe.ClassificationType.BOTH,
       perPositionHeight:false//是否绝对高度(当设置非空间面时候一定要设置false,空间面一定要设置true)
   }
});

单体化要素获取

JavaScript
//id 绘制单体化时加入的唯一标识
var entity = monomerDataSource.entities.getById(id)

单体化显示隐藏

JavaScript
//entity获取到的单体化对象
entity.show=true/false;

单体化飞行

JavaScript
//entity获取到的单体化对象
//单体化飞行(贴地,贴模型)
var entity = monomerDataSource.entities.getById(id);
if (entity) {
    entity.polygon.material = LSGlobe.Color.fromRandom({
        red: entity.polygon.material.color._value.red,
        green: entity.polygon.material.color._value.green,
        blue: entity.polygon.material.color._value.blue,
        alpha: 0.7
    });
    var entityPosition = getRealPosition(entity);
    //获取单体化真实飞行坐标
    viewer.camera.flyTo({
        destination: LSGlobe.Cartesian3.fromDegrees(entityPosition.lng, entityPosition.lat, entityPosition.alt),
        duration: 3
    })
}

function getRealPosition(Entities) {
    if (Entities._corridor) {
        var aPos = Entities._corridor.positions._value;
    } else {
        var aPos = Entities.polygon.hierarchy._value.positions || Entities.polygon.hierarchy._value;
    }
    var iX = 0,
    iY = 0,
    iZ = 0,
    maxX = 0,
    maxY = 0,
    minX, minY, realheight;
    for (var i = 0; i < aPos.length; i++) {
        iX = aPos[i].x + iX;
        iY = aPos[i].y + iY;
        iZ = aPos[i].z + iZ;
    }
    iX = iX / aPos.length;
    iY = iY / aPos.length;
    iZ = iZ / aPos.length;
    //中心点经纬度
    var WorlsPos = new LSGlobe.Cartesian3(iX, iY, iZ);
    var oDegree = ellipsoid.cartesianToCartographic(WorlsPos);
    var lng = LSGlobe.Math.toDegrees(oDegree.longitude);
    var lat = LSGlobe.Math.toDegrees(oDegree.latitude);
    for (var a = 0; a < aPos.length; a++) {
        //当前点的经纬度
        var sWorlsPos = new LSGlobe.Cartesian3(aPos[a].x, aPos[a].y, aPos[a].z);
        var sDegree = ellipsoid.cartesianToCartographic(sWorlsPos);
        var slng = LSGlobe.Math.toDegrees(sDegree.longitude);
        var slat = LSGlobe.Math.toDegrees(sDegree.latitude);
        //中心点经纬度
        var oPos = {
            "x": slng,
            "y": slat
        };
        var currentheight = getDistance(oPos, lng, lat);
        if (a == 0) {
            realheight = currentheight
        }
        if (realheight < currentheight) {
            realheight = currentheight
        }
    }
    var sTileset = whichTileset(lng, lat)[0];
    //获取单体化当前依附的模型
    if (sTileset) {
        var alt = realheight * 1.7320508075689 + 50 + sTileset._boundingSphere.center.z * 1 + sTileset.name.position.split(",")[2] * 1;
        return {
            "lat": lat,
            "lng": lng,
            "alt": alt
        };
    } else {
        return {
            "lat": lat,
            "lng": lng,
            "alt": realheight
        };
    }
    return {
        "lat": lat,
        "lng": lng,
        "alt": alt
    };
}
//根据经纬度获取当前经纬度下的模型集合
//x经度值 y维度值
function whichTileset(x, y) {
    var returnValue = [];
    for (var i = 0; i < viewer.scene.pageLODLayers._pageLODs.length; i++) {
        var aTileSet = viewer.scene.pageLODLayers._pageLODs[i];
        var oCenter = aTileSet.tileBoundingSphere.center;
        var ellipsoid = viewer.scene.globe.ellipsoid;
        var cartesian3 = new LSGlobe.Cartesian3(oCenter.x, oCenter.y, oCenter.z);
        var cartographic = ellipsoid.cartesianToCartographic(cartesian3);
        var lat = LSGlobe.Math.toDegrees(cartographic.latitude);
        var lng = LSGlobe.Math.toDegrees(cartographic.longitude);
        var position = {
            x: lng,
            y: lat,
            z: cartographic.height
        };
        var distance = getDistance(position, x, y);
        if (distance < aTileSet.tileBoundingSphere.radius) {
            returnValue.push(aTileSet);
        }
    }
    return returnValue;
}
//获取两个经纬度之间的距离函数
function getDistance(position, x, y) {
    var radLatA = position.y * 0.0174532925199432957692369077;
    var radLatB = y * 0.0174532925199432957692369077;
    var radLonA = position.x * 0.0174532925199432957692369077;
    var radLonB = x * 0.0174532925199432957692369077;
    return Math.acos(Math.cos(radLatA) * Math.cos(radLatB) * Math.cos(radLonA - radLonB) + Math.sin(radLatA) * Math.sin(radLatB)) * 6378137;
}

单体化删除

JavaScript
//单个单体化删除
//id绘制时添加的唯一标识
monomerDataSource.entities.removeById(id)

//删除monomerDataSource对象中的所有单体化
monomerDataSource.entities.removeAll();

单体化编辑

JavaScript
//entity获取到的单体化要素对象
//1.编辑单体化样式
//编辑单体化的特殊字段
entity.name = '单体化面';
//编辑单体化材质(颜色)
entity.polygon.material = LSGlobe.Color.fromCssColorString('rgb(0,0,0)');
//编辑单体化的透明度
entity.polygon.material = LSGlobe.Color.fromCssColorString('rgb(0,0,0)').withAlpha('0.5')

//2.获取属性和属性值展示出来
var oEntityProperties = entity.properties.getValue();

for (var key in oEntityProperties) {
    console.log(key+":"+oEntityProperties.key);
}
//3.编辑单体化的属性属性值
//添加属性属性值
entity.properties.addProperty("属性","属性值");
//下面是整体属性替换(谨慎使用,会覆盖之前的属性)
entities.properties = {
    "属性":"属性值"
};
//删除属性属性值
entity.properties.removeProperty("属性");

单体化点击获取

JavaScript

//初始化一个鼠标事件
var handlerMonomer = new LSGlobe.ScreenSpaceEventHandler(viewer.scene.canvas);
handlerMonomer.setInputAction(function(movement) {
    var posit = viewer.scene.pick(movement.position);
    if (LSGlobe.defined(posit)) {
        //如果posit值存在说明鼠标点击的地方有内容
        //(该内容可以是标注,标绘,单体化,矢量数据等要素)需要判断该数据是什么类型需要根据该对象中的特殊字段来判断或者是否包含关系
        if ( !! posit.id && monomerDataSource.entities.contains(posit.id)) {
            //如果被monomerDataSource.entities包含则是单体化

        }
    }
},
LSGlobe.ScreenSpaceEventType.LEFT_CLICK);

单体化存储

单体化的存储是以 json 格式保存的,直接赋值给 oSubSceneData.monomer,然后随场景保存接口一并提交保存

JavaScript
oSubSceneData.monomer = monomerDataSource.toGeoJson()

单体化重载

标绘获取接口,参数 jsonType 为 3

//localhost:8000/wish3dearth/api/scene/v1.0.0/getSceneJsonInfo

JavaScript
var oGeoJson = result.data;
//result.data前面获取的标绘数据json
var promise = LSGlobe.GeoJsonDataSource.load(oGeoJson, {});
promise.then(function(dataSource) {
    //将数据再次加载到初始化存储标绘要素的对象中
    monomerDataSource = dataSource;
    //添加到球中
    viewer.dataSources.add(dataSource);
}).otherwise(function(error) {
    console.log(error);
});

压平

压平面的保存和标绘、单体化相同,都是使用 togeojson()的方式直接转换为 json 格式数据上传保存,但是压平需要额外调用压平接口

压平绘制

JavaScript

var pushDataSource;
//存储压平绘制的面要素会保存到该对象中
var promise = viewer.dataSources.add(new LSGlobe.GeoJsonDataSource("pushDataSource"));
promise.then(function(dataSource) {
    pushDataSource = dataSource;
}).otherwise(function(error) {

});

//压平面的绘制
var pushHandler = new LSGlobe.ScreenSpaceEventHandler(viewer.scene.canvas);
pushHandler.setInputAction(function(movement) {
    //获取的坐标上添加标绘点,具体的坐标获取参照坐标转换
    var Pos = scene.pickGlobe(movement.position);
},
LSGlobe.ScreenSpaceEventType.LEFT_CLICK);
//根据上面获取到的点集合经过处理后达到新的数据
var oValuePoint = ChangePolygonPosition(event.positions);
//该面是辅助设置压平面的面,最后压平的高度和范围是该面显示的高度和范围(该面用于保存,存储于pushDataSource.entities,如果需要对比高度效果可以多创建一个面)
pushDataSource.entities.add({
    name: '压平面',//压平面名称
    id: id,
    polygon: {
        hierarchy: {
            positions:LSGlobe.Cartesian3.fromDegreesArrayHeights(oValuePoint)
        },
        material: new LSGlobe.Color(0.5, 1.0, 1.0, 0.7),
        fill: true,
        //显示填充
        outline: false,
        outlineColor: LSGlobe.Color.YELLOW,
        perPositionHeight: true
    }
});
//坐标转换函数
function ChangePolygonPosition(oPositions) {
    var oValuePoint = [];
    //所有点统一高度,使压平面在同一水平面(此处计算所有点的平均高度)
    var fSumHeight = 0;
    for (var a = 0; a < oPositions.length; a++) {
        var cartographic = LSGlobe.Cartographic.fromCartesian(oPositions[a]);
        fSumHeight = fSumHeight + cartographic.height;
    }
    var Height = fSumHeight / oPositions.length;

    for (var a = 0; a < oPositions.length; a++) {
        var CurrentPoint = oPositions[a];
        var cartographic = LSGlobe.Cartographic.fromCartesian(CurrentPoint);
        var currentClickLon = LSGlobe.Math.toDegrees(cartographic.longitude);
        var currentClickLat = LSGlobe.Math.toDegrees(cartographic.latitude);
        oValuePoint.push(currentClickLon);
        oValuePoint.push(currentClickLat);
        oValuePoint.push(Height);
    }
    return oValuePoint;
};

//模型的压平
var pos = oValuePoint;//同上面oValuePoint

//根据辅助面中的点来获取需要压平的模型
var myPolygon = new LSGlobe.PolygonGeometry({
    polygonHierarchy: new LSGlobe.PolygonHierarchy(pos),
    perPositionHeight: true
});

viewer.scene.pageLODLayers.addFlattenPolygon(myPolygon);

//可以选择让辅助面是否显示
pushDataSource.entities.getById(id).show = false;

//获取当前压平的模型对象函数
function whichTileset(x, y) {
    var returnValue = [];
    for (var i = 0; i < viewer.scene.pageLODLayers._pageLODs.length; i++) {
        var aTileSet = viewer.scene.pageLODLayers._pageLODs[i];
        var oCenter = aTileSet.tileBoundingSphere.center;
        var ellipsoid = viewer.scene.globe.ellipsoid;
        var cartesian3 = new LSGlobe.Cartesian3(oCenter.x, oCenter.y, oCenter.z);
        var cartographic = ellipsoid.cartesianToCartographic(cartesian3);
        //ellipsoid表示球对象
        var lat = LSGlobe.Math.toDegrees(cartographic.latitude);
        var lng = LSGlobe.Math.toDegrees(cartographic.longitude);
        var position = {
            x: lng,
            y: lat,
            z: cartographic.height
        };
        var distance = getDistance(position, x, y);
        if (distance < aTileSet.tileBoundingSphere.radius) {
            returnValue.push(aTileSet);
        }
    }
    return returnValue;
}
//获取两个经纬度之间的距离函数
function getDistance(position, x, y) {
    var radLatA = position.y * 0.0174532925199432957692369077;
    var radLatB = y * 0.0174532925199432957692369077;
    var radLonA = position.x * 0.0174532925199432957692369077;
    var radLonB = x * 0.0174532925199432957692369077;
    return Math.acos(Math.cos(radLatA) * Math.cos(radLatB) * Math.cos(radLonA - radLonB) + Math.sin(radLatA) * Math.sin(radLatB)) * 6378137;
}

压平面的编辑

JavaScript

//1).设置高度
//获取对应参考面
var entity = pushDataSource.entities.getById(id);
//获取压平点坐标
var aFlatArray = ChangePolygonPosition(entity.polygon.hierarchy.getValue().positions);
for (var i = 2; i < aFlatArray.length; i = i + 3) {
    aFlatArray[i] = height; //height 改变后的高度值
}

//删除原参考面,新增参考面
pushDataSource.entities.remove(entity);
pushDataSource.entities.add({
    name: '压平面',
    //压平面名称
    id: id,
    polygon: {
        hierarchy: {
            positions: LSGlobe.Cartesian3.fromDegreesArrayHeights(aFlatArray)
        },
        material: new LSGlobe.Color(0.5, 1.0, 1.0, 0.7),
        fill: true,
        //显示填充
        outline: false,
        outlineColor: LSGlobe.Color.YELLOW,
        perPositionHeight: true
    }
});

// 清空所有压平面和辅助面
viewer.scene.pageLODLayers.removeAllFlattenPolygons();
//重新压平
var aPushEntities = pushDataSource.entities.values;
for (var i = 0; i < aPushEntities.length; i++) {
    if (aPushEntities[i].show) {
        var aTileset = [];
        var pos = aPushEntities[i].polygon.hierarchy.getValue().positions;

        //使用辅助面的点集合绘制一个面对象
        var myPolygon = new LSGlobe.PolygonGeometry({
            polygonHierarchy: new LSGlobe.PolygonHierarchy(pos),
            perPositionHeight: true
        });
       viewer.scene.pageLODLayers.addFlattenPolygon(myPolygon);
    }
}

//2).设置名称
entity.name = "修改后的名称";

压平面的飞行

JavaScript
//压平面的飞行借助了压平辅助面
var entity = pushDataSource.entities.getById(id);
//粗略定位
viewer.flyTo(entity);

//精准定位(参考单体化定位)
var entity = pushDataSource.entities.getById(id);
    var entityPosition = getRealPosition(entity);
    viewer.camera.flyTo({
        destination: LSGlobe.Cartesian3.fromDegrees(entityPosition.lng,entityPosition.lat,entityPosition.alt),
        duration: 3
    })

设置显示隐藏

JavaScript

//对应的实景三维模型
tileset._flattenPolygons[0].show=true;//true显示,false:影藏
tileset.updateFlatten();
//对应的entity也要做对应同步
entity.show=true;//true显示,false:影藏

压平面的删除

JavaScript

//删除对应的entity
pushDataSource.entities.removeById(id);
//删除所有压平
viewer.scene.pageLODLayers.removeAllFlattenPolygons();
//重新压所有
//参照编辑里面的重新压平

压平存储

压平的存储是以 json 格式保存的,直接赋值给 oSubSceneData.push,然后随场景保存接口一并提交保存

JavaScript
oSubSceneData.push = pushDataSource.toGeoJson()

压平面的重载

压平获取接口,参数 jsonType 为 4

//localhost:8000/wish3dearth/api/scene/v1.0.0/getSceneJsonInfo

JavaScript
var oGeoJson = result.data;
//result.data前面获取的标绘数据json
var promise = LSGlobe.GeoJsonDataSource.load(oGeoJson, {});
promise.then(function(dataSource) {
    //将数据再次加载到初始化存储压平的对象中
    pushDataSource = dataSource;
    //添加到球中
    viewer.dataSources.add(dataSource);

     var aPagelodLayers = viewer.scene.pageLODLayers._pageLODs;
        for (var i = 0; i < aPagelodLayers.length; i++) {
            try {
                aPagelodLayers[i].cleanflattenPolygon();
            } catch (e) {
            }
        }
        //重新压平
        var aPushEntities = pushDataSource.entities.values;
        for (var i = 0; i < aPushEntities.length; i++) {
            if(aPushEntities[i].id.indexOf("common") < 0){
                aPushEntities[i].polygon.perPositionHeight=false;
            }
            if (aPushEntities[i].show && aPushEntities[i].id.indexOf("common") < 0) {
                var aPushPos=aPushEntities[i].polygon.hierarchy.getValue().positions?aPushEntities[i].polygon.hierarchy.getValue().positions:aPushEntities[i].polygon.hierarchy.getValue();
                var oDegree = fnCartesian2Degreen(aPushPos[0]);
                var mtileset = whichTileset(oDegree.lng, oDegree.lat);
                var myPolygon = new LSGlobe.PolygonGeometry({
                        polygonHierarchy: new LSGlobe.PolygonHierarchy(aPushPos),
                        perPositionHeight: true
                    });
                    for (var j = 0; j < mtileset.length; j++) {
                        mtileset[j]._flattenPolygons.push(myPolygon);
                        mtileset[j].updateFlatten();
                    }
            }
        }
}).otherwise(function(error) {
    console.log(error);
});

水面

水面的保存和压平相同,都是使用 togeojson()的方式直接转换为 json 格式数据上传保存,水面需要额外调用水面接口,需要引用插件 Water.js

HTML
<script type="text/javascript" src="Build/Plugins/Water/Water.js"></script>

水面绘制

JavaScript

var waterDataSource;
//存储水面的面要素会保存到该对象中
var promise = viewer.dataSources.add(new LSGlobe.GeoJsonDataSource("waterDataSource"));
promise.then(function(dataSource) {
    waterDataSource = dataSource;
}).otherwise(function(error) {

});

//水面的绘制
var waterHandler = new LSGlobe.ScreenSpaceEventHandler(viewer.scene.canvas);
waterHandler.setInputAction(function(movement) {
    //获取的坐标上添加标绘点,具体的坐标获取参照坐标转换
    var Pos = scene.pickGlobe(movement.position);
},LSGlobe.ScreenSpaceEventType.LEFT_CLICK);

//根据上面获取到的点集合经过处理后达到新的数据
var oValuePoint = ChangePolygonPosition(event.positions);//同压平的坐标处理方法



var pos = oValuePoint;//同上面oValuePoint

//创建
var wateritem = new LSGlobe.Water(viewer.scene);
wateritem.name = "水面";//水面名称
wateritem.id = id;//水面的id
wateritem.waveWidth = 5;//波纹宽度
wateritem.flowDirection = 90;//水流方向
wateritem.flowSpeed =10;//水流速度
wateritem._waterColor = LSGlobe.Color.fromCssColorString("#FFFF00");//水面颜色
wateritem.des = "";//水面描述
wateritem.alpha = 100;//
wateritem.waterPolygon = new LSGlobe.PolygonGeometry({
    polygonHierarchy: new LSGlobe.PolygonHierarchy(LSGlobe.Cartesian3.fromDegreesArrayHeights(oValuePoint)),
    perPositionHeight: true
});

//属性
var oWaterEntityProp = {};
oWaterEntityProp.waveWidth = wateritem.waveWidth;
oWaterEntityProp.flowDirection = wateritem.flowDirection;
oWaterEntityProp.flowSpeed = wateritem.flowSpeed;
oWaterEntityProp._waterColor = "#006ab4";
oWaterEntityProp.alpha = 100;
oWaterEntityProp.des = wateritem.des;
oWaterEntityProp.name = wateritem.name;
//该面是辅助设置水面的面,最后水面的高度和范围是该面显示的高度和范围(该面用于保存,存储于waterDataSource.entities)
var waterEntity = waterDataSource.entities.add({
    name: '水面',//水面名称
    id: id,
    polygon: {
        hierarchy: {
            positions:LSGlobe.Cartesian3.fromDegreesArrayHeights(oValuePoint)
        },
        material: new LSGlobe.Color(0.5, 1.0, 1.0, 0.01),
        fill: true,
        //显示填充
        outline: false,
        outlineColor: LSGlobe.Color.YELLOW,
        perPositionHeight: true
    }
});
waterEntity.properties = oWaterEntityProp;

viewer.scene.waterCollection._water.push(wateritem);

水面编辑

JavaScript
//获取水面对象
function fnGetOwaterById(id) {
    var oSingleWater;
    var aWater = scene.waterCollection._water;
    for (var i = 0; i < aWater.length; i++) {
        if (id == aWater[i].id) {
            aWater[i].index = i;
            oSingleWater = aWater[i];
            break;
        }
    }
    return oSingleWater;
}
//笛卡尔积转经纬度
function fnCartesian2Degreen(oCartesian){
    var ellipsoid=viewer.scene.globe.ellipsoid;
    var cartesian3=new LSGlobe.Cartesian3(oCartesian.x,oCartesian.y,oCartesian.z);
    var cartograhphic=ellipsoid.cartesianToCartographic(cartesian3);
    var lat=LSGlobe.Math.toDegrees(cartograhphic.latitude);
    var lng=LSGlobe.Math.toDegrees(cartograhphic.longitude);
    var alt=cartograhphic.height;
    return {lng:lng,lat:lat,alt:alt}
}
//经纬度转笛卡尔积坐标
function  fnDegreen2Cartesian(oDegreen) {
    return LSGlobe.Cartesian3.fromDegrees(oDegreen.lng?oDegreen.lng:oDegreen.x, oDegreen.lat?oDegreen.lat:oDegreen.y, oDegreen.alt?oDegreen.alt:oDegreen.z, viewer.scene.globe.ellipsoid);
}

var oWater = fnGetOwaterById(id);//水面对象
var oWaterEntity = waterDataSource.entities.getById(id);//水面数据存储对象

//水面名称修改
oWater.name = "水面新名称";
oWaterEntity.name = = "水面新名称";

//水面描述修改
oWater.des = "水面新描述";
oWaterEntity.properties.addProperty("des", "水面新描述");

//水面位置修改
var originWaterCenter = fnCartesian2Degreen(oWater._waterCenterPos);//原水面的中心的经纬度坐标
oWater._waterCenterPos=SGlobe.Cartesian3.fromDegrees(120, 30, 10, viewer.scene.globe.ellipsoid);//新的水面中心坐标

//计算出originWaterCenter和新中心坐标(120,30,10)的经纬度高度差值
var fDiffLng=120-originWaterCenter.lng;
var fDiffLat=30-originWaterCenter.lat;
var fDiffAlt=10-originWaterCenter.alt;

//获取原水面所有点坐标
var aWaterPointArray = ChangePolygonPosition(oWaterEntity.polygon.hierarchy.getValue().positions);

//经度差值不为0
for (var i = 0; i < aWaterPointArray.length; i = i + 3) {
    aWaterPointArray[i] += fDiffLng; //height 改变后的高度值
}
//纬度差值不为0
for (var i = 1; i < aWaterPointArray.length; i = i + 3) {
    aWaterPointArray[i] += fDiffLat; //height 改变后的高度值
}
//高度差值不为0
for (var i = 2; i < aWaterPointArray.length; i = i + 3) {
    aWaterPointArray[i] += fDiffAlt; //height 改变后的高度值
}
//重新存储坐标点
oWaterEntity.polygon.hierarchy = {positions:LSGlobe.Cartesian3.fromDegreesArrayHeights(aWaterPointArray)};

//波纹宽度
oWater.waveWidth = 5;
oWaterEntity.properties.addProperty("waveWidth", 5);

//水流速度
oWater.flowSpeed = 5;
oWaterEntity.properties.addProperty("flowSpeed", 5);

//水立方向
oWater.flowDirection = 90;
oWaterEntity.properties.addProperty("flowDirection", 90);

//水面的颜色
oWater._waterColor = LSGlobe.Color.fromCssColorString("#FF0000").withAlpha(1);
oWaterEntity.properties.addProperty("_waterColor", "#FF0000");

水面显示隐藏

JavaScript

oWater.isVisible = true;//true:显示,false:隐藏

水面飞行

JavaScript

var entity = waterDataSource.entities.getById(waterid);
var entityPosition = getRealPosition(entity);//同单体化
viewer.camera.flyTo({
    destination: LSGlobe.Cartesian3.fromDegrees(entityPosition.lng, entityPosition.lat, entityPosition.alt),
    duration: 3
})

水面删除

JavaScript

waterDataSource.entities.removeById(id);
var oWater = fnGetOwaterById(treeNode.id);
if (oWater) oWater.destroy();

水面存储

水面存储是以 json 格式保存的,直接赋值给 oSubSceneData.water,然后随场景保存接口一并提交保存

JavaScript
oSubSceneData.water = waterDataSource.toGeoJson()

水面重载

水面获取接口,参数 jsonType 为 5

//localhost:8000/wish3dearth/api/scene/v1.0.0/getSceneJsonInfo

JavaScript
var oGeoJson = result.data;
//result.data前面获取的水面数据json
var promise = LSGlobe.GeoJsonDataSource.load(oGeoJson, {});
promise.then(function(dataSource) {
    //将数据再次加载到初始化存储水面的对象中
    waterDataSource = dataSource;
    //添加到球中
    viewer.dataSources.add(dataSource);

    var entities = waterDataSource.entities._entities._array;
    for (var i = 0; i < entities.length; i++) {
        var entity = entities[i];
        var WaterId = entity.id;
        var WaterName = entity.name;
        if (entity.polygon) {
            entity.polygon.outline = false;
            var wateritem = new LSGlobe.Water(viewer.scene);
            wateritem.waterPolygon = new LSGlobe.PolygonGeometry({
                polygonHierarchy: new LSGlobe.PolygonHierarchy(entity.polygon.hierarchy._value.positions),
                perPositionHeight: true
            });
            var oProperties = entity.properties.getValue();
            wateritem.id = WaterId;
            wateritem.waveWidth = oProperties.waveWidth;
            wateritem.flowDirection = oProperties.flowDirection;
            wateritem.flowSpeed = oProperties.flowSpeed;
            wateritem._waterColor = LSGlobe.Color.fromCssColorString(oProperties._waterColor).withAlpha(oProperties.alpha / 100);
            wateritem.name = WaterName;
            wateritem.des = oProperties.des;
            wateritem.alpha = oProperties.alpha;
            wateritem.isVisible = entity.show;
            viewer.scene.waterCollection._water.push(wateritem);
        }
    }
}).otherwise(function(error) {
    console.log(error);
});

模型裁剪

裁剪的保存和水面相同,都是使用 togeojson()的方式直接转换为 json 格式数据上传保存,裁剪需要额外调用裁剪接口

模型裁剪绘制

JavaScript
var cutDataSource;
//裁剪的面要素会保存到该对象中
var promise = viewer.dataSources.add(new LSGlobe.GeoJsonDataSource("cutDataSource"));
promise.then(function(dataSource) {
    cutDataSource = dataSource;
}).otherwise(function(error) {

});

//裁剪的绘制
var cutHandler = new LSGlobe.ScreenSpaceEventHandler(viewer.scene.canvas);
cutHandler.setInputAction(function(movement) {
    //获取的坐标上添加标绘点,具体的坐标获取参照坐标转换
    var Pos = scene.pickGlobe(movement.position);
},LSGlobe.ScreenSpaceEventType.LEFT_CLICK);

//根据上面获取到的点集合经过处理后达到新的数据
var oValuePoint = ChangePolygonPosition(event.positions);//同压平的坐标处理方法

包含模式

JavaScript
var oClipProperty = {
    name: "裁剪面",
    cutType: "clip"
};
var clipPolygon = new LSGlobe.PolygonGeometry({
    polygonHierarchy: new LSGlobe.PolygonHierarchy(oValuePoint),
    perPositionHeight: true
});
clipPolygon.id = sEntityGuid;//裁剪id
clipPolygon.name = oClipProperty.name;

var cutEntity = cutDataSource.entities.add({
    name: '裁剪面',
    id: sEntityGuid,
    polygon: {
        hierarchy: {
            positions: oValuePoint
        },
        material: new LSGlobe.Color(0.5, 1.0, 1.0, 0.01),
        fill: true,
        perPositionHeight: true,
        outline: false
    }
});
var entityPosition = getRealPosition(cutEntity);

var oTargetTileset = whichTileset(entityPosition.lng, entityPosition.lat)[0];
if (oTargetTileset) {
    oClipProperty.tilesetId = oTargetTileset.name.id;
    if (oTargetTileset._clipPolygons.length > 0 ) {
        alert("实景三维模型只能进行一次包含模式裁剪!");
        cutDataSource.entities.removeById(sEntityGuid);
        return;
    } else {
        oTargetTileset.cleanClipPolygons();
    }
    cutEntity.properties = oClipProperty;
    oTargetTileset.addClipPolygon(clipPolygon);
} else {
    cutDataSource.entities.removeById(sEntityGuid);
}

抠取模式

JavaScript
var oClipProperty = {
    name: "裁剪面",
    cutType: "pit"
};
var clipPolygon = new LSGlobe.PolygonGeometry({
    polygonHierarchy: new LSGlobe.PolygonHierarchy(oValuePoint),
    perPositionHeight: true
});
clipPolygon.id = sEntityGuid;//裁剪id
clipPolygon.name = oClipProperty.name;

var cutEntity = cutDataSource.entities.add({
    name: '裁剪面',
    id: sEntityGuid,
    polygon: {
        hierarchy: {
            positions: oValuePoint
        },
        material: new LSGlobe.Color(0.5, 1.0, 1.0, 0.01),
        fill: true,
        perPositionHeight: true,
        outline: false
    }
});
var entityPosition = getRealPosition(cutEntity);

var oTargetTileset = whichTileset(entityPosition.lng, entityPosition.lat)[0];
if (oTargetTileset) {
    oClipProperty.tilesetId = oTargetTileset.name.id;
    cutEntity.properties = oClipProperty;
    oTargetTileset.pitPolygons.push(clipPolygon);
    oTargetTileset.oPageLOD.updatePit();
} else {
    cutDataSource.entities.removeById(sEntityGuid);
}

裁剪编辑

主要通过操作裁剪集合数据-cutDataSource.entities,然后进行对应的裁剪类型进行操作

JavaScript
var entities = cutDataSource.entities.values;
    for (var i = 0; i < entities.length; i++) {
        var entity = entities[i];
        var oProperties=entity.properties.getValue();
        var CutId = entity.id;
        var CutName = entity.name;
        if(tilesetid&&oProperties.tilesetId!=tilesetid){
            continue;
        }
        if (entity.polygon&&entity.show) {
            entity.polygon.outline=false;
            var cutPolygon= new LSGlobe.PolygonGeometry({
                polygonHierarchy: new LSGlobe.PolygonHierarchy(entity.polygon.hierarchy._value.positions),
                perPositionHeight : true
            });
            cutPolygon.name=CutName;
            cutPolygon.id=CutId;
            var oPageLOD=getPageLODLayersById(oProperties.tilesetId);//实景三维数据获取方法
            if(oPageLOD){
                if("clip"==oProperties.cutType){
                    oPageLOD.addClipPolygon(cutPolygon);
                }else{
                    oPageLOD.pitPolygons.push(cutPolygon);
                    oPageLOD.updatePit();
                }
            }
        }
    }

裁剪显示隐藏

JavaScript
var cutEntity = cutDataSource.entities.getById(id);//获取对应裁剪entity.
cutEntity.show=true;//true:显示,false:隐藏
var oProperties = cutEntity.properties.getValue();//获取裁剪的类型
var tileset = getPageLODLayersById(oProperties.tilesetId);//实景三维数据获取方法

if(oProperties.cutType=="clicp"){
    if(cutEntity.show){
        var cutPolygon = new LSGlobe.PolygonGeometry({
            polygonHierarchy: new LSGlobe.PolygonHierarchy(cutEntity.polygon.hierarchy._value.positions),
            perPositionHeight: true
        });
        tileset.addClipPolygon(cutPolygon);
    }else{
        tileset.cleanClipPolygons();
    }
}else{
    for (var i = 0; i < tileset._pitPolygons.length; i++) {
        if (cutEntity.id == tileset._pitPolygons[i].id) {
            tileset._pitPolygons[i].show = cutEntity.show;
            tileset.updatePit();
        }
    }
}

裁剪飞行

JavaScript

var entity = cutDataSource.entities.getById(id);
var entityPosition = getRealPosition(entity);//同单体化
viewer.camera.flyTo({
    destination: LSGlobe.Cartesian3.fromDegrees(entityPosition.lng, entityPosition.lat, entityPosition.alt),
    duration: 3
})

裁剪删除

JavaScript
var cutEntity = cutDataSource.entities.getById(id);//根据裁剪id获取对应的参考entity
var oProperties = cutEntity.properties.getValue();//获取裁剪的类型
var tileset = getPageLODLayersById(oProperties.tilesetId);//实景三维数据获取方法

if(oProperties.cutType=="clicp"){
    tileset.cleanClipPolygons();
}else{
    for (var i = 0; i < tileset._pitPolygons.length; i++) {
        if (cutEntity.id == tileset._pitPolygons[i].id) {
            tileset._pitPolygons[i].show =false;
            tileset.updatePit();
        }
    }
}

cutDataSource.entities.removeById(id);

裁剪存储

裁剪存储是以 json 格式保存的,直接赋值给 oSubSceneData.clip,然后随场景保存接口一并提交保存

JavaScript
oSubSceneData.clip = cutDataSource.toGeoJson()

裁剪重载

裁剪获取接口,参数 jsonType 为 6

//localhost:8000/wish3dearth/api/scene/v1.0.0/getSceneJsonInfo

JavaScript
var oGeoJson = result.data;
//result.data前面获取的压平数据json
var promise = LSGlobe.GeoJsonDataSource.load(oGeoJson, {});
promise.then(function(dataSource) {
    //将数据再次加载到初始化存储裁剪的对象中
    cutDataSource = dataSource;
    //添加到球中
    viewer.dataSources.add(dataSource);

    var entities = cutDataSource.entities._entities._array;
    for (var i = 0; i < entities.length; i++) {
        var entity = entities[i];
        var oProperties = entity.properties.getValue();
        var CutId = entity.id;
        var CutName = entity.name;
        if (tilesetid && oProperties.tilesetId != tilesetid) {
            continue;
        }
        if (entity.polygon && entity.show) {
            entity.polygon.outline = false;
            var cutPolygon = new LSGlobe.PolygonGeometry({
                polygonHierarchy: new LSGlobe.PolygonHierarchy(entity.polygon.hierarchy._value.positions),
                perPositionHeight: true
            });
            cutPolygon.name = CutName;
            cutPolygon.id = CutId;
            var oPageLOD = getPageLODLayersById(oProperties.tilesetId);
            if (oPageLOD) {
                if ("clip" == oProperties.cutType) {
                    oPageLOD.addClipPolygon(cutPolygon);
                } else {
                    oPageLOD.pitPolygons.push(cutPolygon);
                    oPageLOD.updatePit();
                }
            }
        }
    }
}).otherwise(function(error) {
    console.log(error);
});

双屏对比

添加双屏对比

//localhost:8000/wish3dearth/api/scene/v1.0.0/pageList

获取当前用户的场景列表,把要添加的分屏场景数据加到 oSubSceneData.splitscreen.screens 中,如下代码:

JavaScript
oSubSceneData.splitscreen.screens.push(item);//item是场景的数据对象

双屏删除

JavaScript
oSubSceneData.splitscreen.screens.splice(0,1);//删除第一个副场景

双屏对比联动

双屏对比的原理:是同一个页面用两个相同的 iframe 分别加载一个预览的场景;只要在其中一个 iframe 页面中操作,对应的 camera 信息同步到另外一个 iframe 页面。

JavaScript
//在一个iframe中获取到另一个iframe的document对象
var otherIframe = parent.document.getElementById("另一个iframe的唯一标识 id").contentWindow
//camera.position,camera.direction,camera.up
//当前iframe中球的相机位置
otherIframe.jumpToViewPoint(camera.position, camera.direction, camera.up);
//为了让两个球的相机位置相同,移动一个iframe中球的相机位置时,让另一个球的相机位置同步飞到当前iframe中球的相同的相机位置即可
function jumpToViewPoint(position, direction, up) {
    viewer.camera.flyTo({
        destination: new LSGlobe.Cartesian3(position.x, position.y, position.z),
        orientation: {
            direction: new LSGlobe.Cartesian3(direction.x, direction.y, direction.z),
            up: new LSGlobe.Cartesian3(up.x, up.y, up.z)
        },
        duration: 0
    });
}
//上面的操作需要放到鼠标滑动事件中
var handler = new LSGlobe.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function(movement) {
    //在此处执行双屏对比的联动事件
},
LSGlobe.ScreenSpaceEventType.WHEEL);
handler.setInputAction(function(movement) {
    //在此处执行双屏对比的联动事件
},
LSGlobe.ScreenSpaceEventType.MOUSE_MOVE);

双屏保存

随场景保存接口一并保存

分析

光照分析

JavaScript
//是否开启光照
viewer.shadows=true;//光照分析时候一定要设置true

//光照阴影位置和当前的时间有关
//设置当前时间可以改变阴影的位置
var julianDay =computes(new Date());
//当天已经过去的时间单位s
var julianSecound=hour*60*60+minute*60+secound;//hour当前时,minute当前分,secound当前秒
viewer.clock.currentTime= new LSGlobe.JulianDate(julianDay,julianSecound);

//当前时间转换为朱莉安时间
function computes(now){
    var month = now.getUTCMonth() + 1;
    var day = now.getUTCDate();
    var year = now.getUTCFullYear()
    var y = eval(year);
    var m = eval(month);
    var d = eval(day);
    var extra = 100.0*y + m - 190002.5;
    var rjd = 367.0*y;
    rjd -= Math.floor(7.0*(y+Math.floor((m+9.0)/12.0))/4.0);
    rjd += Math.floor(275.0*m/9.0);
    rjd += d;
    rjd += 1721013.5;
    rjd -= 0.5*extra/Math.abs(extra);
    rjd += 0.5;
    return rjd;
}

可视域分析

JavaScript
//1).初始化可视域分析
var viewshed3ding = false; //用于是否正在绘制可视域分析
var viewshed3d; //当前可视域对象
var aViewshed3d = []; //保存可视域分析的数组
//初始化可视域对象
viewshed3d = new LSGlobe.Viewshed3D(viewer.scene);
//将可视域分析对象加入到可是与分析数组中
aViewshed3d.push(viewshed3d);

//2).绘制可视域分析
//初始化鼠标事件
var ViewAnalysisHandler = new LSGlobe.ScreenSpaceEventHandler(viewer.scene.canvas);
ViewAnalysisHandler.setInputAction(function(movement) {
    var cartesian = scene.pickGlobe(movement.position);
    var cartographic = LSGlobe.Cartographic.fromCartesian(cartesian);
    var currentClickLon = LSGlobe.Math.toDegrees(cartographic.longitude);
    var currentClickLat = LSGlobe.Math.toDegrees(cartographic.latitude);
    var CurrentTileSet = whichTileset(currentClickLon, currentClickLat);
    //判断点是否在模型上函数和压平获取压平对象相同
    //可视域分析点必须在模型上
    if (CurrentTileSet.length < 1) {
        //如果点没有点在模型上不在向下走
        return;
    }
    if (cartesian != undefined && !viewshed3ding) {
        viewshed3d.viewerPosition = cartesian;
        //初始添加一个点
        viewshed3ding = true;
    } else {
        viewshed3d.setPoseByTargetPoint(cartesian);
        //点击第二个点绘制结束
        viewshed3ding = false;
    }
},
LSGlobe.ScreenSpaceEventType.LEFT_CLICK);

ViewAnalysisHandler.setInputAction(function(movement) {
    if (viewshed3daction && viewshed3ding) {
        var cartesian = viewer.scene.pickGlobe(movement.endPosition);
        viewshed3d.setPoseByTargetPoint(cartesian);
    }
},
LSGlobe.ScreenSpaceEventType.MOUSE_MOVE);

//3).删除可视域分析
for (var i = 0; i < aViewshed3d.length; i++) {
    try {
        aViewshed3d[i].destroy();
    } catch(e) {}
}
aViewshed3d = [];
viewshed3ding = false;

方量分析

JavaScript
//1).初始化方量分析
var cutfill = new LSGlobe.LSCutFill(viewer);
var nodeMesh, tileset; //实景三维对象
var poinsTemp = []; //用于保存绘制的点
//分析对象
var tempDataSource;
//用于存储方量分析辅助面
var promise = viewer.dataSources.add(new LSGlobe.GeoJsonDataSource("tempDataSource"));
promise.then(function(dataSource) {
    tempDataSource = dataSource;
}).otherwise(function(error) {

});

//2).点击收集构成放量分析的面
//注意:绘制方量分析时点必须点在模型上
//初始化鼠标事件
var oCutFillHandler = new LSGlobe.ScreenSpaceEventHandler(viewer.scene.canvas);
oCutFillHandler.setInputAction(function(movement) {
    var cartesian = scene.pickGlobe(movement.position);
    poinsTemp.push(cartesian);

    var CurrentTileSet = whichTileset(currentClickLon, currentClickLat);
    //判断点是否在模型上函数和压平获取压平对象相同
    //可视域分析点必须在模型上
    if (CurrentTileSet.length < 1) {
        alert("请在模型上点击");
        //如果点没有点在模型上不在向下走
        return;
    } else {

        tempDataSource.entities.add({
            position: cartesian,
            clampToGround: true,
            point: {
                pixelSize: 3,
                color: LSGlobe.Color.YELLOW,
                perPositionHeight: false,
                disableDepthTestDistance: 1000000000 //优先级
            }
        });
        if (poinsTemp.length >= 2) {
            tempDataSource.entities.removeById("20191225");
            tempDataSource.entities.add({
                id: "20191225",
                name: 'line on the surface',
                polyline: {
                    positions: poinsTemp,
                    width: 2,
                    material: LSGlobe.Color.fromCssColorString("rgba(0,186,255,0.5)"),
                    depthFailMaterial: new LSGlobe.PolylineDashMaterialProperty({
                        color: LSGlobe.Color.fromCssColorString("rgba(0,186,255,0.5)")
                    }),
                    disableDepthTestDistance: 1000000000 //优先级
                }
            });
        }

    }

},
LSGlobe.ScreenSpaceEventType.LEFT_CLICK);

oCutFillHandler.setInputAction(function(movement) {
    //生成面
    var oValuePoint = ChangePolygonPosition(poinsTemp);
    //点集合设置为统一高度
    for (var i = 2; i < oValuePoint.length; i = i + 3) {
        oValuePoint[i] = oHeight;
    }
    tempDataSource.entities.removeAll();
    //该面是辅助方量分析结果的面,最后方量分析的高度和范围是该面显示的高度和范围
    tempDataSource.entities.add({
        name: '方量分析辅助面',
        id: new Date().getTime(),
        polygon: {
            hierarchy: LSGlobe.Cartesian3.fromDegreesArrayHeights(oValuePoint),
            material: new LSGlobe.Color(0.5, 1.0, 1.0, 0.7),
            fill: true,
            outline: true,
            outlineColor: LSGlobe.Color.YELLOW,
            perPositionHeight: true
        }
    });
},
LSGlobe.ScreenSpaceEventType.RIGHT_CLICK);

//3).开始分析
function getProgress() {
    nodeMesh = tileset.NodeMesh;
}
modelAnalysis(oHeight);
function modelAnalysis(oHeight) {
    cutfill.clear();
    cutfill.completeEvent.addEventListener(progress);
    var cartographic = LSGlobe.Cartographic.fromCartesian(poinsTemp[0]);

    if (oHeight) {
        cutfill.zFactor = height;
    } else {
        cutfill.zFactor = cartographic.height;
    }
    //分析的面对象
    var Mypolygon = new LSGlobe.PolygonGeometry({
        polygonHierarchy: new LSGlobe.PolygonHierarchy(poinsTemp),
        perPositionHeight: true
    });
    cutfill.polygon = Mypolygon;
    //采样间隔
    cutfill.sampleGap = interval;
    //执行分析
    cutfill.apply();
}

用户系统

该模块包含用户的登录、退出、获取用户信息、验证功能权限等

服务接口文档-用户相关

许可相关

该模块包含获取授权码、上传许可、获取许可信息等

服务接口文档-许可相关

团队权限管理

该模块包含对数据是否有数据预览、数据编辑、数据删除、数据权限配置等权限和是否具有场景预览、场景编辑、场景删除、场景权限配置等权,以及具有哪些菜单栏的权限比如:成员管理、团队管理等

服务接口文档-团队相关

Released under the MIT License.