Cesium中笛卡爾座標系到底是什麼鬼

  使用Cesium開發三維GIS應用離不開笛卡爾座標系,在CesiumJS中定義類型是Cartesian3,這是Cesium的基礎數據類型,所有座標最後均轉換成這個類型參與三維渲染,包括屏幕座標,地理座標系座標。那麼問題來了,這個笛卡爾座標系到底是什麼鬼?常用的WGS84怎麼轉換成這個座標系的?讓我們來看看cesium源碼一探究竟。

Cartesian3.js裏面有個函數fromRadians ,將經緯度轉換成Cartesian3,其中經緯度是wgs84轉換成弧度的經緯度。

Cartesian3.fromRadians = function(longitude, latitude, height, ellipsoid, result) {
    //>>includeStart('debug', pragmas.debug);
    Check.typeOf.number('longitude', longitude);
    Check.typeOf.number('latitude', latitude);
    //>>includeEnd('debug');

    height = defaultValue(height, 0.0);
    var radiiSquared = defined(ellipsoid) ? ellipsoid.radiiSquared : wgs84RadiiSquared;

    var cosLatitude = Math.cos(latitude);
    scratchN.x = cosLatitude * Math.cos(longitude);
    scratchN.y = cosLatitude * Math.sin(longitude);
    scratchN.z = Math.sin(latitude);
    scratchN = Cartesian3.normalize(scratchN, scratchN);

    Cartesian3.multiplyComponents(radiiSquared, scratchN, scratchK);
    var gamma = Math.sqrt(Cartesian3.dot(scratchN, scratchK));
    scratchK = Cartesian3.divideByScalar(scratchK, gamma, scratchK);
    scratchN = Cartesian3.multiplyByScalar(scratchN, height, scratchN);

    if (!defined(result)) {
        result = new Cartesian3();
    }
    return Cartesian3.add(scratchK, scratchN, result);
};
  1. 檢驗經緯度是否符合標準;
Check.typeOf.number('longitude', longitude);
Check.typeOf.number('latitude', latitude);
  1. 如果高度爲空賦值默認爲0;
height = defaultValue(height, 0.0);
  1. 如果座標系爲空默認賦值WGS84座標系;
var radiiSquared = defined(ellipsoid) ? ellipsoid.radiiSquared : wgs84RadiiSquared;
  1. 賦值地球球體半徑(假設爲1)在xy平面上的投影長度;
    cesium假設wgs84座標系構成地球球體是xy平面的正圓,z軸稍微小一點扁橢球:
    在這裏插入圖片描述
    如上圖所示:x軸垂直紙面向上,wgs84座標系定義的x,y平面圓是正圓,半徑是6378137,xz或者yz的圓是橢圓,z軸的半徑是:6356752.3142451793,定義如下:
var wgs84RadiiSquared = new Cartesian3(6378137.0 * 6378137.0, 6378137.0 * 6378137.0, 6356752.3142451793 * 6356752.3142451793);
var cosLatitude = Math.cos(latitude);

所以這句話的意思是假設球半徑爲1,這個半徑投影到xy平面上的長度(當然由於這不是標準球,所以球半徑不是固定的,但是在這裏假設是一個標準球,直到下面第9步驟)。

  1. 求出對應x軸座標(假設球半徑爲1),用上一步求得的投影長度乘以經度的餘弦,直接求得對應x軸座標;
    在這裏插入圖片描述
scratchN.x = cosLatitude * Math.cos(longitude);
  1. 求出對應y軸座標(假設球半徑爲1);
scratchN.y = cosLatitude * Math.sin(longitude);
  1. 求出對應z軸座標(假設球半徑爲1),以上三步驟構成scratchN向量;
scratchN.z = Math.sin(latitude);
  1. 求出scratchN的單位模向量賦值給scratchN本身,這樣做的目的是把這個xyz軸數值同比例縮小到一個單位球,便於後面等比例變化;
    單位模的含義:
    對向量A=[X,Y,Z]求模:
    AM=[X/(X2+Y2+Z2),Y/(X2+Y2+Z2),X/(X2+Y2+Z2)]A_M=[X/(X^2+Y^2+Z^2),Y/(X^2+Y^2+Z^2),X/(X^2+Y^2+Z^2)]
