liujiusheng / blog

个人博客,blog
19 stars 0 forks source link

坐标系经纬度与三维xyz的换算 #138

Open liujiusheng opened 5 years ago

liujiusheng commented 5 years ago

条件:

设坐标点为经度:n(-180 ~ 180), 纬度m(-90 ~ 90),

三维坐标系的空间为2 2 2的正方体,即每个面距正方体中心的距离为1,

正方体中心与球中心一致,中心点坐标为(0 , 0 , 0)。

球为正方体的内切球

球的半径为1,即R=1

计算x和z时要注意因纬度不同,选取的半径不一定都为1

右手坐标系 规定x、y、z方向为 image

计算公式:

y:

0<=m<=90时 y = R * sinm

-90<=m<0时 y = -R * sin(-m)

1 * cosm为计算x,z时圆的半径

x:

0<n<90时 x = - R cos | m | cosn

90<n<180时 x = R cos | m | cos(180-n)

-90<n<0时 x = -R cos | m | cos(-n)

-180<n<-90时 x = R cos | m | cos(180+n)

z:

0<n<90时 z = R cos | m | sinn

90<n<180时 z = R cos | m | sin(180-n)

-90<n<0时 z = -R cos | m | sin(-n)

-180<n<-90时 z = -R cos | m | sin(180+n)

计算函数:

 /**
  * 经纬度转为三维的xyz,要注意经纬度与三角函数中的弧度不是一个东西,经纬度需要先转换为弧度
  * @param {number} lng 经度
  * @param {number} lat 纬度
  * @param {number} R 要绘制的球的半径
  */
 function lnglatToxyz(lng, lat, R) {
    let x = 0;
    let y = 0;
    let z = 0;
    lng_deg = torad(lng);
    lat_deg = Math.abs(torad(lat));
    // 计算y坐标
    if (lat >= 0 && lat <= 90) {
        y = R * Math.sin(lat_deg);
    } else if(lat >= -90 && lat < 0) {
        y = -R * Math.sin(lat_deg);
    }

    // 计算x、z坐标
    if (0 < lng <= 90) {
        x = - R * Math.cos(lat_deg) * Math.cos(lng_deg);
        z = R * Math.cos(lat_deg) * Math.sin(lng_deg);
    } else if(90 < lng <= 180) {
        x = R * Math.cos(lat_deg) * Math.cos(torad(180-lng));
        z = R * Math.cos(lat_deg) * Math.sin(torad(180-lng));
    } else if(-90 < lng <= 0) {
        x = -R * Math.cos(lat_deg) * Math.cos(-lng_deg);
        z = -R * Math.cos(lat_deg) * Math.sin(-lng_deg);
    } else if(-180 <= lng <= -90) {
        x = R * Math.cos(lat_deg) * Math.cos(torad(180+lng));
        z = -R * Math.cos(lat_deg) * Math.sin(torad(180+lng));
    }
    const result = {x:x,y:y,z:z};
    return result;
}

根据three.js中的planeGeometry叠加形成瓦片地图效果的原理可以推导出,使用多个不完整的球叠加也可以实现三维球面地图的效果

orbitcontrols可用于在three.js中做交互 https://github.com/nicolaspanel/three-orbitcontrols-ts