go - 基本坐标转换
问题描述
我正在编写一个可以将任何类型的坐标转换为另一个坐标的库。
我正在用 Go 编写它。我通过将坐标转换为一种类型然后转换回初始类型来测试转换。然后我应该获得相同的起始值(包括浮点精度误差)。
我对Spherical.ToCartesian
实现很有把握,因为当我在 keisan 中测试值时,我得到了相同的值。
这是coordinate.go
文件:
import (
. "math"
)
/////////////
// Cartesian Coordinates
/////////////
type Cartesian struct {
X float64 `json:"x"`
Y float64 `json:"y"`
Z float64 `json:"z"`
}
// func (c Cartesian) ToCartesian() Cartesian {...}
// Following : https://keisan.casio.com/exec/system/1359533867
func (c Cartesian) ToSpherical() Spherical{
r := Sqrt(Pow(c.X, 2.) + Pow(c.Y, 2.) + Pow(c.Z, 2.))
return Spherical{
Latitude: RadToDeg(Atan(Sqrt(c.X * c.X + c.Y * c.Y) / c.Z)),
Longitude: RadToDeg(Atan2(c.Y, c.X)),
Radius: r,
}
}
// func (c Cartesian) ToPolar() Polar {...}
/////////////
// Spherical Coordinates
/////////////
type Spherical struct {
Radius float64 `json:"radius"`
// Aka θ
Longitude float64 `json:"longitude"`
// Aka ϕ
Latitude float64 `json:"latitude"`
}
// Following : https://keisan.casio.com/exec/system/1359534351
func (g Spherical) ToCartesian() Cartesian {
return Cartesian{
// x = r * sin ϕ * cos θ
X: g.Radius * Sin(DegToRad(g.Latitude)) * Cos(DegToRad(g.Longitude)),
// y = r * sin ϕ * sin θ
Y: g.Radius * Sin(DegToRad(g.Latitude)) * Sin(DegToRad(g.Longitude)),
// z = r * cos ϕ
Z: g.Radius * Cos(DegToRad(g.Latitude)),
}
}
这是不起作用的测试:
var g = Spherical{
Longitude: 200,
Latitude: 100,
Radius: 10000,
}
func TestSpherical_ToCartesianToSpherical(t *testing.T) {
v := g.ToCartesian().ToSpherical()
if !IsFloatEq(g.Radius, v.Radius) {
t.Error("Bad Radius conversion. Expected", g.Radius, "got", v.Radius)
}
if !IsFloatEq(g.Longitude, v.Longitude) {
t.Error("Bad Longitude conversion. Expected", g.Longitude, "got", v.Longitude)
}
if !IsFloatEq(g.Latitude, v.Latitude) {
t.Error("Bad Latitude conversion. Expected", g.Latitude, "got", v.Latitude)
}
}
当我go test
,我得到这个:
--- FAIL: TestGeographic_ToCartesianToGeographic (0.00s)
geographic_test.go:34: Bad Longitude conversion. Expected 200 got -160
geographic_test.go:37: Bad Latitude conversion. Expected 100 got -80
FAIL
FAIL common/coordinates 0.113s
FAIL
我真的看不出问题出在哪里。
希望得到任何帮助:)
解决方案
球坐标表示为:
r
:半径,即到原点的直线距离。φ
:倾角或极角,即与垂直轴 Z 的夹角。θ
:方位角或方位角,即投影点从X轴到XY平面的角度。
注意1:在物理学中,用于表示两个角度的希腊字母被交换了,但我将使用这个符号,因为它似乎是您根据公式使用的符号。
注意 2:还有另一种表示倾角的方法,称为仰角,它是从 XY 平面测量的。elevation = 90° - φ
.
注3:在地理上,高程称为纬度,方位角称为经度。
与笛卡尔坐标的不同之处在于,每个点都有一个单一的表示,同一点可以在球坐标中以不同的方式表示。以下转换都创建P2 = {r2, φ2, θ2}
了与原始点具有不同值的新点,P1 = {r1, φ1, θ1}
但它们都是相同的点 ( P2 == P1
),尽管值不同。
/ r2 = r1 / r2 = - r1
| φ2 = φ1 | φ2 = 180° - φ1
\ θ2 = θ1 + 360° \ θ2 = θ1 + 180°
哪个是解决方案?归一化球坐标。最常见的归一化系统仅使用正半径值并将角度限制为 180° 和 360°:
/ 0 <= r < inf
| 0° <= φ <= 180° -> which means -90° <= elevation <= 90°
\ 0° <= θ < 360°
将倾角限制在 180° 的原因是,通过将方位角额外旋转 180° 并具有低于 180° 的倾角,可以获得更高的倾角。
因此,为了能够比较值以检查它们是否相同,您首先需要进行归一化。请按照以下步骤操作:
- 如果
r = 0
:返回{0, 0°, 0°}
(如果半径为零,角度不会改变任何东西,所以返回 0° 角度) - 如果
r < 0
:和r = -r
_φ = 180° - φ
θ += 180°
- 虽然
φ >= 360°
:φ -= 360°
- 虽然
φ < 0°
:φ += 360°
- if
φ = 0°
orφ = 180°
: return{r, φ, 0°}
(如果倾角为null或180°,则该点在垂直轴Z上,所以方位角没有任何意义,使用0°) - 如果
φ > 180°
:φ = 360° - φ
和θ += 180°
- 虽然
θ >= 360°
:θ -= 360°
- 虽然
θ < 0°
:θ += 360°
- 返回
{r, φ, θ}
在地理学中,经度有时会被归一化,-180° < θ <= 180°
这会将第 7 步和第 8 步修改为:
- 虽然
θ > 180°
:θ -= 360°
- 虽然
θ <= -180°
:θ += 360°
在这里,您有一个Playground 链接,其中包含使用归一化和转换方法实现的类Cartesian
,Spherical
和Geograpical
(aSpherical
但它创建自并打印纬度和经度而不是倾角和方位角)。
推荐阅读
- python - python 3.x 中的多线程和子进程问题
- dymola - 如何在 dymola 中启用自动曼哈顿化模式?
- javascript - 是否有一种将标头添加到 $.ajax 帖子调用的全局方法?
- java - 为什么数组不采用前一条指令的值,而只采用最后一条指令的值?
- excel - 如何运行 VBA 宏来复制单元格中具有特定值的行并粘贴到另一个工作表?你能帮我修复这段代码吗?
- kubernetes - Prometheus 将所有节点名更改为小写
- conv-neural-network - 生成图像 CycleGAN 上的白点
- javascript - JQuery 无法从计算机加载文件,错误 0
- c# - 分行覆盖问题
- python - Pandas 按多个条件删除重复的行