Cesium案例解析(三)——Camera相机
1. 概述
Cesium的Camera案例,展示了其关于漫游器镜头的控制,能够调整视图的位置。这里改进了一下这个实例,使之能够展示一些自己关注的兴趣点的情况,并总结遇到的问题。
2. 实例
2.1. Camera.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, maximum-scale=1, minimum-scale=1, user-scalable=no">
<meta name="description" content="Fly to a specified location or view a geographic rectangle.">
<meta name="cesium-sandcastle-labels" content="Beginner, Tutorials, Showcases">
<title>Cesium Demo</title>
<script type="text/javascript" src="../Build/Cesium/Cesium.js"></script>
<style>
@import url(../Build/Cesium/Widgets/widgets.css);
html,
body {
width: 100%;
height: 100%;
margin: 0;
padding: 0;
overflow: hidden;
font-family: sans-serif;
background: #000;
}
.fullSize {
display: block;
position: absolute;
top: 0;
left: 0;
border: none;
width: 100%;
height: 100%;
}
#toolbar {
margin: 5px;
padding: 2px 5px;
position: absolute;
}
</style>
</head>
<body>
<div id="cesiumContainer" class="fullSize"></div>
<div id="toolbar">
<select id = "camera_select", class="cesium-button">
<option value="undefined">
相机选项
</option>
<option value="undefined">
飞行至某一点——武汉大学
</option>
<option value="undefined">
飞行至某区域——武汉市
</option>
<option value="undefined">
设置相机点——华中科技大学
</option>
<option value="undefined">
设置相机区域——上海市
</option>
<option value="undefined">
从武大飞向华科
</option>
</select>
</div>
<script src="Camera.js"></script>
</body>
</html>
这段代码在数字地球展示组件的基础上新添加了一个视图控制的下拉列表框,选择相应的选项能够将当前的视图调整到对应的位置。
2.2. Camera.js
//Add your ion access token from cesium.com/ion/
Cesium.Ion.defaultAccessToken = '你在Cesium申请的key';
var tdtKey = "你在天地图申请的key";
'use strict';
//默认BING影像地图
var viewer = new Cesium.Viewer('cesiumContainer', {
imageryProvider: Cesium.createWorldImagery({
style: Cesium.IonWorldImageryStyle.AERIAL
}),
baseLayerPicker: false
});
//全球影像中文注记服务
var imageryLayers = viewer.scene.imageryLayers;
var tdtAnnoLayer = imageryLayers.addImageryProvider(new Cesium.WebMapTileServiceImageryProvider({
url: "http://t0.tianditu.gov.cn/cva_w/wmts?SERVICE=WMTS&REQUEST=GetTile&VERSION=1.0.0&LAYER=cva&STYLE=default&TILEMATRIXSET=w&FORMAT=tiles&TILEMATRIX={TileMatrix}&TILEROW={TileRow}&TILECOL={TileCol}&tk=" + tdtKey,
layer: "tdtAnnoLayer",
style: "default",
format: "image/jpeg",
tileMatrixSetID: "GoogleMapsCompatible"
}));
var camera_select = document.getElementById("camera_select");
if (camera_select) {
camera_select.onchange = function gradeChange() {
switch (camera_select.selectedIndex) {
case 1:
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(114.35231209, 30.53542614, 5000.0),
orientation: {
heading: Cesium.Math.toRadians(0.0),
pitch: Cesium.Math.toRadians(-90.0),
roll: Cesium.Math.toRadians(0.0)
}
});
break;
case 2:
viewer.camera.flyTo({
destination: Cesium.Rectangle.fromDegrees(113.683333, 29.966667, 115.083333, 31.366667)
});
break;
case 3:
viewer.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(114.40782845, 30.51011682, 5000.0),
orientation: {
heading: Cesium.Math.toRadians(0.0),
pitch: Cesium.Math.toRadians(-90.0),
roll: Cesium.Math.toRadians(0.0)
}
});
break;
case 4:
viewer.camera.setView({
destination: Cesium.Rectangle.fromDegrees(120.86667, 30.66667, 122.2, 31.883333)
});
break;
case 5: {
var whdxOptions = {
destination: Cesium.Cartesian3.fromDegrees(114.35231209, 30.53542614, 5000.0),
duration: 5,
orientation: {
heading: Cesium.Math.toRadians(0.0),
pitch: Cesium.Math.toRadians(-90.0),
roll: Cesium.Math.toRadians(0.0)
}
};
var hzkjdxOptions = {
destination: Cesium.Cartesian3.fromDegrees(114.40782845, 30.51011682, 5000.0),
orientation: {
heading: Cesium.Math.toRadians(0.0),
pitch: Cesium.Math.toRadians(-90.0),
roll: Cesium.Math.toRadians(0.0)
},
duration: 5,
//flyOverLongitude: Cesium.Math.toRadians(60.0)
};
whdxOptions.complete = function () {
setTimeout(function () {
viewer.camera.flyTo(hzkjdxOptions);
}, 1000);
};
// if (adjustPitch) {
// tokyoOptions.pitchAdjustHeight = 1000;
// laOptions.pitchAdjustHeight = 1000;
// }
viewer.camera.flyTo(whdxOptions);
}
break;
default:
break;
}
}
}
这段代码首先添加了Cesium.Viewer默认的Bing影像地图和天地图的中文标注;然后根据id获取HTML页面的下拉列表框控件camera_select;最后根据选项调整相应的相机视图。这里展示了几种调整视图的方式。
2.2.1. 飞行至某一点
设置相机镜头逐渐从当前位置飞行到某一点是通过Cesium.Camera的flyTo()函数实现的,其具体的函数定义如下:
该函数传入了键值对配置对象,其中destination、orientation这两项,分别表示相机镜头的位置和姿态。本例中相应的代码如下:
viewer.camera.flyTo({
destination: Cesium.Cartesian3.fromDegrees(114.35231209, 30.53542614, 5000.0),
orientation: {
heading: Cesium.Math.toRadians(0.0),
pitch: Cesium.Math.toRadians(-90.0),
roll: Cesium.Math.toRadians(0.0)
}
});
这段设置相机视图的代码意思就是,将相机的位置移动到经纬度位置(114.35231209, 30.53542614),离地面5000米的点;航向角(heading)设置为0度,俯仰角(pitch)设置为-90度,滚转角(roll)设置为0度。实际页面的显示效果为逐渐飞往某一点:
此时数字地球会显示在武汉大学附近,视线看上去会垂直与地面,并且东西南北方向也基本上与常规地图一致。实际上当不设置姿态参数orientation只设置位置参数destination也能达到同样的效果,说明(0.0,-90.0,0.0)的三个姿态角是设置相机视图的默认值。在Cesium的设定中,heading、pitch、roll的定义如下:

