开源三维地球GIS引擎Cesium常用功能的开发
Cesium是一個非常優秀的三維地球GIS引擎(開源且免費)。能夠加載各種符合標準的地圖圖層,瓦片圖、矢量圖等都支持。支持3DMax等建模軟件生成的obj文件,支持通用的GIS計算;支持DEM高程圖。測試中的3D-Tiles分支還支持傾斜攝影生成的城市三維建筑群。國內許多三維GIS產品都基于Cesium進行封裝(包括一些大廠)。因為工作關系,我對Cesium的一些基本GIS功能進行了研究,特此記錄下來。
如上圖,這是一個給市政GISBIM管理平臺做的原型,GIS部分使用Cesium,BIM部分使用第三方商業引擎。GIS控制宏觀、BIM支持微觀(現在還沒有什么好的引擎能做到GISBIM的無縫切換)。
常用功能介紹:
衛星矢量地圖切換
我這里使用的是天地圖提供的服務,衛星地圖和矢量地圖分別調用不同的接口,衛星地圖顯示效果如上圖,矢量地圖顯示如下圖:
道路及基本標注
點“道路及基本標注”后,將路名等顯示并加載在原先的圖層上
加標記點
首先在地圖上點擊需要加點的位置,然后在彈出框內選取顏色,設置提示文字和顯示內容,點擊保存;可以添加多個標記。
繪制線段
連續點擊地圖兩次就可以繪制線段(可繪制折線)
繪制圓形
支持繪制多個圓形,每個圓形隨機顏色,能夠顯示園的半徑、面積等
繪制多邊形
連續點擊地圖上的點,再右鍵閉合,就可以繪制多邊形,能夠計算多邊形每一邊的邊長、總面積等
保存視角、跳轉視角
保存當前的視角;輸入經緯度,跳轉到指定位置
隱藏、加載模型
可以動態加載、隱藏三維模型(為了便于演示,所有的模型均放大了幾百倍);地圖上的繪制功能對所有模型都有效,包含在范圍內的模型會自動高亮并顯示;點選模型能自動居中并提示是否跳轉到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(''));
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(''));
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 tempPinLon = Cesium.Math.toDegrees(cartographic.longitude);
347 tempPinLat = Cesium.Math.toDegrees(cartographic.latitude);
348 $('#addPinModal').modal('show');
349 }
350 }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
351 }
352 else if ("erase" == mode)
353 {
354 handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
355 handler.setInputAction(function (click) {
356 var pick = scene.pick(click.position);
357 if (Cesium.defined(pick) && Cesium.defined(pick.id) && Cesium.defined(pick.id._id)) {
358 for (var i = 0; i < models.length; i++) {
359 if ( pick.id != undefined && tempPinEntities[i].id == pick.id._id) {
360 removePoint(tempPinEntities[i]);
361 tempPinEntities.splice(i, 1);
362 }
363 }
364 }
365 }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
366 }
367 else if ("drawLine" == mode)
368 {
369 tempPoints = [];
370 handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
371 handler.setInputAction(function (click) {
372 var cartesian = viewer.camera.pickEllipsoid(click.position, scene.globe.ellipsoid);
373 if (cartesian) {
374 var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
375 var longitudeString = Cesium.Math.toDegrees(cartographic.longitude);
376 var latitudeString = Cesium.Math.toDegrees(cartographic.latitude);
377 tempPoints.push({ lon: longitudeString, lat: latitudeString });
378 var tempLength = tempPoints.length;
379 drawPoint(tempPoints[tempPoints.length - 1]);
380 if (tempLength > 1) {
381 drawLine(tempPoints[tempPoints.length - 2], tempPoints[tempPoints.length - 1], true);
382 }
383 }
384 }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
385 handler.setInputAction(function (click) {
386 tempPoints = [];
387 }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
388 }
389 else if ("drawCircle" == mode)
390 {
391 tempPoints = [];
392 handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
393 handler.setInputAction(function (click) {
394 var cartesian = viewer.camera.pickEllipsoid(click.position, scene.globe.ellipsoid);
395 if (cartesian) {
396 var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
397 var longitudeString = Cesium.Math.toDegrees(cartographic.longitude);
398 var latitudeString = Cesium.Math.toDegrees(cartographic.latitude);
399 tempPoints.push({ lon: longitudeString, lat: latitudeString });
400 var tempLength = tempPoints.length;
401 if (tempLength == 1) {
402 drawPoint(tempPoints[0]);
403 }
404 else if (tempLength == 2) {
405 drawPoint(tempPoints[1]);
406 drawLine(tempPoints[0], tempPoints[1], true);
407 //算兩點間距離
408 var distance = getFlatternDistance(tempPoints[0].lat, tempPoints[0].lon, tempPoints[1].lat, tempPoints[1].lon);
409
410 var entity =
411 viewer.
412 entities.add({
413 position: Cesium.Cartesian3.fromDegrees(tempPoints[0].lon, tempPoints[0].lat),
414 ellipse: {
415 semiMinorAxis: distance,
416 semiMajorAxis: distance,
417 height: 0,
418 material: Cesium.Color.fromRandom({ alpha: 0.8 })
419 }
420 });
421 tempEntities.push(entity);
422
423 //高亮圈內模型
424 for (var i = 0; i < loadedModels.length; i++) {
425 for (var j = 0; j < models.length; j++) {
426 if (loadedModels[i].id == models[j].id && getFlatternDistance(models[j].lat, models[j].lon, tempPoints[0].lat, tempPoints[0].lon) <= distance) {
427 loadedModels[i].color = Cesium.Color.SPRINGGREEN;
428 }
429 }
430 }
431
432 //面積
433 setTimeout(function () { alert("面積是 " + Math.PI * distance * distance + "平方米") },500);
434
435 tempPoints = [];
436 }
437 }
438 }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
439 }
440 else if ("drawSquare" == mode) {
441 tempPoints = [];
442 handler = new Cesium.ScreenSpaceEventHandler(scene.canvas);
443 handler.setInputAction(function (click) {
444 var cartesian = viewer.camera.pickEllipsoid(click.position, scene.globe.ellipsoid);
445 if (cartesian) {
446 var cartographic = Cesium.Cartographic.fromCartesian(cartesian);
447 var longitudeString = Cesium.Math.toDegrees(cartographic.longitude);
448 var latitudeString = Cesium.Math.toDegrees(cartographic.latitude);
449 tempPoints.push({ lon: longitudeString, lat: latitudeString });
450 var tempLength = tempPoints.length;
451 if (tempLength == 1) {
452 drawPoint(tempPoints[0]);
453 }
454 else if (tempLength == 2) {
455 //算兩點間距離
456 var distance = getFlatternDistance(tempPoints[0].lat, tempPoints[0].lon, tempPoints[1].lat, tempPoints[1].lon);
457
458 var entity =
459 viewer.
460 entities.add({
461 position: Cesium.Cartesian3.fromDegrees(tempPoints[0].lon, tempPoints[0].lat),
462 ellipse: {
463 semiMinorAxis: distance,
464 semiMajorAxis: distance,
465 height: 0,
466 material: Cesium.Color.fromRandom({ alpha: 0.8 })
467 }
468 });
469 tempEntities.push(entity);
470
471 //高亮圈內模型
472 for (var i = 0; i < loadedModels.length; i++) {
473 for (var j = 0; j < models.length; j++) {
474 if (loadedModels[i].id == models[j].id && getFlatternDistance(models[j].lat, models[j].lon, tempPoints[0].lat, tempPoints[0].lon) <= distance) {
475 loadedModels[i].color = Cesium.Color.SPRINGGREEN;
476 }
477 }
478 }
479
480 tempPoints = [];
481 }
482 }
483 }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
484 }
485 }
486
487 function drawPoint(point) {
488 var entity =
489 viewer.entities.add({
490 position: Cesium.Cartesian3.fromDegrees(point.lon, point.lat),
491 point: {
492 pixelSize: 10,
493 color: Cesium.Color.CHARTREUSE
494 }
495 });
496 tempEntities.push(entity);
497 }
498
499 function removePoint(entity) {
500 viewer.entities.remove(entity);
501 }
502
503 function drawLine(point1, point2, showDistance) {
504 var entity =
505 viewer.entities.add({
506 polyline: {
507 positions: [Cesium.Cartesian3.fromDegrees(point1.lon, point1.lat), Cesium.Cartesian3.fromDegrees(point2.lon, point2.lat)],
508 10.0,
509 material: new Cesium.PolylineGlowMaterialProperty({
510 color: Cesium.Color.CHARTREUSE.withAlpha(.5)
511 })
512 }
513 });
514 tempEntities.push(entity);
515 if (showDistance) {
516 var w = Math.abs(point1.lon - point2.lon);
517 var h = Math.abs(point1.lat - point2.lat);
518 var offsetV = w >= h ? 0.0005 : 0;
519 var offsetH = w < h ? 0.001 : 0;
520 var distance = getFlatternDistance(point1.lat, point1.lon, point2.lat, point2.lon);
521 entity =
522 viewer.entities.add({
523 position: Cesium.Cartesian3.fromDegrees(((point1.lon + point2.lon) / 2) + offsetH,
524 ((point1.lat + point2.lat) / 2) + offsetV),
525 label: {
526 text: distance.toFixed(1) + 'm',
527 font: '22px Helvetica',
528 fillColor: Cesium.Color.WHITE
529 }
530 });
531 tempEntities.push(entity);
532 }
533 }
534
535 function drawPoly(points) {
536 var pArray = [];
537 for (var i = 0; i < points.length; i ++) {
538 pArray.push(points[i].lon);
539 pArray.push(points[i].lat);
540 }
541 var entity =
542 viewer.entities.add({
543 polygon: {
544 hierarchy: new Cesium.PolygonHierarchy(Cesium.Cartesian3.fromDegreesArray(pArray)),
545 material: Cesium.Color.CHARTREUSE.withAlpha(.5)
546 }
547 });
548 tempEntities.push(entity);
549 }
550
551 function getColor(colorName, alpha) {
552 var color = Cesium.Color[colorName.toUpperCase()];
553 return Cesium.Color.fromAlpha(color, parseFloat(alpha));
554 }
555
556 //判斷點是否在多邊形內
557 function PointInPoly(point, polyPoints) {
558 for (var c = false, i = -1, l = polyPoints.length, j = l - 1; ++i < l; j = i)
559 ((polyPoints[i].lat <= point.lat && point.lat < polyPoints[j].lat) || (polyPoints[j].lat <= point.lat && point.lat < polyPoints[i].lat))
560 && (point.lon < (polyPoints[j].lon - polyPoints[i].lon) * (point.lat - polyPoints[i].lat) / (polyPoints[j].lat - polyPoints[i].lat) + polyPoints[i].lon)
561 && (c = !c);
562 return c;
563 }
564
565 //選區內模型高亮
566 function highLightAssetsInArea(points) {
567
568 for (var i = 0; i < loadedModels.length; i++) {
569 for (var j = 0; j < models.length; j ++) {
570 if (loadedModels[i].id == models[j].id && PointInPoly(models[j], points)) {
571 loadedModels[i].color = Cesium.Color.SPRINGGREEN;
572 }
573 }
574 }
575 }
576
577 //高亮模型
578 function highLigthModel(modelId) {
579 for (var i = 0; i < loadedModels.length; i ++) {
580 if (loadedModels[i].id == modelId) {
581 loadedModels[i].color = Cesium.Color.SPRINGGREEN;
582 }
583 }
584 }
585
586 //取消高亮模型
587 function unHighLightModel(modelId) {
588 for (var i = 0; i < loadedModels.length; i++) {
589 if (loadedModels[i].id == modelId) {
590 loadedModels[i].color = {
591 red: 1,
592 green: 1,
593 blue: 1,
594 alpha: 1
595 };
596 }
597 }
598 }
599
600 //定位
601 function goLocation() {
602 $('#flyToModal').modal('hide');
603 $('#flyToModal').on('hidden.bs.modal', function(e) {
604 viewer.camera.flyTo({
605 destination: Cesium.Cartesian3.fromDegrees($("#jumpLon").val(), $("#jumpLat").val(), 1000.0)
606 });
607 });
608 }
609
610 //加點
611 function addPin() {
612 $('#addPinModal').modal('hide');
613 var pin = viewer.entities.add({
614 name: $("#pinContent").val(),
615 position: Cesium.Cartesian3.fromDegrees(tempPinLon, tempPinLat),
616 billboard: {
617 image: $("#pinLabel").val() == "" ? pinBuilder.fromColor(Cesium.Color[$("#pinColor").val().toUpperCase()], 48).toDataURL() :
618 pinBuilder.fromText($("#pinLabel").val(), Cesium.Color[$("#pinColor").val().toUpperCase()], 64).toDataURL(),
619 verticalOrigin: Cesium.VerticalOrigin.BOTTOM
620 }
621 });
622 tempPinEntities.push(pin);
623 $("#pinLabel").val("");
624 $("#pinContent").val("");
625 }
626
627 //計算兩點間距離
628 function getFlatternDistance(lat1, lng1, lat2, lng2) {
629 var EARTH_RADIUS = 6378137.0; //單位M
630 var PI = Math.PI;
631
632 function getRad(d) {
633 return d * PI / 180.0;
634 }
635 var f = getRad((lat1 + lat2) / 2);
636 var g = getRad((lat1 - lat2) / 2);
637 var l = getRad((lng1 - lng2) / 2);
638
639 var sg = Math.sin(g);
640 var sl = Math.sin(l);
641 var sf = Math.sin(f);
642
643 var s, c, w, r, d, h1, h2;
644 var a = EARTH_RADIUS;
645 var fl = 1 / 298.257;
646
647 sg = sg * sg;
648 sl = sl * sl;
649 sf = sf * sf;
650
651 s = sg * (1 - sl) + (1 - sf) * sl;
652 c = (1 - sg) * (1 - sl) + sf * sl;
653
654 w = Math.atan(Math.sqrt(s / c));
655 r = Math.sqrt(s * c) / w;
656 d = 2 * w * a;
657 h1 = (3 * r - 1) / 2 / c;
658 h2 = (3 * r + 1) / 2 / s;
659
660 return d * (1 + fl * (h1 * sf * (1 - sg) - h2 * (1 - sf) * sg));
661 }
662
663 //計算多邊形面積
664 var earthRadiusMeters = 6371000.0;
665 var metersPerDegree = 2.0 * Math.PI * earthRadiusMeters / 360.0;
666 var radiansPerDegree = Math.PI / 180.0;
667 var degreesPerRadian = 180.0 / Math.PI;
668 var pointArr;
669 function SphericalPolygonAreaMeters(points) {
670 var totalAngle = 0;
671 for (var i = 0; i < points.length; i++) {
672 var j = (i + 1) % points.length;
673 var k = (i + 2) % points.length;
674 totalAngle += Angle(points[i], points[j], points[k]);
675 }
676 var planarTotalAngle = (points.length - 2) * 180.0;
677 var sphericalExcess = totalAngle - planarTotalAngle;
678 if (sphericalExcess > 420.0) {
679 totalAngle = points.length * 360.0 - totalAngle;
680 sphericalExcess = totalAngle - planarTotalAngle;
681 } else if (sphericalExcess > 300.0 && sphericalExcess < 420.0) {
682 sphericalExcess = Math.abs(360.0 - sphericalExcess);
683 }
684 return sphericalExcess * radiansPerDegree * earthRadiusMeters * earthRadiusMeters;
685 }
686
687 /*角度*/
688 function Angle(p1, p2, p3) {
689 var bearing21 = Bearing(p2, p1);
690 var bearing23 = Bearing(p2, p3);
691 var angle = bearing21 - bearing23;
692 if (angle < 0) {
693 angle += 360;
694 }
695 return angle;
696 }
697 /*方向*/
698 function Bearing(from, to) {
699 var lat1 = from.lat * radiansPerDegree;
700 var lon1 = from.lon * radiansPerDegree;
701 var lat2 = to.lat * radiansPerDegree;
702 var lon2 = to.lon * radiansPerDegree;
703 var angle = -Math.atan2(Math.sin(lon1 - lon2) * Math.cos(lat2), Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(lon1 - lon2));
704 if (angle < 0) {
705 angle += Math.PI * 2.0;
706 }
707 angle = angle * degreesPerRadian;
708 return angle;
709 }
710
711 function LoadBim(projId) {
712 //加載模型
713 $('#myTabs li:eq(1) a').tab('show');
714
715 }
View Code
總結
以上是生活随笔為你收集整理的开源三维地球GIS引擎Cesium常用功能的开发的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 小米商城如何到店自取(小米官方售后服务)
- 下一篇: 八闽生活app怎么注销