# vue使用cesium

  • 安装
npm install cesium@1.95.0 --save
  • 将node_modules/Build下的Cesium复制到public文件夹下面
<link href="./cesium/Widgets/widgets.css" rel="stylesheet">
<script src="./cesium/Cesium.js"></script>

//获取全局的Cesium
const Cesium = window.Cesium
  • 或者在vue的main.js中引入
//全局引入Cesium
import 'cesium/Build/Cesium/Widgets/widgets.css'
import * as Cesium from 'cesium'
Vue.prototype.$Cesium = Cesium
window.Cesium = Cesium
  • 封装自己的cesium方法,例如在src创建utils文件夹,在utils文件夹下面创建mCesium.js
import * as Cesium from 'cesium'
Cesium.Ion.defaultAccessToken ="token"; //这里的token是自己申请的token
window.CESIUM_BASE_URL = "/";

class mMap{
    constructor(id){
      this.id = id; //地图容器
      this.viewer = null;
      this.scene = null;
    }
    //初始化地图
    initMap(){
      console.log(this.id)
      this.viewer = new Cesium.Viewer(this.id,{
        geocoder: false,                //是否显示地名查找控件
        sceneModePicker: false,         //是否显示投影方式控件
        navigationHelpButton: false,    //是否显示帮助信息控件
        baseLayerPicker: false,         //是否显示图层选择控件
        homeButton: false,              //是否显示Home按钮
        fullscreenButton: false,        //是否显示全屏按钮
        animation: false, //左下角的动画控件的显示
        shouldAnimate: false, //控制模型动画
        timeline: false, //底部的时间轴
        selectionIndicator: false,
        infoBox: false
      });
      //定位到指定位置
      this.viewer.camera.flyTo({
        destination : Cesium.Cartesian3.fromDegrees(112.876942, 28.235312, 1500.0)
      });
      //去cesium logo水印 或 css
      this.viewer.cesiumWidget.creditContainer.style.display = "none";
      //创建场景
      this.scene = this.viewer.scene;
      if(!this.scene.pickPositionSupported){
        window.alert("此浏览器不支持拾取位置!")
      }
      this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.canvas); 
    }
  }
  
  export function createMap(id){
    window.map = new mMap(id)
  }
}
  • 使用
<template>
	<div id="mMap"></div>
</template>
import { createMap} from './utils/cesium/mcesium'
mounted() {
    createMap("mMap");
    window.map.initMap()
}

# 绘制不同的形状(Entity)

// 点实体
viewer.entities.add({
    position: position, // 格式为世界坐标的点位置
	point: {
        show: ture, // 点是否可见
        pixelSize: Number, // 点的大小
        color: color, // 点的颜色
        outlineClor: color, // 边框颜色
        outlineWidth: Number, // 轮廓宽度
    },
});

// 线实体
viewer.entities.add({
    polyline: {
        show: Boolean, // 线是否可见
        positions: positions, // 格式为世界坐标的线位置数组
        width: Number, // 线的宽度
        material: color, // 线的颜色
        clampToGround: Boolean, // 线是否固定在地面
    },
});

// 面实体
viewer.entities.add({
    polygon: {
        show: Boolean, // 面是否可见
        hierarchy: positions, // 格式为世界坐标的面位置数组
        height: Number, // 面相对于椭球表面的高度
        fill: Boolean, // 面是否有填充
        material: color, // 面的填充颜色
        outline: Boolean, // 面是否有边框
        outlinColor: color, // 边框的颜色
        outlineWidth: Number, // 边框的宽度,无论设置为多少宽度始终只会显示为 1
        perPositionHeight: Boolean, // 面是否使用每个位置的高度
    },
});

// 添加广告牌,也就是一张图片、图标数据
addEntityBillboard() {
	let entityBillBoard = new Cesium.Entity({
		id: 'EntityBillboard0',
		name: 'EntityBillboard',
		show: true,
		description: '广告牌招租13390133157',
		position: new Cesium.Cartesian3.fromDegrees(116.0, 39.9, 100),
		billboard: {
			image: 'static/image/ziranzaihai.png',
			show: true,
			sacle: 1000.01,
			color: Cesium.Color.YELLOWGREEN,
			width: 100,
			height: 100
		}
	})
	let billboadrGeom = window.viewer.entities.add(entityBillBoard)
	window.viewer.zoomTo(entityBillBoard)
}

// 添加立方体实体。可以根据不同的材质进行设置box的外观
addEntityBox() {
   var heading = Cesium.Math.toRadians(90.0)
   var pitch = 0.0
   var roll = 0.0
   var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll)
   var orientation = Cesium.Transforms.headingPitchRollQuaternion(position,hpr)
	 let entityBox = new Cesium.Entity({
        id: 'entityBox0',
        name: 'entityBox',
        position: Cesium.Cartesian3.fromDegrees(111.0, 41.0),
        orientation: orientation,
        box: {
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
            dimensions: new Cesium.Cartesian3(100000, 100000, 100000),
            material: new Cesium.ImageMaterialProperty({
                image: 'static/image/entityBillboard.ico',
                color: Cesium.Color.YELLOWGREEN,
                repeat: new Cesium.Cartesian2(16, 16),
                transparent: true
            }),
            outline: true,
            fill: true,
            outlineColor: Cesium.Color.RED,
            outlineWidth: 100
        }
    })

    let boxGeom = window.viewer.entities.add(entityBox)
    window.viewer.flyTo(entityBox, {
        duration: 3,
        maximumHeight: 1000,
        offset: Cesium.HeadingPitchRange(1, 1, 1)
    })
}

// 添加走廊通道实体,可以拉伸高度
addEntityCorridor() {
    let entityCorridor = new Cesium.Entity({
        id: 'entityCorridor0',
        name: 'entityCorridor0',
        position: Cesium.Cartesian3.fromDegrees(123.0, 43.0),
        corridor: {
            positions: Cesium.Cartesian3.fromDegreesArray([
                123.0, 40.0, 122.0, 40.0, 123.0, 42.0, 121.0, 42.0
            ]),
            width: 10000,
            material: new Cesium.ImageMaterialProperty({
								//可以设置贴图
                // image: 'static/image/corridor.png',
                color: Cesium.Color.YELLOWGREEN,
                repeat: new Cesium.Cartesian2(32, 32)
                // transparent: true
            }),
            extrudedHeight: 10000,
            outline: false
        }
    })
    let corridorGeom = window.viewer.entities.add(entityCorridor)
    window.viewer.zoomTo(entityCorridor)
},

// 添加圆柱实体
addEntityCylinder() {
    let entityCylinder = new Cesium.Entity({
        id: 'entityCylinder0',
        name: 'entityCylinder',
        position: Cesium.Cartesian3.fromDegrees(116.0, 40.0, 50000),
        cylinder: {
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
            topRadius: 10000,
            bottomRadius: 10000,
            length: 20000,
            material: new Cesium.ImageMaterialProperty({
                // image: 'static/image/corridor.png',
                color: Cesium.Color.fromCssColorString('#FFD700'),
                transparent: false
            })
        }
    })
    let cylinderGeom = window.viewer.entities.add(entityCylinder)
    window.viewer.zoomTo(entityCylinder)
}

// 添加椭圆实体,面状,可以拉伸成体
addEntityEllipse() {
    let entityEllipse = new Cesium.Entity({
        id: 'entityEllipse0',
        name: 'entityEllipse',
        position: Cesium.Cartesian3.fromDegrees(123.0, 45.0),
        ellipse: {
            semiMajorAxis: 100000,
            semiMinorAxis: 60000,
            material: Cesium.Color.fromRandom().withAlpha(1),
						//拉伸
            extrudedHeight: 100000,
            heightReference: Cesium.HeightReference.CLAMP_TO_EDGE,
            rotation: 0.9,
            shadows: Cesium.ShadowMode.ENABLED
        }
    })
    let ellipseCeom = window.viewer.entities.add(entityEllipse)
    window.viewer.zoomTo(entityEllipse)
}

// 添加椭球实体
addEntityEllipsoid() {
    this.trackedEntity = new Cesium.Entity({
        id: 'EntityEllipsoid0',
        name: 'EntityEllipsoid',
        position: Cesium.Cartesian3.fromDegrees(111, 35, 100),
        ellipsoid: {
            heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
            radii: new Cesium.Cartesian3(30000, 50000, 30000),
            material: Cesium.Color.fromRandom().withAlpha(1),
            outline: true,
            outlineColor: Cesium.Color.BLACK
        }
    })
    let ellipsoidGeom = window.viewer.entities.add(this.trackedEntity)
    window.viewer.zoomTo(this.trackedEntity)
},

// 添加文本标签, 可以根据缩放的程度控制标签大小或者显示与隐藏
addEntityLabel() {
    let entityLabel = new Cesium.Entity({
        id: 'entityLabel0',
        name: 'entityLabel',
        position: Cesium.Cartesian3.fromDegrees(123.5, 45.5, 1000),
        label: {
            text: '臣本布衣,躬耕于陇亩',
            fillColor: Cesium.Color.YELLOWGREEN,
            style: Cesium.LabelStyle.FILL_AND_OUTLINE,
            showBackground: true,
            backgroundColor: Cesium.Color(255, 255, 0),
            scaleByDistance: new Cesium.NearFarScalar(1.5e2, 2.0, 1.5e7, 0.5),
            translucencyByDistance: new Cesium.NearFarScalar(
                1.5e2,
                1.0,
                1.5e8,
                0.0
            ),
            verticalOrigin: Cesium.VerticalOrigin.LEFT
        }
    })
    let labelsGeom = window.viewer.entities.add(entityLabel)
    window.viewer.zoomTo(entityLabel)
},

// 添加平面实体, 没有厚度
addEntityPlane() {
    let entityPlane = new Cesium.Entity({
        id: 'entityPlane0',
        name: 'entityPlane',
        position: Cesium.Cartesian3.fromDegrees(123.6, 45.8),
        plane: {
            plane: new Cesium.Plane(Cesium.Cartesian3.UNIT_Y, 0.0),
            dimensions: new Cesium.Cartesian2(400000.0, 300000.0),
            material: Cesium.Color.BLUE
        }
    })
    let planeGeom = window.viewer.entities.add(entityPlane)
    window.viewer.zoomTo(planeGeom)
},

// 添加类似管装线实体
addEntityPloylineVolum() {
    let entityPolylineVolum = new Cesium.Entity({
        id: 'EntityPloylineVolum',
        name: 'addEntityPloylineVolum',
        polylineVolume: {
            positions: Cesium.Cartesian3.fromDegreesArray([
                120.0, 40.0, 120.0, 45.0, 125.0, 45.0
            ]),
            shape: [
                new Cesium.Cartesian2(-10000, 0),
                new Cesium.Cartesian2(10000, 0),
                new Cesium.Cartesian2(20000, 17340),
                new Cesium.Cartesian2(0, 37340),
                new Cesium.Cartesian2(-20000, 17340)
            ],
            material: Cesium.Color.YELLOWGREEN,
            fill: true,
            outline: true,
            outlineColor: Cesium.Color.YELLOW,
            outlineWidth: 10
        }
    })
    let polylineVolume = window.viewer.entities.add(entityPolylineVolum)
    window.viewer.zoomTo(polylineVolume)
}

// 添加矩形实体
addEntityRectangle() {
    let entityRectangle = new Cesium.Entity({
        id: 'entityRectangle0',
        name: 'entityRectangle',
        rectangle: {
			// west, south, east, north
            coordinates: Cesium.Rectangle.fromDegrees(120.0, 40, 125, 45), 
            // material: Cesium.Color.PURPLE.withAlpha(0.6),
            material: 'static/image/hzw.png'
            // outline: true, // height must be set for outline to display
            // outlineColor: Cesium.Color.RED,
            // extrudedHeight: 10000,
        }
    })
    let rectangleGeom = window.viewer.entities.add(entityRectangle)
    window.viewer.zoomTo(rectangleGeom)
},

// 添加墙实体
addEntityWall() {
    let entityWall = new Cesium.Entity({
        id: 'enttiyWall0',
        name: 'entityWall',
        wall: {
            positions: Cesium.Cartesian3.fromDegreesArrayHeights([
                123.0, 40.0, 100000, 123.5, 40.5, 12012, 124.0, 41.0, 210000, 124.5,
                41.5, 220000, 125.0, 42.0, 52136
            ]),
            material: new Cesium.ImageMaterialProperty({
                image: 'static/image/corridor.png',
                repeat: new Cesium.Cartesian2(32, 32)
            })
        }
    })
    let wallGeom = window.viewer.entities.add(entityWall)
    window.viewer.zoomTo(entityWall)
}

// 点实体
viewer.entities.add({
    position: position, // 格式为世界坐标的点位置
    point: new Cesium.PointGraphics({
        show: Boolean, // 点是否可见
        pixelSize: Number, // 点的大小
        color: color, // 点的颜色
        outlineClor: color, // 边框宽度
        outlineWidth: Boolean, // 轮廓颜色
    });
});

// 线实体
viewer.entities.add({
    golyline: new Cesium.PolylineGraphics({
        show: Boolean, // 线是否可见
        positions: positions, // 格式为 Cartesian3 的线位置数组
        width: Number, // 线的宽度
        material: color, // 线的颜色
        clampToGround: Boolean, // 线是否固定在地面
    });
});

// 面实体
viewer.entities.add({
    golygon: new Cesium.PolygonGraphics({
        show: Boolean, // 面是否可见
        hierarchy: positions, // 格式为 Cartesian3 的面位置数组
        height: Number, // 面相对于椭球表面的高度
        fill: Boolean, // 面是否有填充
        material: color, // 面的填充颜色
        outline: Boolean, // 面是否有边框
        outlinColor: color, // 边框的颜色
        outlineWidth: Number, // 边框的宽度,无论设置为多少宽度始终只会显示为 1
        perPositionHeight: Boolean, // 面是否使用每个位置的高度
    });
});

