在利用threejs做一些例如城市模型等3D开发时,会发现threejs无法直接支持经纬度坐标,例如城市模型的某个建筑,它在空间直角坐标系中的位置,可以用一个x,y,z表示,但是没法和实际世界中地球坐标系的经度、纬度相关联,二者之间有一套相互映射的算法,这样当有需求需要在某个经纬度位置添加某个东西时,也可以正确的显示在三维模型中。
- 首先需要和建模工程师确定好他们建模的坐标0点具体是哪个位置,以及此点对应的实际世界中的经纬度坐标。且建模工程师建模一定要和真实城市街区比例一致(当然按一定比例缩小也可以)
- 具体实现代码
// 这个就是和建模工程师确定的建模时的0点对应的真实世界的经纬度坐标(本文经纬度为wgs84坐标系,如果是其他坐标系,需要先转换成wgs84)
const threeMapZeroCenter = {
lng: 114.2858126490011,
lat: 30.581177854141437
}
// wgs84经纬度坐标转threejs三维坐标
function wgs84ToThreePosition(lng, lat, height) {
// 模型世界坐标0点对应的wgs84坐标
// TODO: 需要和模型组的确定准确坐标
const cityModelCenterPos = {
lng: threeMapZeroCenter.lng,
lat: threeMapZeroCenter.lat,
height: 0,
}
// 找到地图的中心对应的经纬度坐标
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
// 这一步是重点:墨卡托平面坐标系很大,需要结合模型调试一个合适的比例,例如下面的0.85,是结合模型上两个实际点位调试出的大概比例,通常通过0点和另外一个点确定这比例系数需要设置多少。
return {
x: (center.x - x) * 0.85,
y: y - center.y,
z: (center.z - z) * 0.85,
}
}
// 经纬度坐标转墨卡托
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 }
}