cesium笔记集合

时间:2024-05-20 10:14:15

一、认识Cesium

概念

  • Cesium 是一个跨平台、跨浏览器的展示三维地球和地图的 javascript 库;
  • Cesium 使用WebGL 来进行硬件加速图形,使用时不需要任何插件支持,但是浏览器必须支持WebGL;
  • Cesium是基于Apache2.0 许可的开源程序。它可以免费的用于商业和非商业用途。

作用

  • 多种场景模式(3D,2.5D以及2D场景)的支持,真正的二三维一体化
  • 可以绘制各种几何图形、高亮区域,支持导入图片,甚至3D模型等多种数据可视化展示;
  • 可用于动态数据可视化并提供良好的触摸支持,支持绝大多数的浏览器和mobile;
  • Cesium还支持基于时间轴的动态数据展示。
  • 全球级别的高精度的地形和影像服务
  • 地形影像、模型、倾斜、二三维场景与时态数据

二、环境建立

开发之前设置步骤:

  1. 访问Cesium Viewer确保您的系统与Cesium兼容

  2. 安装Node.js的

  3. 克隆或下载zip并提取内容。

  4. 在控制台中,导航到根cesium-workshop目录。

  5. 运行npm install

  6. 运行npm start,点击控制台上的http://localhost:8080

应用程序目录

  • Source/ : 我们项目的代码。

  • ThirdParty/ : 外部js库,目前只包含cesium。

  • LICENSE.md : 我们项目的说明条款。

  • index.html : 主页,包含项目程序代码和页面结构。

  • server.js : 简单的基于nodejs的http服务器。

CesiumJS完全兼容现代javascript 库和框架,下面是一些示例:

使用说明

点击 http://localhost:8080/ 出现的页面:

  • Documentation

    里面是Cesium的完整的API说明,里面可以找到:
    1、某一个模块的所有函数、属性
    2、部分效果截图

    3、部分函数,属性调用代码示例

  • Sandcastle

    一个沙盒,你可以在里面浏览当前版本的一些功能特性:
    1、一个可运行的代码库
    2、新建一个页面,进行代码测试
    3、导出测试代码

快速搭建最简环境

  1. 创建文件夹 cesium-test

  2. 引入编译成果 ,将cesium源码中的Build文件夹,拷入cesium-test

  3. 创建html ,将cesium源码中Apps/ 中的HelloWorld.html 拷入cesium-test

  4. 修改js和css的文件路径

  5. 发布

三、界面以及小组件显示隐藏

viewer介绍

  1. Geocoder : 查找位置工具,查找到之后会将镜头对准找到的地址,默认使用bing地图
  2. Home Button :视角返回初始位置
  3. Scene Mode Picker : 选择视角的模式,有三种:3D,2D,哥伦布视图(CV)
  4. Base Layer Picker : 图层选择器,选择要显示的地图服务和地形服务
  5. Navigation Help Button :导航帮助按钮,显示默认的地图控制帮助
  6. Animation : 动画器件,控制视图动画的播放速度
  7. Timeline :时间线,指示当前时间,并允许用户跳到特定的时间
  8. Credits Display :版权显示,显示数据归属,必选
  9. Fullscreen Button :全屏按钮

隐藏界面中的元素

1、通过js代码控制

界面上默认的小控件可以通过在初始化Viewer的时候设置相应的属性来关闭

var viewer = new Cesium.Viewer('cesiumContainer',{
    geocoder:false,
    homeButton:false,
    sceneModePicker:false,
    baseLayerPicker:false,
    navigationHelpButton:false,
    animation:false,
    creditContainer:"credit",
    timeline:false,
    fullscreenButton:false,
    vrButton:false,
    });
//界面默认的小控件的关闭方法,还有很多额外的属性,可以查看帮助文档

2、通过css控制

 /* 不占据空间,无法点击 */
      .cesium-viewer-toolbar,             /* 右上角按钮组 */
      .cesium-viewer-animationContainer,  /* 左下角动画控件 */
      .cesium-viewer-timelineContainer,   /* 时间线 */
      .cesium-viewer-bottom               /* logo信息 */
      {
        display: none;
      }
      .cesium-viewer-fullscreenContainer  /* 全屏按钮 */
     { position: absolute; top: -999em;  }
/*注:全屏按钮不能通过display:none的方式来达到隐藏的目的,这是因为生成的按钮控件的行内样式设置了display属性,会覆盖引入的css属性*/

