4. 场景
4.1. 场景构建保存
- 场景构建
场景是用数据构建成的,场景中可以添加多种数据(目前该平台支持:osgb、obj、skp、shp、kml、tif影像、tif地形等),每种数 据也可添加多个,对于人工模型只上传一次即可在场景中添加多个相同的数据,用户可以使用自己添加的数据来构建自己想要的各种场景,除此之外还可以利用标绘 功能进行点、线、面、单体化、压平、水面、裁剪,达到预期的效果。
场景添加
进行场景构建之前需要先定义场景,由于场景的数据保存是以json的格式保存所以也可以人为的拼接一个和场景相关的json数据和定义场景关联起来,以达到场景构建时就拥有某些数据(该方法主要用于添加场景默认的底图)
保存场景的接口(既可以新增也可以更新,区别在于传参里面的sceneId数据库是否已存在,存在即更新,反之是新增)
http://localhost:1000/wish3dearth/api/scene/v1.0.0/saveScene
其中dataJson需要注意,是json对象通过JSON.stringify()方法转换而来的字符串,json对象实例代码如下:
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()得到
http://localhost:1000/wish3dearth/api/material/shp/v1.0.0/setStyle
场景基本信息获取
通过接口获取当前场景的基本信息,返回信息包含场景id、名称、描述、缩略图、默认视角等信息,详情参照一下接口。
http://localhost:1000/wish3dearth/api/scene/v1.0.0/getSceneJsonInfo
场景飞行到默认位置(相机定位接口)
从上一条获取到场景的默认视角字段,经过转换后得到视角信息, 然后利用以下方法飞行到默认位置。
//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) } });
场景删除
删除接口参照:
http://localhost:1000/wish3dearth/api/scene/v1.0.0/deleteScene
场景图层信息
获取场景图层信息接口,参数jsonType=1如下:
http://localhost:1000/wish3dearth/api/scene/v1.0.0/getSceneJsonInfo
返回参数data直接加载到场景中,方法如下:
//加载到场景 viewer.fromJSON(data); //使用上面方法数据会自动加载到球上形成一个场景
zTreec插件使用方法可以参照插件官网
data.Tree数据,树结构渲染(通过 zTree插件渲染)
//初始化树 $.fn.zTree.init($(""), {}, data.Tree);
场景中数据管理
场景中一般有多个,多种类型的数据,我们需要对这些数据进行操作管理达到构建场景的目的。
1.场景中的数据获取
//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.场景中的数据飞行
//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.场景中的数据显示隐藏
//1).实景三维数据显示隐藏 //tileset第一步获取的数据对象 tileset.show=false; //false 隐藏 true 显示 //2).人工三维数据显示隐藏 //参考实景三维数据显示隐藏 //3).矢量数据显示隐藏 //参考实景三维数据显示隐藏 //4).影像数据显示隐藏 //参考实景三维数据显示隐藏 //5).地形数据显示隐藏 //参考实景三维数据显示隐藏
4.场景中的数据删除
//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)
4.2. 场景底图
4.2.1. 加载在线影像
//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);
4.2.2. 加载lrc文件作为底图
var oLrcPath = "lrc文件路径";
var oLrc = new LSGlobe.LSLRCImageryProvider(oLrcPath);
viewer.imageryLayers.addImageryProvider(oLrc);
4.2.3. 设置图层的层级
//初始添加影像时设置层级
viewer.imageryLayers.addImageryProvider(bing, index);
//index影像图层的层级number类型,对lrp也适用
//设置某一个影像为最高层级
viewer.imageryLayers.raiseToTop(imageLayer)
//imageLayer获取的影像对象
4.2.4. 设置在线google地形(google地形为国外数据加载较慢)
var stkTerrainProviderMeshes = new LSGlobe.CesiumTerrainProvider({
url: 'http://assets02.agi.com/stk-terrain/v1/tilesets/world/tiles',
requestWaterMask: true,
requestVertexNormals: true
});
viewer.terrainLayers.addTerrainProvider(terrainLayer);
4.3. 飞行
4.3.1. 飞行路径构建
添加一条飞行路径,即向场景JSON,oSubSceneData.fly.lines数组添加路径
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" //视点的缩略图路径 });
修改、删除某条飞行路径
修改数飞行路径的名称和视点仅修改对应数组的信息,最后随场景保存接口一并提交
获取飞行路径
根据场景id获取飞行路径
http://localhost:1000/wish3dearth/api/scene/v1.0.0/getSceneJsonInfo
生成视点缩略图,并上传该图片,同时修改对应视点的缩略图路径(标注缩略图获取方法相同)
//截取canvas方形图片 var oOriginImg = $(""); 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数组
上传飞行视点的缩略图
上传接口参照http://localhost:1000/wish3dearth/api/scene/v1.0.0/uploadTempImg
4.3.2. 飞行路径的预览
初始化一条飞行路径
var cameraTrackControls = new LSGlobe.LSCameraTrackControls(viewer.scene);
向飞行路径中添加视点信息
//向飞行路径中添加单个视点 //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 }); //添加视点完成该飞行路径初始化完成
飞行路径的操作
//开始飞行路径的飞行或继续飞行路径的飞行 cameraTrackControls.play(); //暂停飞行路径的飞行,从暂停视点开始飞行 cameraTrackControls.pause(); //清除飞行路径并停止飞行路径的飞行 cameraTrackControls.clear(); //停止飞行路径的飞行,再次飞行从第一个视点飞行 cameraTrackControls.stop()
4.4. 标绘
标绘功能包含标绘点、标绘线、标绘面。这些标绘信息统一保存在一个drawDataSource对象中,保存时数据可转换为json文件,加载时获取到之前保存的json,可以统一一次将各种标绘数据加载到场景中并与保存前的显示效果一致。
为了更好的绘制体验,标绘线面的绘制可以应用现在封装好的线面绘制插件来绘制。而标注的绘制需要在事件句柄中点击绘制添加
4.4.1. 初始化标绘存储对象
var drawDataSource;
//标绘存储对象绘制的标绘要素(线或者面)会保存到该对象中
var promise = viewer.dataSources.add(new LSGlobe.GeoJsonDataSource("drawDataSource"));
promise.then(function(dataSource) {
drawDataSource = dataSource;
}).otherwise(function(error) {
});
4.4.2. 标绘绘制
4.4.2.1. 绘制点
添加至场景
//第一步新加事件句柄 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刚刚添加的标绘点对象 //标绘点自定义属性中一般需要有标绘点的图片地址信息和相机位置信息 这些信息需要添加到自定义的属性中用于再次加载时使用
缩略图信息上传
获取标绘点缩略图同飞行视点获取视点的缩略图一致。
标会点附属信息
每个标绘点都可以挂载附属信息,分为文本、图片、视频、全景,在Wish3DEarth中称其为附属信息。在场景设置中,所有标会点的附属信息,均存储在oSubSceneData.drawDetail.points中(如需要其他标绘也可以挂载在不同属性中),
//附属信息容器 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: '全景地址' }] }
附属信息-图片和视频(本地视频,非在线)上传
上传接口参照http://localhost:1000//wish3dearth/api/scene/v1.0.0/uploadTempFile
4.4.2.2. 标绘线
//获取线上点,>=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:空间线
}
});
4.4.2.3. 标绘面
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)
}
});
4.4.2.4. 标绘要素获取
//id 绘制线面时加入的唯一标识
var entity = drawDataSource.entities.getById(id)
4.4.2.5. 标绘显示隐藏
//entity获取到的标绘要素对象
entity.show=true;//true:显示,false:隐藏
4.4.2.6. 标绘飞行
//entity获取到的标绘要素对象
//空间线面的飞行(发光线等都是空间线)
viewer.flyto(entity)
//特殊线面的飞行(贴地,贴模型)
//使用单体化的飞行方式飞行
4.4.2.7. 标绘删除
//单个标绘线面删除
//id绘制时添加的唯一标识
drawDataSource.entities.removeById(id)
//删除drawDataSource对象中的所有标绘要素
drawDataSource.entities.removeAll();
4.4.3. 标绘编辑
4.4.3.1. 编辑标绘点
//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)');
//单独修改标注文字信息中的文本填充颜色
4.4.3.2. 编辑标绘线
//编辑线的特殊字段
entity.name = '面标绘名称';
//编辑线宽度
entity.polyline.width = 10;
//编辑线材质(颜色)
entity.polyline.materia = LSGlobe.Color.fromCssColorString('rgb(0,0,0)');
//编辑线的透明度
entity.polyline.materia = LSGlobe.Color.fromCssColorString('rgb(0,0,0)').withAlpha('0.5')
//线的材质
/*
1.虚实线
entity.polyline.materia = new LSGlobe.PolylineDashMaterialProperty({
color: oMaterial,
dashPattern: LSGlobe.LineType.SOLID //SOLID:实线,DASH:虚线,DOT:浮点,DASHDOT:-.-.-,DASHDOTDOT:-..-..
})
2.箭头:
entity.polyline.materia = new LSGlobe.PolylineArrowMaterialProperty(LSGlobe.Color.PURPLE)
3.边框线:material: new LSGlobe.PolylineOutlineMaterialProperty({
color: LSGlobe.Color.ORANGE,
outlineWidth: 2,
outlineColor: LSGlobe.Color.BLACK
})
4.发光线:
entity.polyline.materia = 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:空间线
4.4.3.3. 编辑标绘面
//编辑线的特殊字段
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)
4.4.4. 标绘存储
标绘的存储是以json格式保存的,直接赋值给oSubSceneData.draw,然后随场景保存接口一并提交保存
oSubSceneData.draw = drawDataSource.toGeoJson()
4.4.5. 标绘重载
标绘获取接口,参数jsonType为2
http://localhost:1000/wish3dearth/api/scene/v1.0.0/getSceneJsonInfo
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);
});
4.5. 单体化
单体化原理:本质就是贴模型地表的标绘面,在默认0.01的透明度下,当鼠标移动到该面时候,改变面的材质的透明度为1,当鼠标移出后透明度重新设置透明度为0.01,从而实现高亮效果。
4.5.1. 单体化绘制
//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)
}
});
4.5.1.1. 单体化要素获取
//id 绘制单体化时加入的唯一标识
var entity = monomerDataSource.entities.getById(id)
4.5.1.2. 单体化显示隐藏
//entity获取到的单体化对象
entity.show=true/false;
4.5.1.3. 单体化飞行
//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;
}
4.5.1.4. 单体化删除
//单个单体化删除
//id绘制时添加的唯一标识
monomerDataSource.entities.removeById(id)
//删除monomerDataSource对象中的所有单体化
monomerDataSource.entities.removeAll();
4.5.1.5. 单体化编辑
//entity获取到的单体化要素对象
//1.编辑单体化样式
//编辑单体化的特殊字段
entity.name = '单体化面';
//编辑单体化材质(颜色)
entity.polygon.materia = LSGlobe.Color.fromCssColorString('rgb(0,0,0)');
//编辑单体化的透明度
entity.polygon.materia = 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("属性");
4.5.1.6. 单体化(以及单体化类似对象)的鼠标点击获取
//初始化一个鼠标事件
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);
4.5.2. 单体化存储
单体化的存储是以json格式保存的,直接赋值给oSubSceneData.monomer,然后随场景保存接口一并提交保存
oSubSceneData.monomer = monomerDataSource.toGeoJson()
4.5.3. 单体化重载
标绘获取接口,参数jsonType为3
http://localhost:1000/wish3dearth/api/scene/v1.0.0/getSceneJsonInfo
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);
});
4.6. 压平
压平面的保存和标绘、单体化相同,都是使用togeojson()的方式直接转换为json格式数据上传保存,但是压平需要额外调用压平接口
4.6.1. 压平绘制
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 aTileset = [];
//遍历所有点存储有交集的实景三维模型
for (var i = 0; i < pos.length; i++) {
var cartographic = LSGlobe.Cartographic.fromCartesian(pos[i]);
var longitude = LSGlobe.Math.toDegrees(cartographic.longitude);
var latitude = LSGlobe.Math.toDegrees(cartographic.latitude);
var tileset = whichTileset(longitude, latitude);
if (tileset.length < 1) {
continue;
}else{
for(var j =0;j<tileset.length;j++){
if(aTileset.indexOf(tileset[j])<0){
aTileset.push(tileset[j]);
}
}
}
}
//根据辅助面中的点来获取需要压平的模型
var myPolygon = new LSGlobe.PolygonGeometry({
polygonHierarchy: new LSGlobe.PolygonHierarchy(pos),
perPositionHeight: true
});
//使用辅助面的点集合绘制一个面对象
for (var i = 0; i < aTileset.length; i++) {
aTileset[i]._flattenPolygons.push(myPolygon);
aTileset[i].updateFlatten();
}
//可以选择让辅助面是否显示
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;
}
4.6.1.1. 压平面的编辑
//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
}
});
// 清空所有压平面和辅助面
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].show) {
var aTileset = [];
var pos = aPushEntities[i].polygon.hierarchy.getValue().positions;
//遍历所有点存储有交集的实景三维模型
for (var i = 0; i < pos.length; i++) {
var cartographic = LSGlobe.Cartographic.fromCartesian(pos[i]);
var longitude = LSGlobe.Math.toDegrees(cartographic.longitude);
var latitude = LSGlobe.Math.toDegrees(cartographic.latitude);
var tileset = whichTileset(longitude, latitude);
if (tileset.length < 1) {
continue;
} else {
for (var j = 0; j < tileset.length; j++) {
if (aTileset.indexOf(tileset[j]) < 0) {
aTileset.push(tileset[j]);
}
}
}
}
//使用辅助面的点集合绘制一个面对象
var myPolygon = new LSGlobe.PolygonGeometry({
polygonHierarchy: new LSGlobe.PolygonHierarchy(pos),
perPositionHeight: true
});
for (var i = 0; i < aTileset.length; i++) {
aTileset[i]._flattenPolygons.push(myPolygon);
aTileset[i].updateFlatten();
}
}
}
//2).设置名称
entity.name = "修改后的名称";
4.6.1.2. 压平面的飞行
//压平面的飞行借助了压平辅助面
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
})
4.6.1.3. 设置显示隐藏
//对应的实景三维模型
tileset._flattenPolygons[0].show=true;//true显示,false:影藏
tileset.updateFlatten();
//对应的entity也要做对应同步
entity.show=true;//true显示,false:影藏
4.6.1.4. 压平面的删除
//删除对应的entity
pushDataSource.entities.removeById(id);
//对应的实景三维模型的对应的压平面隐藏并更新
tileset._flattenPolygons[0].show=false;
tileset.updateFlatten();
4.6.2. 压平存储
压平的存储是以json格式保存的,直接赋值给oSubSceneData.push,然后随场景保存接口一并提交保存
oSubSceneData.push = pushDataSource.toGeoJson()
4.6.3. 压平面的重载
压平获取接口,参数jsonType为4
http://localhost:1000/wish3dearth/api/scene/v1.0.0/getSceneJsonInfo
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);
});
4.7. 水面
水面的保存和压平相同,都是使用togeojson()的方式直接转换为json格式数据上传保存,水面需要额外调用水面接口,需要引用插件Water.js
<script type="text/javascript" src="Build/Plugins/Water/Water.js"></script>
4.7.1. 水面绘制
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("");//水面颜色
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 = "";
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);
4.7.1.1. 水面编辑
//获取水面对象
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("").withAlpha(1);
oWaterEntity.properties.addProperty("_waterColor", "");
4.7.1.2. 水面显示隐藏
oWater.isVisible = true;//true:显示,false:隐藏
4.7.1.3. 水面飞行
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
})
4.7.1.4. 水面删除
waterDataSource.entities.removeById(id);
var oWater = fnGetOwaterById(treeNode.id);
if (oWater) oWater.destroy();
4.7.2. 水面存储
水面存储是以json格式保存的,直接赋值给oSubSceneData.water,然后随场景保存接口一并提交保存
oSubSceneData.water = waterDataSource.toGeoJson()
4.7.3. 水面重载
水面获取接口,参数jsonType为5
http://localhost:1000/wish3dearth/api/scene/v1.0.0/getSceneJsonInfo
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);
});
4.8. 模型裁剪
裁剪的保存和水面相同,都是使用togeojson()的方式直接转换为json格式数据上传保存,裁剪需要额外调用裁剪接口
4.8.1. 模型裁剪绘制
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);//同压平的坐标处理方法
4.8.1.1. 包含模式
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);
}
4.8.1.2. 抠取模式
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);
}
4.8.1.3. 裁剪编辑
主要通过操作裁剪集合数据-cutDataSource.entities,然后进行对应的裁剪类型进行操作
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();
}
}
}
}
4.8.1.4. 裁剪显示隐藏
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();
}
}
}
4.8.1.5. 裁剪飞行
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
})
4.8.1.6. 裁剪删除
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);
4.8.2. 裁剪存储
裁剪存储是以json格式保存的,直接赋值给oSubSceneData.clip,然后随场景保存接口一并提交保存
oSubSceneData.clip = cutDataSource.toGeoJson()
4.8.3. 裁剪重载
裁剪获取接口,参数jsonType为6
http://localhost:1000/wish3dearth/api/scene/v1.0.0/getSceneJsonInfo
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);
});
4.9. 双屏对比
4.9.1. 添加双屏对比
http://localhost:1000/wish3dearth/api/scene/v1.0.0/pageList
获取当前用户的场景列表,把要添加的分屏场景数据加到oSubSceneData.splitscreen.screens中,如下代码:
oSubSceneData.splitscreen.screens.push(item);//item是场景的数据对象
4.9.2. 双屏删除
oSubSceneData.splitscreen.screens.splice(0,1);//删除第一个副场景
4.9.3. 双屏对比联动
双屏对比的原理:是同一个页面用两个相同的iframe分别加载一个预览的场景;只要在其中一个iframe页面中操作,对应的camera信息同步到另外一个iframe页面。
//在一个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);
4.9.4. 双屏保存
随场景保存接口一并保存