开源三维地球GIS引擎Cesium常用功能的开发

Posted thanks的.net(C#)技术博客

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了开源三维地球GIS引擎Cesium常用功能的开发相关的知识,希望对你有一定的参考价值。

    Cesium是一个非常优秀的三维地球GIS引擎(开源且免费)。能够加载各种符合标准的地图图层,瓦片图、矢量图等都支持。支持3DMax等建模软件生成的obj文件,支持通用的GIS计算;支持DEM高程图。测试中的3D-Tiles分支还支持倾斜摄影生成的城市三维建筑群。国内许多三维GIS产品都基于Cesium进行封装(包括一些大厂)。因为工作关系,我对Cesium的一些基本GIS功能进行了研究,特此记录下来。

 

 

    如上图,这是一个给市政GIS\\BIM管理平台做的原型,GIS部分使用Cesium,BIM部分使用第三方商业引擎。GIS控制宏观、BIM支持微观(现在还没有什么好的引擎能做到GIS\\BIM的无缝切换)。

常用功能介绍:

  • 卫星\\矢量地图切换

     

 

    我这里使用的是天地图提供的服务,卫星地图和矢量地图分别调用不同的接口,卫星地图显示效果如上图,矢量地图显示如下图:

 

  • 道路及基本标注

    点“道路及基本标注”后,将路名等显示并加载在原先的图层上

 

 

  • 加标记点

首先在地图上点击需要加点的位置,然后在弹出框内选取颜色,设置提示文字和显示内容,点击保存;可以添加多个标记。

 

 

  • 绘制线段

连续点击地图两次就可以绘制线段(可绘制折线)

 

  • 绘制圆形

支持绘制多个圆形,每个圆形随机颜色,能够显示园的半径、面积等

 

  • 绘制多边形

 

    连续点击地图上的点,再右键闭合,就可以绘制多边形,能够计算多边形每一边的边长、总面积等

 

  • 保存视角、跳转视角

保存当前的视角;输入经纬度,跳转到指定位置

 

  • 隐藏、加载模型

可以动态加载、隐藏三维模型(为了便于演示,所有的模型均放大了几百倍);地图上的绘制功能对所有模型都有效,包含在范围内的模型会自动高亮并显示;点选模型能自动居中并提示是否跳转到BIM模型显示(BIM模型也是基于三维WebGL的)

 

  • 搜索

可以根据输入的关键词进行搜索,使用百度或者高德的API,或者使用天地图的API,搜索后进行定位,只是百度、高德、天地图等用的是不同的坐标系,转换非常麻烦。

 

  • 清除绘制

清除所有绘制的部分

 

以上功能只要再完善下,封装下就可以成为一个很不错的三维GIS项目基础平台了,附我们公司做的GIS+BIM的产品截图,使用了3D-Tiles:)

 