显示帧速(FPS)

viewer.scene.debugShowFramesPerSecond = true;

四、绘制形状

通过Entity添加形状

案例:添加立方体

var viewer = new Cesium.Viewer('cesiumContainer');
var redBox = viewer.entities.add({
  name : 'Red box with black outline',
  position: Cesium.Cartesian3.fromDegrees(-107.0, 40.0, 300000.0),
  box : {
    dimensions : new Cesium.Cartesian3(400000.0, 300000.0, 500000.0),
    material : Cesium.Color.RED.withAlpha(0.5),
    outline : true,
    outlineColor : Cesium.Color.BLACK
  }
});

viewer.zoomTo(viewer.entities);

通过CZML添加

  • CZML也可以添加几何形状,而且CZML还可以描述动画

官方说明:CZML是一种JSON格式的字符串,用于描述与时间有关的动画场景,CZML包含点、线、地标、模型、和其他的一些图形元素,并指明了这些元素如何随时间而变化。某种程度上说, Cesium 和 CZML的关系就像 Google Earth 和 KML

var czml = [{
    "id" : "document",
    "name" : "box",
    "version" : "1.0"
},{
    "id" : "shape2",
    "name" : "Red box with black outline",
    "position" : {
        "cartographicDegrees" : [-107.0, 40.0, 300000.0]
    },
    "box" : {
        "dimensions" : {
            "cartesian": [400000.0, 300000.0, 500000.0]
        },
        "material" : {
            "solidColor" : {
                "color" : {
                    "rgba" : [255, 0, 0, 128]
                }
            }
        },
        "outline" : true,
        "outlineColor" : {
            "rgba" : [0, 0, 0, 255]
        }
    }
}];

var viewer = new Cesium.Viewer('cesiumContainer');
var dataSourcePromise = Cesium.CzmlDataSource.load(czml);
viewer.dataSources.add(dataSourcePromise);
viewer.zoomTo(dataSourcePromise);

五、3D Tiles

3D Tiles 是什么

3D Tiles是一种开放式规范,用于跨桌面,Web和移动应用程序共享,可视化,融合以及与大量异构3D地理空间内容交互。

3D Tiles将用于流式传输3D内容,包括建筑物,树木,点云和矢量数据。

参考[官网 3dtiles 介绍 ][https://cesium.com/blog/2015/08/10/introducing-3d-tiles/]

3D Tiles 运用

//contextCapture 可以将无人机成果转换成Cesium支持的倾斜摄影成果 ,数据的加载比较简单 
//但是问题在于生成的数据不一定是落在地面上,有可能是浮在空中的 

var tileset = viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
	url: url, //数据路径   
	maximumScreenSpaceError: 2, //最大的屏幕空间误差
	maximumNumberOfLoadedTiles: 1000, //最大加载瓦片个数
	modelMatrix: m //形状矩阵
}))

希望拍摄的成果能贴到地面上,和地图能很好的融合在一起

modelMatrix

Cesium3DTile里面的一个属性:可以更改位置

  1. 自己获取偏移量

    目标位置 = 平移矩阵 * 原始位置 (参考《WebGl编程指南》的第三章第四章)

    //Tx,Ty,Tz就是我们需要设置的 x,y,z方向上的平移距离
    //由于Cesium的矩阵是列主序的,所以这里写成:
    
    //创建平移矩阵方法一
    /*m = Cesium.Matrix4.fromArray([
    	1.0, 0.0, 0.0, 0.0,
    	0.0, 1.0, 0.0, 0.0,
    	0.0, 0.0, 1.0, 0.0,
    	x, y, z, 1.0
    ])*/
    
    //创建平移矩阵方法二
    var translation=Cesium.Cartesian3.fromArray([x, y, z]);
    m= Cesium.Matrix4.fromTranslation(translation);
    
    //生效
    tileset._modelMatrix = m;
    
    /*这里我们只需要不断的修改 x,y,z,就可以调整物体的位置了
    获取 x,y,z 之后,在加载3D Tiles 时将modelMatrix 设置成目标 x,y,z值,就完成了*/
    
    
  2. 计算偏移量

    [官方示例 ][https://cesiumjs.org/Cesium/Build/Apps/Sandcastle/index.html?src=3D Tiles Adjust Height.html]

//直接调用函数,调整高度,height表示物体离地面的高度
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);
}

六、cesium中的坐标

