基本坐标转换
Basic coordinates conversions
我正在编写一个可以将任何类型的坐标转换为另一种坐标的库。
我正在用 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° - φ
.
NOTE3:在地理上,仰角称为纬度,方位角称为经度。
与笛卡尔坐标的不同之处在于,每个点都具有单一的表示形式,即同一点可以在球面坐标中以不同的方式表示。以下转换都创建了新点 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°,可以获得更高的倾角。
因此,为了能够比较值以检查它们是否相同,您首先需要进行归一化。按照以下步骤操作:
- If
r = 0
: return {0, 0°, 0°}
(如果半径为零,角度不会改变任何东西所以 return 0° 角度)
- 如果
r < 0
:r = -r
、φ = 180° - φ
和θ += 180°
- 同时
φ >= 360°
:φ -= 360°
- 同时
φ < 0°
:φ += 360°
- If
φ = 0°
or φ = 180°
: return {r, φ, 0°}
(如果倾角为空或180°,则该点在垂直轴Z上,因此方位角不没有任何意义,请使用 0°)
- 如果
φ > 180°
:φ = 360° - φ
和θ += 180°
- 同时
θ >= 360°
:θ -= 360°
- 同时
θ < 0°
:θ += 360°
- Return
{r, φ, θ}
在地理学中,经度有时会标准化为 -180° < θ <= 180°
,这会将第 7 步和第 8 步修改为:
- 同时
θ > 180°
:θ -= 360°
- 同时
θ <= -180°
:θ += 360°
这里你有一个 Playground link 和 类 补充了 Cartesian
、Spherical
和 Geograpical
的规范化和转换方法(Spherical
但它是根据纬度和经度而不是倾角和方位角创建并打印的。
我正在编写一个可以将任何类型的坐标转换为另一种坐标的库。
我正在用 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° - φ
.
NOTE3:在地理上,仰角称为纬度,方位角称为经度。
与笛卡尔坐标的不同之处在于,每个点都具有单一的表示形式,即同一点可以在球面坐标中以不同的方式表示。以下转换都创建了新点 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°,可以获得更高的倾角。
因此,为了能够比较值以检查它们是否相同,您首先需要进行归一化。按照以下步骤操作:
- If
r = 0
: return{0, 0°, 0°}
(如果半径为零,角度不会改变任何东西所以 return 0° 角度) - 如果
r < 0
:r = -r
、φ = 180° - φ
和θ += 180°
- 同时
φ >= 360°
:φ -= 360°
- 同时
φ < 0°
:φ += 360°
- If
φ = 0°
orφ = 180°
: return{r, φ, 0°}
(如果倾角为空或180°,则该点在垂直轴Z上,因此方位角不没有任何意义,请使用 0°) - 如果
φ > 180°
:φ = 360° - φ
和θ += 180°
- 同时
θ >= 360°
:θ -= 360°
- 同时
θ < 0°
:θ += 360°
- Return
{r, φ, θ}
在地理学中,经度有时会标准化为 -180° < θ <= 180°
,这会将第 7 步和第 8 步修改为:
- 同时
θ > 180°
:θ -= 360°
- 同时
θ <= -180°
:θ += 360°
这里你有一个 Playground link 和 类 补充了 Cartesian
、Spherical
和 Geograpical
的规范化和转换方法(Spherical
但它是根据纬度和经度而不是倾角和方位角创建并打印的。