Three.js 地理坐标和三维空间坐标的转换

Easter79
• 阅读 1432

奇技指南 本文作者高峰,360奇舞团前端工程师,W3C性能工作组/WOT工作组成员 本文转载自奇舞周刊

引言

在实现3D地球时,球面是通过地理贴图渲染的。所以我们所说的地理坐标和三维空间坐标的转换,是指将地理贴图上的坐标,转换为球面坐标(https://en.wikipedia.org/wiki/Spherical_coordinate_system),即three.js中的三维坐标。

在介绍他们之间如何转换之前,我们先来了解下这两种坐标。

地理坐标(贴图坐标)

一个完整的地理贴图坐标 (https://zh.wikipedia.org/wiki/%E5%9C%B0%E7%90%86%E5%9D%90%E6%A0%87%E7%B3%BB)如下,其中第一张为简图,能够帮我们快速理解经纬度与地理坐标,第二张为详细经纬度分布图。

Three.js 地理坐标和三维空间坐标的转换 Three.js 地理坐标和三维空间坐标的转换

可以看出贴图横向表示经度,范围[-180(西经),180(东经)],竖向表示纬度[-90(南纬), 90(北纬)],因此坐标转化就成了经纬度到球面坐标的转化。

球面坐标

在three.js中,创建球体时有以下几个重要参数:

  • 半径(radius)以及分段数
  • 水平方向起始角度(phiStart)
  • 水平方向角度大小(phiLength)
  • 垂直方向起始角(thetaStart)
  • 垂直方向角度大小(thetaLength)

其中phiStart的默认值0,起始点为x轴负方向。thetaStart的默认值也为0,起始点为z轴正方向。如下图所示:

Three.js 地理坐标和三维空间坐标的转换

如上图,其中phi的值为0-Math.PI*2,对应的经度范围为-180到180,所以与经度对应的phi应为180+lng(lng为经度longitude)。theta的值为0-Math.PI,对应的纬度为90到-90,所以与纬度对应的theta值应为90-lat(lat为纬度latitude)。

坐标转换

三角函数计算法

基于上述得出的经纬度和球体创建时角度的对应关系,结合三角函数,我们应该可以很方便地算出对应的三维坐标,如下:

y = r * cos(theta)
z = r * sin(theta) * sin(phi)

如下转换为JS代码:

  const phi = (180 + lng) * (Math.PI / 180)
  const theta = (90 - lat) * (Math.PI / 180)
  return {
    x: -radius * Math.sin(theta) * Math.cos(phi),
    y: radius * Math.cos(theta),
    z: radius * Math.sin(theta) * Math.sin(phi),
  }
}

three.js自带方法

除了上述直接用三角函数来算以外,我们也可以通过Three.js中的提供的方式来计算。主要涉及THREE.SphericalTHREE.Vector3

THREE.Spherical

THREE.Spherical是three.js中的球面坐标类,用法如下:

  • radius:半径,默认为1
  • phi: 以y轴正方向为起点的垂直方向弧度值,默认0
  • theta: 以z轴正方向为起点的水平方向弧度值,默认0

可以看出,这里的球面坐标类与我们在定义球时所用的球面坐标中的角是有区别的。phi和theta与上面恰恰相反。对应关系分别为(加’的为此处的角度):

  • phi’ = theta = 90 - lat
  • theta’ = phi - 90 = 90 + lng

THREE.Vector3

THREE.Vector3用于表示三维向量,它有一个setFromSpherical的方法,顾名思义,表示可以从球面坐标得到三维向量坐标。其实,three.js中可以可以实现球面坐标和三维坐标的相互转换,THREE.Spherical也存在类似的setFromVector3方法。 综上,通过three.js自带的方法来转换经纬度时可以用以下方法:

  const theta = (90 + lng) * (Math.PI / 180)
  const phi = (90 - lat) * (Math.PI / 180)
  return (new THREE.Vector3()).setFromSpherical(new THREE.Spherical(radius, phi, theta))
},

Three.js 地理坐标和三维空间坐标的转换

关于360技术 360技术是360技术团队打造的技术分享公众号,每天推送技术干货内容 更多技术信息欢迎关注“360技术”微信公众号

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
2年前
java将前端的json数组字符串转换为列表
记录下在前端通过ajax提交了一个json数组的字符串,在后端如何转换为列表。前端数据转化与请求varcontracts{id:'1',name:'yanggb合同1'},{id:'2',name:'yanggb合同2'},{id:'3',name:'yang
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Wesley13 Wesley13
2年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
Easter79
Easter79
Lv1
今生可爱与温柔,每一样都不能少。
文章
2.8k
粉丝
5
获赞
1.2k