概念

cesium中常用的坐标有两种WGS84地理坐标系和笛卡尔空间坐标系(世界坐标)。

  • WGS84坐标一般以经纬度来指明一个地点,原点在椭球的质心 。

  • 笛卡尔空间坐标系常用来做一些空间位置变换如平移旋转缩放等等,坐标原点在椭球的中心 。

三维空间的右手笛卡尔坐标

偏航(yaw)/俯仰(pitch)/滚动(roll)

cesium笔记集合

屏幕坐标----------------------------------------------->Pick

世界坐标----------------------------------------------->Cartesian

地理坐标(弧度) ---------------------------------->cartographic

经纬度坐标-------------------------------------------->Point

说明:以经纬度固定模型位置,要先将经纬度转换为世界坐标

1.坐标系

new Cesium.Cartesian2(1,1) //表示一个二维笛卡尔坐标系,也就是直角坐标系(屏幕坐标系)
new Cesium.Cartesian3(1,1,1) //表示一个三维笛卡尔坐标系,也是直角坐标系(真实世界的坐标系)

2. 二维屏幕坐标系到三维坐标系的转换

var pick1= scene.globe.pick(viewer.camera.getPickRay(pt1), scene) 
//其中pt1为一个二维屏幕坐标。

3. 三维坐标到地理坐标的转换

var geoPt1= scene.globe.ellipsoid.cartesianToCartographic(pick1) 
//其中pick1是一个Cesium.Cartesian3对象。

4. 地理坐标到经纬度坐标的转换

var point1=[geoPt1.longitude / Math.PI * 180,geoPt1.latitude / Math.PI * 180]; 
//其中geoPt1是一个地理坐标。

5. 经纬度坐标转地理坐标(弧度)

var cartographic = Cesium.Cartographic.fromDegree(point) //point是经纬度值
var coord_wgs84 = Cesium.Cartographic.fromDegrees(lng, lat, alt);//单位:度,度,米

6. 经纬度坐标转世界坐标

var cartesian = Cesium.Cartesian3.fromDegree(point)

7. 计算两个三维坐标系之间的距离

var d = Cesium.Cartesian3.distance(
    new Cesium.Cartesian3(pick1.x, pick1.y, pick1.z), 
    new Cesium.Cartesian3(pick3.x, pick3.y, pick3.z)
); 
//pick1、pick3都是三维坐标系

七、相机(camera)

概念

  • 相机相当于我们在场景中的视野,模拟人的眼睛,用于观察视角。

Cesium默认支持使用鼠标和触摸事件控制相机 :

  • 左键单击并拖动 - 移动整个地图
  • 右键单击并拖动 - 放大和缩小相机。
  • 中轮滚动 - 也可以放大和缩小相机。
  • 中间点击并拖动 - 围绕地球表面的点旋转相机。

设置相机的位置

方法一、Cartesian

camera.setView({
    destination : new Cesium.Cartesian3(x, y, z),
    orientation: {
        //heading/pitch/roll 的单位是弧度
        heading : headingAngle,  //方向向量以正东方向为轴的旋转角度 
        pitch : pitchAngle,		//方向和水平平面的夹角 
        roll : rollAngle		//方向向量指向水平平面上方,反之表示方向向量指向平面下方
    }
});```

##### 方法二、Rectangle

>  设置为一个矩形区域

```js

viewer.camera.setView({
   ///西,南,东,北 
    destination : Cesium.Rectangle.fromDegrees(west, south, east, north),
    orientation: {
        heading : headingAngle,
        pitch : pitchAngle,
        roll : rollAngle
    }
})
//参数为可选参数,如果不设置默认以当前的相机去计算对应的属性  

方法三、flyTo

跳转镜头到指定位置

//lookAt(target, offect) 
//target目标位置在世界坐标,offect以目标为中心的当地东北向参考系中的目标的偏移量。
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 () {
         // 到达位置后执行的回调函数
         console.log('到达位置');
     },
     cancle: function () {
         // 如果取消飞行则会调用此函数
         console.log('取消飞行')
     },
     // 如果摄像机飞越高于该值,则调整俯仰俯仰的俯仰角度,并将地球保持在视口中。
     pitchAdjustHeight: -90, 
     maximumHeight:5000, // 相机最大飞行高度
     flyOverLongitude: 100, // 如果到达目的地有2种方式,设置具体值后会强制选择方向飞过这个经度
 });
    
