前言
Cesium項目中經常涉及到模型加載、瀏覽以及不同數據之間的坐標轉換,弄明白Cesium中采用的坐標系以及各個坐標系之間的轉換,是我們邁向三維GIS大門的前提,本文詳細的介紹了Cesium中采用的兩大坐標系以及之間轉換的各種方法。
Cesium中的坐標系
Cesium中常用的坐標有兩種WGS84地理坐標系和笛卡爾空間坐標系,我們平時常用的以經緯度來指明一個地點就是用的WGS84坐標,笛卡爾空間坐標系常用來做一些空間位置變換如平移旋轉縮放等等。二者的聯系如下圖。
其中,WGS84地理坐標系包括 WGS84經緯度坐標系(沒有實際的對象)和 WGS84弧度坐標系(Cartographic);
笛卡爾空間坐標系包括 笛卡爾空間直角坐標系(Cartesian3)、平面坐標系(Cartesian2),4D笛卡爾坐標系(Cartesian4)。
WGS84坐標系
World Geodetic System 1984,是為GPS全球定位系統使用而建立的坐標系統,坐標原點為地球質心,其地心空間直角坐標系的Z軸指向BIH (國際時間服務機構)1984.O定義的協議地球極(CTP)方向,X軸指向BIH 1984.0的零子午面和CTP赤道的交點,Y軸與Z軸、X軸垂直構成右手坐標系。我們平常手機上的指南針顯示的經緯度就是這個坐標系下當前的坐標,進度范圍[-180,180],緯度范圍[-90,90]。

Cesium目前支持兩種坐標系WGS84和WebMercator,但是在Cesium中沒有實際的對象來描述WGS84坐標,都是以弧度的方式來進行運用的也就是Cartographic類:
new Cesium.Cartographic(longitude, latitude, height),這里的參數也叫longitude、latitude,就是經度和緯度,計算方法:弧度= π/180×經緯度角度。
笛卡爾空間直角坐標系(Cartesian3)
笛卡爾空間坐標的原點就是橢球的中心,我們在計算機上進行繪圖時,不方便使用經緯度直接進行繪圖,一般會將坐標系轉換為笛卡爾坐標系,使用計算機圖形學中的知識進行繪圖。這里的Cartesian3,有點類似於三維系統中的Point3D對象,new Cesium.Cartesian3(x, y, z),里面三個分量x、y、z。

平面坐標系(Cartesian2)
平面坐標系也就是平面直角坐標系,是一個二維笛卡爾坐標系,與Cartesian3相比少了一個z的分量,new Cesium.Cartesian2(x, y)。Cartesian2經常用來描述屏幕坐標系,比如鼠標在電腦屏幕上的點擊位置,返回的就是Cartesian2,返回了鼠標點擊位置的xy像素點分量。

