在利用threejs做一些例如城市模型等3D開發(fā)時(shí),會(huì)發(fā)現(xiàn)threejs無(wú)法直接支持經(jīng)緯度坐標(biāo),例如城市模型的某個(gè)建筑,它在空間直角坐標(biāo)系中的位置,可以用一個(gè)x,y,z表示,但是沒(méi)法和實(shí)際世界中地球坐標(biāo)系的經(jīng)度、緯度相關(guān)聯(lián),二者之間有一套相互映射的算法,這樣當(dāng)有需求需要在某個(gè)經(jīng)緯度位置添加某個(gè)東西時(shí),也可以正確的顯示在三維模型中。
- 首先需要和建模工程師確定好他們建模的坐標(biāo)0點(diǎn)具體是哪個(gè)位置,以及此點(diǎn)對(duì)應(yīng)的實(shí)際世界中的經(jīng)緯度坐標(biāo)。且建模工程師建模一定要和真實(shí)城市街區(qū)比例一致(當(dāng)然按一定比例縮小也可以)
- 具體實(shí)現(xiàn)代碼
// 這個(gè)就是和建模工程師確定的建模時(shí)的0點(diǎn)對(duì)應(yīng)的真實(shí)世界的經(jīng)緯度坐標(biāo)(本文經(jīng)緯度為wgs84坐標(biāo)系,如果是其他坐標(biāo)系,需要先轉(zhuǎn)換成wgs84)
const threeMapZeroCenter = {
lng: 114.2858126490011,
lat: 30.581177854141437
}
// wgs84經(jīng)緯度坐標(biāo)轉(zhuǎn)threejs三維坐標(biāo)
function wgs84ToThreePosition(lng, lat, height) {
// 模型世界坐標(biāo)0點(diǎn)對(duì)應(yīng)的wgs84坐標(biāo)
// TODO: 需要和模型組的確定準(zhǔn)確坐標(biāo)
const cityModelCenterPos = {
lng: threeMapZeroCenter.lng,
lat: threeMapZeroCenter.lat,
height: 0,
}
// 找到地圖的中心對(duì)應(yīng)的經(jīng)緯度坐標(biāo)
const center = lngLatToMercator(cityModelCenterPos)
const mercatorMax = 20037508.3427892
const y = height ? height : 0
const z = (+lng / 180.0) * mercatorMax
let x = (Math.PI / 180.0) * +lat
const tmp = Math.PI / 4.0 + x / 2.0
x = (mercatorMax * Math.log(Math.tan(tmp))) / Math.PI
// 這一步是重點(diǎn):墨卡托平面坐標(biāo)系很大,需要結(jié)合模型調(diào)試一個(gè)合適的比例,例如下面的0.85,是結(jié)合模型上兩個(gè)實(shí)際點(diǎn)位調(diào)試出的大概比例,通常通過(guò)0點(diǎn)和另外一個(gè)點(diǎn)確定這比例系數(shù)需要設(shè)置多少。
return {
x: (center.x - x) * 0.85,
y: y - center.y,
z: (center.z - z) * 0.85,
}
}
// 經(jīng)緯度坐標(biāo)轉(zhuǎn)墨卡托
function lngLatToMercator({ lng, lat, height }) {
var y = height ? height : 0
var z = (lng / 180.0) * 20037508.3427892
var x = (Math.PI / 180.0) * lat
var tmp = Math.PI / 4.0 + x / 2.0
x = (20037508.3427892 * Math.log(Math.tan(tmp))) / Math.PI
return { x: x, y: y, z: z }
}