首页 > 解决方案 > 基本坐标转换

问题描述

我正在编写一个可以将任何类型的坐标转换为另一个坐标的库。

我正在用 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

我真的看不出问题出在哪里。

希望得到任何帮助:)

标签: gomathcoordinatesformula

解决方案


球坐标表示为:

  1. r:半径,即到原点的直线距离。
  2. φ:倾角或极角,即与垂直轴 Z 的夹角。
  3. θ:方位角或方位角,即投影点从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° 的倾角,可以获得更高的倾角。

因此,为了能够比较值以检查它们是否相同,您首先需要进行归一化。请按照以下步骤操作:

  1. 如果r = 0:返回{0, 0°, 0°}(如果半径为零,角度不会改变任何东西,所以返回 0° 角度)
  2. 如果r < 0:和r = -r_φ = 180° - φθ += 180°
  3. 虽然φ >= 360°φ -= 360°
  4. 虽然φ < 0°φ += 360°
  5. if φ = 0°or φ = 180°: return {r, φ, 0°}(如果倾角为null或180°,则该点在垂直轴Z上,所以方位角没有任何意义,使用0°)
  6. 如果φ > 180°φ = 360° - φθ += 180°
  7. 虽然θ >= 360°θ -= 360°
  8. 虽然θ < 0°θ += 360°
  9. 返回{r, φ, θ}

在地理学中,经度有时会被归一化,-180° < θ <= 180°这会将第 7 步和第 8 步修改为:

  1. 虽然θ > 180°θ -= 360°
  2. 虽然θ <= -180°θ += 360°

在这里,您有一个Playground 链接,其中包含使用归一化和转换方法实现的类CartesianSphericalGeograpical(aSpherical但它创建自并打印纬度和经度而不是倾角和方位角)。


推荐阅读