坐標轉換
經緯度和弧度的轉換
var radians=Cesium.Math.toRadians(degrees);//經緯度轉弧度 var degrees=Cesium.Math.toDegrees(radians);//弧度轉經緯度
WGS84經緯度坐標和WGS84弧度坐標系(Cartographic)的轉換
//方法一: var longitude = Cesium.Math.toRadians(longitude1); //其中 longitude1為角度 var latitude= Cesium.Math.toRadians(latitude1); //其中 latitude1為角度 var cartographic = new Cesium.Cartographic(longitude, latitude, height); //方法二: var cartographic= Cesium.Cartographic.fromDegrees(longitude, latitude, height);//其中,longitude和latitude為角度 //方法三: var cartographic= Cesium.Cartographic.fromRadians(longitude, latitude, height);//其中,longitude和latitude為弧度
WGS84坐標系和笛卡爾空間直角坐標系(Cartesian3)的轉換
通過經緯度或弧度進行轉換
var position = Cesium.Cartesian3.fromDegrees(longitude, latitude, height);//其中,高度默認值為0,可以不用填寫;longitude和latitude為角度 var positions = Cesium.Cartesian3.fromDegreesArray(coordinates);//其中,coordinates格式為不帶高度的數組。例如:[-115.0, 37.0, -107.0, 33.0] var positions = Cesium.Cartesian3.fromDegreesArrayHeights(coordinates);//coordinates格式為帶有高度的數組。例如:[-115.0, 37.0, 100000.0, -107.0, 33.0, 150000.0] //同理,通過弧度轉換,用法相同,具體有Cesium.Cartesian3.fromRadians,Cesium.Cartesian3.fromRadiansArray,Cesium.Cartesian3.fromRadiansArrayHeights等方法
注意:上述轉換函數中最后均有一個默認參數ellipsoid(默認值為Ellipsoid.WGS84)。
通過過度進行轉換
具體過度原理可以參考上邊的注意事項。
var position = Cesium.Cartographic.fromDegrees(longitude, latitude, height); var positions = Cesium.Ellipsoid.WGS84.cartographicToCartesian(position); var positions = Cesium.Ellipsoid.WGS84.cartographicArrayToCartesianArray([position1,position2,position3]);
笛卡爾空間直角坐標系轉換為WGS84
直接轉換
var cartographic= Cesium.Cartographic.fromCartesian(cartesian3);
轉換得到WGS84弧度坐標系后再使用經緯度和弧度的轉換,進行轉換到目標值
間接轉換
var cartographic = Cesium.Ellipsoid.WGS84.cartesianToCartographic(cartesian3); var cartographics = Cesium.Ellipsoid.WGS84.cartesianArrayToCartographicArray([cartesian1,cartesian2,cartesian3]);
平面坐標系(Cartesian2)和笛卡爾空間直角坐標系(Cartesian3)的轉換
平面坐標系轉笛卡爾空間直角坐標系
這里注意的是當前的點(Cartesian2)必須在三維球上,否則返回的是undefined;通過ScreenSpaceEventHandler回調會取到的坐標都是Cartesian2。
屏幕坐標轉場景坐標-獲取傾斜攝影或模型點擊處的坐標
這里的場景坐標是包含了地形、傾斜攝影表面、模型的坐標。
通過viewer.scene.pickPosition(movement.position)獲取,根據窗口坐標,從場景的深度緩沖區中拾取相應的位置,返回笛卡爾坐標。
var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); handler.setInputAction(function (movement) { var position = viewer.scene.pickPosition(movement.position); console.log(position); }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
注:若屏幕坐標處沒有傾斜攝影表面、模型時,獲取的笛卡爾坐標不准,此時要開啟地形深度檢測(viewer.scene.globe.depthTestAgainstTerrain = true; //默認為false)。
屏幕坐標轉地表坐標-獲取加載地形后對應的經緯度和高程
這里是地球表面的世界坐標,包含地形,不包括模型、傾斜攝影表面。
通過viewer.scene.globe.pick(ray, scene)獲取,其中ray=viewer.camera.getPickRay(movement.position)。
var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); handler.setInputAction(function (movement) { var ray = viewer.camera.getPickRay(movement.position); var position = viewer.scene.globe.pick(ray, viewer.scene); console.log(position); }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
注:通過測試,此處得到的坐標通過轉換成wgs84后,height的為該點的地形高程值。
屏幕坐標轉橢球面坐標-獲取鼠標點的對應橢球面位置
這里的橢球面坐標是參考橢球的WGS84坐標(Ellipsoid.WGS84),不包含地形、模型、傾斜攝影表面。
通過 viewer.scene.camera.pickEllipsoid(movement.position, ellipsoid)獲取,可以獲取當前點擊視線與橢球面相交處的坐標,其中ellipsoid是當前地球使用的橢球對象:viewer.scene.globe.ellipsoid,默認為Ellipsoid.WGS84。
var handler = new Cesium.ScreenSpaceEventHandler(viewer.scene.canvas); handler.setInputAction(function (movement) { var position = viewer.scene.camera.pickEllipsoid(movement.position, viewer.scene.globe.ellipsoid); console.log(position); }, Cesium.ScreenSpaceEventType.LEFT_CLICK);
注:通過測試,此處得到的坐標通過轉換成wgs84后,height的為0(此值應該為地表坐標減去地形的高程)。
笛卡爾空間直角坐標系轉平面坐標系
var cartesian2= Cesium.SceneTransforms.wgs84ToWindowCoordinates(viewer.scene,cartesian3)
空間位置變換
經緯度轉換到笛卡爾坐標系后就能運用計算機圖形學中的仿射變換知識進行空間位置變換如平移旋轉縮放。
Cesium為我們提供了很有用的變換工具類:Cesium.Cartesian3(相當於Point3D)Cesium.Matrix3(3x3矩陣,用於描述旋轉變換)Cesium.Matrix4(4x4矩陣,用於描述旋轉加平移變換),Cesium.Quaternion(四元數,用於描述圍繞某個向量旋轉一定角度的變換)。
下面舉個例子:
一個局部坐標為p1(x,y,z)的點,將它的局部坐標原點放置到loc(lng,lat,alt)上,局部坐標的z軸垂直於地表,局部坐標的y軸指向正北,並圍繞這個z軸旋轉d度,求此時p1(x,y,z)變換成全局坐標笛卡爾坐p2(x1,y1,z1)是多少?
var rotate = Cesium.Math.toRadians(d);//轉成弧度 var quat = Cesium.Quaternion.fromAxisAngle(Cesium.Cartesian3.UNIT_Z, rotate); //quat為圍繞這個z軸旋轉d度的四元數 var rot_mat3 = Cesium.Matrix3.fromQuaternion(quat);//rot_mat3為根據四元數求得的旋轉矩陣 var v = new Cesium.Cartesian3(x, y, z);//p1的局部坐標 var m = Cesium.Matrix4.fromRotationTranslation(rot_mat3, Cesium.Cartesian3.ZERO);//m為旋轉加平移的4x4變換矩陣,這里平移為(0,0,0),故填個Cesium.Cartesian3.ZERO m = Cesium.Matrix4.multiplyByTranslation(m, v);//m = m X v var cart3 = ellipsoid.cartographicToCartesian(Cesium.Cartographic.fromDegrees(lng, lat, alt)); //得到局部坐標原點的全局坐標 var m1 = Cesium.Transforms.eastNorthUpToFixedFrame(cart3);//m1為局部坐標的z軸垂直於地表,局部坐標的y軸指向正北的4x4變換矩陣 m = Cesium.Matrix4.multiplyTransformation(m, m1);//m = m X m1 var p2 = Cesium.Matrix4.getTranslation(m);//根據最終變換矩陣m得到p2 console.log('x=' + p2.x + ',y=' + p2.y + ',z=' + p2.z );
總結
通過本文,介紹了各個坐標系間的轉換問題,在具體項目中,可結合實際需求,靈活組合解決具體的實際問題。注意,博文是參照網上相關博客及結合自己的實踐總結得來,希望本文對你有所幫助,后續會更新更多內容,感興趣的朋友可以加關注,歡迎留言交流!