文章目录
0.引言
现有的gis开发方向较流行的是webgis开发,其中Cesium是一款开源的WebGIS库,主要用于实时地球和空间数据的可视化和分析。它提供了丰富的地图显示和数据可视化功能,并能实现三维可视化开发。本文介绍Cesium中的坐标系统及相互转换关系,讲解如何在构造的三维场景中交互绘制点、线、面、体等多种空间对象并对这些空间对象进行管理。
1.坐标系统
Cesium中经常会涉及各类数据的加载、浏览,以及不同数据之间的坐标转换,所以我们不得不弄清楚Cesium中常用的坐标系统,以及不同坐标系统之间的转换关系和转换方法等。这里主要介绍Cesium中常用的WGS-84坐标系(包括弧度和度的形式)、世界坐标系(笛卡儿空间直角坐标系)及平面坐标系,并介绍这些坐标系统之间的转换关系和转换方法。
(1)坐标系统相互转换代码
4_1_坐标转换.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>场景绘制篇_坐标转换</title>
<script src="./Build/Cesium/Cesium.js"></script>
<link rel="stylesheet" href="./Build/Cesium//Widgets/widgets.css">
<style>
html,
body,
#cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
</style>
</head>
<body>
<div id="cesiumContainer">
</div>
<script>
Cesium.Ion.defaultAccessToken = '你的token';
var viewer = new Cesium.Viewer("cesiumContainer", {
animation: false, //是否显示动画工具
timeline: false, //是否显示时间轴工具
fullscreenButton: false, //是否显示全屏按钮工具
});
viewer.scene.globe.depthTestAgainstTerrain = true
var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function (movement) {
//屏幕坐标
console.log('屏幕坐标:', movement.position);
//屏幕坐标 转 世界坐标(场景坐标,包括地形、倾斜摄影模型等的坐标)
var cartesian3= viewer.scene.pickPosition(movement.position); //注意此处的屏幕坐标一定要在球上,否则结果为undefined
console.log('屏幕坐标转世界坐标(场景):', cartesian3);
//屏幕坐标 转 世界坐标(地表坐标,包括地形但不包括模型、倾斜摄影等)
var ray = viewer.camera.getPickRay(movement.position);
var cartesian3 = viewer.scene.globe.pick(ray, viewer.scene);
console.log('屏幕坐标转世界坐标(地表):', cartesian3);
//屏幕坐标 转 世界坐标(椭球面坐标,不包括地形、模型、倾斜摄影等)
var cartesian3= viewer.scene.camera.pickEllipsoid(movement.position)
console.log('屏幕坐标转世界坐标(椭球面):', cartesian3);
//世界坐标 转 屏幕坐标
var cartesian2 = Cesium.SceneTransforms.wgs84ToWindowCoordinates(viewer.scene, cartesian3)
console.log('世界坐标转屏幕坐标:', cartesian2);
//世界坐标 转 WGS84坐标,结果为弧度形式
var cartographic = Cesium.Cartographic.fromCartesian(cartesian3);
console.log('世界坐标转WGS84弧度坐标:', cartographic);
//WGS84弧度坐标 转 经纬度坐标
longitude = Cesium.Math.toDegrees(cartographic.longitude);
latitude = Cesium.Math.toDegrees(cartographic.latitude);
height = cartographic.height;
console.log('WGS84弧度坐标转WGS84经纬度坐标:' + longitude + ',' + latitude + ',' + height);
//WGS84经纬度坐标 转 弧度坐标
var radians = Cesium.Cartographic.fromDegrees(longitude, latitude, height);
console.log('WGS84经纬度转WGS84弧度坐标', radians);
//WGS84经纬度坐标 转 世界坐标
var position = Cesium.Cartesian3.fromDegrees(longitude, latitude, height);
console.log('WGS84经纬度转世界坐标', position);
//WGS84弧度坐标 转 世界坐标
var position2 = Cesium.Cartesian3.fromRadians(cartographic.longitude, cartographic.latitude, cartographic.height);
console.log('WGS84弧度转世界坐标', position2);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
</script>
</body>
</html>
(2)结果输出
运行代码后出现网页地球,按F12,调出控制台,点击球体一个位置,下图右侧控制台显示屏幕点坐标及其他坐标转换结果。
2.几何图形绘制
几何图形绘制一直以来都是GIS必备的基础功能之一,例如,点、线、面的绘制在各种GIS中屡见不鲜,而Cesium不仅支持点、线、面的绘制,还支持柱体、椭球体、盒子及三维模型等几何图形的绘制。
Cesium在几何图形绘制方面提供了两种不同类型的API:一种是较为高级的,不需要使用者对计算机图形学有很深的理解,可以直接拿来使用的API,即Entity API;另一种是面向图形开发人员的,更为复杂的API,即Primitive API。对于新手来说,本书推荐使用Entity API,因为Entity API本质上是对Primitive API的二次封装,目的是让使用者不必对计算机图形学有多么高深的理解,就能轻松绘制出各式各样的几何图形。
2.1Entity绘制实体
Entity通过Entity类实现实体绘制,支持点、线、面、椭球体、广告牌、盒子、标签、模型、墙等多种实体的绘制。用户可以手动创建实体并将它们添加到场景中,或者由数据源(如CzmlDataSource和GeoJsonDataSource)进行添加。此处以手动创建并添加实体为例来介绍各种类型的实体绘制方式。
(1)关键代码
4_2.1_Entity方式直接绘制.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>绘制实体_Entity方式</title>
<script src="./Build/Cesium/Cesium.js"></script>
<link rel="stylesheet" href="./Build/Cesium//Widgets/widgets.css">
<!-- <script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script> -->
<style>
html,
body,
#cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
.toolbar {
position: absolute;
top: 10px;
left: 20px;
background-color: rgb(0, 0, 0, 0);
}
</style>
</head>
<body>
<div id="cesiumContainer">
</div>
<div id="menu" class="toolbar">
<select id="dropdown" onchange="addEntity()">
<option value="null">null</option>
<option value="addPoint">添加点</option>
<option value="addLines">添加线</option>
<option value="addPolygon">添加面</option>
<option value="addRectangle">添加矩形</option>
<option value="addEllipse">添加椭圆</option>
<option value="addCylinder">添加圆柱体</option>
<option value="addCorridor">添加走廊</option>
<option value="addWall">添加墙</option>
<option value="addBox">添加方盒</option>
<option value="addEllipsoid">添加球体</option>
<option value="addModel">添加模型</option>
<option value="addBillboard">添加广告牌</option>
</select>
<select id="dropdown2" onchange="removeEntity()">
<option value="null">null</option>
<option value="removePoint">删除点</option>
<option value="removeLines">删除线</option>
<option value="removePolygon">删除面</option>
<option value="removeRectangle">删除矩形</option>
<option value="removeEllipse">删除椭圆</option>
<option value="removeCylinder">删除圆柱体</option>
<option value="removeCorridor">删除走廊</option>
<option value="removeWall">删除墙</option>
<option value="removeBox">删除方盒</option>
<option value="removeEllipsoid">删除球体</option>
<option value="removeModel">删除模型</option>
<option value="removeBillboard">删除广告牌</option>
</select>
</div>
<script>
Cesium.Ion.defaultAccessToken =
'你的token';
var viewer = new Cesium.Viewer("cesiumContainer", {
animation: false, //是否显示动画工具
timeline: false, //是否显示时间轴工具
fullscreenButton: false, //是否显示全屏按钮工具
});
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(118, 32, 6000000),
orientation: {
heading: 0.010152402293521767,
pitch: -1.5705337480193866,
roll: 0.00003681052934645379
},
})
// 点
var addPoint = {
id: 'point',
name: '点',
show: true, //显示.
position: Cesium.Cartesian3.fromDegrees(118, 32, 0.0),
point: {
color: Cesium.Color.BLUE, //颜色
pixelSize: 5, //点大小
}
}
// 线
var addLine = {
id: 'line',
name: '线',
show: true, //显示
polyline: {
positions: Cesium.Cartesian3.fromDegreesArray([118, 30, 119, 32, 116, 35]),
width: 1, //线条粗细
material: Cesium.Color.RED, //线条材质
//clampToGround: true
}
}
//面
var addPolygon = {
id: 'polygon',
name: '面',
show: true,
polygon: {
hierarchy: Cesium.Cartesian3.fromDegreesArray([118, 30, 119, 32, 116, 32, 116, 30]),
//outline: false,
material: Cesium.Color.RED.withAlpha(0.4),
}
}
//矩形
var addRectangle = {
id: 'rectangle',
name: '矩形',
show: true,
rectangle: {
coordinates: Cesium.Rectangle.fromDegrees(80.0, 30.0, 100.0, 35.0),
material: Cesium.Color.BLUE.withAlpha(0.5),
/* height:0,
outline: true,
outlineWidth:10,
outlineColor: Cesium.Color.BLUE */
}
}
//椭圆
var addEllipse = {
id: 'ellipse',
name: '椭圆',
show: true,
position: Cesium.Cartesian3.fromDegrees(103.0, 40.0),
ellipse: {
semiMinorAxis: 250000.0, //短半轴
semiMajorAxis: 400000.0, //长半轴
material: Cesium.Color.RED.withAlpha(0.5),
/* height:0,
outline: true,
outlineColor: Cesium.Color.RED */
}
}
//圆柱体
var addCylinder = {
id: 'cylinder',
name: '圆柱体',
show: true,
//位置
position: Cesium.Cartesian3.fromDegrees(100.0, 40.0, 200000.0),
cylinder: {
length: 400000.0, //圆柱长度
topRadius: 200000.0, //顶面半径
bottomRadius: 200000.0, //底面半径
material: Cesium.Color.GREEN.withAlpha(0.6),
outline: false,
outlineColor: Cesium.Color.DARK_GREEN
}
}
//走廊
var addCorridor = {
id: 'corridor',
name: '走廊',
show: true,
corridor: {
positions: Cesium.Cartesian3.fromDegreesArray([
100.0, 40.0,
105.0, 40.0,
105.0, 35.0
]),
width: 200000.0,
material: Cesium.Color.YELLOW.withAlpha(0.5),
/* height:0,
outline: true, //外轮廓线
outlineColor: Cesium.Color.RED */
}
}
//墙
var addWall = {
id: 'wall',
name: '墙',
show: true,
wall: {
positions: Cesium.Cartesian3.fromDegreesArrayHeights([
107.0, 43.0, 200000.0,
97.0, 43.0, 100000.0,
97.0, 40.0, 100000.0,
107.0, 40.0, 100000.0,
107.0, 43.0, 100000.0
]),
material: Cesium.Color.GREEN
}
}
//方盒
var addBox = {
id: 'box',
name: '方盒',
show: true,
position: Cesium.Cartesian3.fromDegrees(110, 35, 200000.0),
box: {
dimensions: new Cesium.Cartesian3(400000.0, 300000.0, 400000.0), //指定框的长度,宽度和高度
material: Cesium.Color.BLUE
}
}
//球体
var addEllipsoid = {
id: 'ellipsoid',
name: '椭球体',
show: true,
position: Cesium.Cartesian3.fromDegrees(107.0, 40.0, 300000.0),
ellipsoid: {
radii: new Cesium.Cartesian3(200000.0, 200000.0, 300000.0), //椭球的半径
material: Cesium.Color.BLUE.withAlpha(0.5),
outline: true,
outlineColor: Cesium.Color.WHITE
}
}
// 模型
var heading = Cesium.Math.toRadians(60); //60度航向
var pitch = 0; //俯仰角
var roll = 0; //翻滚角
var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
var addModel = {
id: 'model', //id唯一
name: '小车模型', // 名称
show: true, //显示
position: Cesium.Cartesian3.fromDegrees(118, 30, 5000), // 小车位置
orientation: Cesium.Transforms.headingPitchRollQuaternion(Cesium.Cartesian3.fromDegrees(118, 30, 5000),
hpr), //飞机航向
model: {
uri: './3D格式数据/glTF/CesiumMilkTruck.gltf',
minimumPixelSize: 300, //模型最小
maximumScale: 50000, //模型最大
//color: Cesium.Color.ORANGE, // 模型颜色
scale: 30000, //当前比例
}
}
//广告牌
var addBillboard = {
id: 'billboard',
name: '广告牌',
show: true,
position: Cesium.Cartesian3.fromDegrees(108, 30, 50),
billboard: {
image: './RasterImage/图片/single.jpg',
scale: 0.1, //比例
}
}
var dropdown = document.getElementById('dropdown');
var dropdown2 = document.getElementById('dropdown2');
function addEntity() {
switch (dropdown.value) {
case 'addPoint':
viewer.entities.add(addPoint);
break;
case 'addLines':
viewer.entities.add(addLine);
break;
case 'addPolygon':
viewer.entities.add(addPolygon);
break;
case 'addRectangle':
viewer.entities.add(addRectangle);
break;
case 'addEllipse':
viewer.entities.add(addEllipse);
break;
case 'addCylinder':
viewer.entities.add(addCylinder);
break;
case 'addCorridor':
viewer.entities.add(addCorridor);
break;
case 'addWall':
viewer.entities.add(addWall);
break;
case 'addBox':
viewer.entities.add(addBox);
break;
case 'addEllipsoid':
viewer.entities.add(addEllipsoid);
break;
case 'addModel':
viewer.entities.add(addModel);
break;
case 'addBillboard':
viewer.entities.add(addBillboard);
break;
default:
break;
}
}
function removeEntity() {
switch (dropdown2.value) {
case 'removePoint':
viewer.entities.removeById("point");
break;
case 'removeLines':
viewer.entities.removeById("line");
break;
case 'removePolygon':
viewer.entities.removeById("polygon");
break;
case 'removeRectangle':
viewer.entities.removeById("rectangle");
break;
case 'removeEllipse':
viewer.entities.removeById("ellipse");
break;
case 'removeCylinder':
viewer.entities.removeById("cylinder");
break;
case 'removeCorridor':
viewer.entities.removeById("corridor");
break;
case 'removeWall':
viewer.entities.removeById("wall");
break;
case 'removeBox':
viewer.entities.removeById("box");
break;
case 'removeEllipsoid':
viewer.entities.removeById("ellipsoid");
break;
case 'removeModel':
viewer.entities.removeById("model");
break;
case 'removeBillboard':
viewer.entities.removeById("billboard");
break;
default:
break;
}
}
</script>
</body>
</html>
(2)显示结果
2.2Entity绘制贴地图形
Entity在三维平面上(不包含地形、倾斜摄影模型)绘制实体,但是在实际应用中,往往会遇到以下需求,例如,要求绘制的实体(通常指的是平面图形而不是立体几何图形)贴合在地形表面或者倾斜摄影模型表面上,这时就必须设置Entity的某个属性以满足这个要求。对于Entity绘制的实体,除polyline对象必须通过设置clampToGround属性为true来控制实体贴地之外,其余的对象都通过heightReference或classificationType属性来控制实体贴地。
(1)关键代码
4_2.2_Entity绘制贴地.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>绘制实体_Entity绘制贴地</title>
<script src="./Build/Cesium/Cesium.js"></script>
<link rel="stylesheet" href="./Build/Cesium//Widgets/widgets.css">
<!-- <script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script> -->
<style>
html,
body,
#cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
.toolbar {
position: absolute;
top: 10px;
left: 20px;
background-color: rgb(0, 0, 0, 0);
}
</style>
</head>
<body>
<div id="cesiumContainer">
</div>
<div id="menu" class="toolbar">
<select id="dropdown" onchange="addEntity()">
<option value="null">null</option>
<option value="addPoint">添加点</option>
<option value="addLines">添加线</option>
<option value="addPolygon">添加面</option>
<option value="addRectangle">添加矩形</option>
<option value="addEllipse">添加椭圆</option>
<option value="addCorridor">添加走廊</option>
<option value="addModel">添加模型</option>
</select>
<select id="dropdown2" onchange="removeEntity()">
<option value="null">null</option>
<option value="removePoint">删除点</option>
<option value="removeLines">删除线</option>
<option value="removePolygon">删除面</option>
<option value="removeRectangle">删除矩形</option>
<option value="removeEllipse">删除椭圆</option>
<option value="removeCorridor">删除走廊</option>
<option value="removeModel">删除模型</option>
</select>
</div>
<script>
Cesium.Ion.defaultAccessToken = '你的token';
var terrainModels = Cesium.createWorldTerrain();
var viewer = new Cesium.Viewer("cesiumContainer", {
terrainProvider: terrainModels,
animation: false, //是否显示动画工具
timeline: false, //是否显示时间轴工具
fullscreenButton: false, //是否显示全屏按钮工具
});
//viewer.scene.globe.depthTestAgainstTerrain = false;
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(118, 32, 6000000),
orientation: {
heading: 0.010152402293521767,
pitch: -1.5705337480193866,
roll: 0.00003681052934645379
},
})
// 点
var addPoint = {
id:'point',
name:'点',
show: true, //显示.
position: Cesium.Cartesian3.fromDegrees(118, 32),
point: {
color: Cesium.Color.BLUE, //颜色
pixelSize: 50,//点大小
disableDepthTestDistance:Number.POSITIVE_INFINITY,
heightReference:Cesium.HeightReference.CLAMP_TO_GROUND //贴地
}
}
// 线
var addLine = {
id: 'line',
name:'线',
show: true, //显示
polyline: {
positions: Cesium.Cartesian3.fromDegreesArray([118, 30, 119, 32, 116,35]),
width: 2, //线条粗细
material: Cesium.Color.RED, //线条材质
clampToGround: true //贴地
}
}
//面
var addPolygon = {
id:'polygon',
name: '面',
show:true,
polygon: {
hierarchy: Cesium.Cartesian3.fromDegreesArray([118, 30, 119, 32,116,32,116,30]),
//outline: false,
material: Cesium.Color.RED.withAlpha(0.4),
classificationType:Cesium.ClassificationType.BOTH , //贴地
}
}
//矩形
var addRectangle = {
id:'rectangle',
name: '矩形',
show:true,
rectangle: {
coordinates: Cesium.Rectangle.fromDegrees(80.0, 30.0, 100.0, 35.0),
material: Cesium.Color.BLUE.withAlpha(0.5),
classificationType:Cesium.ClassificationType.BOTH , //贴地
/* height:0,
outline: true,
outlineWidth:10,
outlineColor: Cesium.Color.BLUE */
}
}
//椭圆
var addEllipse = {
id:'ellipse',
name: '椭圆',
show:true,
position: Cesium.Cartesian3.fromDegrees(103.0, 40.0),
ellipse: {
semiMinorAxis: 250000.0, //短半轴
semiMajorAxis: 400000.0, //长半轴
material: Cesium.Color.CYAN.withAlpha(0.5),
classificationType:Cesium.ClassificationType.BOTH , //贴地
/* height:0,
outline: true,
outlineColor: Cesium.Color.RED */
}
}
//走廊
var addCorridor = {
id:'corridor',
name: '走廊',
show:true,
corridor: {
positions: Cesium.Cartesian3.fromDegreesArray([
100.0, 40.0,
105.0, 40.0,
105.0, 35.0
]),
width: 200000.0,
material: Cesium.Color.YELLOW.withAlpha(0.5),
classificationType:Cesium.ClassificationType.BOTH , //贴地
/* height:0,
outline: true, //外轮廓线
outlineColor: Cesium.Color.RED */
}
}
// 模型
var heading = Cesium.Math.toRadians(60); //60度航向
var pitch = 0; //俯仰角
var roll = 0; //翻滚角
var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
var addModel = {
id: 'model', //id唯一
name: '小车模型', // 名称
show: true, //显示
position: Cesium.Cartesian3.fromDegrees(118, 32), // 模型位置
orientation: Cesium.Transforms.headingPitchRollQuaternion(Cesium.Cartesian3.fromDegrees(118, 30), hpr), //飞机航向
model: {
uri: './3D格式数据/glTF/CesiumMilkTruck.gltf',
minimumPixelSize: 30, //模型最小
maximumScale: 50000, //模型最大
//color: Cesium.Color.ORANGE, // 模型颜色
scale: 20000, //当前比例
heightReference: Cesium.HeightReference.CLAMP_TO_GROUND //贴地
}
}
var dropdown = document.getElementById('dropdown');
var dropdown2 = document.getElementById('dropdown2');
function addEntity(){
switch (dropdown.value){
case 'addPoint':
viewer.entities.add(addPoint);
break;
case 'addLines':
viewer.entities.add(addLine);
break;
case 'addPolygon':
viewer.entities.add(addPolygon);
break;
case 'addRectangle':
viewer.entities.add(addRectangle);
break;
case 'addEllipse':
viewer.entities.add(addEllipse);
break;
case 'addCorridor':
viewer.entities.add(addCorridor);
break;
case 'addModel':
viewer.entities.add(addModel);
break;
default:
break;
}
}
function removeEntity(){
switch (dropdown2.value){
case 'removePoint':
viewer.entities.removeById ("point");
break;
case 'removeLines':
viewer.entities.removeById ("line");
break;
case 'removePolygon':
viewer.entities.removeById("polygon");
break;
case 'removeRectangle':
viewer.entities.removeById("rectangle");
break;
case 'removeEllipse':
viewer.entities.removeById("ellipse");
break;
case 'removeCorridor':
viewer.entities.removeById ("corridor");
break;
case 'removeModel':
viewer.entities.removeById("model");
break;
default:
break;
}
}
</script>
</body>
</html>
(2)显示结果
2.3Entity管理
对于Entity绘制的几何对象来说,默认的材质样式都比较简单,可能并不能满足实际需求,这时就需要我们手动设置想要的材质以满足需求。材质通常可以被认为是几何对象表面的样式,例如,绘制出来的几何对象颜色或者某种特殊的纹理图案等。Cesium为Entity绘制的几何对象提供了MaterialProperty类,以供用户对材质进行修改和设置。
(1)关键代码
4_2.3_Entity管理.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>绘制实体_Entity管理</title>
<script src="./Build/Cesium/Cesium.js"></script>
<link rel="stylesheet" href="./Build/Cesium//Widgets/widgets.css">
<!-- <script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script> -->
<style>
html,
body,
#cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
.toolbar {
position: absolute;
top: 10px;
left: 20px;
background-color: rgb(0, 0, 0, 0);
}
</style>
</head>
<body>
<div id="cesiumContainer">
</div>
<div id="menu" class="toolbar">
<select id="dropdown" onchange="edit()">
<option value="edit0">null</option>
<option value="edit1">虚线</option>
<option value="edit2">箭头线</option>
<option value="edit3">修改颜色</option>
<option value="edit4">添加条纹</option>
<option value="edit5">添加边框</option>
<option value="edit6">添加拉伸</option>
<option value="edit7">添加贴图</option>
<option value="edit8">修改角度</option>
<option value="edit9">显示与隐藏</option>
<option value="edit10">移除单个实体</option>
<option value="edit11">移除全部实体</option>
</select>
</div>
<script>
Cesium.Ion.defaultAccessToken = '你的token';
var viewer = new Cesium.Viewer("cesiumContainer", {
animation: false, //是否显示动画工具
timeline: false, //是否显示时间轴工具
fullscreenButton: false, //是否显示全屏按钮工具
//加载天地图影像图
imageryProvider: new 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=你的tk",
subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], //服务负载子域
layer: "tdtImgLayer",
style: "default",
format: "image/jpeg",
tileMatrixSetID: "GoogleMapsCompatible",//使用谷歌的瓦片切片方式
show: true
})
});
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(118, 30, 7000000),
orientation: {
heading: 0.010152402293521767,
pitch: -1.5705337480193866,
roll: 0.00003681052934645379
},
})
// 线
var addLine = viewer.entities.add({
id: 'line',
name: '线',
show: true, //显示
polyline: {
positions: Cesium.Cartesian3.fromDegreesArray([111, 40, 116, 45]),
width: 6, //线条粗细
followSurface: false, //取消弯曲
material: Cesium.Color.RED, //线条材质
//clampToGround: true
},
})
//面
var addPolygon = viewer.entities.add({
id: 'polygon',
name: '面',
polygon: {
hierarchy: Cesium.Cartesian3.fromDegreesArray([108, 30, 108, 36, 100, 36, 100, 30]),
height:0,
outline: false,
material: Cesium.Color.RED.withAlpha(0.6),
}
})
// 模型
var degree = 60;
var heading = Cesium.Math.toRadians(degree); //60度航向
var pitch = 0;
var roll = 0;
var hpr = new Cesium.HeadingPitchRoll(heading, pitch, roll);
var addModel = viewer.entities.add({
id: 'model', //id唯一
name: '模型', // 名称
show: true, //显示
position: Cesium.Cartesian3.fromDegrees(115, 33, 5000), // 飞机位置
orientation: Cesium.Transforms.headingPitchRollQuaternion(Cesium.Cartesian3.fromDegrees(118, 30, 5000), hpr), //飞机航向
model: {
uri: './3D格式数据/glTF/CesiumMilkTruck.gltf',
minimumPixelSize: 300, //模型最小
maximumScale: 50000, //模型最大
//color: Cesium.Color.ORANGE, // 模型颜色
scale: 30000, //当前比例
}
})
var dropdown = document.getElementById('dropdown');
function edit(){
switch (dropdown.value){
case 'edit1':
addLine.polyline.material = new Cesium.PolylineDashMaterialProperty({
color: Cesium.Color.BLUE,
});
break;
case 'edit2':
addLine.polyline.material = new Cesium.PolylineArrowMaterialProperty(Cesium.Color.CYAN);
break;
case 'edit3':
addPolygon.polygon.material = Cesium.Color.BLUE.withAlpha(0.6);
break;
case 'edit4':
var stripeMaterial = new Cesium.StripeMaterialProperty({
orientation: Cesium.StripeOrientation.VERTICAL,
evenColor: Cesium.Color.WHITE,
oddColor: Cesium.Color.BLACK,
repeat: 16,
});
addPolygon.polygon.material = stripeMaterial;
break;
case 'edit5':
addPolygon.polygon.outline = true;
addPolygon.polygon.outlineColor = Cesium.Color.YELLOW;
addPolygon.polygon.outlineWidth = 30;
break;
case 'edit6':
addPolygon.polygon.extrudedHeight = 100000;
break;
case 'edit7':
addPolygon.polygon.material = "./RasterImage/图片/single.jpg";
break;
case 'edit8':
degree += 15;
addModel.orientation = Cesium.Transforms.headingPitchRollQuaternion(
Cesium.Cartesian3.fromDegrees(118, 30, 5000),
new Cesium.HeadingPitchRoll(Cesium.Math.toRadians(degree), 0, 0))
break;
case 'edit9':
if (addPolygon.show != false)
//console.log("@@",addPolygon);
addPolygon.show = false;
else {
addPolygon.show = true;
}
break;
case 'edit10':
viewer.entities.remove(addEllipsoid); //直接移除实体
//viewer.entities.removeById("ellipsoid");//根据ID移除实体
break;
case 'edit11':
viewer.entities.removeAll();//移除集合中全部实体
break;
default:
break;
}
}
</script>
</body>
</html>
(2)显示结果
2.4Primitive绘制图形
Primitive其实是一种比较复杂的、面向图形开发人员的类。Primitive绘制图形的方式更接近渲染引擎底层。
Primitive绘制的图形由两部分组成:第一部分为几何形状(Geometry),用于定义Primitive图形的结构,如面、椭圆、线条等;第二部分为外观(Appearance),主要用于定义Primitive图形的渲染着色,通俗来讲,就是定义Primitive图形的外观材质。
(1)关键代码
4_2.4_Primitive方式直接绘制.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>绘制实体_Primitive方式直接绘制</title>
<script src="./Build/Cesium/Cesium.js"></script>
<link rel="stylesheet" href="./Build/Cesium//Widgets/widgets.css">
<!-- <script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script> -->
<style>
html,
body,
#cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
.toolbar {
position: absolute;
top: 10px;
left: 20px;
background-color: rgb(0, 0, 0, 0);
}
</style>
</head>
<body>
<div id="cesiumContainer">
</div>
<div id="menu" class="toolbar">
<select id="dropdown" onchange="addPrimitive()">
<option value="null">null</option>
<option value="addPolylineGeometry">添加线</option>
<option value="addPolygonGeometry">添加面</option>
<option value="addEllipseGeometry">添加椭圆</option>
<option value="addCircleGeometry">添加圆</option>
<option value="addCorridorGeometry">添加走廊</option>
<option value="addRectangleGeometry">添加矩形</option>
<option value="addWallGeometry">添加墙</option>
<option value="addBoxGeometry">添加盒子</option>
<option value="addEllipsoidGeometry">添加椭球体</option>
<option value="addCylinderGeometry">添加圆柱体</option>
</select>
<select id="dropdown2" onchange="removePrimitive()">
<option value="null">null</option>
<option value="removePolylineGeometry">删除线</option>
<option value="removePolygonGeometry">删除面</option>
<option value="removeEllipseGeometry">删除椭圆</option>
<option value="removeCircleGeometry">删除圆</option>
<option value="removeCorridorGeometry">删除走廊</option>
<option value="removeRectangleGeometry">删除矩形</option>
<option value="removeWallGeometry">删除墙</option>
<option value="removeBoxGeometry">删除盒子</option>
<option value="removeEllipsoidGeometry">删除椭球体</option>
<option value="removeCylinderGeometry">删除圆柱体</option>
</select>
</div>
<script>
Cesium.Ion.defaultAccessToken = '你的token';
var viewer = new Cesium.Viewer("cesiumContainer", {
animation: false, //是否显示动画工具
timeline: false, //是否显示时间轴工具
fullscreenButton: false, //是否显示全屏按钮工具
//加载天地图影像图
imageryProvider: new 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=你的tk",
subdomains: ['0', '1', '2', '3', '4', '5', '6', '7'], //服务负载子域
layer: "tdtImgLayer",
style: "default",
format: "image/jpeg",
tileMatrixSetID: "GoogleMapsCompatible",//使用谷歌的瓦片切片方式
show: true
})
});
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(108, 42, 6000000),
})
//绘制线
//定义几何形状
var polyline = new Cesium.GeometryInstance({
geometry: new Cesium.PolylineGeometry({
positions: Cesium.Cartesian3.fromDegreesArray([
108.0, 31.0,
100.0, 36.0,
105.0, 39.0
]),
width: 2.0
})
});
//定义外观
var polylineAppearance = new Cesium.PolylineMaterialAppearance({
material: Cesium.Material.fromType('Color')
})
//创建Primitive
var addPolylineGeometry = new Cesium.Primitive({
geometryInstances: polyline,
appearance: polylineAppearance
})
//绘制面
//定义几何形状
var polygon = new Cesium.GeometryInstance({
geometry: new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArray([
108, 45,
109, 48,
104, 48,
103, 45
])
)
})
});
//定义外观
var polygonAppearance = new Cesium.MaterialAppearance({
material: Cesium.Material.fromType('Dot'),
})
//创建Primitive
var addPolygonGeometry = new Cesium.Primitive({
geometryInstances: polygon,
appearance: polygonAppearance
})
//绘制椭圆
//定义几何形状
var ellipse = new Cesium.GeometryInstance({
geometry: new Cesium.EllipseGeometry({
center: Cesium.Cartesian3.fromDegrees(105, 40.0),
semiMajorAxis: 500000.0,
semiMinorAxis: 300000.0,
//rotation: Cesium.Math.toRadians(60.0)
})
});
//定义外观
var ellipseAppearance = new Cesium.EllipsoidSurfaceAppearance({
material: Cesium.Material.fromType('Stripe')
})
//创建Primitive
var addEllipseGeometry = new Cesium.Primitive({
geometryInstances: ellipse,
appearance: ellipseAppearance
})
//绘制圆
//定义几何形状
var circle = new Cesium.GeometryInstance({
geometry: new Cesium.CircleGeometry({
center: Cesium.Cartesian3.fromDegrees(100, 45.0),
radius: 300000.0,
})
});
//定义外观
var circleAppearance = new Cesium.EllipsoidSurfaceAppearance({
material: Cesium.Material.fromType('Grid')
})
//创建Primitive
var addCircleGeometry = new Cesium.Primitive({
geometryInstances: circle,
appearance: circleAppearance
})
//绘制走廊
//定义几何形状
var corridor = new Cesium.GeometryInstance({
geometry: new Cesium.CorridorGeometry({
positions: Cesium.Cartesian3.fromDegreesArray([100.0, 40.0, 105.0, 35.0, 102.0, 33.0]),
width: 100000
}),
attributes: {
color: new Cesium.ColorGeometryInstanceAttribute(0.2, 0.5, 0.2, 0.7)
}
});
//定义外观
var corridorAppearance = new Cesium.PerInstanceColorAppearance({
flat: true,
translucent: true
})
//创建Primitive
var addCorridorGeometry = new Cesium.Primitive({
geometryInstances: corridor,
appearance: corridorAppearance
})
//绘制矩形
//定义几何形状
var rectangle = new Cesium.GeometryInstance({
geometry: new Cesium.RectangleGeometry({
rectangle: Cesium.Rectangle.fromDegrees(95.0, 39.0, 100.0, 42.0),
//height: 10000.0
})
});
//定义外观
var rectangleAppearance = new Cesium.EllipsoidSurfaceAppearance({
material: Cesium.Material.fromType('Water')
})
//创建Primitive
var addRectangleGeometry = new Cesium.Primitive({
geometryInstances: rectangle,
appearance: rectangleAppearance
})
//绘制墙
//定义几何形状
var wall = new Cesium.GeometryInstance({
geometry: new Cesium.WallGeometry({
positions: Cesium.Cartesian3.fromDegreesArrayHeights([
107.0, 43.0, 100000.0,
97.0, 43.0, 100000.0,
97.0, 40.0, 100000.0,
107.0, 40.0, 100000.0,
107.0, 43.0, 100000.0
])
})
})
//定义外观
var wallAppearance = new Cesium.MaterialAppearance({
material: Cesium.Material.fromType('Color'),
})
//创建Primitive
var addWallGeometry = new Cesium.Primitive({
geometryInstances: wall,
appearance: wallAppearance
})
//绘制盒子
//本地参考中心点
var boxCenter = Cesium.Cartesian3.fromDegrees(106.0, 45.0);
//转移矩阵
var transformMatrix = Cesium.Transforms.eastNorthUpToFixedFrame(boxCenter)
//仿射变换矩阵
var affineMatrix = Cesium.Matrix4.multiplyByTranslation(
//左侧乘的转换矩阵
transformMatrix,//从具有东北向上轴的参考帧计算4x4变换矩阵,以提供的原点为中心
//转化
new Cesium.Cartesian3(0.0, 0.0, 80000.0),
new Cesium.Matrix4()
)
//将几何图形从模型坐标转换为世界坐标的模型矩阵
var boxModelMatrix = Cesium.Matrix4.multiplyByUniformScale(
//左侧乘的仿射矩阵
affineMatrix,
//比例
1.0,
new Cesium.Matrix4()
);
//定义几何实体
var box = new Cesium.GeometryInstance({
modelMatrix: boxModelMatrix,
geometry: Cesium.BoxGeometry.fromDimensions({
dimensions: new Cesium.Cartesian3(200000.0, 200000.0, 200000.0)
}),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromRandom({
alpha: 0.7
}))
}
});
//定义外观
var boxAppearance = new Cesium.PerInstanceColorAppearance({
//translucent: false,
//closed: true
})
//创建Primitive
var addBoxGeometry = new Cesium.Primitive({
geometryInstances: box,
appearance: boxAppearance
})
//绘制椭球体
//本地参考中心点
var ellipsoidCenter = Cesium.Cartesian3.fromDegrees(102.0, 45.0);
//将几何图形从模型坐标转换为世界坐标的模型矩阵
var ellipsoidModelMatrix = Cesium.Matrix4.multiplyByUniformScale(
//仿射变换矩阵
Cesium.Matrix4.multiplyByTranslation(
Cesium.Transforms.eastNorthUpToFixedFrame(ellipsoidCenter),//转移矩阵
new Cesium.Cartesian3(0.0, 0.0, 300000.0),
new Cesium.Matrix4()),
200,
new Cesium.Matrix4()
);
//定义几何形状
var ellipsoid = new Cesium.GeometryInstance({
modelMatrix: ellipsoidModelMatrix,
geometry: new Cesium.EllipsoidGeometry({
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
radii: new Cesium.Cartesian3(800, 800, 800)//定义椭球体x、y、z方向上的半径
}),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromRandom())
}
});
//定义外观
var ellipsoidAppearance = new Cesium.PerInstanceColorAppearance({
translucent: false,
});
//创建Primitive
var addEllipsoidGeometry = new Cesium.Primitive({
geometryInstances: ellipsoid,
appearance: ellipsoidAppearance
})
//绘制柱体
//将几何图形从模型坐标转换为世界坐标的模型矩阵
var cylinderModelMatrix = Cesium.Matrix4.multiplyByTranslation(
//转移矩阵
Cesium.Transforms.eastNorthUpToFixedFrame(
Cesium.Cartesian3.fromDegrees(100.0, 40.0)//本地参考中心点
),
new Cesium.Cartesian3(0.0, 0.0, 200000.0),
new Cesium.Matrix4()
);
//定义几何形状
var cylinder = new Cesium.GeometryInstance({
geometry: new Cesium.CylinderGeometry({
length: 400000.0,//高度
topRadius: 200000.0,//顶面半径
bottomRadius: 200000.0,//底面半径
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
}),
modelMatrix: cylinderModelMatrix,
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromRandom())
}
});
//定义外观
var cylinderAppearance = new Cesium.PerInstanceColorAppearance({
translucent: false,
})
//创建Primitive
var addCylinderGeometry = new Cesium.Primitive({
geometryInstances: cylinder,
appearance: cylinderAppearance
})
/* //绘制球体
//将几何图形从模型坐标转换为世界坐标的模型矩阵
var sphereModelMatrix = Cesium.Matrix4.multiplyByUniformScale(
//仿射矩阵
Cesium.Matrix4.multiplyByTranslation(
//转移矩阵
Cesium.Transforms.eastNorthUpToFixedFrame(
Cesium.Cartesian3.fromDegrees(116.0, 42.0)//本地参考中心点
),
new Cesium.Cartesian3(0.0, 0.0, 100000.0),
new Cesium.Matrix4()),
90000.0,
new Cesium.Matrix4());
var sphereGeometry = new Cesium.GeometryInstance({
modelMatrix: sphereModelMatrix,
geometry: new Cesium.SphereGeometry({
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT,
radius: 1,
}),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromRandom({
alpha: 0.5
}))
}
});
//定义外观并添加
var addSphereGeometry = new Cesium.Primitive({
geometryInstances: sphereGeometry,
appearance: new Cesium.PerInstanceColorAppearance({
translucent: false,
closed: true
})
}) */
var primitiveCollection = new Cesium.PrimitiveCollection();
primitiveCollection.destroyPrimitives = false;
viewer.scene.primitives.add(primitiveCollection);
var dropdown = document.getElementById('dropdown');
var dropdown2 = document.getElementById('dropdown2');
function addPrimitive() {
switch (dropdown.value) {
case 'addPolylineGeometry':
if (!primitiveCollection.contains(addPolylineGeometry))
primitiveCollection.add(addPolylineGeometry)
break;
case 'addPolygonGeometry':
if (!primitiveCollection.contains(addPolygonGeometry))
primitiveCollection.add(addPolygonGeometry)
break;
case 'addEllipseGeometry':
if (!primitiveCollection.contains(addEllipseGeometry))
primitiveCollection.add(addEllipseGeometry)
break;
case 'addCircleGeometry':
if (!primitiveCollection.contains(addCircleGeometry))
primitiveCollection.add(addCircleGeometry)
break;
case 'addCorridorGeometry':
if (!primitiveCollection.contains(addCorridorGeometry))
primitiveCollection.add(addCorridorGeometry)
break;
case 'addRectangleGeometry':
if (!primitiveCollection.contains(addRectangleGeometry))
primitiveCollection.add(addRectangleGeometry)
break;
case 'addWallGeometry':
if (!primitiveCollection.contains(addWallGeometry))
primitiveCollection.add(addWallGeometry)
break;
case 'addBoxGeometry':
if (!primitiveCollection.contains(addBoxGeometry))
primitiveCollection.add(addBoxGeometry)
break;
case 'addEllipsoidGeometry':
if (!primitiveCollection.contains(addEllipsoidGeometry))
primitiveCollection.add(addEllipsoidGeometry)
break;
case 'addCylinderGeometry':
if (!primitiveCollection.contains(addCylinderGeometry))
primitiveCollection.add(addCylinderGeometry)
break;
case 'addSphereGeometry':
if (!primitiveCollection.contains(addSphereGeometry))
primitiveCollection.add(addSphereGeometry)
break;
default:
break;
}
}
function removePrimitive() {
switch (dropdown2.value) {
case 'removePolylineGeometry':
primitiveCollection.remove(addPolylineGeometry)
break;
case 'removePolygonGeometry':
primitiveCollection.remove(addPolygonGeometry)
break;
case 'removeEllipseGeometry':
primitiveCollection.remove(addEllipseGeometry)
break;
case 'removeCircleGeometry':
primitiveCollection.remove(addCircleGeometry)
break;
case 'removeCorridorGeometry':
primitiveCollection.remove(addCorridorGeometry)
break;
case 'removeRectangleGeometry':
primitiveCollection.remove(addRectangleGeometry)
break;
case 'removeWallGeometry':
primitiveCollection.remove(addWallGeometry)
break;
case 'removeBoxGeometry':
primitiveCollection.remove(addBoxGeometry)
break;
case 'removeEllipsoidGeometry':
primitiveCollection.remove(addEllipsoidGeometry)
break;
case 'removeCylinderGeometry':
primitiveCollection.remove(addCylinderGeometry)
break;
case 'removeSphereGeometry':
primitiveCollection.remove(addSphereGeometry)
break;
default:
break;
}
}
</script>
</body>
</html>
(2)显示结果
2.5GroundPrimitive绘制贴地图形
GroundPrimitive可以被看作Primitive的扩展,顾名思义,该类就是帮助用户将几何图形贴地的类,官方解释为Scene中的地形或3D Tiles上叠加的几何图形。与Primitive不同的是,GroundPrimitive中的几何图形必须来自单个几何图形,目前还不支持对多个几何图形进行批处理。
(1)关键代码
4_2.5_Primitive绘制贴地.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>绘制实体_Primitive绘制贴地</title>
<script src="./Build/Cesium/Cesium.js"></script>
<link rel="stylesheet" href="./Build/Cesium//Widgets/widgets.css">
<!-- <script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script> -->
<style>
html,
body,
#cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
.toolbar {
position: absolute;
top: 10px;
left: 20px;
background-color: rgb(0, 0, 0, 0);
}
</style>
</head>
<body>
<div id="cesiumContainer">
</div>
<div id="menu" class="toolbar">
<select id="dropdown" onchange="addPrimitive()">
<option value="null">null</option>
<option value="addPolylineGeometry">添加线</option>
<option value="addPolygonGeometry">添加面</option>
<option value="addEllipseGeometry">添加椭圆</option>
<option value="addCircleGeometry">添加圆</option>
<option value="addCorridorGeometry">添加走廊</option>
<option value="addRectangleGeometry">添加矩形</option>
</select>
<select id="dropdown2" onchange="removePrimitive()">
<option value="null">null</option>
<option value="removePolylineGeometry">删除线</option>
<option value="removePolygonGeometry">删除面</option>
<option value="removeEllipseGeometry">删除椭圆</option>
<option value="removeCircleGeometry">删除圆</option>
<option value="removeCorridorGeometry">删除走廊</option>
<option value="removeRectangleGeometry">删除矩形</option>
</select>
</div>
<script>
Cesium.Ion.defaultAccessToken = '你的token';
var viewer = new Cesium.Viewer("cesiumContainer", {
animation: false, //是否显示动画工具
timeline: false, //是否显示时间轴工具
fullscreenButton: false, //是否显示全屏按钮工具
terrainProvider: Cesium.createWorldTerrain()
});
//viewer.scene.globe.depthTestAgainstTerrain = true;
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(108, 42, 6000000),
})
//绘制线
//定义几何形状
var polyline = new Cesium.GeometryInstance({
geometry: new Cesium.GroundPolylineGeometry({ //贴地线
positions: Cesium.Cartesian3.fromDegreesArray([
108.0, 31.0,
100.0, 36.0,
105.0, 39.0
]),
width: 5.0
})
});
//定义外观
var polylineAppearance = new Cesium.PolylineMaterialAppearance({
material: Cesium.Material.fromType('Color')
})
//创建GroundPrimitive
var addGroundPolylinePrimitive = new Cesium.GroundPolylinePrimitive({ //仅支持GroundPolylineGeometry
geometryInstances: polyline,
appearance: polylineAppearance
})
//绘制面
//定义几何形状
var polygon = new Cesium.GeometryInstance({
geometry: new Cesium.PolygonGeometry({
polygonHierarchy: new Cesium.PolygonHierarchy(
Cesium.Cartesian3.fromDegreesArray([
110.0, 30.0,
114.0, 38.0,
106.0, 35.0,
108.0, 30.0,
])
)
})
});
//定义外观
var polygonAppearance = new Cesium.MaterialAppearance({
material: Cesium.Material.fromType('Color', {
color: new Cesium.Color(0.5, 0.8, 0.0, 0.6)
}),
faceForward: true
})
//创建GroundPrimitive
var addPolygonGroundPrimitive = new Cesium.GroundPrimitive({ //贴地面
geometryInstances: polygon,
appearance: polygonAppearance
})
//绘制椭圆
//定义几何形状
var ellipse = new Cesium.GeometryInstance({
geometry: new Cesium.EllipseGeometry({
center: Cesium.Cartesian3.fromDegrees(105, 40.0),
semiMajorAxis: 500000.0,
semiMinorAxis: 300000.0,
rotation: Cesium.Math.toRadians(60.0)
})
});
//定义外观
var ellipseAppearance = new Cesium.EllipsoidSurfaceAppearance({
material: Cesium.Material.fromType('Stripe')
})
//创建GroundPrimitive
var addEllipseGroundPrimitive = new Cesium.GroundPrimitive({ //贴地椭圆
geometryInstances: ellipse,
appearance: ellipseAppearance
})
//绘制圆
//定义几何形状
var circle = new Cesium.GeometryInstance({
geometry: new Cesium.CircleGeometry({
center: Cesium.Cartesian3.fromDegrees(100, 45.0),
radius: 300000.0,
})
});
//定义外观
var circleAppearance = new Cesium.EllipsoidSurfaceAppearance({
material: Cesium.Material.fromType('Grid')
})
//创建GroundPrimitive
var addCircleGroundPrimitive = new Cesium.GroundPrimitive({ //贴地圆
geometryInstances: circle,
appearance: circleAppearance
})
//绘制矩形
//定义几何形状
var rectangle = new Cesium.GeometryInstance({
geometry: new Cesium.RectangleGeometry({
rectangle: Cesium.Rectangle.fromDegrees(95.0, 39.0, 100.0, 42.0),
//height: 10000.0
})
});
//定义外观
var rectangleAppearance = new Cesium.EllipsoidSurfaceAppearance({
material: Cesium.Material.fromType('Water')
})
//创建GroundPrimitive
var addRectangleGroundPrimitive = new Cesium.GroundPrimitive({ //贴地矩形
geometryInstances: rectangle,
appearance: rectangleAppearance
})
//绘制走廊
//定义几何形状
var corridor = new Cesium.GeometryInstance({
geometry: new Cesium.CorridorGeometry({
vertexFormat: Cesium.VertexFormat.POSITION_ONLY,
positions: Cesium.Cartesian3.fromDegreesArray([100.0, 40.0, 105.0, 35.0, 102.0, 33.0]),
width: 100000
}),
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(new Cesium.Color(0.2, 0.5, 0.2, 0.7))
}
});
//定义外观
var corridorAppearance = new Cesium.PerInstanceColorAppearance({
flat: true,
translucent: true
})
//创建GroundPrimitive
var addCorridorGroundPrimitive = new Cesium.GroundPrimitive({ //贴地走廊
geometryInstances: corridor,
appearance: corridorAppearance
})
var primitiveCollection = new Cesium.PrimitiveCollection();
primitiveCollection.destroyPrimitives = false;
viewer.scene.primitives.add(primitiveCollection);
var dropdown = document.getElementById('dropdown');
var dropdown2 = document.getElementById('dropdown2');
function addPrimitive(){
switch (dropdown.value){
case 'addPolylineGeometry':
if (!primitiveCollection.contains(addGroundPolylinePrimitive))
primitiveCollection.add(addGroundPolylinePrimitive)
break;
case 'addPolygonGeometry':
if (!primitiveCollection.contains(addPolygonGroundPrimitive))
primitiveCollection.add(addPolygonGroundPrimitive)
break;
case 'addEllipseGeometry':
if (!primitiveCollection.contains(addEllipseGroundPrimitive))
primitiveCollection.add(addEllipseGroundPrimitive)
break;
case 'addCircleGeometry':
if (!primitiveCollection.contains(addCircleGroundPrimitive))
primitiveCollection.add(addCircleGroundPrimitive)
break;
case 'addCorridorGeometry':
if (!primitiveCollection.contains(addCorridorGroundPrimitive))
primitiveCollection.add(addCorridorGroundPrimitive)
break;
case 'addRectangleGeometry':
if (!primitiveCollection.contains(addRectangleGroundPrimitive))
primitiveCollection.add(addRectangleGroundPrimitive)
break;
default:
break;
}
}
function removePrimitive(){
switch (dropdown2.value){
case 'removePolylineGeometry':
primitiveCollection.remove(addGroundPolylinePrimitive)
break;
case 'removePolygonGeometry':
primitiveCollection.remove(addPolygonGroundPrimitive)
break;
case 'removeEllipseGeometry':
primitiveCollection.remove(addEllipseGroundPrimitive)
break;
case 'removeCircleGeometry':
primitiveCollection.remove(addCircleGroundPrimitive)
break;
case 'removeCorridorGeometry':
primitiveCollection.remove(addCorridorGroundPrimitive)
break;
case 'removeRectangleGeometry':
primitiveCollection.remove(addRectangleGroundPrimitive)
break;
default:
break;
}
}
</script>
</body>
</html>
(2)显示结果
2.6Primitive管理
一个Primitive图形是由两部分组成的:第一部分为几何形状(Geometry),用于定义Primitive图形的结构;第二部分为外观(Appearance),主要用于定义Primitive图形的渲染着色。
Primitive中可以有多个几何实例,即我们可以通过Primitive绘制多个几何对象,但是多个几何对象只能使用一个外观,这可以称为合并绘制几何图形。
(1)关键代码
4_2.6_Primitive管理.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>绘制实体_Primitive管理</title>
<script src="./Build/Cesium/Cesium.js"></script>
<link rel="stylesheet" href="./Build/Cesium//Widgets/widgets.css">
<!-- <script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script> -->
<style>
html,
body,
#cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
.toolbar {
position: absolute;
top: 10px;
left: 20px;
background-color: rgb(0, 0, 0, 0);
}
</style>
</head>
<body>
<div id="cesiumContainer">
</div>
<div id="menu" class="toolbar">
<select id="dropdown" onchange="edit()">
<option value="null">null</option>
<option value="edit1">合并添加几何</option>
<option value="edit2">拾取几何图形</option>
<option value="edit3">更改实例属性</option>
<option value="edit4">移除单个实体</option>
<option value="edit5">移除全部实体</option>
</select>
</div>
<script>
Cesium.Ion.defaultAccessToken = '你的token';
var viewer = new Cesium.Viewer("cesiumContainer", {
animation: false, //是否显示动画工具
timeline: false, //是否显示时间轴工具
fullscreenButton: false, //是否显示全屏按钮工具
});
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(108, 42, 6000000),
})
//合并多个矩形
var instances = []; //存储几何实例
for (var lon = -180.0; lon < 180.0; lon += 5.0) {
for (var lat = -85.0; lat < 85.0; lat += 5.0) {
instances.push(new Cesium.GeometryInstance({
geometry: new Cesium.RectangleGeometry({
rectangle: Cesium.Rectangle.fromDegrees(lon, lat, lon + 5.0, lat + 5.0),
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
}),
id: lon + "-" + lat,
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(
Cesium.Color.fromRandom(
{
alpha: 0.6
}
)
)
}
}));
}
}
//创建Primitive
var mergeInstances = new Cesium.Primitive({
geometryInstances: instances,
appearance: new Cesium.PerInstanceColorAppearance()
})
//绘制柱体
//将几何图形从模型坐标转换为世界坐标的模型矩阵
var cylinderModelMatrix = Cesium.Matrix4.multiplyByTranslation(
//转移矩阵
Cesium.Transforms.eastNorthUpToFixedFrame(
Cesium.Cartesian3.fromDegrees(100.0, 40.0)//本地参考中心点
),
new Cesium.Cartesian3(0.0, 0.0, 200000.0),
new Cesium.Matrix4()
);
//定义几何形状
var cylinder = new Cesium.GeometryInstance({
geometry: new Cesium.CylinderGeometry({
length: 400000.0,//高度
topRadius: 200000.0,//顶面半径
bottomRadius: 200000.0,//底面半径
vertexFormat: Cesium.PerInstanceColorAppearance.VERTEX_FORMAT
}),
modelMatrix: cylinderModelMatrix,
attributes: {
color: Cesium.ColorGeometryInstanceAttribute.fromColor(Cesium.Color.fromRandom())
}
});
//定义外观
var cylinderAppearance = new Cesium.PerInstanceColorAppearance({
translucent: false,
})
//创建Primitive
var addCylinderGeometry = new Cesium.Primitive({
geometryInstances: cylinder,
appearance: cylinderAppearance
})
//viewer.scene.primitives.add(addCylinderGeometry);
var primitivesCollection = new Cesium.PrimitiveCollection();
primitivesCollection.destroyPrimitives = false;
viewer.scene.primitives.add(primitivesCollection);
var dropdown = document.getElementById('dropdown');
function edit(){
switch (dropdown.value){
case 'edit1':
primitivesCollection.add(mergeInstances);
break;
case 'edit2':
var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas);
handler.setInputAction(function (movement) {
var pick = viewer.scene.pick(movement.position);
alert('点击实例id为:'+pick.id)
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
break;
case 'edit3':
var attributes = mergeInstances.getGeometryInstanceAttributes('105-40');
attributes.color = Cesium.ColorGeometryInstanceAttribute.toValue(Cesium.Color.fromRandom({
alpha: 1.0
}));
break;
case 'edit4':
viewer.scene.primitives.remove(addCylinderGeometry)
break;
case 'edit5':
primitivesCollection.removeAll()
break;
default:
break;
}
}
</script>
</body>
</html>
(2)显示结果
2.7交互绘制
根据前面所学的坐标系统和几何图形绘制来实现在倾斜摄影三维模型场景中交互绘制点、线、面、圆、矩形,以及单击添加模型的功能。
(1)关键代码
4_2.7_交互绘制.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>绘制实体_交互绘制</title>
<script src="./Build/Cesium/Cesium.js"></script>
<link rel="stylesheet" href="./Build/Cesium//Widgets/widgets.css">
<!-- <script src="http://libs.baidu.com/jquery/2.1.4/jquery.min.js"></script> -->
<style>
html,
body,
#cesiumContainer {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
}
.toolbar {
position: absolute;
top: 10px;
left: 20px;
background-color: rgb(0, 0, 0, 0);
}
</style>
</head>
<body>
<div id="cesiumContainer">
</div>
<div id="menu" class="toolbar">
<select id="dropdown" onchange="draw()">
<option value="null">null</option>
<option value="drawPoint">绘制点</option>
<option value="drawLine">绘制线</option>
<option value="drawPolygon">绘制面</option>
<option value="drawCircle">绘制圆</option>
<option value="drawRectangle">绘制矩形</option>
<option value="drawModel">添加模型</option>
<option value="clear">清除</option>
</select>
</div>
<script>
Cesium.Ion.defaultAccessToken = '你的token';
var viewer = new Cesium.Viewer("cesiumContainer", {
terrainProvider: Cesium.createWorldTerrain(), //添加在线地形
animation: false, //是否显示动画工具
timeline: false, //是否显示时间轴工具
fullscreenButton: false, //是否显示全屏按钮工具
});
//开启地形检测
viewer.scene.globe.depthTestAgainstTerrain = true;
//加载三维模型
var tileset = viewer.scene.primitives.add(
new Cesium.Cesium3DTileset({
url: './倾斜摄影/大雁塔3DTiles/tileset.json'
})
);
//定位过去
viewer.zoomTo(tileset);
//绘制实体
var activeShapePoints = []; //动态点数组
var activeShape; //动态图形
var floatingPoint; //第一个点 判断是否开始获取鼠标移动结束位置并添加至activeShapePoints
var drawingMode; //绘制模式
//绘制点
function drawPoint(position) {
var pointGeometry = viewer.entities.add({
name: "点几何对象",
position: position,
point: {
color: Cesium.Color.SKYBLUE,
pixelSize: 6,
outlineColor: Cesium.Color.YELLOW,
outlineWidth: 2,
//disableDepthTestDistance: Number.POSITIVE_INFINITY
}
});
return pointGeometry;
};
//添加模型
function addModel(position) {
var ceshi = viewer.entities.add({
name: '小车模型',
position: position,
model: {
uri: './3D格式数据/glTF/CesiumMilkTruck.gltf',
scale: 2 //放大倍数
}
})
}
//绘制图形
function drawShape(positionData) {
var shape;
if (drawingMode === 'line') {
shape = viewer.entities.add({
polyline: {
positions: positionData,
width: 5.0,
material: new Cesium.PolylineGlowMaterialProperty({
color: Cesium.Color.GOLD,
}),
clampToGround: true
}
});
}
else if (drawingMode === 'polygon') {
shape = viewer.entities.add({
polygon: {
hierarchy: positionData,
material: new Cesium.ColorMaterialProperty(Cesium.Color.SKYBLUE.withAlpha(0.7))
}
});
}
else if (drawingMode === 'circle') {
//当positionData为数组时绘制最终图,如果为function则绘制动态图
var value = typeof positionData.getValue === 'function' ? positionData.getValue(0) : positionData;
shape = viewer.entities.add({
position: activeShapePoints[0],
ellipse: {
semiMinorAxis: new Cesium.CallbackProperty(function () {
//半径 两点间距离
var r = Math.sqrt(Math.pow(value[0].x - value[value.length - 1].x, 2) + Math
.pow(value[0].y - value[value.length - 1].y, 2));
return r ? r : r + 1;
}, false),
semiMajorAxis: new Cesium.CallbackProperty(function () {
var r = Math.sqrt(Math.pow(value[0].x - value[value.length - 1].x, 2) + Math
.pow(value[0].y - value[value.length - 1].y, 2));
return r ? r : r + 1;
}, false),
material: Cesium.Color.BLUE.withAlpha(0.5),
outline: true
}
});
}
else if (drawingMode === 'rectangle') {
//当positionData为数组时绘制最终图,如果为function则绘制动态图
var arr = typeof positionData.getValue === 'function' ? positionData.getValue(0) : positionData;
shape = viewer.entities.add({
rectangle: {
coordinates: new Cesium.CallbackProperty(function () {
var obj = Cesium.Rectangle.fromCartesianArray(arr);
return obj;
}, false),
material: Cesium.Color.RED.withAlpha(0.5)
}
});
}
return shape;
}
var handler = new Cesium.ScreenSpaceEventHandler(viewer.canvas);
//鼠标左键
handler.setInputAction(function (event) {
// 用 `viewer.scene.pickPosition` 代替 `viewer.camera.pickEllipsoid`
// 当鼠标在地形上移动时可以得到正确的点.
var earthPosition = viewer.scene.pickPosition(event.position);
if (drawingMode == "point") {
drawPoint(earthPosition); //绘制点
}
else if (drawingMode == "model") {
addModel(earthPosition); //添加模型
}
// `如果鼠标不在地球上 则earthPosition是未定义
else if (drawingMode == "line" || drawingMode == "polygon" || drawingMode == "circle" || drawingMode == "rectangle") {
if (Cesium.defined(earthPosition)) {
//第一次点击时,通过CallbackProperty绘制动态图
if (activeShapePoints.length === 0) {
floatingPoint = drawPoint(earthPosition);
activeShapePoints.push(earthPosition);
//动态点通过CallbackProperty实时更新渲染
var dynamicPositions = new Cesium.CallbackProperty(function () {
if (drawingMode === 'polygon') {
//如果绘制模式是polygon 回调返回的值就要是PolygonHierarchy类型
return new Cesium.PolygonHierarchy(activeShapePoints);
}
return activeShapePoints;
}, false);
activeShape = drawShape(dynamicPositions);//绘制动态图
}
//添加当前点进activeShapePoints,实时渲染动态图
activeShapePoints.push(earthPosition);
drawPoint(earthPosition);
}
}
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
//鼠标移动
handler.setInputAction(function (event) {
if (Cesium.defined(floatingPoint)) {
var newPosition = viewer.scene.pickPosition(event.endPosition); //获取鼠标移动最终位置
if (Cesium.defined(newPosition)) {
//动态去除数组中最后一个点,再添加最新一个点,保证只保留鼠标位置点
activeShapePoints.pop();
activeShapePoints.push(newPosition);
}
}
}, Cesium.ScreenSpaceEventType.MOUSE_MOVE);
// 删除动态绘制的图形 并绘制最终结果图
/* function terminateShape() {
activeShapePoints.pop();//去除最后一个动态点
if (activeShapePoints.length) {
drawShape(activeShapePoints);//绘制最终图
}
viewer.entities.remove(floatingPoint);//移除第一个点(重复了)
viewer.entities.remove(activeShape);//去除动态图形
floatingPoint = undefined;
activeShape = undefined;
activeShapePoints = [];
} */
//鼠标右键
handler.setInputAction(function (event) {
activeShapePoints.pop();//去除最后一个动态点
if (activeShapePoints.length) {
drawShape(activeShapePoints);//绘制最终图
}
viewer.entities.remove(floatingPoint);//移除第一个点(重复了)
viewer.entities.remove(activeShape);//去除动态图形
floatingPoint = undefined;
activeShape = undefined;
activeShapePoints = [];
//terminateShape();
}, Cesium.ScreenSpaceEventType.RIGHT_CLICK);
var dropdown = document.getElementById('dropdown');
function draw() {
switch (dropdown.value) {
case 'null':
drawingMode = 'null';
break;
case 'drawPoint':
drawingMode = 'point';
break;
case 'drawLine':
drawingMode = 'line';
break;
case 'drawPolygon':
drawingMode = 'polygon';
break;
case 'drawCircle':
drawingMode = 'circle';
break;
case 'drawRectangle':
drawingMode = 'rectangle';
break;
case 'drawModel':
drawingMode = 'model';
break;
case 'clear':
viewer.entities.removeAll();
break;
default:
break;
}
}
</script>
</body>
</html>
(2)显示结果
参考资料:
[1] 郭明强. 《WebGIS之Cesium三维软件开发》; 2023-04-01 [accessed 2024-01-26].
[2] GIS-CL. cesium entities 图形绘制; 2021-07-11 [accessed 2024-01-26].
[3] easyCesium. Cesium 态势标绘 军事标绘(已兼容在地形和模型上绘制); 2019-04-29 [accessed 2024-01-26].
[4] vtxf. Cesium的拾取问题总结; 2018-09-17 [accessed 2024-01-26].