方法四、lookAt

lookAt会将视角固定在设置的点上


var center = Cesium.Cartesian3.fromDegrees(-72.0, 40.0);
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));

直接限制相机高度范围

  • 设置后当相机高度达到设置的最大和最小高度时将不再放大和缩小

//相机的高度的最小值
	viewer.scene.screenSpaceCameraController.minimumZoomDistance = 250000;
//相机高度的最大值
	viewer.scene.screenSpaceCameraController.maximumZoomDistance = 22000000; 
//设置相机缩小时的速率
	viewer.scene.screenSpaceCameraController._minimumZoomRate = 30000; 
//设置相机放大时的速率
	viewer.scene.screenSpaceCameraController._maximumZoomRate=5906376272000  

官网Demo笔记

    var viewer = new Cesium.Viewer('cesiumDemo',{
        baseLayerPicker: false,
        imageryProvider: new Cesium.ArcGisMapServerImageryProvider({
            url: 'http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer'
        })
    });

    var scene = viewer.scene;
    var canvas = viewer.canvas; // 获取画布
    canvas.setAttribute('tabindex', '0'); // 获取焦点
    canvas.onclick = function() {
        canvas.focus();
    };
    var ellipsoid = viewer.scene.globe.ellipsoid; // 获取地球球体对象

    // 禁用默认的事件处理程序
    // 如果为真,则允许用户旋转相机。如果为假,相机将锁定到当前标题。此标志仅适用于2D和3D。
    scene.screenSpaceCameraController.enableRotate = false;
    // 如果为true,则允许用户平移地图。如果为假,相机将保持锁定在当前位置。此标志仅适用于2D和Columbus视图模式。
    scene.screenSpaceCameraController.enableTranslate = false;
    // 如果为真,允许用户放大和缩小。如果为假,相机将锁定到距离椭圆体的当前距离
    scene.screenSpaceCameraController.enableZoom = false;
    // 如果为真,则允许用户倾斜相机。如果为假,相机将锁定到当前标题。这个标志只适用于3D和哥伦布视图。
    scene.screenSpaceCameraController.enableTilt = false;
    // 如果为true,则允许用户使用免费外观。如果错误,摄像机视图方向只能通过转换或旋转进行更改。此标志仅适用于3D和哥伦布视图模式。
    scene.screenSpaceCameraController.enableLook = false;

    // 鼠标开始位置
    var startMousePosition;
    // 鼠标位置
    var mousePosition;
    // 鼠标状态标志
    var flags = {
        looking : false,
        moveForward : false, // 向前
        moveBackward : false, // 向后
        moveUp : false,// 向上
        moveDown : false,// 向下
        moveLeft : false,// 向左
        moveRight : false// 向右
    };

    var handler = new Cesium.ScreenSpaceEventHandler(canvas);

    // 接收用户鼠标(手势)事件
    handler.setInputAction(function(movement) {
        // 处理鼠标按下事件
        // movement: 接收值为一个对象,含有鼠标单击的x,y坐标
        flags.looking = true;
        // 设置鼠标当前位置
        mousePosition = startMousePosition = Cesium.Cartesian3.clone(movement.position);
    }, Cesium.ScreenSpaceEventType.LEFT_DOWN);

    handler.setInputAction(function(movement) {
        // 处理鼠标移动事件
        // 更新鼠标位置
        mousePosition = movement.endPosition;
    }, Cesium.ScreenSpaceEventType.MOUSE_MOVE);

    handler.setInputAction(function(position) {
        // 处理鼠标左键弹起事件
        flags.looking = false;
    }, Cesium.ScreenSpaceEventType.LEFT_UP);

    // 根据键盘按键返回标志
    function getFlagForKeyCode(keyCode) {
        switch (keyCode) {
            case 'W'.charCodeAt(0):
                return 'moveForward';
            case 'S'.charCodeAt(0):
                return 'moveBackward';
            case 'Q'.charCodeAt(0):
                return 'moveUp';
            case 'E'.charCodeAt(0):
                return 'moveDown';
            case 'D'.charCodeAt(0):
                return 'moveRight';
            case 'A'.charCodeAt(0):
                return 'moveLeft';
            default:
                return undefined;
        }
    }
    // 监听键盘按下事件
    document.addEventListener('keydown', function(e) {
        // 获取键盘返回的标志
        var flagName = getFlagForKeyCode(e.keyCode);
        if (typeof flagName !== 'undefined') {
            flags[flagName] = true;
        }
    }, false);

    // 监听键盘弹起时间
    document.addEventListener('keyup', function(e) {
        // 获取键盘返回的标志
        var flagName = getFlagForKeyCode(e.keyCode);
        if (typeof flagName !== 'undefined') {
            flags[flagName] = false;
        }
    }, false);

    // 对onTick事件进行监听
    // onTick事件:根据当前配置选项,从当前时间提前计时。应该每个帧都调用tick,而不管动画是否发生。
    // 简单的说就是每过一帧都会执行这个事件
    viewer.clock.onTick.addEventListener(function(clock) {
        // 获取实例的相机对象
        var camera = viewer.camera;

        if (flags.looking) {
            // 获取画布的宽度
            var width = canvas.clientWidth;
            // 获取画布的高度
            var height = canvas.clientHeight;

            // Coordinate (0.0, 0.0) will be where the mouse was clicked.
            var x = (mousePosition.x - startMousePosition.x) / width;
            var y = -(mousePosition.y - startMousePosition.y) / height;
            var lookFactor = 0.05;

            camera.lookRight(x * lookFactor);
            camera.lookUp(y * lookFactor);
        }

        // 获取相机高度
        // cartesianToCartographic(): 将笛卡尔坐标转化为地图坐标,方法返回Cartographic对象,包含经度、纬度、高度
        var cameraHeight = ellipsoid.cartesianToCartographic(camera.position).height;

        var moveRate = cameraHeight / 100.0;

        // 如果按下键盘就移动
        if (flags.moveForward) {
            camera.moveForward(moveRate);
        }
        if (flags.moveBackward) {
            camera.moveBackward(moveRate);
        }
        if (flags.moveUp) {
            camera.moveUp(moveRate);
        }
        if (flags.moveDown) {
            camera.moveDown(moveRate);
        }
        if (flags.moveLeft) {
            camera.moveLeft(moveRate);
        }
        if (flags.moveRight) {
            camera.moveRight(moveRate);
        }
    });

