天天看點

Cesium坐标系及坐标轉換詳解

Cesium項目中經常涉及到模型加載、浏覽以及不同資料之間的坐标轉換,弄明白Cesium中采用的坐标系以及各個坐标系之間的轉換,是我們邁向三維GIS大門的前提,本文詳細的介紹了Cesium中WGS84地理坐标系和笛卡爾空間坐标系,以及他們之間的各種轉換關系。

前言

Cesium項目中經常涉及到模型加載、浏覽以及不同資料之間的坐标轉換,弄明白Cesium中采用的坐标系以及各個坐标系之間的轉換,是我們邁向三維GIS大門的前提,本文詳細的介紹了Cesium中采用的兩大坐标系以及之間轉換的各種方法。

Cesium中的坐标系

Cesium中常用的坐标有兩種WGS84地理坐标系和笛卡爾空間坐标系,我們平時常用的以經緯度來指明一個地點就是用的WGS84坐标,笛卡爾空間坐标系常用來做一些空間位置變換如平移旋轉縮放等等。二者的聯系如下圖。

Cesium坐标系及坐标轉換詳解

其中,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坐标系

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。

Cesium坐标系及坐标轉換詳解

笛卡爾空間直角坐标系

平面坐标系(Cartesian2)

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

Cesium坐标系及坐标轉換詳解

平面坐标系

坐标轉換

經緯度和弧度的轉換

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 );      

總結

通過本文,介紹了各個坐标系間的轉換問題,在具體項目中,可結合實際需求,靈活組合解決具體的實際問題。注意,博文是參照網上相關部落格及結合自己的實踐總結得來,希望本文對你有所幫助,後續會更新更多内容,感興趣的朋友可以加關注,歡迎留言交流!