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. 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. width: 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. }

开源三维地球GIS引擎Cesium常用功能的开发的更多相关文章

  1. 驰骋开源的asp.net工作流程引擎java工作流 2015 正文 驰骋工作流引擎ccflow6的功能列表

    关键词: 驰骋工作流引擎   ccflow的功能列表   工作流功能列表  表单引擎功能列表 我们工作流引擎ccflow6重构之后对功能做了一些调整,要想快速了解ccbpm的功能,可以以下面列表为准 ...

  2. 无插件,跨平台,基于WebGL的三维地球来了!!!

    用户通过浏览器即可递交数据到同一个地理信息系统中,操作简单,跨平台 ,无插件,可扩展,高效共享 ,完美匹配超大数据量发布! 近年来,随着计算机图形学.虚拟现实.卫星遥感.航空摄影.激光雷达等技术的迅猛 ...

  3. 开源项目OEIP 游戏引擎与音视频多媒体(UE4/Unity3D)

    现开源一个项目 OEIP 项目实现的功能Demo展示 这个项目演示了在UE4中,接入摄像机通过OEIP直接输出到UE4纹理上,并直接把UE4里的RenderTarget当做输入源通过OEIP里GPU管 ...

  4. C#两行代码实现三维地球

    一.             为什么要用三维地球? 三维地球是地理信息技术的一个重要发展方向,相比较二维地图技术,三维地球最大的特点是更直观更形象地表达地理信息和空间上的方位.我们可以在三维气象模拟. ...

  5. 前端3D引擎-Cesium自定义动态材质

    本文代码基于Vue-cli4和使用WebGL的地图引擎Cesium,主要内容为三维场景下不同对象的动态材质构建. 参考了很多文章,链接附在文末. 为不同的几何对象添加动态材质 不知道这一小节的名称概况 ...

  6. JavaScript 常用功能总结

    小编吐血整理加上翻译,太辛苦了~求赞! 本文主要总结了JavaScript 常用功能总结,如一些常用的JS 对象,基本数据结构,功能函数等,还有一些常用的设计模式. 目录: 众所周知,JavaScri ...

  7. CSS3常用功能的写法

    随着浏览器的升级,CSS3已经可以投入实际应用了. 但是,不同的浏览器有不同的CSS3实现,兼容性是一个大问题.上周的YDN介绍了CSS3 Please网站,该网站总结了一些常用功能的写法. 以下就是 ...

  8. Keil的使用方法 - 常用功能(一)

    Ⅰ.概述 学习一门软件的开发,开发工具的掌握可以说尤为重要.由于Keil集成开发工具支持多种MCU平台的开发,是市面上比较常见的,也是功能比较强大一款IDE.所以,对于大多数人说,选择Keil几乎是单 ...

  9. CSS3常用功能的写法 转

    CSS3常用功能的写法 作者: 阮一峰   随着浏览器的升级,CSS3已经可以投入实际应用了. 但是,不同的浏览器有不同的CSS3实现,兼容性是一个大问题.上周的YDN介绍了CSS3 Please网站 ...

随机推荐

  1. spring boot RESTFul API拦截 以及Filter和interceptor 、Aspect区别

    今天学习一下RESTFul api拦截 大概有三种方式 一.通过Filter这个大家很熟悉了吧,这是java规范的一个过滤器,他会拦截请求.在springboot中一般有两种配置方式. 这种过滤器拦截 ...

  2. centos6快速搭建nginx

    step1:配置本地 yum库,保存   $vi   /etc/yum.repos.d/nginx.repo   [nginx] name=nginx repo baseurl=http://ngin ...

  3. JS 监听微信、支付宝等移动app及浏览器的返回、后退、上一页按钮的事件方法

    在实际的应用中,我们常常需要实现在移动app和浏览器中点击返回.后退.上一页等按钮实现自己的关闭页面.调整到指定页面或执行一些其它操作的需求: 那在代码中怎样监听当点击微信.支付宝.百度糯米.百度钱包 ...

  4. hadoop的安装和配置(一)本地模式

    博主会用三篇文章来为大家详细的说明hadoop的三种模式: 本地模式 伪分布模式 完全分布模式 本地模式: 思路走向 |--------------------| | ①:配置Java环境  | | ...

  5. http转https实战教程iis7.5

    HTTP转HTTPS实战教程IIS7.5 (备注:确保IIS安装完成.ASP.NET 等配置无误) 1.          本文以阿里云为例,先在阿里云注册域名并且进行备案.备案完成后,在左侧菜单申请 ...

  6. 在阿里云 ECS 搭建 nginx https nodejs 环境(三、nodejs)

    在阿里云 ECS 搭建 nginx https nodejs 环境(三.nodejs) 在阿里云 ECS 搭建 nginx https nodejs 环境(三.nodejs) 第一步 指定版本源 执行 ...

  7. Linux 笔记 #03# 在 Debian远程服务器上运行 Java socket程序

    我试图做什么:把我的破代码放到服务器上运行,并成功与客户端进行 socket通信. 预备环境:刚安装好 MySQL 和 JVM 的 Linux远程服务器(Debian 8)一台. 主要有如下几个步骤: ...

  8. 入门干货之用DVG打造你的项目主页-Docfx、Vs、Github

    由于这三项技术涉及到的要点以及内容较多,希望大家有空能自己挖掘一下更多更深的用法. 0x01.介绍 VS,即VS2017以及以上版本,宇宙最好的IDE,集成了宇宙最有前景的平台,前阶段也支持了宇宙最好 ...

  9. 【转载】mysql binlog日志自动清理及手动删除

    说明:当开启mysql数据库主从时,会产生大量如mysql-bin.00000* log的文件,这会大量耗费您的硬盘空间.mysql-bin.000001mysql-bin.000002mysql-b ...

  10. 【转载】netstat--查看服务器[有效]连接数--统计端口并发数--access.log分析

    简介 Netstat 命令用于显示各种网络相关信息,如网络连接,路由表,接口状态 (Interface Statistics),masquerade 连接,多播成员 (Multicast Member ...