附:示例程序的js部分代码

  1     var bimEngine; var msgControl; var toolbar; var fileControl; var spaceControl; var domainControl; var propertyControl; var searchControl; var markControl;
  2     var storeyControl; var roamingControl; var bimevent;
  3     
  4     var viewer = new Cesium.Viewer("cesiumContainer", {
  5         animation: false, //是否显示动画控件
  6         baseLayerPicker: false, //是否显示图层选择控件
  7         geocoder: true, //是否显示地名查找控件
  8         timeline: false, //是否显示时间线控件
  9         sceneModePicker: true, //是否显示投影方式控件
 10         navigationHelpButton: false, //是否显示帮助信息控件
 11         infoBox: true, //是否显示点击要素之后显示的信息
 12         imageryProvider: new Cesium.WebMapTileServiceImageryProvider({
 13             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",
 14             layer: "tdtBasicLayer",
 15             style: "default",
 16             format: "image/jpeg",
 17             tileMatrixSetID: "GoogleMapsCompatible",
 18             show: false
 19         })
 20     });
 21     var scene = viewer.scene;
 22     var pinBuilder = new Cesium.PinBuilder();
 23 
 24     var vecLayer = null, roadLayer = null, electricLayers = null;
 25     
 26     var getEnumPropertyNames = function(obj) {
 27         var props = [];
 28         for (prop in obj) {
 29             props.push(prop + \': \' + obj[prop]);
 30         }
 31         return props;
 32     }
 33 
 34     var models = new Array();
 35     models[0] = { id: \'house1\', name: \'house1\', url: \'../SampleData/house/house1.gltf\', lon: 121.41, lat: 31.22, height: 0, pid: \'4e027d42-f033-4bab-87f1-e34c8860b90e\' };
 36     models[1] = { id: \'house2\', name: \'house2\', url: \'../SampleData/house/house2.gltf\', lon: 121.42, lat: 31.21, height: 0, pid: \'918dcfaa-4568-4468-ba03-e379deaa99b7\' };
 37     models[2] = { id: \'house3\', name: \'house3\', url: \'../SampleData/house/house3.gltf\', lon: 121.43, lat: 31.20, height: 0, pid: \'2071736b-0054-4041-ad34-34f2e7a975e5\' };
 38     models[3] = { id: \'house4\', name: \'house4\', url: \'../SampleData/house/house4.gltf\', lon: 121.44, lat: 31.22, height: 0, pid: \'4e027d42-f033-4bab-87f1-e34c8860b90e\' };
 39     models[4] = { id: \'house5\', name: \'house5\', url: \'../SampleData/house/house5.gltf\', lon: 121.41, lat: 31.21, height: 0, pid: \'918dcfaa-4568-4468-ba03-e379deaa99b7\' };
 40     models[5] = { id: \'house6\', name: \'house6\', url: \'../SampleData/house/house6.gltf\', lon: 121.42, lat: 31.20, height: 0, pid: \'2071736b-0054-4041-ad34-34f2e7a975e5\' };
 41     models[6] = { id: \'house7\', name: \'house7\', url: \'../SampleData/house/house7.gltf\', lon: 121.43, lat: 31.22, height: 0, pid: \'4e027d42-f033-4bab-87f1-e34c8860b90e\' };
 42     models[7] = { id: \'house8\', name: \'house8\', url: \'../SampleData/house/house8.gltf\', lon: 121.44, lat: 31.21, height: 0, pid: \'918dcfaa-4568-4468-ba03-e379deaa99b7\' };
 43     models[8] = { id: \'house9\', name: \'house9\', url: \'../SampleData/house/house9.gltf\', lon: 121.45, lat: 31.20, height: 0, pid: \'2071736b-0054-4041-ad34-34f2e7a975e5\' };
 44     models[9] = { id: \'house10\', name: \'house10\', url: \'../SampleData/house/house10.gltf\', lon: 121.46, lat: 31.21, height: 0, pid: \'918dcfaa-4568-4468-ba03-e379deaa99b7\' };
 45     models[10] = { id: \'house11\', name: \'house11\', url: \'../SampleData/house/house11.gltf\', lon: 121.40, lat: 31.20, height: 0, pid: \'4e027d42-f033-4bab-87f1-e34c8860b90e\' };
 46     models[11] = { id: \'villa\', name: \'villa\', url: \'../SampleData/house3/house3.gltf\', lon: 121.45, lat: 31.22, height: 0, pid: \'2071736b-0054-4041-ad34-34f2e7a975e5\' };
 47 
 48     var loadedModels = [];
 49 
 50     var shapes = new Array();
 51     shapes[0] = { layer: \'测试层\', author: \'liu\', date: \'2017-06-18\', ploy: [
 52         { name: \'A区\', type: \'ploy\', points: [] }
 53     ]};
 54 
 55     var tempPoints = [];
 56     var tempEntities = [];
 57     var tempPinEntities = [];
 58     var tempPinLon, tempPinLat;
 59 
 60     var handler = null;
 61 
 62     $(function() {
 63 
 64         /**初始化**/
 65         $("input[name=\'optionsRadios\']").click(function() {
 66             if ($("input[name=\'optionsRadios\']:eq(1)").prop("checked")) {
 67                 //viewer.imageryLayers.addImageryProvider(vecLayer);
 68                 vecLayer = viewer.imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({
 69                     url: "http://t0.tianditu.com/vec_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=vec&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles",
 70                     layer: "tdtVecBasicLayer",
 71                     style: "default",
 72                     format: "image/jpeg",
 73                     tileMatrixSetID: "GoogleMapsCompatible",
 74                     show: false
 75                 }));
 76             } else if ($("input[name=\'optionsRadios\']:eq(0)").prop("checked")) {
 77                 if (viewer.imageryLayers.contains(vecLayer)) {
 78                     viewer.imageryLayers.remove(vecLayer);
 79                 }
 80             }
 81         });
 82         //标记层
 83         $("#cbxPinLayer").change(function() {
 84             if ($("#cbxPinLayer").prop("checked")) {
 85                 for (var i = 0; i < tempPinEntities.length; i++) {
 86                     viewer.entities.add(tempPinEntities[i]);
 87                 }
 88 
 89             } else {
 90                 for (var i = 0; i < tempPinEntities.length; i ++) {
 91                     viewer.entities.remove(tempPinEntities[i]);
 92                 }
 93             }
 94         });
 95         $("#pinColor").change(function() {
 96             $(this).css("background-color", $(this).val());
 97         });
 98 
 99         $("#cbxRoad").click(function() {
100             if ($(this).prop("checked")) {
101                 roadLayer = viewer.imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({
102                     url: "http://t0.tianditu.com/cia_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=cia&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles",
103                     layer: "tdtImgAnnoLayer",
104                     style: "default",
105                     format: "image/jpeg",
106                     tileMatrixSetID: "GoogleMapsCompatible",
107                     show: false
108                 }));
109             } else {
110                 viewer.imageryLayers.remove(roadLayer);
111             }
112         });
113         $("#cbxTestArc").click(function() {
114             if ($(this).prop("checked")) {
115                 electricLayers = viewer.imageryLayers.addImageryProvider(new Cesium.ArcGisMapServerImageryProvider({
116                     url: \'https://nationalmap.gov.au/proxy/http://services.ga.gov.au/site_3/rest/services/Electricity_Infrastructure/MapServer\'
117                 }));
118                 viewer.camera.flyTo({
119                     destination: Cesium.Rectangle.fromDegrees(114.591, -45.837, 148.970, -5.730)
120                 });
121             } else {
122                 viewer.imageryLayers.remove(electricLayers);
123             }
124         });
125         $("#opts .btn").click(function () {
126             window.setTimeout(function() {
127                 if ($("input[name=\'opt\']:eq(0)").prop("checked")) {
128                     clearEffects();
129                     setTips("");
130                 }
131                 else if ($("input[name=\'opt\']:eq(1)").prop("checked")) {
132                     clearEffects();
133                     SetMode("addPin");
134                     setTips("首先在地图上点击需要加点的位置,然后在弹出框内选取颜色,设置提示文字和显示内容,点击保存");
135                 }
136                 else if ($("input[name=\'opt\']:eq(2)").prop("checked")) {
137                     tempPoints = [];
138                     for (var i = 0; i < tempEntities.length; i++) {
139                         viewer.entities.remove(tempEntities[i]);
140                     }
141                     for (var i = 0; i < loadedModels.length; i++) {
142                         if (loadedModels[i].color == Cesium.Color.SPRINGGREEN) {
143                             loadedModels[i].color = {red:1,green:1, blue:1, alpha:1};
144                         }
145                     }
146                     clearEffects();
147                     setTips("绘制的图形被清除,点选页面标记可以删除标记");
148                     SetMode("erase");
149                 }
150                 else if ($("input[name=\'opt\']:eq(3)").prop("checked")) {
151                     clearEffects();
152                     SetMode("drawLine");
153                     setTips("在地图上分别点击,即可绘制多个线段,点右键结束绘制");
154                 }
155                 else if ($("input[name=\'opt\']:eq(4)").prop("checked")) {
156                     clearEffects();
157                     SetMode("drawCircle");
158                     setTips("第一次点击绘制圆心,第二次点击根据和圆心的位置绘制半径");
159                 }
160                 else if ($("input[name=\'opt\']:eq(5)").prop("checked")) {
161                     clearEffects();
162                     SetMode("drawSquare");
163                     setTips("第一、二次点击绘制长方形的一个边,再次点击根据点和边的距离绘制方形");
164                 }
165                 else if ($("input[name=\'opt\']:eq(6)").prop("checked")) {
166                     clearEffects();
167                     SetMode("drawPloy");
168                     setTips("如果需要绘制多边形,在地图上使用左键逐个点选地点,右击闭合多边形");
169                 }
170                 else if ($("input[name=\'opt\']:eq(7)").prop("checked")) {
171                     clearEffects();
172                     SetMode("pickBuilding");
173                     setTips("点选建筑查看详细的三维模型");
174                 }
175             },100);
176         });
177 
178         var homeView = {
179             destination: new Cesium.Cartesian3(-2852877.756667368, 4655857.919027944, 3288673.682311567),
180             orientation: {
181                 direction: new Cesium.Cartesian3(0.5437275903005284, -0.8386290220423197, -0.03258329225728158),
182                 up: new Cesium.Cartesian3(0.05520718287689969, -0.00299987805272847, 0.9984704140286108)
183             },
184             complete: function() { LoadModel(); },
185         };
186         
187         setTimeout(
188             function() {
189                 // scene.primitives.removeAll();
190                 //reset();
191                 viewer.camera.flyTo(homeView);
192                 
193                 //viewer.zoomTo(wyoming);
194             }, 3000);
195 
196         //var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(
197         //Cesium.Cartesian3.fromDegrees(121.49, 31.22, 0.0));
198         //var model = scene.primitives.add(Cesium.Model.fromGltf({
199         //    url: \'../SampleData/house/house1.gltf\',
200         //    modelMatrix: modelMatrix,
201         //    scale: 20.0,
202         //    name: \'SampleHouse\',
203         //    color: getColor(\'Red\', 1)
204         //}));
205 
206         $("#poly-show").click(function () {
207             LoadModel();
208         });
209 
210         $("#poly-hide").click(function () {
211             HideModel();
212         });
213 
214         //alert(getEnumPropertyNames(model).join(\'\\r\'));
215 
216     });
217 
218     function LoadModel() {
219         for (var i = 0; i < models.length; i++) {
220             var hasLoaded = false;
221             for (var j = 0; j < loadedModels.length; j ++) {
222                 if (models[i].id == loadedModels[j].id) {
223                     hasLoaded = true;
224                 }
225             }
226             if (!hasLoaded) {
227                 var modelMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(
228                     Cesium.Cartesian3.fromDegrees(models[i].lon, models[i].lat, models[i].height));
229 
230                 var model = scene.primitives.add(
231                     Cesium.Model.fromGltf({
232                         url: models[i].url,
233                         modelMatrix: modelMatrix,
234                         scale: 20.0,
235                         name: models[i].name,
236                         id: models[i].id
237                     }));
238                 loadedModels.push(model);
239             }
240         }
241         //var cartesian = viewer.camera.pickEllipsoid(loadedModels[0].modelMatrix, scene.globe.ellipsoid);
242         //alert(getEnumPropertyNames(cartesian).join(\'\\r\'));
243         
244     }
245 
246     function HideModel() {
247         for (var i = 0; i < loadedModels.length; i++) {
248             scene.primitives.remove(loadedModels[i]);
249         }
250         loadedModels = [];
251     }
252 
253     function setTips(message, close) {
254         if ("" == message) {
255             $("#message").fadeOut();
256         } else {
257             if (close != undefined && close == true) {
258                 $("#message").html(message).fadeOut();
259             } else {
260                 $("#message").html(message).fadeIn();
261             }
262         }
263     }
264 
265     function clearEffects() {
266         if (handler != null) {
267             handler.destroy();
268         }
269     }
270 
271     //设置各种操作模式
272     function SetMode(mode) {
273         if (mode == "drawPloy")
274         {
275             tempPoints = [];
276             handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
277             handler.setInputAction(function (click) {
278                 var cartesian = viewer.camera.pickEllipsoid(click.position, scene.globe.ellipsoid);
279                 if (cartesian) {
280                     var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
281                     var longitudeString = Cesium.Math.toDegrees(cartographic.longitude);
282                     var latitudeString = Cesium.Math.toDegrees(cartographic.latitude);
283                     tempPoints.push({ lon: longitudeString, lat: latitudeString });
284                     var tempLength = tempPoints.length;
285                     drawPoint(tempPoints[tempPoints.length-1]);
286                     if (tempLength > 1) {
287                         drawLine(tempPoints[tempPoints.length - 2], tempPoints[tempPoints.length - 1], true);
288                     }
289                 } 
290             }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
291 
292             handler.setInputAction(function (click) {
293                 var cartesian = viewer.camera.pickEllipsoid(click.position, scene.globe.ellipsoid);
294                 if (cartesian) {
295                     var tempLength = tempPoints.length;
296                     if (tempLength < 3) {
297                         alert(\'请选择3个以上的点再执行闭合操作命令\');
298                     } else {
299                         drawLine(tempPoints[0], tempPoints[tempPoints.length - 1], true);
300                         drawPoly(tempPoints);
301                         highLightAssetsInArea(tempPoints);
302                         alert(\'多边形面积\' + SphericalPolygonAreaMeters(tempPoints) + \'平方米\');
303                         tempPoints = [];
304                     }
305 
306                 }
307             }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
308         }
309         else if (mode == "pickBuilding")
310         {
311             handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
312             handler.setInputAction(function(click) {
313                 var pick = scene.pick(click.position);
314                 if (Cesium.defined(pick) && Cesium.defined(pick.node) && Cesium.defined(pick.mesh)) {
315                     for (var i = 0; i < models.length; i ++) {
316                         if (models[i].id == pick.node._model.id) {
317                             var modelName = models[i].name;
318                             var modelId = models[i].id;
319                             var modelBimId = models[i].pid;
320                             highLigthModel(modelId);
321                             viewer.camera.flyTo({
322                                 destination: Cesium.Cartesian3.fromDegrees(models[i].lon, parseFloat(models[i].lat) - 0.01, 2000.0),
323                                 orientation: {
324                                     direction: new Cesium.Cartesian3(0.5437275903005284, -0.8386290220423197, -0.03258329225728158),
325                                     up: new Cesium.Cartesian3(0.05520718287689969, -0.00299987805272847, 0.9984704140286108)
326                                 },
327                                 complete: function() {
328                                     if (confirm("你选择的是" + modelName + ",是否查看详细模型?")) {
329                                         LoadBim(modelBimId);
330                                     }
331                                     unHighLightModel(modelId);
332                                 },
333                             });
334                         }
335                     }
336                 }
337             }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
338         }
339         else if ("addPin" == mode)
340         {
341             handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
342             handler.setInputAction(function (click) {
343                 var cartesian = viewer.camera.pickEllipsoid(click.position, scene.globe.ellipsoid);
344                 if (cartesian) {
345                     var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
346                  

以上是关于开源三维地球GIS引擎Cesium常用功能的开发的主要内容,如果未能解决你的问题,请参考以下文章

用three.js开发三维地图实例

3DEarth PPT :一款专为GIS系统研发的三维汇报演示系统

Cesium的扩展工具包-EarthSDK使用指南1

cesium 卫星扫过哪里显示地球上的图片一部分

个人笔记三维GIS开发-cesium坐标系统

openlayers和cesium实现地图二三维切换