这说明航向角(heading)是绕Z后负方向旋转的角度,俯仰角(pitch)是绕Y轴负方向旋转的角度,滚转角(roll)是绕X轴正方向旋转的角度。那么问题来了,这个定义里面的X、Y、Z轴的指的是什么呢?我这里认为这个函数蕴含了一种视图变换,使得基于相机的视空间坐标系成为一种类似于一种北东地站心坐标系(NED)坐标系,XYZ轴指的正是这个视空间坐标系的XYZ轴。在这个视空间坐标系中,Z轴垂直球面向下(Down),Y轴沿纬线指东(East),X轴沿经线向北(North),而位于视空间坐标系原点的相机的姿态为由南看向北。在这种情况下,只需要使相机绕Y轴正向旋转90度,也就是俯仰角(pitch)设为90,就可以得到视线垂直于地图,东西南北向正常的视图。
2.2.2. 飞行至某区域
flyTo()函数另外一个很有用的功能就是根据设定的范围显示视图,这在显示特定空间的视图时特别有用,例如加载的三维模型的范围,一个地区的范围等等。实现也很很简单,只需要给位置参数destination传入一个Cesium.Rectangle对象即可:
viewer.camera.flyTo({
destination: Cesium.Rectangle.fromDegrees(113.683333, 29.966667, 115.083333, 31.366667)
});
将武汉市的经纬度范围传入,实际的显示结果如下:
2.2.3. 两地之间飞行
flyTo()函数还可以传入一个配置项complete,可以给其设定一个飞行结束后再运行的函数,通过这个配置项可以实现两地或多地飞行:
var whdxOptions = {
destination: Cesium.Cartesian3.fromDegrees(114.35231209, 30.53542614, 5000.0),
duration: 5,
orientation: {
heading: Cesium.Math.toRadians(0.0),
pitch: Cesium.Math.toRadians(-90.0),
roll: Cesium.Math.toRadians(0.0)
}
};
var hzkjdxOptions = {
destination: Cesium.Cartesian3.fromDegrees(114.40782845, 30.51011682, 5000.0),
orientation: {
heading: Cesium.Math.toRadians(0.0),
pitch: Cesium.Math.toRadians(-90.0),
roll: Cesium.Math.toRadians(0.0)
},
duration: 5,
//flyOverLongitude: Cesium.Math.toRadians(60.0)
};
whdxOptions.complete = function () {
setTimeout(function () {
viewer.camera.flyTo(hzkjdxOptions);
}, 1000);
};
// if (adjustPitch) {
// tokyoOptions.pitchAdjustHeight = 1000;
// laOptions.pitchAdjustHeight = 1000;
// }
viewer.camera.flyTo(whdxOptions);
这段代码分别定义了两个飞行配置项whdxOptions和hzkjdxOptions,并且给whdxOptions的complete项配置了一个函数,表示完成1S之后,自动进行hzkjdxOptions的飞行。运行结果如下图所示:
2.2.4. 设置视图到某一点
设置当前视图通过setView()函数实现的,它跟flyTo()最大的不同是没有持续时间,没有飞行过程,是立即生效的。其具体的配置选项也比较相似,都是需要设置位置以及姿态:
viewer.camera.setView({
destination: Cesium.Cartesian3.fromDegrees(114.40782845, 30.51011682, 5000.0),
orientation: {
heading: Cesium.Math.toRadians(0.0),
pitch: Cesium.Math.toRadians(-90.0),
roll: Cesium.Math.toRadians(0.0)
}
});
2.2.5. 设置视图到某区域
设置具体的显示范围,也是立即生效,这两个部分因为与flyTo()函数比较类似,就不再具体讲解了。
viewer.camera.setView({
destination: Cesium.Rectangle.fromDegrees(120.86667, 30.66667, 122.2, 31.883333)
});
3. 其他
3.1. 事件及相应函数
Cesium.Camera还提供了当前视图发生变化的事件changed、视图发生移动的事件moveStart/moveEnd,它们都可以通过addEventListener()给其添加相应的响应函数。
3.2. setReferenceFrame
自带案例Camera中还提供了另外一种视图控制方式:
function setReferenceFrame() {
Sandcastle.declare(setReferenceFrame);
var center = Cesium.Cartesian3.fromDegrees(-75.59777, 40.03883);
var transform = Cesium.Transforms.eastNorthUpToFixedFrame(center);
// View in east-north-up frame
var camera = viewer.camera;
camera.constrainedAxis = Cesium.Cartesian3.UNIT_Z;
camera.lookAtTransform(transform, new Cesium.Cartesian3(-120000.0, -120000.0, 120000.0));
// Show reference frame. Not required.
referenceFramePrimitive = scene.primitives.add(new Cesium.DebugModelMatrixPrimitive({
modelMatrix: transform,
length: 100000.0
}));
}
这段代码的意思是选定一个经纬度的点,可以计算出以该点为中心的东北天(ENU)站心坐标系与地心坐标系的转换矩阵,将这个矩阵传入给Cesium.Camera的lookAtTransform函数,从而达到设置视图的目的。但是这样做会导致当前世界坐标系发生变化,当前漫游器的键鼠交互操作不再以地心坐标系原点为中心,而以站心坐标系的原点为中心,导致这个时候的键鼠交互操作难以操作。
3.3. viewInICRF
Cesium默认是基于ITRF,也就是国际地球地心参考框架。自带案例还提供了一种将其转换为ICRF参考框架的视图设置方式。关于ICRF我也不是很了解,查阅网上资料只知道是一种原点在太阳系的质心的天文参考框架,留待以后需要用到的时候再研究。
4. 参考
[1]. 北东地/东北天两种导航坐标系与姿态转换
[2]. Cesium中的相机—HeadingPitchRoll
[3]. Cesium类HeadingPitchRoll及heading、pitch、roll等参数详解
Cesium案例解析(三)——Camera相机的更多相关文章
- Cesium案例解析(四)——3DModels模型加载
目录 1. 概述 2. 代码 3. 解析 4. 参考 1. 概述 Cesium自带的3D Models示例,展示了如何加载glTF格式三维模型数据.glTF是为WebGL量身定制的数据格式,在网络环境 ...
- Cesium中级教程3 - Camera - 相机(摄像机)
Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/ Camera CesiumJS中的Camera控制场景的视图.有 ...
- Cesium案例解析(二)——ImageryLayers影像图层
目录 1. 概述 2. 实例 2.1. ImageryLayers.html 2.2. ImageryLayers.js 2.2.1. 代码 2.2.2. 解析 3. 结果 1. 概述 Cesium支 ...
- Cesium案例解析(六)——3DTilesInspector监视器
目录 1. 概述 2. 案例 1. 概述 3D Tiles作为传输和渲染大规模3D地理空间数据的格式,应对的都是大规模数据的场景,Cesium提供了一个监视3D Tiles数据的监视器,可以通过这个监 ...
- Cesium案例解析(五)——3DTilesPhotogrammetry摄影测量3DTiles数据
目录 1. 概述 2. 案例 3. 结果 1. 概述 3D Tiles是用于传输和渲染大规模3D地理空间数据的格式,例如摄影测量,3D建筑,BIM / CAD,实例化特征和点云等.与常规的模型文件格式 ...
- Cesium案例解析(一)——HelloWorld
目录 1. 概述 2. 实例 2.1. HelloWorld.html 2.2. HelloWorld.js 3. 结果 1. 概述 感觉网上已经有不少关于cesium的教程了,但是学习一个框架最快的 ...
- 【Python五篇慢慢弹(5)】类的继承案例解析,python相关知识延伸
类的继承案例解析,python相关知识延伸 作者:白宁超 2016年10月10日22:36:57 摘要:继<快速上手学python>一文之后,笔者又将python官方文档认真学习下.官方给 ...
- Android Camera 相机程序编写
Android Camera 相机程序编写 要自己写一个相机应用直接使用相机硬件,首先应用需要一个权限设置,在AndroidManifest.xml中加上使用设备相机的权限: <uses-per ...
- 案例解析|政府信息化的BI建设应用 .
一.行业背景 某建设厅综合监管信息化平台,是政企业务协同的平台之一,同时兼具协作.门户.办公应用集成.用户权限管理等多项功能.在此要求基础上,选择中间件基础技术平台,可以在最大程度满足平台功能需求的前 ...
随机推荐
- Python-直接存储类实例作为序列的元素
如果我们需要存储的数据有很多属性,并且存储的数量很多,可选择定义一个类来表示数据类型,而类的实体作为单个的成员进行存储,这样做的好处是可以只存储一个容器,而不需要每次都存储大量的数据,并且可以限制对数 ...
- 现在啊还不太清楚 nodejs和coffeescript 的关系
我怎么会思考这个问题,今天看到用coffeescript做的一个服务引导 挺好 看博客里提 安装node之后 呢 npm 可以安装coffeescript 难道 coffee 是 node的 一个方言 ...
- shell脚本快速配置yum源
我们在使用Red Hat系列的Linux系统时经常要配置yum源,本文档提出一个快速配置yum源的方法,就是用shell脚本来实现. 我们在使用Red Hat系列的Linux系统时经常要配置yum源, ...
- git使用的常见命令汇总
git的简单介绍 git是分布式版本控制工具 git 的基本操作指令 git init 初始化git仓库 git add 文件名 git add . 把文件 添加到 git 暂存区中 git stat ...
- Hello,world!一切的开始
普及知识 当我们准备开发Java程序时,我们需要两样基础的工具--JDK与IDE.在这里需要解释一下什么是JDK还有IDE.JDK的全称是Java Development kit,即Java开发工具集 ...
- vue-particles做背景,鼠标动画粒子连线填坑(按钮没有点击响应)
为了提高页面展示效果,登录界面内容比较单一的,粒子效果作为背景经常使用到,vue工程中利用vue-particles可以很简单的实现页面的粒子背景效果. 解决问题: 以背景方式显示 无法获取按钮焦点, ...
- Mysql百万数据量级数据快速导入Redis
前言 随着系统的运行,数据量变得越来越大,单纯的将数据存储在mysql中,已然不能满足查询要求了,此时我们引入Redis作为查询的缓存层,将业务中的热数据保存到Redis,扩展传统关系型数据库的服务能 ...
- cloud-init使用技巧
对于 Linux 镜像,cloud-init 负责 instance 的初始化工作.cloud-init 功能很强大,能做很多事情,而且我们可以通过修改配置文件灵活定制 cloud-init. clo ...
- 计算机原理基础:DNS
DNS服务的作用 将域名解析成IP地址 端口号:53 域名服务器 根域名服务器 所有的根域名服务器都知道所有的顶级域名服务器的域名和IP地址. 不管是哪一个本地域名服务器,若要对因特网上任何一个域名进 ...
- js算法题
//较Low,看到的大神 帮补充 1.给定一个数组:,定义一个函数获取数组中所有的奇数,返回一个新数组:var arr1=[1,3,4,5,6,7,8,3,4,2,3,6]; function ...