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()函数实现的,其具体的函数定义如下:

图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度。实际页面的显示效果为逐渐飞往某一点:

图2:飞行至武汉大学附近

此时数字地球会显示在武汉大学附近,视线看上去会垂直与地面,并且东西南北方向也基本上与常规地图一致。实际上当不设置姿态参数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)
});

将武汉市的经纬度范围传入,实际的显示结果如下:

图3:飞行至武汉市

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的飞行。运行结果如下图所示:

图4:武大飞行至华科

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相机的更多相关文章

  1. Cesium案例解析(四)——3DModels模型加载

    目录 1. 概述 2. 代码 3. 解析 4. 参考 1. 概述 Cesium自带的3D Models示例,展示了如何加载glTF格式三维模型数据.glTF是为WebGL量身定制的数据格式,在网络环境 ...

  2. Cesium中级教程3 - Camera - 相机(摄像机)

    Cesium中文网:http://cesiumcn.org/ | 国内快速访问:http://cesium.coinidea.com/ Camera CesiumJS中的Camera控制场景的视图.有 ...

  3. Cesium案例解析(二)——ImageryLayers影像图层

    目录 1. 概述 2. 实例 2.1. ImageryLayers.html 2.2. ImageryLayers.js 2.2.1. 代码 2.2.2. 解析 3. 结果 1. 概述 Cesium支 ...

  4. Cesium案例解析(六)——3DTilesInspector监视器

    目录 1. 概述 2. 案例 1. 概述 3D Tiles作为传输和渲染大规模3D地理空间数据的格式,应对的都是大规模数据的场景,Cesium提供了一个监视3D Tiles数据的监视器,可以通过这个监 ...

  5. Cesium案例解析(五)——3DTilesPhotogrammetry摄影测量3DTiles数据

    目录 1. 概述 2. 案例 3. 结果 1. 概述 3D Tiles是用于传输和渲染大规模3D地理空间数据的格式,例如摄影测量,3D建筑,BIM / CAD,实例化特征和点云等.与常规的模型文件格式 ...

  6. Cesium案例解析(一)——HelloWorld

    目录 1. 概述 2. 实例 2.1. HelloWorld.html 2.2. HelloWorld.js 3. 结果 1. 概述 感觉网上已经有不少关于cesium的教程了,但是学习一个框架最快的 ...

  7. 【Python五篇慢慢弹(5)】类的继承案例解析,python相关知识延伸

    类的继承案例解析,python相关知识延伸 作者:白宁超 2016年10月10日22:36:57 摘要:继<快速上手学python>一文之后,笔者又将python官方文档认真学习下.官方给 ...

  8. Android Camera 相机程序编写

    Android Camera 相机程序编写 要自己写一个相机应用直接使用相机硬件,首先应用需要一个权限设置,在AndroidManifest.xml中加上使用设备相机的权限: <uses-per ...

  9. 案例解析|政府信息化的BI建设应用 .

    一.行业背景 某建设厅综合监管信息化平台,是政企业务协同的平台之一,同时兼具协作.门户.办公应用集成.用户权限管理等多项功能.在此要求基础上,选择中间件基础技术平台,可以在最大程度满足平台功能需求的前 ...

随机推荐

  1. [洛谷P2962] [USACO09NOV] 灯Lights

    Description Bessie and the cows were playing games in the barn, but the power was reset and the ligh ...

  2. [bzoj2326] [洛谷P3216] [HNOI2011] 数学作业

    想法 最初的想法就是记录当前 \(%m\) 值为cur,到下一个数时 \(cur=cur \times 10^x + i\) n这么大,那就矩阵乘法呗. 矩阵乘法使用的要点就是有一个转移矩阵会不停的用 ...

  3. Redis(七):set/sadd/sismember/sinter/sdiffstore 命令源码解析

    上两篇我们讲了hash和list数据类型相关的主要实现方法,同时加上前面对框架服务和string相关的功能介绍,已揭开了大部分redis的实用面纱. 现在还剩下两种数据类型: set, zset. 本 ...

  4. python实现一个客户端与服务端的通信

    函数介绍 Socket对象方法: 服务端: 函数 描述 .bind() 绑定地址关键字,AF_INET下以元组的形式表示地址.常用bind((host,port)) .listen() 监听TCP,可 ...

  5. DirectX11 With Windows SDK--30 图像模糊、索贝尔算子

    前言 到这里计算着色器的主线学习基本结束,剩下的就是再补充两个有关图像处理方面的应用.这里面包含了龙书11的图像模糊,以及龙书12额外提到的Sobel算子进行边缘检测.主要内容源自于龙书12,项目源码 ...

  6. 【CMake】CMake GUI构建VS等项目

    一.CMake官网(https://cmake.org/)上的介绍: CMake is an open-source, cross-platform family of tools designed ...

  7. 《C# GDI+ 破境之道》:第一境 GDI+基础 —— 第二节:画矩形

    有了上一节画线的基础,画矩形的各种边线就特别好理解了,所以,本节在矩形边线上,就不做过多的讲解了,关注一下画“随机矩形”的具体实现就好.与画线相比较,画矩形稍微复杂的一点就是在于它多了很多填充的样式. ...

  8. python学习(1)python的基本概念

    1.python是世界上最流行的程序语言之一,用途广泛. 2.python是解释型语言,与C++编译类语言相比,python扩展性强,简单易上手.但是缺点也很明显,执行速度慢. 3.python定义中 ...

  9. JVM性能优化系列-(4) 编写高效Java程序

    4. 编写高效Java程序 4.1 面向对象 构造器参数太多怎么办? 正常情况下,如果构造器参数过多,可能会考虑重写多个不同参数的构造函数,如下面的例子所示: public class FoodNor ...

  10. kali重置root密码

    像这样,kali系统的root密码忘记了,只需一分钟时间,快速重置root密码 第一步: 电脑开机后kali系统会进入引导界面,这是我们只需 “e” 进入启动前编辑命令(若系统没有出现这个页面,大家在 ...