scratchN = Cartesian3.normalize(scratchN, scratchN);
  1. ScratchN同比例放大一定倍數;
    x軸放大6378137.0 * 6378137.0倍數, Y軸放大6378137.0 * 6378137.0倍數, Z軸放大6356752.3142451793 * 6356752.3142451793倍數,結果放到scratchK中,scratchN保持不變
Cartesian3.multiplyComponents(radiiSquared, scratchN, scratchK)
  1. 求經緯度座標對應的xyz座標;
    設scratchN向量爲[NX,NY,NZ][N_X,N_Y,N_Z],放大倍數向量爲[RX2,RY2,RZ2][R_{X}^2,R_{Y}^2,R_Z^2],在cesium中已經定義了RXR_X=6378137,RYR_Y=6378137,RZR_Z=6356752.3142451793,
    則scratchK=[NXRX2,NYRY2,NZRZ2][N_X*R_X^2,N_Y*R_Y^2,N_Z*R_Z^2](上一步計算結果)
var gamma = Math.sqrt(Cartesian3.dot(scratchN, scratchK))

該語句執行結果:
gamma=NX2RX2+NY2RY2+NZ2RZ2gamma=\sqrt{N_X^2*R_X^2+N_Y^2*R_Y^2+N_Z^2*R_Z^2}

scratchK = Cartesian3.divideByScalar(scratchK, gamma, scratchK);

該語句執行結果:
scratchK向量NK=[NXRX2/gamma,NYRY2/gamma,NYRX2/gamma]N_K=[N_X*R_X^2/gamma,N_Y*R_Y^2/gamma,N_Y*R_X^2/gamma]
其實就是:[(NXRX/gamma)RX,(NYRY/gamma)RY,(NZRZ/gamma)RZ][(N_X*R_X/gamma)*R_X,(N_Y*R_Y/gamma)*R_Y,(N_Z*R_Z/gamma)*R_Z]
也就是[NXRX,NYRY,NZRZ][N_X*R_X,N_Y*R_Y,N_Z*R_Z]的模向量[NXRX/gamma,NYRY/gamma,NZRZ/gamma][N_X*R_X/gamma,N_Y*R_Y/gamma,N_Z*R_Z/gamma]再乘以各個軸對應的放大倍數。

var gamma = Math.sqrt(Cartesian3.dot(scratchN, scratchK));
scratchK = Cartesian3.divideByScalar(scratchK, gamma, scratchK);

回頭看到這裏的步驟,其實cesium做了兩次取模運算,第一次目的是算出經緯度對應的標準球體上面xyz比例,第二次是算出在wgs84座標系下面進行橢球體拉伸後的xyz比例,最後再用這個拉伸後的比例乘以實際值(以米爲單位)算出實際xyz座標。

  1. 求高程對應的xyz座標增量寫入scratchN;
scratchN = Cartesian3.multiplyByScalar(scratchN, height, scratchN)

增量H向量=[heightNX,heightNY,heightNZ][height*N_X,height*N_Y,height*N_Z]之所以不用第二次拉伸,個人認爲是height跟地球半徑相比很小,差別可以忽略不計。
如果進行第二次拉伸此處應該是:
增量H向量=[height(NXRX/gamma),height(NYRY/gamma),height(NZRZ/gamma)][height*(N_X*R_X/gamma),height*(N_Y*R_Y/gamma),height*(N_Z*R_Z/gamma)]

12.將第十步驟和第十一步驟對應的座標相加得到最終xyz值。

return Cartesian3.add(scratchK, scratchN, result)


總結推論:
1)笛卡爾座標系是米單位;
2)笛卡爾座標系原點是地球幾何中心;
3)xz平面是中央經線和180度經線組成的平面,其中x軸正方向指向的是中央經線,x軸負方向指向180度經線;
4)y軸正方向指向東經90度經線,負方向指向西經90度經線。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章