更多其他的多边形

# polygon添加边界线不起作用

关于cesium添加polygon,有时需要添加边界线。但是设置outline不起作用,outline不起作用的原因

viewer.entities.add({
  name: '等值线',
  polygon: {
    hierarchy: {
      positions: Cesium.Cartesian3.fromDegreesArray(polyArr),
    },
    material: Cesium.Color.RED.withAlpha(1),
    zIndex: zIndex,
    height: zIndex * 10000,  //多层次
    outline: true,
    outlineColor: Cesium.Color.BLACK,
    outlineWidth:1,
  }
});

首先说明一下绘制多个polygon中,zIndex和height的区别:

  • 绘制多个polygon,相当于将多个polygon贴在地球表面
  • zIndex的作用就是设置绘制的等级。zindex越高,绘制的polygon会贴在最上面
  • height的作用则是在不同层次上绘制polygon。每个polygon的height不一样,则边界就会显现出来
所以outline不起作用的原因在于:多个polygon在同一height,没有设置height区分图层
所有polygon在同一图层上,outline不起作用

明白绘制不出原因后,就可以有两个解决思路:

  • 设置zindex和height。如下:可以展示多维效果
viewer.entities.add({
  name: '等值线',
  polygon: {
    hierarchy: {
      positions: Cesium.Cartesian3.fromDegreesArray(polyArr),
    },
    material: Cesium.Color.RED.withAlpha(1),
    zIndex: zIndex,
    height: zIndex * 10000,  //多层次
    outline: true,
    outlineColor: Cesium.Color.BLACK,
    outlineWidth:1,
  }
});
  • 再绘制完polygon后,再循环一遍,同样的数据,绘制polyline
polyline:{
	positions: Cesium.Cartesian3.fromDegreesArray(polyArr),
	material: Cesium.Color.fromCssColorString(contourColor).withAlpha(1),
	loop: true,
	width: 2
}

# polygon中extrudedHeight 和 height 的区别

  • height: 多边形的高度(多边形底部到地球表面的高度)
  • extrudedHeight: extrudedHeight 根据情况不同所代表的高度是不同的

# extrudedHeight > height 情况

  • height:多边形下表面到地球表面的高度
  • extrudedHeight: 多边体的高度 + height`(多边形上表面到地球表面的高度)

extrudedHeight

# extrudedHeight < height 情况

  • height:多边形下表面到地球表面的高度
  • extrudedHeight: height - 多边体的高度`(多边形下表面到地球表面的高度)

extrudedHeight

# extrudedHeight = height 情况

就是多边形的一个平面,不是多边体了

extrudedHeight

# 多边形中心点偏移问题解决

之前在网上搜到的获取中心点的方法如下:

var viewer = new Cesium.Viewer("cesiumContainer");
var polygon = viewer.entities.add({
  name: "Red polygon on surface",
  polygon: {
    hierarchy: Cesium.Cartesian3.fromDegreesArray([-115.0,37.0,-115.0,32.0,-107.0,33.0]),
    material: Cesium.Color.RED.withAlpha(0.5),
  },
});
var polyPositions = polygon.hierarchy.getValue(Cesium.JulianDate.now()).positions;
var polyCenter = Cesium.BoundingSphere.fromPoints(polyPositions).center;//中心点
polyCenter = Cesium.Ellipsoid.WGS84.scaleToGeodeticSurface(polyCenter);
// 添加label
redPolygon.label={
    position: polyCenter,
    text:'polygon title',
    color : Cesium.Color.fromCssColorString('#fff'),
    font:'normal 32px MicroSoft YaHei',
    showBackground : true,
    scale : 0.5,
    color: Cesium.Color.fromCssColorString('#fff'),
    font: 'normal 32px MicroSoft YaHei',
    showBackground: true,
    scale: 0.5,
    verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
    horizontalOrigin: Cesium.HorizontalOrigin.CENTER,
    heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
};
viewer.zoomTo(viewer.entities);

但是如果多边形不太规则或者点比较多的情况下,标记的位置就不在中心点了,会有偏移,boundingsphere 计算的中心点是外接圆的圆心,所以导致了中心点会在图形外

// 多边形的坐标集合(如果已经获取到了,就跳过这一步)
var polygon_point_arr = polygon_point_entity.polygon.hierarchy.getValue(Cesium.JulianDate.now()).positions;
// 保存转换后的点数组,这个格式必须按照 turf 的要求来
let turf_arr = [[]];
// 坐标转换
polygon_point_arr.forEach(val => {
	let polyObj = {}
	// 空间坐标转世界坐标(弧度) 同 Cesium.Cartographic.fromCartesian
	let cartographic = viewer.scene.globe.ellipsoid.cartesianToCartographic(val)
	// 弧度转为角度(经纬度)
	polyObj.lon = Cesium.Math.toDegrees(cartographic.longitude)
	polyObj.lat = Cesium.Math.toDegrees(cartographic.latitude)
	turf_arr[0].push([polyObj.lon, polyObj.lat])
})
// turf 需要将整个点闭合,所以最后一个点必须和起点重合。
turf_arr[0].push(turf_arr[0][0])
let turf_position = turf.polygon(turf_arr)
let turf_position_point = turf.centerOfMass(turf_position)
// 设置点标记坐标
polygon_point_entity.position = Cesium.Cartesian3.fromDegrees(turf_position_point.geometry.coordinates[0], turf_position_point.geometry.coordinates[1], 0)
// 添加点标记
polygon_point_entity.label = {
	// 点标记参数
}

# 动态绘制点、线、面

# 动态绘制点

在鼠标移动事件中,第一次触发移动事件时,就创建一个点实体,以后触发移动事件时就先删除上一次触发移动事件创建的实体,再创建一个新的实体

# 动态绘制线

动态绘制线与动态绘制点相似,但是,在绘制过程中, polyline 中的 positions 属性值需要使用 Cesium.CallbackProperty() 方法来获取

viewer.entities.add({
    polyline: {
        positions: new Cesium.CallbackProperty(function() {
            return positions;
        }, false),
        material: Color,
        width: Number,
    }
});

# 动态绘制面

动态绘制面与动态绘制线相似,但是,在 polygon 中的 hierarchy 属性值除需要使用 Cesium.CallbackProperty() 方法来获取外,还需要使用 Cesium.PolygonHierarchy() 返回

viewer.entities.add({
    polygon: {
        hierarchy: new Cesium.CallbackProoerty(function() {
            return new Cesium.PolyHierarchy(positions);
        }, false),
        material: Color,
    }
});

# 面的编辑

初始化变量

// 创建监听的handler
this.handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);

// 用于保存实体的对象
let gon = undefined;

// 判断是否处于编辑状态
let isEditting = false;

// 设置当前的编辑点
let currentPoint = undefined;

// 清空编辑点ID数组
this.pointsId = [];

创建鼠标按下的监听事件

// 对鼠标按下事件的监听
this.handler.setInputAction((event) => {

  // 获取屏幕坐标
  let windowPosition = event.position;
  
  // 通过屏幕坐标获取当前位置的实体信息
  let pickedObject = viewer.scene.pick(windowPosition);

  // 如果实体信息存在则说明该位置存在实体
  if (Cesium.defined(pickedObject)) {
  	   
	  // 获取当前点的实体
      let entity = pickedObject.id;
		
	  // 如果实体为面同时没有处于编辑状态,那么保存面的实体 
      if (entity.name === "polygon" && !isEditting) {
          gon = entity;

          // 生成编辑点
          for (let cartesian of gon.polygon.hierarchy._value) {
              let point = viewer.entities.add({
                  name: "gon_point",
                  position: cartesian,
                  point: {
                      color: Cesium.Color.WHITE,
                      pixelSize: 8,
                      outlineColor: Cesium.Color.BLACK,
                      outlineWidth: 1
                  }
              });
				 
			  // 保存点的ID以便删除
              this.pointsId.push(point.id);
          }
			
		  // 设置编辑状态为true 
          isEditting = true;
			
		  // 禁止地球旋转和缩放,地球的旋转会对鼠标移动监听有影响,所以需要禁止
          viewer.scene.screenSpaceCameraController.enableRotate = false;
          viewer.scene.screenSpaceCameraController.enableZoom = false;
          
      } else if (entity.name === "gon_point") {
      
      	  // 如果实体为编辑点,那么设置当前编辑点为该点
          currentPoint = entity;
      }
  }
}, Cesium.ScreenSpaceEventType.LEFT_DOWN);

创建鼠标移动的监听事件

