4. 场景
4.1. 场景构建
- 场景添加
场景是用数据构建成的,场景中可以添加多种数据(目前该平台支持的多种数据都可添加),每种数据也可添加多个,对于人工模型转换为lmz格式的只上传一次即可在场景中添加多个相同的数据,用户可以使用自己添加的数据来构建自己想要的各种场景。
场景添加
进行场景构建之前需要先定义场景,由于场景的数据保存是以json的格式保存所以也可人为的拼接一个和场景相关的json数据和定义场景关联起来,以达到场景构建时就拥有某些数据(该方法主要用于添加场景默认的底图)
添加场景的接口
http://localhost:1000/api/scene/1.0.0/add
场景数据存储json和场景关联
场景信息修改
场景的缩略图获取和视点的缩略图获取参考“素材修改”中缩略图获取截取方法
根据id获取公开场景信息接口
http://localhost:1000/api/scene/1.0.0/getPublic
根据id获取私有场景信息接口
http://localhost:1000/api/scene/1.0.0/getPrivate
场景信息修改接口
http://localhost:1000/api/scene/1.0.0/set
场景默认视角获取
http://localhost:1000/api/viewpoint/1.0.0/get/{id}
场景默认视角设置 http://localhost:1000/api/viewpoint/1.0.0/setSceneDefault
场景缩略图设置
http://localhost:1000/api/scene/1.0.0/setImg
设置场景公开私有
场景管理
场景信息列表获取
http://localhost:1000/api/scene/1.0.0/get
场景删除
场景飞行到默认位置
//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) } });
场景构建
场景构建,构建场景需要将数据添加到场景中,添加的方法产考“素材预览”中的模型加入球中的方法,数据添加完成以后即可进行场景的保存(场景保存方式是json文件)
1).将构建好的场景转换为json格式的数据用于保存 场景转换为json数据的方法
viewer.toJSON();
2).场景json介绍
{ "asset":{ "version":"1.0.0", "date":"2018-08-15T05:17:03.6659999999974389Z" //可用于保底层库版本信息和常最后一个修改时间 }, "scene":{ "properties":{ "minimumDisableDepthTestDistance":0, "shadows":false }, "imageryLayers":[ //imageryLayers保存所有影像数据的对象 { "show":true, "name":"http://localhost:8080/LSGlobe/Build/LSGlobe/Assets/Textures/GlobalBkLayer.jpg", "url":"http://localhost:8080/LSGlobe/Build/LSGlobe/Assets/Textures/GlobalBkLayer.jpg", "tileWidth":1024, "tileHeight":512, "tilingScheme":{ "type":"GeographicTilingScheme", "numberOfLevelZeroTilesX":1, "numberOfLevelZeroTilesY":1 } //球的底图示例(必须有不然只有一个蓝色的球) },{ "type":"UrlTemplateImageryProvider", "show":true, "name":"google", "url":"http://mt0.google.cn/vt/lyrs=s&hl=zh-CN&x={x}&y={y}&z={z}", "tileWidth":256, "tileHeight":256, "maximumLevel":20, "minimumLevel":0, "tilingScheme":{ "type":"WebMercatorTilingScheme", "numberOfLevelZeroTilesX":1, "numberOfLevelZeroTilesY":1 } //google影像格式数据示例 },{ "type":"LSLRCImageryProvider", "show":true, "name":"skyLandImage", "url":"http://localhost:8080/lrc/skyLandMarker.lrc", "tilingScheme":{ "type":"GeographicTilingScheme", "numberOfLevelZeroTilesX":2, "numberOfLevelZeroTilesY":1 } //lrc影像格式数据示例 },{ "type":"LRPImageryProvider", "show":true, "name":{ "guid":"eb20018a-171e-46bd-8ddb-35fe3fe25f91", "serverType":4, "jsonPath":"", "title":"suzhou", "position":"120,30,0", "description":"", "dataType":"lrp", }, "url":"http://10.16.30.12:8080/TX_DataManager", "lrpName":"lrpdata/eb20018a-171e-46bd-8ddb-35fe3fe25f91/data.lrp", "tileWidth":"256", "tileHeight":"256", "maximumLevel":"17", "minimumLevel":"1", "tilingScheme":{ "type":"GeographicTilingScheme", "numberOfLevelZeroTilesX":2, "numberOfLevelZeroTilesY":1 } //lrp影像格式数据示例 } ], "terrainLayers":[ //terrainLayers保存所有地形数据的对象 { "type":"LRPTerrainProvider", "show":true, "name":{ "guid":"e4f05ecf-9133-ef41-ea45-e0b4bc763f85", "serverType":5, "jsonPath":"", "title":"dixing-lrp", "position":"120,30,0", "description":"", "dataType":"lrp" }, "url":"http://localhost:8080/TX_DataManager", "lrpName":"lrpdata/e4f05ecf-9133-ef41-ea45-e0b4bc763f85/data.lrp" //lrp地形格式数据示例 } ], "layers":[ //layers保存所有人工模型数据的对象 { "type":"modelLOD", "name":{ "guid":"f8adcd2a-5133-ef43-c892-2b2b512667f7", "serverType":2, "jsonPath":"", "title":"fbx-small", "position":"120,30,0", "description":"", "dataType":"fbx" }, "url":"http://localhost:8080/TX_DataManager/data/ffec62ef-daed-40fe-a047-4b97ca705ce5/slf.lmz", "position":{ "x":109.99999999999986, "y":35.0037953410724, "z":10 }, "rotate":{ "x":0, "y":0, "z":0 }, "scale":{ "x":"1", "y":"1", "z":"1" }, "shadows":1, "show":true //lmz格式数据示例 },{ "name":{ "guid":"c5ea3f5b-8321-479c-ae8b-210523f68c67", "serverType":2, "jsonPath":"c5ea3f5b-8321-479c-ae8b-210523f68c67/Data/data.json", "title":"leshou", "position":"120,30,0", "description":"", "dataType":"skp" }, "type":"Cesium3DTileset", "url":"http://localhost:8080/TX_DataManager/data/c5ea3f5b-8321-479c-ae8b-210523f68c67/Data/data.json", "maximumScreenSpaceError":0, "shadows":1, "show":true //3DTiles格式数据示例 } ], "pageLODLayers":[ //pageLODLayers保存所有实景三维数据的对象 { "name":{ "guid":"d2a27e43-8133-ef41-ea44-a4d69ea8cada", "serverType":1, "jsonPath":"", "title":"data-xiao", "position":"120,30,0", "description":"", "dataType":"osgb" }, "type":"pageLOD", "url":"http://localhost:8080/TX_DataManager/data/d2a27e43-8133-ef41-ea44-a4d69ea8cada/data/model.json?1534310091372", "shadows":1, "show":true //osgb格式数据示例 } ], "datasources":[ //datasources保存所有矢量数据的对象 { "name":{ "guid":"ce05ffa8-e133-ef41-ea44-5c8a13bd284c", "serverType":3, "jsonPath":"", "title":"company_bouns", "position":"120,30,0", "description":"", "dataType":"kml" }, "show":true, "type":"kmlDataSource", "sourceUri":"http://localhost:8080/TX_DataManager/data/ce05ffa8-e133-ef41-ea44-5c8a13bd284c/data.kml", "clampToGround":false //kml格式数据示例 },{ "name":{ "guid":"a71da44b-3e5f-40f8-b2e5-c94604b95b65", "serverType":3, "jsonPath":"", "title":"shptest", "position":"120,30,0", "description":"", "dataType":"shp", }, "show":true, "type":"GeoJsonDataSource", "sourceUri":"http://10.16.30.12:8080/TX_DataManager/data/a71da44b-3e5f-40f8-b2e5-c94604b95b65/data.geojson", "attachPolygon":true, "clampToGround":true //shp格式数据示例 } ] } } //json数据中的name值是数据对应的基本新信息不可或缺,如果需要自定义添加字段也可以添加到name属性中 name属性值的意义 guid //数据的唯一标识 serverType //数据的类型实景为1;人工为2;矢量为3;影像为4;地形为5 jsonPath //空值为lmz格式人模型工,有值为3dtiles格式人工模型 title //数据的名称 position //数据的位置 description //数据描述 dataType //源数据类型
3).json保存接口
http://localhost:1000/api/scene/1.0.0/upload
4).json数据保存的数据信息不可改变,为防止更换ip或网站以后json数据不能正常读取,可将数地址网站或ip部分在保存时替换为某个特殊字符串,前台添加时再统一替换回当前的ip或网址比如将http://10.16.30.12:8080/替换为[rootPath]
5).前台加载json文件
加载场景接口
http://localhost:1000/api/scene/1.0.0/getSceneJson
//result.data 上面借口返回的内容 viewer.fromJSON(result.data); //使用上面方法数据会自动加载到球上形成一个场景
6.如果json中的路径替换为“[rootPath]”保存后再次加载前,前台对json处理,再替换回来当前的ip或网址,函数如下
function fnChangeResult(result) { result.scene.datasources = fnChangeSceneJson(result.scene.datasources, "datasources"); result.scene.imageryLayers = fnChangeSceneJson(result.scene.imageryLayers, "imageryLayers"); result.scene.layers = fnChangeSceneJson(result.scene.layers, "layers"); result.scene.pageLODLayers = fnChangeSceneJson(result.scene.pageLODLayers, "pageLODlayers"); result.scene.terrainLayers = fnChangeSceneJson(result.scene.terrainLayers, "terrainLayers"); return result; } function fnChangeSceneJson(oSceneData, type) { for (var i = 0; i < oSceneData.length; i++) { if (type == "datasources") { if(oSceneData[i].sourceUri){ oSceneData[i].sourceUri = oSceneData[i].sourceUri.replace("[ROOTPATH]", ""); } if (oSceneData[i].name && typeof(oSceneData[i].name) == "string") { oSceneData[i].name = oSceneData[i].name.replace("[ROOTPATH]", "当前的ip或网址"); } } else if (type == "imageryLayers") { if (i == 0) { oSceneData[i].name = oSceneData[i].name.replace("[ROOTPATH]","当前的ip或网址"); } if(oSceneData[i].imageUrlTemplate){ oSceneData[i].imageUrlTemplate = oSceneData[i].imageUrlTemplate.replace("[ROOTPATH]", "当前的ip或网址"); } oSceneData[i].url = oSceneData[i].url.replace("[ROOTPATH]", "当前的ip或网址"); } else if (type == "layers") { oSceneData[i].url = oSceneData[i].url.replace("[ROOTPATH]", "当前的ip或网址"); } else if (type == "pageLODlayers") { oSceneData[i].url = oSceneData[i].url.replace("[ROOTPATH]","当前的ip或网址"); } else if (type == "terrainLayers") { oSceneData[i].url = oSceneData[i].url.replace("[ROOTPATH]","当前的ip或网址"); if(oSceneData[i].tileUrlTemplate){ oSceneData[i].tileUrlTemplate=oSceneData[i].tileUrlTemplate.replace("[ROOTPATH]", "当前的ip或网址"); } if(oSceneData[i].metadataUrl){ oSceneData[i].metadataUrl=oSceneData[i].metadataUrl.replace("[ROOTPATH]", "当前的ip或网址"); } } } return oSceneData; }
7.替换完成后再执行viewer.fromJSON(result)将数据加载到球上,result处理后的json数据
8.球的加载需要获取许可的信息 具体的获取接口
http://localhost:1000/api/license/1.0.0/getLicenseConf
返回信息是许可路径和许可码的拼接字符串用#分个开 许可路径和许可码用与初始化球
9.初始化球的代码
viewer = new LSGlobe.Viewer('cesiumContainer', { baseLayerPicker: false, sceneModePicker: false, fullscreenButton:false, guid:"许可码",//许可接口获取内容#前面部分 "licenseUrl":"许可路径"//许可接口获取内容#后面部分 });
场景中数据管理
场景中一般有多个,多种类型的数据,我们需要对这些数据进行操作管理达到构建场景的目的。
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第一步获取的数据对象 tilese.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. 场景底图
场景地图加载
加载在线影像
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_c/wmts?service=WMTS&version=1.0.0&request=GetTile&tilematrix={TileMatrix}&layer=img&style={style}&tilerow={TileRow}&tilecol={TileCol}&tilematrixset={TileMatrixSet}&format=tiles', layer: 'img', style: 'default', format: 'tiles', tileMatrixSetID: 'c', subdomains: ['t0', 't1', 't2', 't3', 't4', 't5', 't6', 't7'], maximumLevel: 18, tilingScheme: new LSGlobe.GeographicTilingScheme(), tileMatrixLabels: ['1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19'] }); viewer.imageryLayers.addImageryProvider(tianditu); 3).bingmap var bing = new LSGlobe.BingMapsImageryProvider({ url: 'https://dev.virtualearth.net', key: 'Ak1xFbfMYLAAsWU7cZMRyvDHY13HFN1PESWP98WJLoK49OQDb8HSeUjBV3MpC5Yf', mapStyle: LSGlobe.BingMapsStyle.AERIAL }); viewer.imageryLayers.addImageryProvider(bing);
加载lrc文件作为底图
var oLrcPath="lrc文件路径"; var oLrc=new LSGlobe.LSLRCImageryProvider(oLrcPath); viewer.imageryLayers.addImageryProvider(oLrc);
设置图层的层级
初始添加影像时设置层级 viewer.imageryLayers.addImageryProvider(bing,index); //index影像图层的层级number类型,对lrp也适用 //设置某一个影像为最高层级 viewer.imageryLayers.raiseToTop(imageLayer) imageLayer获取的影像对象
设置在线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. 飞行
- 飞行路径构建
添加一条飞行路径
添加飞行路径的接口
修改某条飞行路径
修改数飞行路径的名称和视点id集合 视点id集合是按照顺序获取飞行路径对应视点的重要参数 该参数在某条飞行路径添加视点删除视点时都需要同步更新
获取飞行路径
根据飞行路径的GUID查询其对应的视点列表
http://localhost:1000/api/flyline/1.0.0/getBySid/{sId}
sId 飞行路径唯一标识
根据场景GUID获取所有飞行路径
http://localhost:1000/api/viewpoint/1.0.0/getByFlyLine/{flId}
flId 飞行路径唯一
删除某条飞行路径
删除一条飞行路径接口
飞行路径与视点绑定
在飞行路径中的添加一个视点
飞行路径和视点进行绑定接口
http://localhost:1000/api/viewpoint/1.0.0/add
同步添加视点的图片接口
http://localhost:1000/api/viewpoint/1.0.0/upload
截取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"); }); 注意:每添加一个飞行视点或者删除一个视点都需要更新一下对应该条飞行路径的视点集合
修改飞行路径中的某个视点
修改飞行路径单个视点位置的坐标
http://localhost:1000/api/viewpoint/1.0.0/update
修改飞行路径的单个视点位置信息(名称和时间间隔)
删除飞行路径中的某个视点
删除单个视点
http://host:8080/api/viewpoint/1.0.0/del
注意:每添加一个飞行视点或者删除一个视点都需要更新一下对应该条飞行路径的视点集合
飞行路径的预览
初始化一条飞行路径
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();
4.4. 标绘
标绘功能包含标绘点、标绘线、标绘面。这些标绘信息统一保存在一个drawDataSource对象中,保存时数据可转换为json文件,加载时获取到之前保存的json,可以统一一次将各种标绘数据加载到场景中并与保存前的显示效果一致。
标绘绘制
为了更好的绘制体验,标绘线面的绘制可以应用现在封装好的线面绘制插件来绘制。而标注的绘制需要在事件句柄中点击绘制添加
1.初始化标绘存储对象
var drawDataSource; //标绘存储对象绘制的标绘要素(线或者面)会保存到该对象中 var promise = viewer.dataSources.add(new LSGlobe.GeoJsonDataSource("drawDataSource")); promise.then(function(dataSource) { drawDataSource = dataSource; }).otherwise(function(error){ });
2.标绘绘制
1).绘制标绘点
//第一步新加事件句柄 var handler = new LSGlobe.ScreenSpaceEventHandler(viewer.scene.canvas); handler.setInputAction(function (movement) { //获取的坐标上添加标绘点,具体的坐标获取参照坐标转换 }, LSGlobe.ScreenSpaceEventType.LEFT_CLICK); //第二部将标注添加到球上 //drawDataSource 保存标绘集合的对象,标绘初始化定义的 var NewPoint=drawDataSource.add({ //标注的坐标 x,y,z 经度纬度和高度的值 position:new LSGlobe.Cartesian3(x,y,z), label:{ text : name, //标注文字描述 font :FontSize+"px "+FontName, //"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/false //标绘点对象的显示隐藏属性 }); NewPoint.properties.addProperty(des,description); //使用该方法加入单个自定义属性 des自定义属性名 description自定义属性值 //NewPoint刚刚添加的标绘点对象 NewPoint.properties=new LSGlobe.PropertyBag({ des:description }); //使用该方法加入多个自定义属性 des自定义属性名 description自定义属性值 //NewPoint刚刚添加的标绘点对象 //标绘点自定义属性中一般需要有标绘点的图片地址信息和相机位置信息 这些信息需要添加到自定义的属性中用于再次加载时使用
缩略图信息上传
http://localhost:1000/api/viewpoint/1.0.0/update
获取标注视点的canvas图片参照飞行路径中方形截图的获取方法
每一个生成的标注信息都必须至少有一个tab页,在添加完标注以后为该标注添加一个文字的tab页
标注的tab页信息
tab页分为4种文、图片、视频、全景
添加一个tab页(图片,视频,全景) http://localhost:1000/api/marker/1.0.0/addTabMedia
添加一个tab页(文本) http://localhost:1000/api/marker/1.0.0/addTabTxt
修改一个tab页(图片,视频,全景) http://localhost:1000/api/marker/1.0.0/updateTabMedia
修改一个tab页(文本) http://localhost:1000/api/marker/1.0.0/updateTabTxt
删除一个tab页
http://localhost:1000/api/marker/1.0.0/delTab
添加tab图片页中的一张图片 http://localhost:1000/api/marker/1.0.0/uploadTabImg
添加tab页中的一个视频文件 http://localhost:1000/api/server/1.0.0/uploadVideo
根据标注id获取该标注的所有tab信息 http://localhost:1000/api/marker/1.0.0/getTab
2).绘制标绘线
viewer.geometryEditer.viewModel.onCreatedEvent.addEventListener(function (event) { //绘制插件绘制完成后使用返回的点集合来绘制标绘要素 //使用返回的点来绘制空间线(普通线) //drawDataSource保存线面要素的对象 drawDataSource.entities.add({ //特殊字段该字段会保存下来,可以是字符串也可以是个对象 name: "标绘线", //线的唯一标识会存储下来,再次加载也不改变,用于查找 id:sEntityGuid, polyline: { //线点的集合 positions: event.position, //线宽 width:2, //线的材质 material:LSGlobe.Color.fromCssColorString("rgb(0,186,255)"), //线被遮挡的部分以虚线来显示 depthFailMaterial: new LSGlobe.PolylineDashMaterialProperty({ color:LSGlobe.Color.fromCssColorString("rgba(0,186,255,0.5)") }) } }); //使用返回的点来绘制空间线(虚线) drawDataSource.entities.add({ name: '虚线', id:sEntityGuid, polyline: { positions: event.positions, width: 4, //线的材质,生成虚线的主要属性 material: new LSGlobe.PolylineDashMaterialProperty({ color: LSGlobe.Color.CYAN }) } }); //使用返回的点来绘制空间线(带箭头线) drawDataSource.entities.add({ name: '带箭头线', id:sEntityGuid, polyline: { positions: event.positions, width: 30, followSurface: false, //线的材质,生成虚线的主要属性 material: new LSGlobe.PolylineArrowMaterialProperty(LSGlobe.Color.PURPLE) } }); //使用返回的点来绘制空间线(边框线) drawDataSource.entities.add({ name: '边框线', id:sEntityGuid, polyline: { positions: event.positions, width: 20.0, //线的材质,生成虚线的主要属性 material: new LSGlobe.PolylineOutlineMaterialProperty({ color: LSGlobe.Color.ORANGE, outlineWidth: 2, outlineColor: LSGlobe.Color.BLACK }) } }); //使用返回的点来绘制空间线(发光线) drawDataSource.entities.add({ name: '发光线', id:sEntityGuid, polyline: { positions: event.positions, width: 10, //线的材质,生成虚线的主要属性 material: new LSGlobe.PolylineGlowMaterialProperty({ glowPower: 0.2, color: LSGlobe.Color.BLUE }) } }); //使用返回的点来绘制特殊面 //drawDataSource保存线面要素的对象 drawDataSource.entities.add({ //特殊字段该字段会保存下来,可以是字符串也可以是个对象 name: "标绘线", //线的唯一标识会存储下来,再次加载也不改变,用于查找 id:sEntityGuid, corridor: { //线点的集合 positions: event.positions, //线宽 width: 5.0/100, cornerType: LSGlobe.CornerType.ROUNDED, //线的材质 material: LSGlobe.Color.fromCssColorString("rgb(0,186,255)"), outline: true, //线的类型 //LSGlobe.ClassificationType.BOTH 即可贴地又可贴模型 //LSGlobe.ClassificationType.TERRAIN 仅贴地 //LSGlobe.ClassificationType.CESIUM_3D_TILE 仅贴模型 classificationType: LSGlobe.ClassificationType.BOTH } }); });
3).绘制标绘面
viewer.geometryEditer.viewModel.onCreatedEvent.addEventListener(function (event){ //绘制插件绘制完成后使用返回的点集合来绘制标绘要素 //使用返回的点来绘制空间面(普通面) //drawDataSource保存线面要素的对象 drawDataSource.entities.add({ //特殊字段该字段会保存下来,可以是字符串也可以是个对象 name: '标绘面', //面的唯一标识会存储下来,再次加载也不改变,用于查找 id:id, clampToGround : false, attachPolygon:true, 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)"), //面的外边框的宽度 outlineWidth:2, perPositionHeight:true } }); //使用返回的点来绘制特殊面 //drawDataSource保存线面要素的对象 drawDataSource.entities.add({ //特殊字段该字段会保存下来,可以是字符串也可以是个对象 name:'标绘面', //面的唯一标识会存储下来,再次加载也不改变,用于查找 id:id, polygon: { hierarchy: { //面的点集合 positions: event.positions, }, //面的材质 material: LSGlobe.Color.fromCssColorString("rgb(0,186,255)"), //是否填充面 fill: true, //面的类型 //LSGlobe.ClassificationType.BOTH 即可贴地又可贴模型 //LSGlobe.ClassificationType.TERRAIN 仅贴地 //LSGlobe.ClassificationType.CESIUM_3D_TILE 仅贴模型 classificationType: LSGlobe.ClassificationType.BOTH } }); });
- 标绘要素获取
//id 绘制线面时加入的唯一标识 var entities = drawDataSource.entities.getById(id)
- 标绘显示隐藏
//entities获取到的标绘要素对象 entities.show=true/false;
标绘飞行
//entities获取到的标绘要素对象 //空间线面的飞行(发光线等都是空间线) viewer.flyto(entities) //特殊线面的飞行(贴地,贴模型) //使用单体化的飞行方式飞行
标绘删除
//单个标绘线面删除 //id绘制时添加的唯一标识 drawDataSource保存线面要素集合的对象 drawDataSource.entities.removeById(id) //删除drawDataSource对象中的所有标绘要素 drawDataSource.entities.removeAll();
- 标绘编辑
//entities获取到的标绘要素对象 1.编辑标绘点 //markid是标注添加时的唯一标识 entities.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), }); //修改标注图标信息 entities.label=new LSGlobe.LabelGraphics({ text : objEntity.name, //修改后的文字信息 font : (parseInt(objEntity.FontSize)*2)+"px "+objEntity.FontName, //"32px 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 }); //修改标注文字信息 entities.position=new LSGlobe.Cartesian3.fromDegrees(position.x,position.y,position.z); //修改标注位置信息 entities.label.text = new LSGlobe.ConstantProperty(objEntity.name); //单独修改标注文字信息中的文本 entities.label.fillColor=LSGlobe.Color.fromCssColorString('rgb(255,255,255)'); //单独修改标注文字信息中的文本填充颜色 2.编辑标绘线 1).编辑空间线的属性 //编辑线的特殊字段 entities.name = '面标绘名称'; //编辑线宽度 entities.polyline.width=10; //编辑线材质(颜色) entities.polyline.materia= LSGlobe.Color.fromCssColorString('rgb(0,0,0)'); //编辑线的透明度 entities.polyline.materia= LSGlobe.Color.fromCssColorString('rgb(0,0,0)').withAlpha('0.5') //编辑线的遮挡部分虚线属性 entities.polyline.depthFailMaterial = new LSGlobe.PolylineDashMaterialProperty({ color: LSGlobe.Color.fromCssColorString('rgb(0,0,0)').withAlpha('0.5') }); 2).编辑特殊线的属性 //编辑线的特殊字段 entities.name= '面标绘名称'; //编辑线宽度 entities._corridor.width=10; //编辑线材质(颜色) entities._corridor.materia= LSGlobe.Color.fromCssColorString('rgb(0,0,0)'); //编辑线的透明度 entities._corridor.materia= LSGlobe.Color.fromCssColorString('rgb(0,0,0)').withAlpha('0.5'); 3.编辑标绘线 //编辑面的特殊字段 entities.name= '面标绘名称'; //编辑面的材质 entities.polygon.material=LSGlobe.Color.fromCssColorString('rgb(0,0,0)'); //编辑面的透明度 entitie.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');
标绘存储
标绘的存储是以json格式保存的
1).将标绘对象转换为json数据
drawDataSource.toGeoJson()
2).转换为标绘对象的数据通过保存接口保存到后台 保存标绘接口 http://localhost:1000/api/attach/1.0.0/upload
标绘重载
标绘获取接口
http://localhost:1000/api/attach/1.0.0/getDraw
//sceneid标绘对应场景的唯一标识 var geojsonUrl = result.data; //result.data前面获取的标绘数据json var promise =LSGlobe.GeoJsonDataSource.load(geojsonUrl, {}); promise.then(function(dataSource){ //将数据再次加载到初始化存储标绘要素的对象中 drawDataSource = dataSource; //添加到球中 viewer.dataSources.add(dataSource); }).otherwise(function(error) { console.log(error); }); //注意:为了防止标绘对象的多次重复加载需要判断viewer.dataSources中是否有路径为geojsonUrl的对象,如果有直接将该对象赋值给drawDataSource即可
4.5. 单体化
单体化的绘制需要用到绘制插件插件的应用参考标绘绘制时的插件应用
单体化绘制
1).初始化单体化存储对象 var attachPolygonDataSource; //单体化存储对象,绘制的单体化要素会保存到该对象中 var promise = viewer.dataSources.add(new LSGlobe.GeoJsonDataSource("attachPolygonDataSource")); promise.then(function(dataSource) { attachPolygonDataSource= dataSource; }).otherwise(function(error){ }); 2).单体化绘制 viewer.geometryEditer.viewModel.defaultSurfaceOptions.classificationType = LSGlobe.ClassificationType.CESIUM_3D_TILE; //单体化绘制时必须是贴模型的的该设置不能去掉 viewer.geometryEditer.viewModel.setAction(EditAction.CREATE_POLYGON); viewer.geometryEditer.viewModel.onCreatedEvent.removeAllEventListener(); viewer.geometryEditer.viewModel.onCreatedEvent.addEventListener(function(event){ //根据返回的点来生成单体化面 //添加单体化面前需要将返回点中的高度值去掉 var _pointArray=[]; for(var i=0;i<event.positions.length-2;i=i+3){ _pointArray.push(oValuePoint[i]); _pointArray.push(oValuePoint[i+1]); } //绘制单体化 attachPolygonDataSource.entities.add({ name: '单体化面', //单体化的唯一标识 id:id, attachPolygon:true, polygon: { hierarchy: { //单体化的点集合 positions : _pointArray }, //单体化的材质 material:new LSGlobe.Color(0.5,1.0,1.0,0.7), //单体化面的材质是否填充 fill: true, outline: false, outlineColor: LSGlobe.Color.YELLOW } }); });
- 单体化要素获取
//id 绘制单体化时加入的唯一标识 var entities = attachPolygonDataSource.entities.getById(id)
- 单体化显示隐藏
//entities获取到的单体化对象 entities.show=true/false;
单体化飞行
//entities获取到的单体化对象 //单体化飞行(贴地,贴模型) var entity = attachPolygonDataSource.entities.getById(singleId); 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; }
单体化删除
//单个单体化删除 //id绘制时添加的唯一标识 attachPolygonDataSource保存单体化集合的对象 attachPolygonDataSource.entities.removeById(id) //删除attachPolygonDataSource对象中的所有单体化 attachPolygonDataSource.entities.removeAll();
单体化编辑
//entities获取到的单体化要素对象 1.编辑单体化 //编辑单体化的特殊字段 entities.name = '单体化面'; //编辑单体化材质(颜色) entities.polygon.materia= LSGlobe.Color.fromCssColorString('rgb(0,0,0)'); //编辑单体化的透明度 entities.polygon.materia= LSGlobe.Color.fromCssColorString('rgb(0,0,0)').withAlpha('0.5') 2.编辑单体化的属性属性值 1).获取单体化的属性属性值 entities.properties //单体化所有的属性和属性值(自定义的属性属性值和本身具有的属性值)都保存在该对象里 //获取属性和属性值展示出来 var entityProperties = {}; for (var index = 0; index < entities.properties.propertyNames.length;index++){ var propertie = entities.properties.propertyNames[index]; var value = entities.properties[propertie]._value; entityProperties[propertie] = value; //当前单体化所有属性的集合 var isSelfValue=["marker-color","marker-size","title","fill","fill-opacity","stroke-opacity","stroke","stroke-width"]; //单体化自带属性集合,在属性展示的时候不需要展示出来 if(isSelfValue.indexOf(propertie)==-1){ //只展示自定义的属性和属性值 } } 2).设置单体化的属性属性值 //添加属性属性值 entityProperties["属性"]="属性值"; entityProperties当前单体化所有属性的集合; entities.properties = entityProperties; //删除属性属性值 delete entityProperties["属性"]; entityProperties当前单体化所有属性的集合; entities.properties = entityProperties; 3).单体化属性值得展示 //将第一步中获取的entityProperties中的属性名/属性值展示出来
- 单体化(以及单体化类似对象)的鼠标点击获取
//初始化一个鼠标事件 var handlerMonomer = new LSGlobe.ScreenSpaceEventHandler(viewer.scene.canvas); handlerMonomer.setInputAction(function (movement) { var posit = scene.pick(movement.startPosition); if (LSGlobe.defined(posit)){ //如果posit值存在说明鼠标点击的地方有内容 if(!!posit.id){ //如果posit.id存在,那么其就是当前选中的内容 //(该内容可以是标注,标绘,单体化,矢量数据中的要素)需要判断该数据是什么类型需要根据该对象中的特殊字段来判断 } } }, LSGlobe.ScreenSpaceEventType.LEFT_CLICK);
单体化的存储
单体化的存储是以json格式保存的
1).将单体化对象转换为json数据
attachPolygonDataSource.toGeoJson()
2).转换为单体化对象的数据通过保存接口保存到后台 保存单体化接口 http://localhost:1000/api/attach/1.0.0/upload
单体化重载
单体化加载获取接口
http://localhost:1000/api/attach/1.0.0/getAttach
var geojsonUrl = result.data; //result.data上面借口获取的数据 var promise =LSGlobe.GeoJsonDataSource.load(geojsonUrl, {}); promise.then(function(dataSource){ //将数据再次加载到初始化存储单体化要素的对象中 attachPolygonDataSource = dataSource; //添加到球中 viewer.dataSources.add(dataSource); }).otherwise(function(error) { console.log(error); }); 注意:为了防止单体化对象的多次重复加载需要判断viewer.dataSources中是否有路径为geojsonUrl的对象,如果有直接将该对象赋值给attachPolygonDataSource即可
4.6. 双屏对比
添加双屏对比
将其他的场景和该场景关联起来
双屏对比管理
删除与本场景关联的某个场景
http://localhost:1000/api/contrasts/1.0.0/del
查询与本场景关联的所有场景
双屏对比联动
双屏对比的原理:是同一个页面引用两个相同的iframe页面,每个页面加载一个预览的场景;想要双屏联动,必须在一个iframe进行操作时,另一个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);
4.7. 压平
压平面的保存和标绘单体化不同不能使用togeojson()的方式直接转换为json文件,所以压平的json文件是自己定义的
压平绘制
1).先初始化一个文件保存压平面的数据(名称和点集合) var oFlatPosArray={}; 2).初始化一个保存压平面的对象 //压平面无法飞行需要保存一个和压平面同步的空间面,用于飞行 var pressurePolygonDataSource; //单体化存储对象,绘制的单体化要素会保存到该对象中 var promise = viewer.dataSources.add(new LSGlobe.GeoJsonDataSource("pressurePolygonDataSource")); promise.then(function(dataSource) { pressurePolygonDataSource= dataSource; }).otherwise(function(error){ }); 3).压平面的绘制 viewer.geometryEditer.viewModel.setAction(EditAction.CREATE_POLYGON); viewer.geometryEditer.viewModel.onCreatedEvent.removeAllEventListener(); viewer.geometryEditer.viewModel.onCreatedEvent.addEventListener(function (event) { //使用绘制结束后的数据来进行压平面的绘制 //返回的event.maxHeight和event.minHeight分别是绘制的所有点中高度的最高值和最低值 var oHeight=((event.maxHeight*1+event.minHeight*1)/2).toFixed(2); 该值作为压平面的初始高度来压平模型 //返回坐标集合做变换 var oValuePoint = ChangePolygonPosition(event.positions); //点集合设置为统一高度 for (var i = 2; i < oValuePoint.length; i = i + 3) { oValuePoint[i] = oHeight; } //该面是辅助设置压平面的面,最后压平的高度和范围是该面显示的高度和范围 pressurePolygonDataSource.entities.add({ name: '压平面', id: id+"-common", 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 } }); oFlatPosArray[id]={}; oFlatPosArray[id].name='压平面'; oFlatPosArray[id].positions=oValuePoint; oFlatPosArray[id].show=true; //将压平面的信息保存到压平面json文件中 }) 坐标转换函数 function ChangePolygonPosition(oPositions) { var oValuePoint = []; 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(cartographic.height); } return oValuePoint; }; 4).模型的压平 //id+"-common"为辅助压平面的唯一标识 var entity= pressurePolygonDataSource.entities.getById(id+"-common"); var pos = entity.polygon.hierarchy._value.positions; if (!pos) { pos = entity.polygon.hierarchy._value; } //获取该压平面的辅助面中的坐标值 var mtileset = undefined; //定义一个存放模型的变量 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); mtileset = whichTileset(longitude,latitude); if (mtileset.length < 1) { break; } } //根据辅助面中的点来获取需要压平的模型 var myPolygon = new LSGlobe.PolygonGeometry({ polygonHierarchy: new LSGlobe.PolygonHierarchy(pos), perPositionHeight: true }); //使用辅助面的点集合绘制一个面对象 for (var i = 0; i < mtileset.length; i++) { mtileset[i]._flattenPolygon.push(myPolygon); mtileset[i]._needUpateFlatten = true; } //将面对象添加到模型上进行压平,压平效果可以看到 entity.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; }
压平面的修改
1).设置高度 var entity = pressurePolygonDataSource.entities.getById(id+"-common"); //获取压平辅助面 var aFlatArray = oFlatPosArray[id]; for (var i = 2; i < aFlatArray.positions.length; i = i + 3) { aFlatArray[i] = height; //height 改变后的高度值 } //此时oFlatPosArray中的position值已经发生了改变 pressurePolygonDataSource.entities.remove(entity); //移除压平辅助面 pressurePolygonDataSource.entities.add({ name: "压平面", id: id+"-common", polygon: { hierarchy: LSGlobe.Cartesian3.fromDegreesArrayHeights(aFlatArray), material: new LSGlobe.Color(0.5, 1.0, 1.0, 0.7), fill: true, outline: true, 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){ } } pressurePolygonDataSource.entities.removeAll(); //循环加载所有压平面和辅助面 for (var i in oFlatPosArray) { var pos = oFlatPosArray[i].positions; var mtileset = undefined; mtileset = whichTileset(pos[0], pos[1]); //加载所有辅助面即使压平面隐藏也可飞到该位置 pressurePolygonDataSource.entities.add({ name: '压平面', id: i+"-common", clampToGround : true, attachPolygon : true, polygon: { hierarchy: LSGlobe.Cartesian3.fromDegreesArrayHeights(pos), material: new LSGlobe.Color(0.5, 1.0, 1.0, 0.7), fill: true, //显示填充 outline: false, outlineColor: LSGlobe.Color.YELLOW } }); var entity= pressurePolygonDataSource.entities.getById(id+"-common").show=false; if (mtileset.length < 1 || pos.show==false) { // 如果是处于隐藏状态和面没有在模型上的压平面不再绘制 break; } var myPolygon = new LSGlobe.PolygonGeometry({ polygonHierarchy: new LSGlobe.PolygonHierarchy(LSGlobe.Cartesian3.fromDegreesArrayHeights(pos)), perPositionHeight: true }); for (var j = 0; j < mtileset.length; j++) { mtileset[j]._flattenPolygon.push(myPolygon); mtileset[j]._needUpateFlatten = true; } } 2).设置名称 oFlatPosArray[id].name="修改后的名称";
压平面的飞行
//压平面的飞行借助了压平辅助面 var entity= pressurePolygonDataSource.entities.getById(id+"-common"); viewer.flyTo(entity);
- 设置显示隐藏
//第一步更新数据的显示隐藏数据 oFlatPosArray[id].show=false/true; //第二步删除所有压平面(参考压平高度修改) //第三步只加载oFlatPosArray[id].show=true的压平面
- 压平面的删除
// 第一步删除数据中保存的压平面信息 delete oFlatPosArray[id]; //第二步删除所有压平面(参考压平高度修改) //第三步只加载oFlatPosArray[id].show=true的压平面
压平面的保存
1).压平面的存储是以json格式保存的
保存压平面数据的json集合oFlatPosArray通过保存接口保存到后台
2)保存压平面时接口
压平面的重载
压平接口获取
http://localhost:1000/api/attach/1.0.0/getFlatten
//将保存的压平面的信息保存重新复制 oFlatPosArray = result.data; result.data 上面借口获取的内容 //加载压平面 参考压平面的绘制(单个压平面加载)
4.8. 模型裁剪
模型裁剪绘制
//使用绘制插件来绘制裁剪面 viewer.geometryEditer.viewModel.defaultSurfaceOptions.classificationType =LSGlobe.ClassificationType.CESIUM_3D_TILE; viewer.geometryEditer.viewModel.setAction(EditAction.CREATE_POLYGON); viewer.geometryEditer.viewModel.onCreatedEvent.removeAllEventListener(); viewer.geometryEditer.viewModel.onCreatedEvent.addEventListener(function (event){ //绘制完成以后执行事件 返回值event.position 绘制的所有点的集合 var clipPolygon = new LSGlobe.PolygonGeometry({ polygonHierarchy : new LSGlobe.PolygonHierarchy(event.positions), perPositionHeight : true }); tileset.addClipPolygon(clipPolygon); //绘制范围内显示 tileset.addPitPolygon(pitPolygon); //绘制范围内隐藏 });
模型保存重载
模型裁剪暂时还没有后台接口无法保存修改,具体的方法可以参考压平的保存方式