參考地址:https://github.com/CesiumGS/3d-tiles/tree/main/specification#coordinate-reference-system-crs
簡單理解閱讀上面Cesium官方解釋就行呈宇,補充一下項目中遇到的坑,先帖上我項目中的titlset.json文件
前情:傾斜攝影文件是用smart3D生成的,生成的時候格式?jīng)]有選Cesium胰柑,拿到的是osgb文件柒竞,使用CesiumLab轉(zhuǎn)換為Cesium使用的b3dm格式文件勺卢。
補充貼一下github上相關(guān)的解釋:
參考坐標系
3D Tiles 使用右手笛卡爾坐標系膀捷;也就是說关噪,x和y的叉積產(chǎn)生z骑篙。3D Tiles 將z軸定義為局部笛卡爾坐標系的向上蜕提。瓦片集的全球坐標系通常位于WGS 84地心地地固定 (ECEF) 參考系 ( EPSG 4978 ) 中,但它不必須靶端,例如谎势,發(fā)電廠可以在其本地完全定義用于沒有地理空間上下文的建模工具的坐標系凛膏。
可以應(yīng)用額外的圖塊變換來將圖塊的局部坐標系轉(zhuǎn)換為父圖塊的坐標系。(劃重點)
區(qū)域邊界體積使用地理坐標系(緯度它浅、經(jīng)度译柏、高度)指定邊界,特別是EPSG 4979姐霍。
boundingVolume.box
該boundingVolume.box屬性是一個由 12 個數(shù)字組成的數(shù)組鄙麦,用于在 z 軸向上的右手 3 軸 (x, y, z) 笛卡爾坐標系中定義定向邊界框。前三個元素定義框中心的 x镊折、y 和 z 值胯府。接下來的三個元素(索引為 3、4 和 5)定義x軸方向和半長恨胚。接下來的三個元素(索引 6骂因、7 和 8)定義y軸方向和半長。最后三個元素(索引 9赃泡、10 和 11)定義z軸方向和半長寒波。
按照上面的解釋,我取box前三位作為中心的xyz的值升熊,將ECEF參考系換算到WGS 84俄烁,換算失敗,很明顯得可以看出级野,我的文件中的xyz的值不對页屠,因為都是兩位數(shù),地心坐標系的值不可能是兩位數(shù)蓖柔。
為什么會出現(xiàn)這種情況辰企?因為傾斜攝影建模的時候,不是生成的Cesium專用為文件况鸣,選的坐標系不是Cesium的牢贸,原點選的是局部遠點,導致使用CesiumLab轉(zhuǎn)換之后镐捧,box的中心點的值有偏移潜索。此時就需要使用transform中的參數(shù)。
上面圖片中就是github上關(guān)于transform的解釋愤估,但是它說了個寂寞帮辟,并沒有講具體要怎樣來處理矩陣變換。
找到Cesium.js未壓縮版玩焰,去它源碼里面找
transform
這個關(guān)鍵詞由驹,一共搜出來了1651個,靈機一動,transform不是個數(shù)組嗎蔓榄?換著搜索一下transform[
,后面帶個左中括號并炮,就找到了想要的答案transform是一個4x4的矩陣,他把數(shù)組中倒數(shù)第四項第三項第二項當作xyz的值甥郑。那我可不可以簡單理解紅線中的三個數(shù)值就是他中心點偏移量逃魄?(此處理解是不正確,Cesium.js中的計算比較復雜澜搅,但是因為我項目不需要用到非常準確的坐標位置伍俘,就直接當作偏移量拿來簡單使用)
如上圖,把三組數(shù)據(jù)一一對應(yīng)相加勉躺,會拿到一組xyz的值癌瘾,將新拿到的xyz值,當作ECEF坐標點饵溅,轉(zhuǎn)換為WGS84妨退,終于拿到正確的經(jīng)緯度坐標點,將這個坐標點拿去百度經(jīng)緯度拾取反查,也能夠拿到我傾斜攝影對應(yīng)的真實位置
補充一下java將ECEF轉(zhuǎn)WGS84的方法
public static String ECEFtoWGS84(double x, double y, double z) {
double a, b, c, d;
double Longitude;//longitude
double Latitude;//Latitude
double Altitude;//Altitude
double p, q;
double N;
a = 6378137.0;
b = 6356752.31424518;
c = Math.sqrt(((a * a) - (b * b)) / (a * a));
d = Math.sqrt(((a * a) - (b * b)) / (b * b));
p = Math.sqrt((x * x) + (y * y));
q = Math.atan2((z * a), (p * b));
Longitude = Math.atan2(y, x);
Latitude = Math.atan2((z + (d * d) * b * Math.pow(Math.sin(q), 3)), (p - (c * c) * a * Math.pow(Math.cos(q), 3)));
N = a / Math.sqrt(1 - ((c * c) * Math.pow(Math.sin(Latitude), 2)));
Altitude = (p / Math.cos(Latitude)) - N;
Longitude = Longitude * 180.0 / Math.PI;
Latitude = Latitude * 180.0 / Math.PI;
return Longitude + "," + Latitude + "," + Altitude;
}