八、平面裁切

3D Tiles裁切

简单案例:创建一个法线向下的裁切平面并且经过原点,上面黄色区域的就被截掉了,如图所示:

cesium笔记集合

let clippingPlanes = new Cesium.ClippingPlaneCollection({
    planes: [
        new Cesium.ClippingPlane(new Cesium.Cartesian3(0.0, 0.0, -0.1), 0.0)
    ],
    unionClippingRegions: true,
    edgeColor: Cesium.Color.RED,
    edgeWidth: 1
})
 // 设置模型的裁切平面clippingPlanes
this.tileset = this.viewer.scene.primitives.add(new Cesium.Cesium3DTileset({
    url: '../../static/Cesium/Assets/Models/' + this.url, 
    dynamicScreenSpaceError: true,
    cullWithChildrenBounds: false,
    skipLevels: 0,
    maximumScreenSpaceError: 0, 
    clippingPlanes: clippingPlanes
}))

ClippingPlaneCollection

相关概念
  • 指定一组剪裁平面 。

  • 通常,剪裁平面的坐标是相对于它们所附着的对象,因此距离设置为0的平面将剪切穿过对象的中心。

  • 平面的法向,如果法线向下,以平面未界限,相反方向都是外部,如图:

cesium笔记集合

  • 平面法向所在坐标系是以正东方为x轴正方向,正北方为y轴正方向,正上面为z轴正方向的坐标系
  • cesium笔记集合
参数
  • planes:用于在每个平面的外部选择性地禁用渲染的对象数组

    • ClippingPlane:设置平面的法线方向和从原点到平面的最短距离,可以同时创建多个方向切片
  • edgeColor:应用的颜色用于突出显示剪切对象的边缘,就是测试阶段能让你看到剪切的位置

  • edgeWidth:应用于剪裁对象的边缘的高光的宽度(以像素为单位)

  • unionClippingRegions:如果为true,则区域将被剪裁(如果它位于集合中任何平面的外部)。否则,只有区域位于每个平面的外侧,才会剪切区域,就是所谓切片的交集。

    如图所示:黄色区域就是交集,原谅我的图画的好丑啊QAQ…

cesium笔记集合

[ 官方案例][https://cesiumjs.org/Cesium/Build/Apps/Sandcastle/?src=3D%20Tiles%20Clipping%20Planes.html]

cesium笔记集合