// 对鼠标移动事件的监听
this.handler.setInputAction((event) => {

  // 如果处于编辑状态且编辑点已定义,那么开始拖拽编辑
  if (isEditting && currentPoint) {
  
      // 获取屏幕坐标,移动监听与点击有所不同,所以有起始位置和终点位置
      let windowPosition = event.startPosition;
      
      // 将屏幕坐标转为笛卡尔坐标
      let ellipsoid = viewer.scene.globe.ellipsoid;
      let cartesian = viewer.camera.pickEllipsoid(windowPosition, ellipsoid);
	   
	  // 如果点击到地球外,那么返回 
      if (!cartesian) {
          return;
      }
		
	  // 更新编辑点的位置
      currentPoint.position = cartesian;

	  // 创建面标每个点位置信息的数组,并循环赋值
      let points = [];

      for (let id of this.pointsId) {
          points.push(viewer.entities.getById(id).position._value);
      }
	  
	  // 更新面标的位置数组
      gon.polygon.hierarchy = new Cesium.CallbackProperty(() => {
          return points;
      }, false);
  }
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

创建鼠标抬起的监听事件

// 对鼠标抬起事件的监听
this.handler.setInputAction((event) => {
		
	  // 移除当前编辑点
	  currentPoint = undefined;
}, Cesium.ScreenSpaceEventType.LEFT_UP)

结束编辑

// 恢复地球的旋转和缩放
viewer.scene.screenSpaceCameraController.enableRotate = true;
viewer.scene.screenSpaceCameraController.enableZoom = true;

// 移除监听器
if (this.handler !== null && !this.handler.isDestroyed()) {
  this.handler.destroy();
}

// 移除编辑点,清空编辑点数组
for (let id of this.pointsId) {
  viewer.entities.removeById(id);
}

this.pointsId = [];

面的编辑

# 地球二三维切换

// 切换为三维
viewer.scene.morphTo3D({
    duration: Number // 切换花费的时间
});
// 切换为二维
viewer.scene.morphTo2D({
    duration: Number // 切换花费的时间
});

# 测量工具

测距测高在Cesium中有相关的接口用来计算,但是测面没有计算方法,这里是通过turf.js来计算,所以计算的是平面面积

# 测量距离

//距离测量类
export default class MeasureDistance {
    constructor(viewer) {
        this.viewer = viewer;
        this.initEvents();
        this.positions = [];
        this.tempPositions = [];
        this.vertexEntities = [];
        this.labelEntity = undefined;
        this.measureDistance = 0; //测量结果
    }

    //初始化事件
    initEvents() {
        this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
        this.MeasureStartEvent = new Cesium.Event(); //开始事件
        this.MeasureEndEvent = new Cesium.Event(); //结束事件        
    }

    //激活
    activate() {
        this.deactivate();
        this.registerEvents(); //注册鼠标事件  
        //设置鼠标状态 
        this.viewer.enableCursorStyle = false;
        this.viewer._element.style.cursor = 'default';
        this.isMeasure = true;
        this.measureDistance = 0;
    }

    //禁用
    deactivate() {
        if (!this.isMeasure) return;
        this.unRegisterEvents();
        this.viewer._element.style.cursor = 'pointer';
        this.viewer.enableCursorStyle = true;
        this.isMeasure = false;
        this.tempPositions = [];
        this.positions = [];
    }

    //清空绘制
    clear() {
        //清除线对象
        this.viewer.entities.remove(this.lineEntity);
        this.lineEntity = undefined;

        //清除节点
        this.vertexEntities.forEach(item => {
            this.viewer.entities.remove(item);
        });
        this.vertexEntities = [];
    }

    //创建线对象
    createLineEntity() {
        this.lineEntity = this.viewer.entities.add({
            polyline: {
                positions: new Cesium.CallbackProperty(e => {
                    return this.tempPositions;
                }, false),
                width: 2,
                material: Cesium.Color.YELLOW,
                depthFailMaterial: Cesium.Color.YELLOW
            }
        })
    }

    //创建线节点
    createVertex() {
        let vertexEntity = this.viewer.entities.add({
            position: this.positions[this.positions.length - 1],
            id: "MeasureDistanceVertex" + this.positions[this.positions.length - 1],
            type: "MeasureDistanceVertex",
            label: {
                text: spaceDistance(this.positions) + "米",
                scale: 0.5,
                font: 'normal 24px MicroSoft YaHei',
                distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 5000),
                scaleByDistance: new Cesium.NearFarScalar(1000, 1, 3000, 0.4),
                verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                pixelOffset: new Cesium.Cartesian2(0, -30),
                outlineWidth: 9,
                outlineColor: Cesium.Color.WHITE
            },
            point: {
                color: Cesium.Color.FUCHSIA,
                pixelSize: 8,
                disableDepthTestDistance: 500,
            },
        });
        this.vertexEntities.push(vertexEntity);
    }
 
    //创建起点
    createStartEntity() {
        let vertexEntity = this.viewer.entities.add({
            position: this.positions[0],
            type: "MeasureDistanceVertex",
            billboard: {
                image: "../../static/images/start.png",
                scaleByDistance: new Cesium.NearFarScalar(300, 1, 1200, 0.4), //设置随图缩放距离和比例
                distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 10000), //设置可见距离 10000米可见
                verticalOrigin: Cesium.VerticalOrigin.BOTTOM
            },
            point: {
                color: Cesium.Color.FUCHSIA,
                pixelSize: 6,
            },
        });
        this.vertexEntities.push(vertexEntity);
    }

    //创建终点节点
    createEndEntity() {
        //结束时删除最后一个节点的距离标识
        let lastLabel = this.viewer.entities.getById("MeasureDistanceVertex" + this.positions[this.positions.length - 1]);
        this.viewer.entities.remove(lastLabel);
        this.viewer.entities.remove(this.moveVertexEntity);

        let vertexEntity = this.viewer.entities.add({
            position: this.positions[this.positions.length - 1],
            type: "MeasureDistanceVertex",
            label: {
                text: "总距离:" + spaceDistance(this.positions) + "米",
                scale: 0.5,
                font: 'normal 26px MicroSoft YaHei',
                distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 5000),
                scaleByDistance: new Cesium.NearFarScalar(1000, 1, 3000, 0.4),
                verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                pixelOffset: new Cesium.Cartesian2(0, -50),
                outlineWidth: 9,
                outlineColor: Cesium.Color.WHITE,
                eyeOffset: new Cesium.Cartesian3(0, 0, -10)
            },
            billboard: {
                image: "../../static/images/end.png",
                scaleByDistance: new Cesium.NearFarScalar(300, 1, 1200, 0.4), //设置随图缩放距离和比例
                distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 10000), //设置可见距离 10000米可见
                verticalOrigin: Cesium.VerticalOrigin.BOTTOM
            },
            point: {
                color: Cesium.Color.FUCHSIA,
                pixelSize: 6,
            },
        });
        this.vertexEntities.push(vertexEntity);
    }

    //注册鼠标事件
    registerEvents() {
        this.leftClickEvent();
        this.rightClickEvent();
        this.mouseMoveEvent();
    }

    //左键点击事件
    leftClickEvent() {
        //单击鼠标左键画点点击事件
        this.handler.setInputAction(e => {
            this.viewer._element.style.cursor = 'default';
            let position = this.viewer.scene.pickPosition(e.position);
            if (!position) {
                const ellipsoid = this.viewer.scene.globe.ellipsoid;
                position = this.viewer.scene.camera.pickEllipsoid(e.position, ellipsoid);
            }
            if (!position) return;
            this.positions.push(position);
            if (this.positions.length == 1) { //首次点击  
                this.createLineEntity();
                this.createStartEntity();
                return;
            }
            this.createVertex();

        }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    }

    //鼠标移动事件
    mouseMoveEvent() {
        this.handler.setInputAction(e => {
            if (!this.isMeasure) return;
            this.viewer._element.style.cursor = 'default';
            let position = this.viewer.scene.pickPosition(e.endPosition);
            if (!position) {
                position = this.viewer.scene.camera.pickEllipsoid(e.startPosition, this.viewer.scene.globe.ellipsoid);
            }
            if (!position) return;
            this.handleMoveEvent(position);
        }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    }

    //处理鼠标移动
    handleMoveEvent(position) {
        if (this.positions.length < 1) return;
        this.tempPositions = this.positions.concat(position);
    }

    //右键事件
    rightClickEvent() {
        this.handler.setInputAction(e => {
            if (!this.isMeasure || this.positions.length < 1) {
                this.deactivate();
                this.clear();
            } else {
                this.createEndEntity();
                this.lineEntity.polyline = {
                    positions: this.positions,
                    width: 2,
                    material: Cesium.Color.YELLOW,
                    depthFailMaterial: Cesium.Color.YELLOW
                };
                this.measureEnd();
            }

        }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    }

    //测量结束
    measureEnd() {
        this.deactivate();
        this.MeasureEndEvent.raiseEvent(this.measureDistance); //触发结束事件 传入结果
    }

    //解除鼠标事件
    unRegisterEvents() {
        this.handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
        this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
        this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    }
}

# 测量高度

//高度测量类
export default class MeasureHeight {
    constructor(viewer) {
        this.viewer = viewer;
        this.initEvents();
        this.positions = [];
        this.vertexEntities = [];
        this.labelEntity = undefined;
        this.measureHeight = 0; //测量结果
    }

    //初始化事件
    initEvents() {
        this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
        this.MeasureStartEvent = new Cesium.Event(); //开始事件
        this.MeasureEndEvent = new Cesium.Event(); //结束事件        
    }

    //激活
    activate() {
        this.deactivate();
        this.registerEvents(); //注册鼠标事件  
        //设置鼠标状态 
        this.viewer.enableCursorStyle = false;
        this.viewer._element.style.cursor = 'default';
        this.isMeasure = true;
        this.circleRadius = 0.1;
        this.measureHeight = 0;
        this.positions = [];
    }

    //禁用
    deactivate() {
        if (!this.isMeasure) return;
        this.unRegisterEvents();
        this.viewer._element.style.cursor = 'pointer';
        this.viewer.enableCursorStyle = true;
        this.isMeasure = false;
    }

    //清空绘制
    clear() {
        //清除线对象
        this.viewer.entities.remove(this.lineEntity);
        this.lineEntity = undefined;

        //清除文本
        this.viewer.entities.remove(this.labelEntity);
        this.labelEntity = undefined;

        //移除圆
        this.removeCircleEntity();

        //清除节点
        this.vertexEntities.forEach(item => {
            this.viewer.entities.remove(item);
        });
        this.vertexEntities = [];
    }

    //创建线对象
    createLineEntity() {
        this.lineEntity = this.viewer.entities.add({
            polyline: {
                positions: new Cesium.CallbackProperty(e => {
                    return this.positions;
                }, false),
                width: 2,
                material: Cesium.Color.YELLOW,
                depthFailMaterial: new Cesium.PolylineDashMaterialProperty({
                    color: Cesium.Color.RED,
                }),
            }
        })
    }

    //创建结果文本标签
    createLabel() {
        this.labelEntity = this.viewer.entities.add({
            position: new Cesium.CallbackProperty(e => {
                return this.positions[this.positions.length - 1]; //返回最后一个点
            }, false),
            label: {
                text: "",
                scale: 0.5,
                font: 'normal 40px MicroSoft YaHei',
                distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 5000),
                scaleByDistance: new Cesium.NearFarScalar(500, 1, 1500, 0.4),
                verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                pixelOffset: new Cesium.Cartesian2(0, -30),
                outlineWidth: 9,
                outlineColor: Cesium.Color.WHITE
            }
        })
    }

    //创建线节点
    createVertex(index) {
        let vertexEntity = this.viewer.entities.add({
            position: new Cesium.CallbackProperty(e => {
                return this.positions[index];
            }, false),
            type: "MeasureHeightVertex",
            point: {
                color: Cesium.Color.FUCHSIA,
                pixelSize: 6,
                // disableDepthTestDistance: 2000,
            },
        });
        this.vertexEntities.push(vertexEntity);
    }

    //创建圆 这样方便看出水平面的高低
    createCircleEntitiy() {
        this.circleEntity = this.viewer.entities.add({
            position: new Cesium.CallbackProperty(e => {
                return this.positions[this.positions.length - 1]; //返回最后一个点
            }, false),
            ellipse: {
                height: new Cesium.CallbackProperty(e => {
                    return positionHeight(this.positions[this.positions.length - 1]);
                }, false),
                semiMinorAxis: new Cesium.CallbackProperty(e => {
                    return this.circleRadius;
                }, false),
                semiMajorAxis: new Cesium.CallbackProperty(e => {
                    return this.circleRadius;
                }, false),
                material: Cesium.Color.YELLOW.withAlpha(0.5),
            },
        });
    }

    //删除圆
    removeCircleEntity() {
        this.viewer.entities.remove(this.circleEntity);
        this.circleEntity = undefined;
    }

    //注册鼠标事件
    registerEvents() {
        this.leftClickEvent();
        this.rightClickEvent();
        this.mouseMoveEvent();
    }

    //左键点击事件
    leftClickEvent() {
        //单击鼠标左键画点点击事件
        this.handler.setInputAction(e => {
            this.viewer._element.style.cursor = 'default';
            let position = this.viewer.scene.pickPosition(e.position);
            if (!position) {
                const ellipsoid = this.viewer.scene.globe.ellipsoid;
                position = this.viewer.scene.camera.pickEllipsoid(e.position, ellipsoid);
            }
            if (!position) return;

            if (this.positions.length == 0) { //首次点击
                this.positions.push(position);
                this.createVertex(0);
                this.createLineEntity();
                this.createCircleEntitiy();
                this.createLabel();
            } else { //第二次点击结束测量
                this.measureEnd();
            }
        }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    }

    //鼠标移动事件
    mouseMoveEvent() {
        this.handler.setInputAction(e => {
            if (!this.isMeasure) return;
            this.viewer._element.style.cursor = 'default';
            let position = this.viewer.scene.pickPosition(e.endPosition);
            if (!position) {
                position = this.viewer.scene.camera.pickEllipsoid(e.startPosition, this.viewer.scene.globe.ellipsoid);
            }
            if (!position) return;
            this.handleMoveEvent(position);
        }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    }

    //处理鼠标移动
    handleMoveEvent(position) {
        if (this.positions.length < 1) return;
        let firstPoint = cartesian3Point3(this.positions[0]); //第一个点
        let movePoint = cartesian3Point3(position); //鼠标移动点
        const h = movePoint[2] - firstPoint[2];
        firstPoint[2] = movePoint[2];
        const twoPosition = Cesium.Cartesian3.fromDegrees(firstPoint[0], firstPoint[1], movePoint[2]);
        if (this.positions.length < 2) {
            this.positions.push(twoPosition);
            this.createVertex(1);
        } else {
            this.positions[1] = twoPosition;
            this.measureHeight = h.toFixed(3);
            this.labelEntity.label.text = "高度:" + this.measureHeight + " 米"
        }
        //计算圆的半径   
        this.circleRadius = getDistanceH(this.positions[0], position);
    }

    //右键事件
    rightClickEvent() {
        this.handler.setInputAction(e => {
            if (this.isMeasure) {
                this.deactivate();
                this.clear();
            }
        }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    }

    //测量结束
    measureEnd() {
        this.deactivate();
        this.MeasureEndEvent.raiseEvent(this.measureHeight); //触发结束事件 传入结果
    }

    //解除鼠标事件
    unRegisterEvents() {
        this.handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
        this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
        this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    }
}

# 测量面积

//面积测量类
export default class MeasureDistance {
    constructor(viewer) {
        this.viewer = viewer;
        this.initEvents();
        this.positions = [];
        this.tempPositions = [];
        this.vertexEntities = [];
        this.labelEntity = undefined;
        this.measureArea = 0; //测量结果
    }

    //初始化事件
    initEvents() {
        this.handler = new Cesium.ScreenSpaceEventHandler(this.viewer.scene.canvas);
        this.MeasureStartEvent = new Cesium.Event(); //开始事件
        this.MeasureEndEvent = new Cesium.Event(); //结束事件        
    }

    //激活
    activate() {
        this.deactivate();
        this.registerEvents(); //注册鼠标事件  
        //设置鼠标状态 
        this.viewer.enableCursorStyle = false;
        this.viewer._element.style.cursor = 'default';
        this.isMeasure = true;
        this.measureArea = 0;
    }

    //禁用
    deactivate() {
        if (!this.isMeasure) return;
        this.unRegisterEvents();
        this.viewer._element.style.cursor = 'pointer';
        this.viewer.enableCursorStyle = true;
        this.isMeasure = false;
        this.tempPositions = [];
        this.positions = [];
        this.height = undefined;
    }

    //清空绘制
    clear() {
        //清除线面对象
        this.viewer.entities.remove(this.polygonEntity);
        this.polygonEntity = undefined;

        //清除节点
        this.vertexEntities.forEach(item => {
            this.viewer.entities.remove(item);
        });
        this.vertexEntities = [];

        this.viewer.entities.remove(this.mesureResultEntity);
        this.mesureResultEntity = undefined;

        this.height = undefined;
    }

    //创建面对象
    createPolygonEntity() {
        this.polygonEntity = this.viewer.entities.add({
            polygon: {
                hierarchy: new Cesium.CallbackProperty(e => {
                    return new Cesium.PolygonHierarchy(this.tempPositions);
                    //使用最新1.72的时候 必须返回PolygonHierarchy类型 Cannot read property 'length' of undefined
                    //低版本好像都可以
                }, false),
                material: Cesium.Color.RED.withAlpha(0.4),
                perPositionHeight: true, //  
            },
            polyline: {
                positions: new Cesium.CallbackProperty(e => {
                    return this.tempPositions.concat(this.tempPositions[0]);
                }, false),
                width: 1,
                material: new Cesium.PolylineDashMaterialProperty({
                    color: Cesium.Color.YELLOW,
                }),
                depthFailMaterial: new Cesium.PolylineDashMaterialProperty({
                    color: Cesium.Color.YELLOW,
                }),
            }

        })
    }

    //创建节点
    createVertex() {
        let vertexEntity = this.viewer.entities.add({
            position: this.positions[this.positions.length - 1],
            type: "MeasureAreaVertex",
            point: {
                color: Cesium.Color.FUCHSIA,
                pixelSize: 8,
                disableDepthTestDistance: 500,
            },
        });
        this.vertexEntities.push(vertexEntity);
    }

    //测量结果标签
    createResultLabel() {
        this.mesureResultEntity = this.viewer.entities.add({
            position: new Cesium.CallbackProperty(e => {
                return this.getCenterPosition()
            }, false),
            type: "MeasureAreaResult",
            label: {
                text: new Cesium.CallbackProperty(e => {
                    return "面积" + computeArea(this.tempPositions) + "平方米";
                }, false),
                scale: 0.5,
                font: 'normal 28px MicroSoft YaHei',
                distanceDisplayCondition: new Cesium.DistanceDisplayCondition(0, 5000),
                scaleByDistance: new Cesium.NearFarScalar(1000, 1, 3000, 0.4),
                verticalOrigin: Cesium.VerticalOrigin.BOTTOM,
                style: Cesium.LabelStyle.FILL_AND_OUTLINE,
                pixelOffset: new Cesium.Cartesian2(0, -30),
                outlineWidth: 9,
                outlineColor: Cesium.Color.YELLOW
            },
        });

    }

    //获取节点的中心点
    getCenterPosition() {
        let points = [];
        if (this.tempPositions.length < 3) return this.tempPositions[0];
        this.tempPositions.forEach(position => {
            const point3d = this.cartesian3ToPoint3D(position);
            points.push([point3d.x, point3d.y]);
        })

        //构建turf.js  lineString
        let geo = turf.lineString(points);
        let bbox = turf.bbox(geo);
        let bboxPolygon = turf.bboxPolygon(bbox);
        let pointOnFeature = turf.center(bboxPolygon);
        let lonLat = pointOnFeature.geometry.coordinates;

        return Cesium.Cartesian3.fromDegrees(lonLat[0], lonLat[1], this.height + 0.3);
    }


    //注册鼠标事件
    registerEvents() {
        this.leftClickEvent();
        this.rightClickEvent();
        this.mouseMoveEvent();
    }

    //左键点击事件
    leftClickEvent() {
        //单击鼠标左键画点点击事件
        this.handler.setInputAction(e => {
            this.viewer._element.style.cursor = 'default';
            let position = this.viewer.scene.pickPosition(e.position);
            if (!position) {
                const ellipsoid = this.viewer.scene.globe.ellipsoid;
                position = this.viewer.scene.camera.pickEllipsoid(e.position, ellipsoid);
            }
            if (!position) return;
            this.positions.push(position);
            this.height = this.unifiedHeight(this.positions, this.height);
            if (this.positions.length == 1) { //首次点击  
                this.createPolygonEntity();
            }
            this.createVertex();

        }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
    }

    //鼠标移动事件
    mouseMoveEvent() {
        this.handler.setInputAction(e => {
            if (!this.isMeasure) return;
            this.viewer._element.style.cursor = 'default';
            let position = this.viewer.scene.pickPosition(e.endPosition);
            if (!position) {
                position = this.viewer.scene.camera.pickEllipsoid(e.startPosition, this.viewer.scene.globe.ellipsoid);
            }
            if (!position) return;
            this.handleMoveEvent(position);
        }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    }

    //处理鼠标移动
    handleMoveEvent(position) {
        if (this.positions.length < 1) return;

        this.height = this.unifiedHeight(this.positions, this.height);
        this.tempPositions = this.positions.concat(position);
        if (this.tempPositions.length >= 3 && !this.mesureResultEntity) {
            this.createResultLabel();
        }
    }

    //统一节点的高度
    unifiedHeight(positions, height) {
        if (!height) height = this.getPositionHeight(positions[0]); //如果没有指定高度 就用第一个的高度
        let point3d;
        for (let i = 0; i < positions.length; i++) {
            const element = positions[i];
            point3d = this.cartesian3ToPoint3D(element);
            positions[i] = Cesium.Cartesian3.fromDegrees(point3d.x, point3d.y, height)
        }

        return height;
    }

    //获取某个点的高度
    getPositionHeight(position) {
        const cartographic = Cesium.Cartographic.fromCartesian(position);
        return cartographic.height;
    }

    cartesian3ToPoint3D(position) {
        const cartographic = Cesium.Cartographic.fromCartesian(position);
        const lon = Cesium.Math.toDegrees(cartographic.longitude);
        const lat = Cesium.Math.toDegrees(cartographic.latitude);
        return { x: lon, y: lat, z: cartographic.height };
    }


    //右键事件
    rightClickEvent() {
        this.handler.setInputAction(e => {
            if (!this.isMeasure || this.positions.length < 3) {
                this.deactivate();
                this.clear();
            } else {
                this.tempPositions = [...this.positions];
                this.polygonEntity.polyline = {
                    positions: this.positions.concat(this.positions[0]),
                    width: 2,
                    material: Cesium.Color.YELLOW,
                    depthFailMaterial: new Cesium.PolylineDashMaterialProperty({
                        color: Cesium.Color.YELLOW,
                    }),
                };

                this.polygonEntity.polygon.hierarchy = new Cesium.PolygonHierarchy(this.tempPositions);
                this.mesureResultEntity.position = this.getCenterPosition();
                this.mesureResultEntity.label.text = "总面积" + computeArea(this.positions) + "平方米"
                this.measureEnd();
            }

        }, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
    }

    //测量结束
    measureEnd() {
        this.deactivate();
        this.MeasureEndEvent.raiseEvent(this.measureArea); //触发结束事件 传入结果
    }

    //解除鼠标事件
    unRegisterEvents() {
        this.handler.removeInputAction(Cesium.ScreenSpaceEventType.RIGHT_CLICK);
        this.handler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);
        this.handler.removeInputAction(Cesium.ScreenSpaceEventType.MOUSE_MOVE);
    }
}

# 两种添加 model 方法的区别

Cesium 中包含两种添加 model 的方法,分别为:

  • 通过 viewer.entities.add() 函数添加
  • 通过 viewer.scene.primitives.add() 函数添加,更底层一些

两种方法本质上是相通的,方法 1对方法 2在某种程度上进行了封装。

# 两种方法的区别

  • 方法 1通过指定 model 的 position 和 orientation 来控制模型的位置,对模型进行精确变换难度较大
    方法 2通过 modelMatrix 控制模型的位置和方向,可进行较为精确的模型变换
  • 对相机操作时
    方法1提供了较为方便的 viewer.trackedEntity 函数
    方法 2追踪 model 较为复杂,需要手动操作相机变换
  • 对模型进行缩放、变换等操作
    方法 1 需要修改 object.id(Entity 类型) 中 model(ModelGraphics 类型) 的 scale 和 nodeTransformations
    方法 2 可以直接修改 object.primitive(model 类型) 中的 scale 和 modelMatrix
  • Entity没有加载完成事件,而Primitive有加载完成事件
  • Entity只能加载一个对象,而Primitive可以一次加载多个对象
  • Entity类封装了很多个几何对象,非常方便的绘制出几何对象来,而如果使用Primitive的话你需要懂的知识不少,比如几何对象的构造

# 两种方法的相同

  • 构建的对象中还包含 ModelMesh 和 ModeNode,ModelMesh 中包含了模型的网格和材质,ModeNode 中包含了一个 transform,可以在运行时对模型进行动态变换,以实现自定义模型动画。
  • 分别使用方法 1和方法 2建立两个模型,然后对其进行点击操作,查看点击得到的物体。
    两种方法返回同样的对象:{id: object,mesh: ModelMesh,node: ModeNode,primitive: Model}
  • 从 Entity 获得 Model 的方法:
function getModelForEntity(entity) {
    var primitives = viewer.scene.primitives;
    for (var i = 0; i < primitives.length; i++) {
        var primitive = primitives.get(i);
        if (primitive instanceof Cesium.Model && primitive.id === entity) {
            return primitive;
        }
    }
};

# 示例代码











 
 
 
 
 
 
 
 
 
 



function createModel(url, height) {
    viewer.entities.removeAll();

    var position = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, height);
    var heading = Cesium.Math.toRadians(135);
    var pitch = 0;
    var roll = 0;
    var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
    var orientation = Cesium.Transforms.headingPitchRollQuaternion(position, hpr);

    var entity = viewer.entities.add({
        name : url,
        position : position,
        orientation : orientation,
        model : {
            uri : url,
            minimumPixelSize : 128,
            maximumScale : 20000
        }
    });
    viewer.trackedEntity = entity;
}











 
 
 
 
 






























function createModel(url, height, heading, pitch, roll) {
    height = Cesium.defaultValue(height, 0.0);
    heading = Cesium.defaultValue(heading, 0.0);
    pitch = Cesium.defaultValue(pitch, 0.0);
    roll = Cesium.defaultValue(roll, 0.0);
    var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);

    var origin = Cesium.Cartesian3.fromDegrees(-123.0744619, 44.0503706, height);
    var modelMatrix = Cesium.Transforms.headingPitchRollToFixedFrame(origin, hpr);

    scene.primitives.removeAll(); // Remove previous model
    model = scene.primitives.add(Cesium.Model.fromGltf({
        url : url,
        modelMatrix : modelMatrix,
        minimumPixelSize : 128
    }));

    model.readyPromise.then(function(model) {
        model.color = Cesium.Color.fromAlpha(getColor(viewModel.color),
		                                      Number(viewModel.alpha));
        model.colorBlendMode = getColorBlendMode(viewModel.colorBlendMode);
        model.colorBlendAmount = viewModel.colorBlendAmount;
        // Play and loop all animations at half-speed
        model.activeAnimations.addAll({
            speedup : 0.5,
            loop : Cesium.ModelAnimationLoop.REPEAT
        });

        var camera = viewer.camera;

        // Zoom to model
        var controller = scene.screenSpaceCameraController;
        var r = 2.0 * Math.max(model.boundingSphere.radius, camera.frustum.near);
        controller.minimumZoomDistance = r * 0.5;

        var center = Cesium.Matrix4.multiplyByPoint(model.modelMatrix, 
		                                            model.boundingSphere.center, 
													new Cesium.Cartesian3());
        var heading = Cesium.Math.toRadians(230.0);
        var pitch = Cesium.Math.toRadians(-20.0);
        camera.lookAt(center, new Cesium.HeadingPitchRange(heading, pitch, r * 2.0));
    }).otherwise(function(error){
        window.alert(error);
    });
}

# 清除实体和图形的方式

根据ID获取实体并清除

//id为添加实体时的id名称
let entID = viewer.entities.getById('id')
viewer.entities.remove(entID);

根据变量获取实体并清除

let box = viewer.entities.add({
	id:'box',
	position:Cesium.Cartesian3.fromDegrees(108, 34,0)
})
view.entities.remove(box)

删除所有实体

viewer.entities.removeAll()

创建primitive对象并销毁

let react = scene.primitives.add(new Cesium.RectanglePrimitive({
    //绘制矩形
    rectangle : Cesium.Rectangle.fromDegrees(-100.0, 20.0, -90.0, 30.0),
    material : Cesium.Material.fromType('Dot')  //设置材质
}));
//根据变量销毁
react.destroy()

//销毁所有
scene.primitives.removeall(),//谨慎使用,可能删除不必要的primitive

# 获取地形的高度

# 区域地形的最低点和最高点

Cesium.ApproximateTerrainHeights.initialize()
Cesium.ApproximateTerrainHeights.getMinimumMaximumHeights(
                                   Cesium.Rectangle.fromDegrees(110,30,110.5,30.04)
								 )

# 获取地形的高度

不要再使用网上的globe的方法了,现在Cesium已经有两种方法可以获取到地形的高度了,分别为:

  • sampleTerrain:获取非精确的地形的高度
var terrainProvider = Cesium.createWorldTerrain();
var positions = [
    Cesium.Cartographic.fromDegrees(86.925145, 27.988257),
    Cesium.Cartographic.fromDegrees(87.0, 28.0)
];
var promise = Cesium.sampleTerrain(terrainProvider, 11, positions);
Cesium.when(promise, function(updatedPositions) {
    // positions[0].height and positions[1].height have been updated.
    // updatedPositions is just a reference to positions.
});
  • sampleTerrainMostDetailed:获取尽量精确的地形的高度
// Query the terrain height of two Cartographic positions
var terrainProvider = Cesium.createWorldTerrain();
var positions = [
    Cesium.Cartographic.fromDegrees(86.925145, 27.988257),
    Cesium.Cartographic.fromDegrees(87.0, 28.0)
];
var promise = Cesium.sampleTerrainMostDetailed(terrainProvider, positions);
Cesium.when(promise, function(updatedPositions) {
    // positions[0].height and positions[1].height have been updated.
    // updatedPositions is just a reference to positions.
});

# 获取当前视图范围

getPickRay这个方法能够通过屏幕坐标转换成经纬度坐标。屏幕坐标的话,我们可以通过div位置来获取,这样屏幕的左上角坐标和右下角坐标是可以很容易获取到的。

var pt1 = new Cesium.Cartesian2(0,0);
var pt2= new Cesium.Cartesian2(500,500);
 
var pick1= viewer.scene.globe.pick(viewer.camera.getPickRay(pt1), viewer.scene);
var pick2= viewer.scene.globe.pick(viewer.camera.getPickRay(pt2), viewer.scene);
 
//将三维坐标转成地理坐标
var geoPt1= viewer.scene.globe.ellipsoid.cartesianToCartographic(pick1);
var geoPt2= viewer.scene.globe.ellipsoid.cartesianToCartographic(pick2);
 
//地理坐标转换为经纬度坐标
var point1=[geoPt1.longitude / Math.PI * 180,geoPt1.latitude / Math.PI * 180];
var point2=[geoPt2.longitude / Math.PI * 180,geoPt2.latitude / Math.PI * 180];

# 贴地处理

# 实体的贴地处理

实体类型的贴地处理,是设置heightReference属性为CLAMP_TO_GROUND值

let entity = new Cesium.Entity({
  name: '点',
  show: true,
  position: Cesium.Cartesian3.fromDegrees(positions[0], positions[1], positions[2]),
  point: new Cesium.PointGraphics ( {
      show : true,
      pixelSize : 10,
	  //设置HeightReference高度参考类型为CLAMP_TO_GROUND贴地类型
      heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,  
      color : new Cesium.Color ( 255 , 255 , 0 , 1 ),
  } )
});

对于面图层,不设置面的height:0属性,面状数据设置贴地后,边线的数据就不能显示了,需要单独添加边线数据

var geojson = {
  "type": "FeatureCollection",
  "features": [
	{
	  "type": "Feature",
	  "properties": {},
	  "geometry": {
		"type": "Polygon",
		"coordinates": [
		  [
			[
			  93.6474609375,
			  37.10776507118514
			],
			[
			  93.01025390625,
			  35.17380831799959
			],
			[
			  95.11962890625,
			  33.54139466898275
			],
			[
			  97.53662109375,
			  33.54139466898275
			],
			[
			  99.25048828124999,
			  33.96158628979907
			],
			[
			  99.97558593749999,
			  35.191766965947394
			],
			[
			  99.84374999999999,
			  36.38591277287651
			],
			[
			  98.85498046875,
			  37.45741810262938
			],
			[
			  97.18505859374999,
			  37.90953361677018
			],
			[
			  95.16357421875,
			  37.82280243352756
			],
			[
			  93.6474609375,
			  37.10776507118514
			]
		  ]
		]
	  }
	}
  ]
}
var promise = Cesium.GeoJsonDataSource.load(geojson,
{
  camera : viewer.scene.camera,
  canvas : viewer.scene.canvas,
  clampToGround: true//开启贴地
}
);
promise.then(function (dataSource) {
//Get the array of entities
var entities = dataSource.entities.values;
entities.forEach((entitie) => {
  //必须要设置高度边线才有用,可是设置了高度之后贴地就没了
  //entitie.polygon.height = 50;
  entitie.polygon.outline = true;
  entitie.polygon.outlineColor = Cesium.Color.AQUA;
  entitie.polygon.outlineWidth = 50;
  entitie.polygon.closeTop = false;
  //单独设置线条样式
  var positions = entitie.polygon.hierarchy._value.positions;
  entitie.polyline = {
	positions: positions,
	width: 10,
	material: Cesium.Color.BLACK.withAlpha(1),
	clampToGround: true
  }
  viewer.entities.add(entitie);
})
})

# geojson数据

在加载的时候设置clampToGround属性为true

const res = Cesium.GeoJsonDataSource.load("./china.geojson",{
	clampToGround: true,
})

# polyline

设置clampToGround属性为true

const point = viewer.entities.add({
  name: "polyline",
  polyline: {
    positions: Cesium.Cartesian3.fromDegreesArray(arr),
    width: 1,
    material: new Cesium.Color(222/255, 216/255, 192/255, 1),
    clampToGround: true,
  },
});

# kml数据

在加载kml文件时,有的文件,线可以贴地,有的不能贴地,后来通过分析,主要原因是原始的kml文件中设置了贴地,在cesium中才贴地,否则在cesium中设置clampToGround: true也无法实现贴地

  • kml中原始贴地格式如下:tessellate 标签为1时贴地,没有设置贴地一般就没有tessellate这个标签

kml数据

  • cesium中加载kml(主要包含为线和点)
var options = {
	camera: viewer.scene.camera,
	canvas: viewer.scene.canvas,`在这里插入代码片`
	clampToGround: true, //开启贴地
};
var kmlx=viewer.dataSources.add(Cesium.KmlDataSource.load(url, options));
kmlx.then(function (dataSource) {
	viewer.flyTo(kmlx);
    var entities = dataSource.entities.values;
	for (var i = 0; i < entities.length; i++) {
		var entity = entities[i];
	    //只对_billboard进行设置。
		if (entity._billboard) {
			//去掉地形遮挡
			entity._billboard.disableDepthTestDistance = Number.POSITIVE_INFINITY; 
			//设置贴地
			entity.billboard.heightReference=Cesium.HeightReference.CLAMP_TO_GROUND;
			//设置文字标签,没有颜色(白色在cesium中非常不好看)替换成红色			
			entity._label.pixelOffset = new Cesium.Cartesian2(10, -20);
			if ("undefined" === typeof (entity._label.fillColor)) {
				entity._label.fillColor = Cesium.Color.RED;
			}//if
	   	}//if
	}
});

以上//只对_billboard进行设置。当为线时,设置entity.polyline.clampToGround=true可能出现错误,经过测试当发现当kml文件有标签时,是能这样设置贴地;当不存在,线就没这个属性,不能设置,就会导致出错。

  • 解决办法
    • 第一种解决办法是:修改kml文件,在线的标签后添加1
    • 第二种解决办法是修改cesium.js,就是kml加载时,不管kml中有没有标签都设置成贴地;具体如下:
      • 打开cesium.js查找 tessellate字符串
      • 在该字符串后面找到如下代码:else if(t._clampToGround&&!f&&p) 去掉后面的 &&p 保存
      • 就是当cesium中设置了clampToGround,kml无论是否设置了贴地,在加载时都实现贴地
      • 字符P是不同的

# 鼠标事件监听

在Cesium里面,我们可以通过Cesium.ScreenSpaceEventHandler的实例化对象的setInputAction方法绑定鼠标事件:

//添加鼠标点击事件
var handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
//监听触发的事件
handler.setInputAction(function(event) {
   var feature = viewer.scene.pick(event.position);
       //选中某模型
       if (feature && feature instanceof Cesium.Cesium3DTileFeature) {
           console.log(feature);
       }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

// 移除事件
viewer.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);

setInputAction的第一个参数是当事件触发时的回调,第二个参数是绑定的事件类型,,event中的位置格式是平面坐标

  • 鼠标左键双击事件:Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK
  • 鼠标左键按下事件:Cesium.ScreenSpaceEventType.LEFT_DOWN
  • 鼠标左键抬起事件:Cesium.ScreenSpaceEventType.LEFT_UP
  • 鼠标中键单击事​​件:Cesium.ScreenSpaceEventType.MIDDLE_CLICK
  • 鼠标中键按下事件:Cesium.ScreenSpaceEventType.MIDDLE_DOWN
  • 鼠标中键抬起事件:Cesium.ScreenSpaceEventType.MIDDLE_UP
  • 鼠标移动事件:Cesium.ScreenSpaceEventType.MOUSE_MOVE
  • 触摸表面上的双指事件的结束:Cesium.ScreenSpaceEventType.PINCH_END
  • 触摸表面上双指移动事件:Cesium.ScreenSpaceEventType.PINCH_MOVE
  • 触摸表面上双指事件的开始:Cesium.ScreenSpaceEventType.PINCH_START
  • 鼠标右键单击事件:Cesium.ScreenSpaceEventType.RIGHT_CLICK
  • 鼠标右键按下事件:Cesium.ScreenSpaceEventType.RIGHT_DOWN
  • 鼠标滚轮事件:Cesium.ScreenSpaceEventType.WHEEL
viewer.selectedEntityChanged.addEventListener
// 点击左键时,若点击的实体产生变化才会调用
viewer.selectedEntityChanged.addEventListener(entity => {
    console.log(entity);
})

// 开启抗锯齿
viewer.scene.postProcessStages.fxaa.enabled = true;
// 取消默认的左键双击事件
viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);

# 去掉entity的点击事件

//双击
viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_DOUBLE_CLICK);
//单击
viewer.cesiumWidget.screenSpaceEventHandler.removeInputAction(Cesium.ScreenSpaceEventType.LEFT_CLICK);

# 四种点击拾取方法

# viewer.scene.pick()

通过坐标位置拾取实体(Entity)、图元(Primitive)、3DTiles对象,返回scene中指定位置最上层的对象。例如点击获取Entity对象,通过pick.id可以拾取当前的entity对象。拾取后可以用于改变对象的属性参数。

//处理用户输入事件
let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
// 设置左键点击事件
handler.setInputAction(function (event) {
  // 获取 pick 拾取对象
  let pick = viewer.scene.pick(event.position); 
  // 判断是否获取到了对象
  if (Cesium.defined(pick)) {
	// 修改拾取到的entity的样式
    pick.id.billboard.image = "......"          
  }
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

//drillPick 返回拾取到的图元对象集合,图元列表按其在场景中的视觉顺序(从前到后)排序
var pickedObjects = scene.drillPick(new Cesium.Cartesian2(100.0, 200.0));

注意

  • 只能获取一个对象,并且是最顶部的对象。如果拾取点没有对象,则会返回undefined
  • 拾取半透明图元的位置时需要开启:viewer.scene.pickTranslucentDepth = true

# viewer.scene.globe.pick()

返回一个射线(ray)和地球表面的一个交点的Cartesian3坐标。此方法一般用于获取加载地形后的经纬度和高程,不包括模型、倾斜摄影等表面高度。

let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function (event) {
    let ray = viewer.camera.getPickRay(event.position);//获取一条射线
    let position = viewer.scene.globe.pick(ray, viewer.scene);
    console.log("当前拾取的坐标:", position);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

注意

最好开启深度检测:viewer.scene.globe.depthTestAgainstTerrain = true

# viewer.scene.camera.pickEllipsoid()

返回相机视角下鼠标点击的对应椭球面位置。接收屏幕坐标,返回Cartesian3坐标。适用裸球表面的选取,是基于数学模型的椭圆球体。

let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function (event) {
	let ellipsoid = viewer.scene.globe.ellipsoid;
    let position = viewer.scene.camera.pickEllipsoid(event.position, ellipsoid);
    console.log("点击拾取的坐标:", position);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

注意

在有地形的情况下误差较大,在使用时需要关闭深度测试

# viewer.scene.pickPosition()

拾取对应位置的Cartesian3,适用于模型表面位置的选取,拾取三维物体的坐标等。

let handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function (event) {
     let position = viewer.scene.pickPosition(event.position);
     console.log("获取到的坐标:", positionposition);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

TIP

一定开启深度检测:viewer.scene.globe.depthTestAgainstTerrain = true
否则在没有没有3dTile模型的情况下,会出现空间坐标不准的问题

# 倾斜模型单体化

倾斜模型分层单体化需要数据结合代码来实现,数据生产需要采集每层的面坐标串、底部高程、层高、顶部高度等信息。有了数据后在Cesium中通过ClassificationPrimitive渲染出来。

 //创建拉伸的多边形对象
createExtrudedPolygon(id, polygonGeometry) {
	return this.viewer.scene.primitives.add(
		new Cesium.ClassificationPrimitive({
			geometryInstances: new Cesium.GeometryInstance({
				geometry: Cesium.PolygonGeometry.createGeometry(polygonGeometry),
				attributes: {
					color: Cesium.ColorGeometryInstanceAttribute.fromColor(
						Cesium.Color.fromRandom({ alpha: 0.8 })
					),
					show: new Cesium.ShowGeometryInstanceAttribute(true),
				},
				id: id, //设置id有效 其他属性无效
			}),
			classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
		})
	);
},

# 加载影像

# 默认类型

imageryProvider:默认createWorldImagery()

# 其他类型

  • ArcGisMapServerImageryProvider
  • BingMapsImageryProvider
  • OpenStreetMapImageryProvider
  • TileMapServiceImageryProvider
  • GoogleEarthEnterpriseImageryProvider:谷歌企业版
  • GoogleEarthEnterpriseMapsProvider
  • GridImageryProvider
  • IonImageryProvider
  • MapboxImageryProvider
  • MapboxStyleImageryProvider
  • SingleTileImageryProvider
  • TileCoordinatesImageryProvider
  • UrlTemplateImageryProvider:URL模板
  • WebMapServiceImageryProvider
  • WebMapTileServiceImageryProvider

# 示例代码

//加载ArcGIS卫星图
tdtLayer = new Cesium.ArcGisMapServerImageryProvider({
	url: 'https://services.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer'
})
viewer.imageryLayers.addImageryProvider(tdtLayer)
//加载ArcGIS街道图
var tdtLayer = new Cesium.ArcGisMapServerImageryProvider({
	url: "http://services.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"
})
viewer.imageryLayers.addImageryProvider(tdtLayer)
//加载ArcGIS蓝色图
var tdtLayer = new Cesium.UrlTemplateImageryProvider({
	url: "https://map.geoq.cn/arcgis/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}"
})
viewer.imageryLayers.addImageryProvider(tdtLayer)

//高德矢量图
let tdtLayer = new Cesium.UrlTemplateImageryProvider({
	url: "http://webrd02.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=8&x={x}&y={y}&z={z}",
	minimumLevel: 3,
	maximumLevel: 18
})
viewer.imageryLayers.addImageryProvider(tdtLayer)

//高德影像
let tdtLayer = new Cesium.UrlTemplateImageryProvider({
	url: "https://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}",
	minimumLevel: 3,
	maximumLevel: 18
})
viewer.imageryLayers.addImageryProvider(tdtLayer)

//高德路网中文注记
let tdtLayer = new Cesium.UrlTemplateImageryProvider({
	url: "http://webst02.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scale=1&style=8",
	minimumLevel: 3,
	maximumLevel: 18
})
viewer.imageryLayers.addImageryProvider(tdtLayer)


//天地图矢量地图
this.viewer.imageryLayers.addImageryProvider(
	new Cesium.WebMapTileServiceImageryProvider({
		url: "http://{s}.tianditu.gov.cn/vec_c/wmts?service=wmts&request=GetTile&version=1.0.0" +
			"&LAYER=vec&tileMatrixSet=c&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}" +
			"&style=default&format=tiles&tk=天地图的TOKEN",
		layer: "tdtCva",
		style: "default",
		format: "tiles",
		tileMatrixSetID: "c",
		subdomains: ["t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7"],
		tilingScheme: new Cesium.GeographicTilingScheme(),
		tileMatrixLabels: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19"],
		maximumLevel: 18
	})
)
//天地图影像地图
this.viewer.imageryLayers.addImageryProvider(
	new Cesium.WebMapTileServiceImageryProvider({
		url: "http://{s}.tianditu.gov.cn/img_c/wmts?service=wmts&request=GetTile&version=1.0.0" +
			"&LAYER=img&tileMatrixSet=c&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}" +
			"&style=default&format=tiles&tk=天地图的TOKEN",
		layer: "tdtCva",
		style: "default",
		format: "tiles",
		tileMatrixSetID: "c",
		subdomains: ["t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7"],
		tilingScheme: new Cesium.GeographicTilingScheme(),
		tileMatrixLabels: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19"],
		maximumLevel: 18
	})
)
//天地图栅格地图
this.viewer.imageryLayers.addImageryProvider(
	new Cesium.WebMapTileServiceImageryProvider({
		url: "http://{s}.tianditu.gov.cn/ter_c/wmts?service=wmts&request=GetTile&version=1.0.0" +
			"&LAYER=ter&tileMatrixSet=c&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}" +
			"&style=default&format=tiles&tk=天地图的TOKEN",
		layer: "tdtCva",
		style: "default",
		format: "tiles",
		tileMatrixSetID: "c",
		subdomains: ["t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7"],
		tilingScheme: new Cesium.GeographicTilingScheme(),
		tileMatrixLabels: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19"],
		maximumLevel: 18
	})
)
//天地图标记地图
this.viewer.imageryLayers.addImageryProvider(
	new Cesium.WebMapTileServiceImageryProvider({
		url: "http://{s}.tianditu.gov.cn/cia_c/wmts?service=wmts&request=GetTile&version=1.0.0" +
			"&LAYER=cia&tileMatrixSet=c&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}" +
			"&style=default&format=tiles&tk=天地图的TOKEN",
		layer: "tdtCva",
		style: "default",
		format: "tiles",
		tileMatrixSetID: "c",
		subdomains: ["t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7"],
		tilingScheme: new Cesium.GeographicTilingScheme(),
		tileMatrixLabels: ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19"],
		maximumLevel: 18
	})
)
		
//载Mapbox地图
loadMapboxVectorMap () {
  this.vectorMap = this.viewer.imageryLayers.addImageryProvider(
    new Cesium.MapboxStyleImageryProvider({
      url: 'https://api.mapbox.com/styles/v1',
      username: '注册的账号名称',
      styleId: '自定义地图时获取的styleId',
      accessToken: '自定义地图时获取的AccessToken',
	  scaleFactor:true
    })
  )
  this.vectorMap.title = 'mapboxVectorMap'
  this.vectorMap.show = true
}

# 加载地形

# 默认类型

terrainProvider:new EllipsoidTerrainProvider() 没有地形高程,主要是个椭球体

# 其他类型

ArcGISTiledElevationTerrainProvider
CustomHeightmapTerrainProvider
EllipsoidTerrainProvider
CesiumTerrainProvider
VRTheWorldTerrainProvider
GoogleEarthEnterpriseTerrainProvider

# 示例代码

var viewer = new Cesium.Viewer('cesiumContainer', {
    terrainProvider : new Cesium.CesiumTerrainProvider({
        url : Cesium.IonResource.fromAssetId(3956),
        requestVertexNormals : true
    })
});
//加载全球地形图
var viewer = new Cesium.Viewer('cesiumContainer', {
    terrainProvider : Cesium.createWorldTerrain({
        requestWaterMask : true, // 请求水波纹效果
        requestVertexNormals : true // 请求照明
    });
});

# 设置camera视角

# setView

//setView
view.camera.setView({
  destination : Cesium.Cartesian3.fromDegrees(116.435314,39.960521, 15000.0), // 设置位置
  orientation: {
    heading : Cesium.Math.toRadians(20.0), // 方向
    pitch : Cesium.Math.toRadians(-90.0),// 倾斜角度
    roll : 0
  }
});

//rectangle 方式
view.camera.setView({
	destination: Cesium.Rectangle.fromDegrees(0.0, 20.0, 10.0, 30.0),
	orientation: {
		heading : Cesium.Math.toRadians(20.0), // 方向
		pitch : Cesium.Math.toRadians(-90.0),// 倾斜角度
		roll : 0
	} 
});

# flyto

view.camera.flyTo({
  destination :Cesium.Cartesian3.fromDegrees(116.435314,39.960521, 15000.0), // 设置位置
  orientation: {
    heading :Cesium.Math.toRadians(20.0), // 方向
    pitch :Cesium.Math.toRadians(-90.0),// 倾斜角度
    roll :0
  },
  duration:5, // 设置飞行持续时间,默认会根据距离来计算
  complete:function () {
     // 到达位置后执行的回调函数
  },
  cancle:function () {
     // 如果取消飞行则会调用此函数
  },
  pitchAdjustHeight:-90, // 如果摄像机飞越高于该值,则调整俯仰俯仰的俯仰角度,并将地球保持在视口中。
  maximumHeight:5000, // 相机最大飞行高度
  flyOverLongitude:100, // 如果到达目的地有2种方式,设置具体值后会强制选择方向飞过这个经度(这个,很好用)
});

# lookAt

var center = Cesium.Cartesian3.fromDegrees(114.44455, 22.0444);//camera视野的中心点坐标
var heading = Cesium.Math.toRadians(50.0);
var pitch = Cesium.Math.toRadians(-20.0);
var range = 5000.0;
view.camera.lookAt(center, new Cesium.HeadingPitchRange(heading, pitch, range));

# 加载3DTiles

var tileset = new Cesium.Cesium3DTileset({
  url: 'Data/yudingshan/3dtiles/tileset.json',
  //classificationType: Cesium.ClassificationType.CESIUM_3D_TILE,
});
// tileset.style = new Cesium.Cesium3DTileStyle({
//   color: "rgba(255, 0, 0, 0.5)",
// });
tileset.readyPromise.then(function (tileset) {
	viewer.scene.primitives.add(tileset);
	viewer.zoomTo(tileset, new Cesium.HeadingPitchRange(45, -0.5, tileset.boundingSphere.radius * 1.0));
	changeHeight(0);
}).otherwise(function (error) {
	console.log(error);
});
function changeHeight(height) {
	height = Number(height);
	if (isNaN(height)) {
		return;
	}
	var cartographic = Cesium.Cartographic.fromCartesian(tileset.boundingSphere.center);
	var surface = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, cartographic.height);
	var offset = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude,height);
	var translation = Cesium.Cartesian3.subtract(offset, surface, new Cesium.Cartesian3());
	tileset.modelMatrix = Cesium.Matrix4.fromTranslation(translation);
}

# 加载KML

 // 加载kml数据,更改description信息,多了黄色的标签里面包含的
 var kmlOptions = {
	 camera : viewer.scene.camera,
	 canvas : viewer.scene.canvas,
	 clampToGround : true
 };
 // Load geocache points of interest from a KML file
 // Data from : http://catalog.opendata.city/dataset/pediacities-nyc-neighborhoods/resource/91778048-3c58-449c-a3f9-365ed203e914
 var geocachePromise = Cesium.KmlDataSource.load('/Assets/SampleData/sampleGeocacheLocations.kml', kmlOptions);

 // Add geocache billboard entities to scene and style them
 geocachePromise.then(function(dataSource) {
    // Add the new data as entities to the viewer
    viewer.dataSources.add(dataSource);
    // Get the array of entities
    var geocacheEntities = dataSource.entities.values;
	for (var i = 0; i < geocacheEntities.length; i++) {
		var entity = geocacheEntities[i];
		if (Cesium.defined(entity.billboard)) {
			// Adjust the vertical origin so pins sit on terrain
			entity.billboard.verticalOrigin = Cesium.VerticalOrigin.BOTTOM;
			// Disable the labels to reduce clutter
			entity.label = undefined;
			// Add distance display condition
			entity.billboard.distanceDisplayCondition = new Cesium.DistanceDisplayCondition(10.0, 20000.0);
			// Compute latitude and longitude in degrees
			var cartographicPosition = Cesium.Cartographic.fromCartesian(entity.position.getValue(Cesium.JulianDate.now()));
			var latitude = Cesium.Math.toDegrees(cartographicPosition.latitude);
			var longitude = Cesium.Math.toDegrees(cartographicPosition.longitude);

			// Modify description(将信息添加到description描述信息中,我们这里只添加经纬度)
			var description = '<table class="cesium-infoBox-defaultTable cesium-infoBox-defaultTable-lighter"><tbody>' +
			'<tr><th>' + "Longitude" + '</th><td>' + longitude.toFixed(5) + '</td></tr>' +
			'<tr><th>' + "Latitude" + '</th><td>' + latitude.toFixed(5) + '</td></tr>' +
			'</tbody></table>';
			entity.description = description;
		}
	}
});

# 加载CZML

// path and drone
// Load a drone flight path from a CZML file
var dronePromise = Cesium.CzmlDataSource.load('./assets/SampleData/SampleFlight.czml');

// Save a new drone model entity
var drone;
dronePromise.then(function(dataSource) {
	viewer.dataSources.add(dataSource);
	// Get the entity using the id defined in the CZML data
	drone = dataSource.entities.getById('Aircraft/Aircraft1');
	// Attach a 3D model
	drone.model = {
		uri : './assets/SampleData/Models/CesiumDrone.gltf',
		minimumPixelSize : 128,
		maximumScale : 1000,
		silhouetteColor : Cesium.Color.WHITE,
		silhouetteSize : 2
	};
	// Add computed orientation based on sampled positions
	drone.orientation = new Cesium.VelocityOrientationProperty(drone.position);

	// Smooth path interpolation
	drone.position.setInterpolationOptions({
		interpolationAlgorithm : Cesium.HermitePolynomialApproximation,
		interpolationDegree : 2
	});
	drone.viewFrom = new Cesium.Cartesian3(0, -30, 30);

	viewer.trackedEntity = drone;/镜头跟随
});

# 加载服务

<!DOCTYPE html>
<html lang="en">
<head>
    <!-- Use correct character set. -->
    <meta charset="utf-8"/>
    <!-- Tell IE to use the latest, best version. -->
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <!-- Make the application on mobile take up the full browser screen and disable user scaling. -->
    <meta
            name="viewport"
            content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no"
    />
    <title>Cesium 加载天地图示例</title>
    <script src="./Cesium.js"></script>
    <script src="http://www.openlayers.vip/examples/resources/jquery-3.5.1.min.js"></script>
    <style>
        @import url(./Widgets/widgets.css);

        html,
        body,
        #cesiumContainer {
            width: 100%;
            height: 100%;
            margin: 0;
            padding: 0;
            overflow: hidden;
        }
    </style>
    <script>
        var _hmt = _hmt || [];
        (function () {
            var hm = document.createElement("script");
            hm.src = "https://hm.baidu.com/hm.js?f80a36f14f8a73bb0f82e0fdbcee3058";
            var s = document.getElementsByTagName("script")[0];
            s.parentNode.insertBefore(hm, s);
        })();
    </script>
</head>
<body>
<button id="wmts" onClick="WMTS()">添加标准 WMTS 图层</button>
<button id="restWMTS" onClick="restWMTS()">添加 Geoserver Rest WMTS 图层</button>

<br/>
<br/>
<button id="wms" onClick="WMS()">添加 Geoserver WMS 图层</button>
<button id="wfs" onClick="WFS()">添加 Geoserver WFS 图层</button>
<button id="kml" onClick="KML()">添加 Geoserver KML 图层</button>
<div id="cesiumContainer"></div>
<script>
    // 这个 tk 只能在本域名下使用
    var token = '2b7cbf61123cbe4e9ec6267a87e7442f';
    // 服务域名
    var tdtUrl = 'https://t{s}.tianditu.gov.cn/';
    // 服务负载子域
    var subdomains = ['0', '1', '2', '3', '4', '5', '6', '7'];
    var viewer = new Cesium.Viewer('cesiumContainer', {
        shouldAnimate: true,
        selectionIndicator: true,
        animation: false,       //动画
        homeButton: false,       //home键
        geocoder: false,         //地址编码
        baseLayerPicker: false, //图层选择控件
        timeline: false,        //时间轴
        fullscreenButton: false, //全屏显示
        infoBox: false,         //点击要素之后浮窗
        sceneModePicker: false,  //投影方式  三维/二维
        navigationInstructionsInitiallyVisible: false, //导航指令
        navigationHelpButton: false,     //帮助信息
        selectionIndicator: false, // 选择
        imageryProvider: new window.Cesium.WebMapTileServiceImageryProvider({
            //影像底图
            url: "http://t{s}.tianditu.com/img_w/wmts?service=wmts&request=GetTile&version=1.0.0&LAYER=img&tileMatrixSet=w&TileMatrix={TileMatrix}&TileRow={TileRow}&TileCol={TileCol}&style=default&format=tiles&tk=" + token,
            subdomains: subdomains,
            layer: "tdtImgLayer",
            style: "default",
            format: "image/jpeg",
            tileMatrixSetID: "GoogleMapsCompatible",//使用谷歌的瓦片切片方式
            show: true
        })
    });

    viewer.imageryLayers.addImageryProvider(new window.Cesium.WebMapTileServiceImageryProvider({
        //影像注记
        url: "http://t{s}.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.jpg&tk=" + token,
        subdomains: subdomains,
        layer: "tdtCiaLayer",
        style: "default",
        format: "image/jpeg",
        tileMatrixSetID: "GoogleMapsCompatible",
        show: true
    }));

    // // 叠加国界服务
    var iboMap = new window.Cesium.UrlTemplateImageryProvider({
        url: tdtUrl + 'DataServer?T=ibo_w&x={x}&y={y}&l={z}&tk=' + token,
        subdomains: subdomains,
        tilingScheme: new window.Cesium.WebMercatorTilingScheme(),
        maximumLevel: 10
    });

    viewer.imageryLayers.addImageryProvider(iboMap);

    // geoserver叠加参数,EPSG码+图层等级
    const TileMatrixLabels = ['EPSG:900913:0', 'EPSG:900913:1', 'EPSG:900913:2',
        'EPSG:900913:3', 'EPSG:900913:4', 'EPSG:900913:5', 'EPSG:900913:6',
        'EPSG:900913:7', 'EPSG:900913:8', 'EPSG:900913:9', 'EPSG:900913:10',
        'EPSG:900913:11', 'EPSG:900913:12', 'EPSG:900913:13', 'EPSG:900913:14',
        'EPSG:900913:15', 'EPSG:900913:16', 'EPSG:900913:17', 'EPSG:900913:18'];

    // WMTS图层对象
    let layerWMTS;

    // 标准 WMTS 方式叠加
    function WMTS(layerName) {

        // cesium加载
        // 注意:所有参数必填
        layerWMTS = layerWMTS || viewer.imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({
            url: 'http://openlayers.vip/geoserver/gwc/service/wmts',
            layer: layerName || 'cite:xintai18',
            // 强调一下,参数必填,很多博客忽略,导致不能加载成功!
            style: 'raster',
            format: 'image/png',
            tileMatrixSetID: 'EPSG:900913',
            tileMatrixLabels: TileMatrixLabels
        }));

        // 调节图层显隐
        layerWMTSRest && (layerWMTSRest.show = false);
        layerWMTS && (layerWMTS.show = true);

        // 定位
        flyToRectangle();
    }

    // WMTSRest图层
    let layerWMTSRest;

    // Rest 方式叠加图层
    function restWMTS() {

        //cesium加载
        layerWMTSRest = layerWMTSRest || viewer.imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({
            // 注意:gwc/rest/wmts 很多博客这里提供的是错的
            // 注意:{TileMatrixSet}/{TileMatrixSet}:{TileMatrix} 中间有冒号
            url: 'http://openlayers.vip/geoserver/gwc/rest/wmts/cite:xintai18/{style}/{TileMatrixSet}/{TileMatrixSet}:{TileMatrix}/{TileRow}/{TileCol}?format=image/png',
            // 注意:这里的样式参数必须有
            style: 'raster',
            // 图层不传也可以
            layer: 'cite:xintai18',
            // 必填
            format: "image/png",
            // 选填
            maximumLevel: 21,
            // 必填
            tileMatrixSetID: 'EPSG:900913'
        }));

        layerWMTSRest && (layerWMTSRest.show = true);
        layerWMTS && (layerWMTS.show = false);

        flyToRectangle();
    }

    let layerWMS;

    // WMS 图层
    function WMS() {

        // 添加geoserver发布的wms数据
        layerWMS = layerWMS || viewer.imageryLayers.addImageryProvider(new Cesium.WebMapServiceImageryProvider({
            url: "http://openlayers.vip/geoserver/cite/wms",
            // 必填
            layers: "cite:xintai18",
            parameters: {
                transparent: true,
                format: "image/png",
                srs: "EPSG:4326",
                // 非必填
                styles: "",
            },
        }));

        layerWMS && (layerWMS.show = true);
        layerWMTS && (layerWMTS.show = false);
        layerWMTSRest && (layerWMTSRest.show = false);

        flyToRectangle();
    }

    // WFS 图层
    // 这里演示北京区县数据
    function WFS() {

        // 这里使用 cesium加载也可以
        // 因为本身数据为 4490,cesium不识别,因此使用 ajax 请求之后再渲染
        $.ajax({
            //点  坐标:曼哈顿
            url: "http://openlayers.vip/geoserver/cite/ows?service=WFS&version=1.0.0&request=GetFeature&typeName=cite%3At_county_new&maxFeatures=50&outputFormat=application%2Fjson",
            cache: false,
            async: true,
            success: function (data) {
                // 原数据是 4490,这里替换为4326,否则 cesium 不识别4490,会报错
                data.crs.properties.name = data.crs.properties.name.replace("EPSG::4490", "EPSG::4326")
                var datasource = Cesium.GeoJsonDataSource.load(data);
                viewer.dataSources.add(datasource);
            },
            error: function (data) {
                alert("error");
            }
        });

        layerWMS && (layerWMS.show = false);
        layerWMTS && (layerWMTS.show = false);
        layerWMTSRest && (layerWMTSRest.show = false);

        // 定位到北京
        flyToRectangle([
            Cesium.Cartesian3.fromDegrees(
                115.44302181271966,
                39.251141782491445,
                0
            ),
            Cesium.Cartesian3.fromDegrees(
                117.34365657834466,
                40.997967954366445,
                0
            ),
        ]);
    }

    // KML 图层
    // 这里演示北京区县数据
    function KML() {

        var options = {
            camera : viewer.scene.camera,
            canvas : viewer.scene.canvas,
            clampToGround: true //开启贴地
        };
        viewer.dataSources.add(Cesium.KmlDataSource.load('http://openlayers.vip/geoserver/cite/ows?' +
            'service=WFS&version=1.0.0&request=GetFeature&typeName=cite%3At_county_new&maxFeatures=50&' +
            'outputFormat=application%2Fvnd.google-earth.kml%2Bxml', options)).then(function(dataSource){

            // Get the array of entities
            var neighborhoodEntities = dataSource.entities.values;
            for (var i = 0; i < neighborhoodEntities.length; i++) {
                var entity = neighborhoodEntities[i];

                if (Cesium.defined(entity.polygon)) {

                    // 设置颜色
                    entity.polygon.material = Cesium.Color.fromRandom({
                        red : 0.1,
                        maximumGreen : 0.5,
                        minimumBlue : 0.5,
                        alpha : 0.6
                    });
                }
            }

            // 定位到北京
            flyToRectangle([
                Cesium.Cartesian3.fromDegrees(
                    115.44302181271966,
                    39.251141782491445,
                    0
                ),
                Cesium.Cartesian3.fromDegrees(
                    117.34365657834466,
                    40.997967954366445,
                    0
                ),
            ]);
        });

        layerWMS && (layerWMS.show = false);
        layerWMTS && (layerWMTS.show = false);
        layerWMTSRest && (layerWMTSRest.show = false);

        // 定位到北京
        flyToRectangle([
            Cesium.Cartesian3.fromDegrees(
                115.44302181271966,
                39.251141782491445,
                0
            ),
            Cesium.Cartesian3.fromDegrees(
                117.34365657834466,
                40.997967954366445,
                0
            ),
        ]);
    }

    /**
     * @description: 飞行定位到一个矩形
     * @return {*}
     */
    function flyToRectangle(RectangleCD) {

        // 添加定位信息
        RectangleCD = RectangleCD || [
            Cesium.Cartesian3.fromDegrees(
                104.15528644354428,
                30.752166584535513,
                0
            ),
            Cesium.Cartesian3.fromDegrees(
                104.27206271917905,
                30.827572468324576,
                0
            ),
        ];

        var rec = Cesium.Rectangle.fromCartesianArray(RectangleCD);
        var boundingSphere = Cesium.BoundingSphere.fromRectangle3D(rec);
        viewer.camera.flyToBoundingSphere(boundingSphere, {
            duration: 5,
            complete: function () {
            },
            offset: {
                heading: Cesium.Math.toRadians(0.0),
                pitch: Cesium.Math.toRadians(-90),
                range: 0.0,
            },
        });
    }

</script>
</body>
</html>

# 点击请求WMTS GetFeatureInfo接口获取点选的要素信息

# 计算近似层级

Cesium 3D模式下没有层级概念,二维地图才有层级zoom,可以通过相机的高度计算近似层级

heightToZoom(height) {
  let A = 40487.57;
  let B = 0.00007096758;
  let C = 91610.74;
  let D = -40467.74;
  return Math.round(D + (A - D) / (1 + Math.pow(height / C, B)));
}

# 计算点击位置瓦片行列号和像素

分辨率resolution:当前地图范围内,1像素代表实际距离多少米

切片原点在左上角,根据下图可以得到公式:

计算点击位置瓦片行列号和像素

反推,根据鼠标点击坐标转换成web墨卡托[x,y],可计算出tileCol、tileRow、tileI和tileJ

计算点击位置瓦片行列号和像素

# 构建URL发送请求

const _this = this;
var handler3D = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler3D.setInputAction(function (event) {
  // 获取鼠标点击位置的墨卡托坐标
  // 屏幕坐标转世界坐标
  let ellipsoid = viewer.scene.globe.ellipsoid;
  let cartesian3 = viewer.camera.pickEllipsoid(event.position, ellipsoid);
  //笛卡尔坐标转web墨卡托
  let webMercator = _this.cartesianToWebMercator(cartesian3);
  //获取相机高度
  let height = viewer.camera.positionCartographic.height;
  //计算近似层级
  let zoom = _this.heightToZoom(height);  
  let matrixIds = [
    "EPSG:900913:0",
    "EPSG:900913:1",
    "EPSG:900913:2",
    "EPSG:900913:3",
    "EPSG:900913:4",
    "EPSG:900913:5",
    "EPSG:900913:6",
    "EPSG:900913:7",
    "EPSG:900913:8",
    "EPSG:900913:9",
    "EPSG:900913:10",
    "EPSG:900913:11",
    "EPSG:900913:12",
    "EPSG:900913:13",
    "EPSG:900913:14",
    "EPSG:900913:15",
    "EPSG:900913:16",
    "EPSG:900913:17",
    "EPSG:900913:18",
    "EPSG:900913:19",
    "EPSG:900913:20",
    "EPSG:900913:21",
    "EPSG:900913:22",
    "EPSG:900913:23",
    "EPSG:900913:24",
    "EPSG:900913:25",
    "EPSG:900913:26",
    "EPSG:900913:27",
    "EPSG:900913:28",
    "EPSG:900913:29",
    "EPSG:900913:30",
  ];
  let resolutions = [
    156543.03390625, 78271.516953125, 39135.7584765625, 19567.87923828125,
    9783.939619140625, 4891.9698095703125, 2445.9849047851562,
    1222.9924523925781, 611.4962261962891, 305.74811309814453,
    152.87405654907226, 76.43702827453613, 38.218514137268066,
    19.109257068634033, 9.554628534317017, 4.777314267158508,
    2.388657133579254, 1.194328566789627, 0.5971642833948135,
    0.2985821416974068, 0.1492910708487034, 0.0746455354243517,
    0.0373227677121758, 0.0186613838560879, 0.009330691928044,
    0.004665345964022, 0.002332672982011, 0.0011663364910055,
    0.0005831682455027, 0.0002915841227514, 0.0001457920613757,
  ];
  let origin = [-2.003750834e7, 2.0037508e7];
  let tileSize = [256, 256];
  let fx = (webMercator[0] - origin[0]) / (resolutions[zoom] * tileSize[0]);
  let fy = (origin[1] - webMercator[1]) / (resolutions[zoom] * tileSize[1]);
  let tileCol = Math.floor(fx);
  let tileRow = Math.floor(fy);
  let tileI = Math.floor((fx - tileCol) * tileSize[0]);
  let tileJ = Math.floor((fy - tileRow) * tileSize[1]);
  let matrixId = matrixIds[zoom];
  let url = "http://localhost:8090/geoserver/gwc/service/wmts?layer=Cesium:mianpian1984&style=&Request=GetFeatureInfo&Version=1.0.0&tilematrixset=EPSG:900913&InfoFormat=application/json&";
  url = url + "TILEMATRIX=" + matrixId + "&TileCol=" + tileCol + "&TileRow=" + tileRow + "&I=" + tileI + "&J=" + tileJ;
  //发送请求获取要素信息
  _this.GetFeatureInfo(url)
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);

变量matrixIds、resolutions、origin和tileSize都是影像发布后自动生成,可在如图所示位置中找到 构建URL发送请求

构建URL发送请求

构建URL发送请求

methods中定义方法

//笛卡尔坐标转web墨卡托
cartesianToWebMercator(cartesian) {
  // 将笛卡尔坐标转换为地理坐标(弧度)
  let cartographic = Cesium.Cartographic.fromCartesian(cartesian);
  //弧度转经纬度
  cartographic.latitude = Cesium.Math.toDegrees(cartographic.latitude);
  cartographic.longitude = Cesium.Math.toDegrees(cartographic.longitude);
  //度转墨卡托
  let earthRad = 6378137.0;
  let x = ((cartographic.longitude * Math.PI) / 180) * earthRad;
  let a = (cartographic.latitude * Math.PI) / 180;
  let y = (earthRad / 2) * Math.log((1.0 + Math.sin(a)) / (1.0 - Math.sin(a)));
  return [x, y];
},
//调用WMTS服务GetFeatureInfo接口
wmtsGetFeatureInfo(url) {
  return http({
    methods: "GET",
    url: url,
  });
}
//发送请求获取要素信息
async GetFeatureInfo(url){
  const res = await wmtsGetFeatureInfo(url);
  if (res.status === 200){
    console.log(res.data);
  }
}

# 加载不同JSON

# topojson

var viewer = new Cesium.Viewer('cesiumContainer');
var promise= viewer.dataSources.add(Cesium.GeoJsonDataSource.load('../china.topojson', {
	stroke: Cesium.Color.BLACK,
	fill: Cesium.Color.RED,
	strokeWidth: 3,
	markerSymbol: '?'
}));
viewer.flyTo(promise);

# GeoJson

var viewer = new Cesium.Viewer('cesiumContainer');
 //Seed the random number generator for repeatable results.
Cesium.Math.setRandomNumberSeed(0);
var promise=Cesium.GeoJsonDataSource.load('../../Apps/testone.json');
promise.then(function(dataSource) {
	viewer.dataSources.add(dataSource);
	var entities = dataSource.entities.values;
	var colorHash = {};
	for (var i = 0; i < entities.length; i++) {
		var entity = entities[i];
		var name = entity.name;
		var color = colorHash[name];
		if (!color) {
			color = Cesium.Color.fromRandom({
				alpha : 1.0
			});
			colorHash[name] = color;
		}
		entity.polygon.material = color;
		entity.polygon.outline = false;            
		entity.polygon.extrudedHeight =5000.0;
		
		//添加label需要先设置中心点
		entity.position = Cesium.Cartesian3.fromDegrees(x,y,z);
		entity.label={
			text:entity.name,
			color : Cesium.Color.fromCssColorString('#fff'),
			font:'normal 32px MicroSoft YaHei',
			showBackground : true,
			scale : 0.5,
			horizontalOrigin : Cesium.HorizontalOrigin.LEFT_CLICK,
			verticalOrigin : Cesium.VerticalOrigin.BOTTOM,
			disableDepthTestDistance : 100000.0
		};
	}
});
viewer.flyTo(promise);

# 普通json

var viewer = new Cesium.Viewer('cesiumContainer');
    Cesium.Math.setRandomNumberSeed(0);
    Cesium.loadJson('/../Apps/Points.json').then(function(jsonData) {
      for (var i =0 ;i<=jsonData.features.length-10; i++) {
        var ifeature=jsonData.features[i]; 
        for (var k = 0;k<ifeature.geometry.paths[0].length-10; k++) {
            if (ifeature.geometry.paths[0][k].length==2) {
				viewer.entities.add({
					position:Cesium.Cartesian3.fromDegrees(ifeature.geometry.paths[0][k][0],
														 ifeature.geometry.paths[0][k][1]),
					point:{
						pixelSize : 10,
						color :Cesium.Color.YELLOW
					 }
				});
            }           
        }
      }           
   }).otherwise(function(error) {});

# 等高线/坡向/坡度

//设置viewer开启光照
viewer.scene.globe.enableLighting = true;

//定义等高线初始值
var minHeight = -414.0;
var maxHeight = 8777.0;
var contourColor = Cesium.Color.RED.clone();
var contourUniforms = {};
var shadingUniforms = {};

//定义相关处理函数
function getElevationContourMaterial() {
  // Creates a composite material with both elevation shading and contour lines
  return new Cesium.Material({
  fabric: {
	type: "ElevationColorContour",
	materials: {
	contourMaterial: {
	  type: "ElevationContour",
	},
	elevationRampMaterial: {
	  type: "ElevationRamp",
	},
	},
	components: {
	diffuse:
	  "contourMaterial.alpha == 0.0?elevationRampMaterial.diffuse:contourMaterial.diffuse",
	alpha:
	  "max(contourMaterial.alpha, elevationRampMaterial.alpha)",
	},
  },
  translucent: false,
  });
}
 
var elevationRamp = [0.0, 0.045, 0.1, 0.15, 0.37, 0.54, 1.0];
var slopeRamp = [0.0, 0.29, 0.5, Math.sqrt(2) / 2, 0.87, 0.91, 1.0];
var aspectRamp = [0.0, 0.2, 0.4, 0.6, 0.8, 0.9, 1.0];
 
function getColorRamp(selectedShading) {
  var ramp = document.createElement("canvas");
  ramp.width = 100;
  ramp.height = 1;
  var ctx = ramp.getContext("2d");

  var values;
  if (selectedShading === "elevation") {
  values = elevationRamp;
  } else if (selectedShading === "slope") {
  values = slopeRamp;
  } else if (selectedShading === "aspect") {
  values = aspectRamp;
  }

  var grd = ctx.createLinearGradient(0, 0, 100, 0);
  grd.addColorStop(values[0], "#000000"); //black
  grd.addColorStop(values[1], "#2747E0"); //blue
  grd.addColorStop(values[2], "#D33B7D"); //pink
  grd.addColorStop(values[3], "#D33038"); //red
  grd.addColorStop(values[4], "#FF9742"); //orange
  grd.addColorStop(values[5], "#ffd700"); //yellow
  grd.addColorStop(values[6], "#ffffff"); //white

  ctx.fillStyle = grd;
  ctx.fillRect(0, 0, 100, 1);

  return ramp;
}

// The viewModel tracks the state of our mini application.
var viewModel = {
  enableContour: false,
  contourSpacing: 50.0,
  contourWidth: 2.0,
  selectedShading: "none",
  changeColor: function () {
  contourUniforms.color = Cesium.Color.fromRandom(
	{ alpha: 1.0 },
	contourColor
  );
  },
};
 
// Convert the viewModel members into knockout observables.
Cesium.knockout.track(viewModel);

// Bind the viewModel to the DOM elements of the UI that call for it.
var toolbar = document.getElementById("toolbar");
Cesium.knockout.applyBindings(viewModel, toolbar);
 
function updateMaterial() {
    var hasContour = viewModel.enableContour;
    var selectedShading = viewModel.selectedShading;
    var globe = viewer.scene.globe;
    var material;
    if (hasContour) {
      if (selectedShading === "elevation") {
        material = getElevationContourMaterial();
        shadingUniforms = material.materials.elevationRampMaterial.uniforms;
        shadingUniforms.minimumHeight = minHeight;
        shadingUniforms.maximumHeight = maxHeight;
        contourUniforms = material.materials.contourMaterial.uniforms;
      }else {
        material = Cesium.Material.fromType("ElevationContour");
        contourUniforms = material.uniforms;
      }
      contourUniforms.width = viewModel.contourWidth;
      contourUniforms.spacing = viewModel.contourSpacing;
      contourUniforms.color = contourColor;
    } else if (selectedShading === "elevation") {
      material = Cesium.Material.fromType("ElevationRamp");
      shadingUniforms = material.uniforms;
      shadingUniforms.minimumHeight = minHeight;
      shadingUniforms.maximumHeight = maxHeight;
    } 
    if (selectedShading !== "none") {
      shadingUniforms.image = getColorRamp(selectedShading);
    }
    globe.material = material;
}
 
updateMaterial();
 
Cesium.knockout.getObservable(viewModel, "enableContour").subscribe(function (newValue) {
  updateMaterial();
});

Cesium.knockout.getObservable(viewModel, "contourWidth").subscribe(function (newValue) {
  contourUniforms.width = parseFloat(newValue);
});

Cesium.knockout.getObservable(viewModel, "contourSpacing").subscribe(function (newValue) {
  contourUniforms.spacing = parseFloat(newValue);
});

Cesium.knockout.getObservable(viewModel, "selectedShading").subscribe(function (value) {
  updateMaterial();
});

绑定页面控件

<div class="demo-container">
<label><input type="radio" name="shadingMaterials"
  value="none" data-bind="checked: selectedShading">无渲染</label> <label><input
  type="radio" name="shadingMaterials" value="elevation"
  data-bind="checked: selectedShading">高程渲染</label>
</div>
<div class="demo-container">
<div>
  <label><input type="checkbox"
	data-bind="checked: enableContour">等高线</label>
</div>
<div>
  高程 <input style="width: 136px; float: left; width: 100px;"
	type="range" min="1.0" max="500.0" step="1.0"
	data-bind="value: contourSpacing, valueUpdate: 'input', enable: enableContour">
  <span data-bind="text: contourSpacing"></span>m
</div>
<div>
  线宽 <input style="width: 125px; float: left; width: 100px;"
	type="range" min="1.0" max="10.0" step="1.0"
	data-bind="value: contourWidth, valueUpdate: 'input', enable: enableContour">
  <span data-bind="text: contourWidth"></span>px
</div>
<div>
  <button type="button"
	data-bind="click: changeColor, enable: enableContour">颜色</button>
</div>
</div>

等高线/坡向/坡度

# 缓冲区分析

//初始化点缓冲
initPointBuffer() {
	let point = [106.422638966289, 29.5698367125623];
	this.addPoint(point);

	let pointF = turf.point(point);
	let buffered = turf.buffer(pointF, 60, { units: 'meters' });
	let coordinates = buffered.geometry.coordinates;
	let points = coordinates[0];
	let degreesArray = this.pointsToDegreesArray(points);
	this.addBufferPolyogn(Cesium.Cartesian3.fromDegreesArray(degreesArray));
},

//添加点
addPoint(point) {
	this.viewer.entities.add({
		position: Cesium.Cartesian3.fromDegrees(point[0], point[1], 0),
		point: {
			pixelSize: 10,
			color: Cesium.Color.YELLOW,
			outlineWidth: 3,
			outlineColor: Cesium.Color.YELLOW.withAlpha(0.4),
		}
	});
},

//初始化线缓冲
initPolylineBuffer() {
	let points = [
		[106.425203158107, 29.5694914480581],
		[106.428808047023, 29.569230166027],
		[106.431661917416, 29.5692674920729],
		[106.434708906857, 29.5693048181049]
	];
	let degreesArray = this.pointsToDegreesArray(points);
	this.addPolyline(Cesium.Cartesian3.fromDegreesArray(degreesArray));

	let polylineF = turf.lineString(points);
	let buffered = turf.buffer(polylineF, 30, { units: 'meters' });
	let coordinates = buffered.geometry.coordinates;
	points = coordinates[0];
	degreesArray = this.pointsToDegreesArray(points);
	this.addBufferPolyogn(Cesium.Cartesian3.fromDegreesArray(degreesArray));
},

//添加线
addPolyline(positions) {
	this.viewer.entities.add({
		polyline: {
			positions: positions,
			width: 2,
			material: Cesium.Color.YELLOW,
		}
	})
},

//初始化面缓冲
initPolygonBuffer() {
	let points = [
		[106.438549830166, 29.5701073244566],
		[106.440695597377, 29.5701073244566],
		[106.440738512722, 29.5688755679036],
		[106.438700033871, 29.5687262630581],
		[106.438034846035, 29.5690248725284],
		[106.438549830166, 29.5701073244566]
	];

	let degreesArray = this.pointsToDegreesArray(points);
	this.addPolygon(Cesium.Cartesian3.fromDegreesArray(degreesArray));

	let polygonF = turf.polygon([points]);
	let buffered = turf.buffer(polygonF, 60, { units: 'meters' });
	let coordinates = buffered.geometry.coordinates;
	points = coordinates[0];
	degreesArray = this.pointsToDegreesArray(points);
	this.addBufferPolyogn(Cesium.Cartesian3.fromDegreesArray(degreesArray));
},

//添加面
addPolygon(positions) {
	this.viewer.entities.add({
		polygon: {
			hierarchy: new Cesium.PolygonHierarchy(positions),
			material: Cesium.Color.YELLOW.withAlpha(0.6),
			classificationType: Cesium.ClassificationType.BOTH
		},
		polyline: {
			positions: positions,
			width: 2,
			material: Cesium.Color.YELLOW.withAlpha(0.4),
		}
	});
},

//添加缓冲面
addBufferPolyogn(positions) {
	this.viewer.entities.add({
		polygon: {
			hierarchy: new Cesium.PolygonHierarchy(positions),
			material: Cesium.Color.RED.withAlpha(0.6),
			classificationType: Cesium.ClassificationType.BOTH
		},
	});
},

//格式转换
pointsToDegreesArray(points) {
	let degreesArray = [];
	points.map(item => {
		degreesArray.push(item[0]);
		degreesArray.push(item[1]);
	});
	return degreesArray;
},

缓冲区分析

# ArcGIS服务进行属性查询

在发起查询请求的时候,建议都用 post 请求,因为如果直接用 get 请求,url 的长度是有限制的,而且直接用 get 请求相对来说也不是很安全,因此建议直接都用 post 请求

//思路很简单,先获取服务的extent,再根据这个txtent去进行identify获取识别到的多图层要素
const item.url = 'xxx/xxx/xxx/MapServer'
const getExtenUrl = `${item.url}/info/iteminfo?f=pjson`;
fetch(getExtenUrl)
.then((response) => response.json())
.then((res) => {
  const extent = res.extent[0][0] + ',' + res.extent[0][1] + ','
                 + res.extent[1][0] + ',' + res.extent[1][1];
  const requestUrl = `${item.url}/identify`;
  const params = {
	f: 'pjson',
	tolerance: 2,
	returnGeometry: false,
	geometry: JSON.stringify(
	  {
	  x: degreePosition.longitude,
	  y: degreePosition.latitude,
	  spatialReference: {
		wkid: 4326,
	  },
	}
	),
	geometryType: 'esriGeometryPoint',
	mapExtent: extent,
	imageDisplay: '1920,1080,96',
	sr: 4326,
	layers: 'all',
  };
  // post数据以表单形式存储
  const formData = new FormData();
  Object.keys(params).forEach((key) => {
	formData.append(key, params[key]);
  });

  fetch(requestUrl, {
	method: 'POST',
	body: formData,
  })
  .then((response) => response.json())
  .then((res) => {
	console.log('res1111111111', res);
	if (res.results.length > 0) {
	  const featureList = res.results.map((item) => {
		const feature = {
		  layerName: item.layerName,
		  attributes: item.attributes,
		};
		return feature;
	  });
	  console.log('featureList', featureList);
	  // 这里可以根据自己的需求进行处理
	  // 例如:弹出一个弹窗,展示查询到的要素信息
	}
  });
})

# 解决图层有遮挡覆盖问题

  • cesium叠加多个图层时 图层有遮挡覆盖
//设置layerIndex,addImageryProvider的第2个参数
viewer.imageryLayers.addImageryProvider(mapboxlayer,0);
  • geojson的面数据遮挡
//设置polygon拉伸高度
const highLightEntity = new Cesium.Entity({
  id: 'highLightEntity',
  polygon: {
	heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
	material: Cesium.Color.RED,
	extrudedHeight: 0
  }
})