一场大的台风,路径通常很长,可能从靠近赤道的太平洋一直往北吹到东三省。跨度这么大,在三维GIS中,往往不容易看全。如果能够实现相机随动效果,即相机跟随台风步进、移动,就生动许多了。
感觉在cesium中,坐标和视角、相机、view是一个难点,我到现在都搞不清楚。方向(orientation)可以总结一下:
XYZ轴,由负到正,分别对应西东、南北、下上。(cesium是右手)
heading:视场角,观察者(相机?)与地球围绕Y轴转,可以想象为相机向左,地球就向右;反之。
pitch:俯仰角,观察者与地球围绕X轴转;观察者低头,看见地球南极,抬头,看见地球北极。
roll:旋转,观察者与地球围绕Z轴转;可以想象为地球就是一个平面的饼,在围绕圆心在转。
言归正传。一场台风在绘制过程中,每个步骤都有对应的一个坐标值。只要观察者能够跟随这个脚步,从空中俯视,就能观察到每一个步骤的细节。
问题是,如何才能跟随?
相机(camera)的话,有lookAt啦,setView啦,flyTo啦。前面2个在本场景中都用不上,相机不动,光调转角度不行。只有flyTo才会跟随。
但是,flyTo方法,既有viewer.flyTo,又有camera.flyTo。viewer.flyTo,飞向指定坐标点(也就是台风的某个步骤坐标点),该坐标点就会正正好出现在屏幕中央,最符合要求;而camera.flyTo,是相机飞到指定点,如果按照默认值,相机角度是正俯视地球,那么没有问题,指定点也会在屏幕中央;但问题是,相机往往设置了各种倾斜的角度,那么待观察的点就不会在屏幕中央,而是出现在一边,甚至根本看不见!
那我们还犹豫什么,就用viewer.flyTo就好了。不行啊,这个viewer.flyTo,如果当前有数据输出,画面在更新,它不会执行,只有等待一切平静后它才客客气气地执行。这就出现一场台风全部步骤绘制完毕以后,才执行这个viewer.flyTo,黄花菜都凉了。
所以,解决办法还是应该用camera.flyTo。飞到一个合适的坐标点,可以让被观察点(即台风步骤坐标点)出现在屏幕中央。现在的问题是,如何得到这个合适的坐标点,让相机飞过去?
可不可以根据相机的角度,和被观察点的坐标,倒推出这个坐标点,以至于相机来到这里,角度啥的不变,刚好让被观察点出现在屏幕中央?
这个不是方程式,我没有找到计算方法。但是也许可以间接计算。我是这么想的:
台风刚开始的时候,我们先viewer.flyTo台风起点,这时台风起点出现在屏幕中央;
台风前进一步,来到了一个新位置,这时,可以计算它与上一步的位移;
然后我用相机当前位置,加上这个位移,得到一个新的坐标点,这就是那个合适的坐标点
相机飞到这个该死的合适坐标点
以此类推。
代码如下:
//台风开始时,我们飞向起点p
let flyEntity = new Cesium.Entity({
id : 'flyTmp',
position : Cesium.Cartesian3.fromDegrees(p.x,p.y,0),
point : {
pixelSize : 1,
color : Cesium.Color.WHITE.withAlpha(0.0),
}
});
viewer.entities.add(flyEntity);
return viewer.flyTo(flyEntity, {
offset : {
//角度啥都不变
heading : viewer.camera.heading,
pitch : viewer.camera.pitch,
range : HEIGHT
}
});
//一个台风步骤
function step(){
let p1 = ... //上一步骤
let p2 = ... //当前步骤
let cp = viewer.camera.positionCartographic;//当前相机世界坐标
let offset = Cesium.Cartesian3.subtract(//两个台风步骤之间的位移
Cesium.Cartesian3.fromDegrees(p1.x, p2.y,cp.height), //这个高度必不可少
Cesium.Cartesian3.fromDegrees(p1.x, p2.y,cp.height),
new Cesium.Cartesian3());
let newCameraLoc = Cesium.Cartesian3.add(//新的相机坐标点
viewer.camera.position,
offset,
new Cesium.Cartesian3());
viewer.camera.flyTo({
destination : newCameraLoc,
duration:2,//飞行时间2秒
orientation : {
heading : viewer.camera.heading,
pitch : viewer.camera.pitch,
roll : 0.0
},
complete:function(){
//完成后进入下一步;职责链模式
step();
}
});
}
当然啦,实际应用过程中,不会步步跟随,而是20步跟随一次,否则系统估计会卡死。
cesium中定位方法使用