Basi c преобразование координат - PullRequest
0 голосов
/ 05 марта 2020

Я пишу библиотеку, которая может преобразовать любой тип координат в другой.

Я пишу это в 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

Я действительно не вижу, в чем проблема.

Надеюсь на любую помощь:)

1 Ответ

1 голос
/ 06 марта 2020

Сферические координаты представлены как:

  1. r: радиус, который является расстоянием стриха от начала координат.
  2. φ: угол наклона или полярный угол, который равен угол от вертикальной оси Z.
  3. θ: азимут или азимутальный угол, который является углом проецируемой точки в плоскость XY от оси X.

ПРИМЕЧАНИЕ1: в Physichs греческие буквы, используемые для обозначения обоих углов, меняются местами, но я буду использовать это обозначение, так как оно похоже на то, которое вы используете на основе ваших формул.

ПРИМЕЧАНИЕ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. Если φ = 0° или φ = 180°: возврат {r, φ, 0°} (если наклон нулевой или 180 °, точка находится на вертикальной оси Z, поэтому азимут ничего не значит, используйте 0 °)
  6. Если φ > 180°: φ = 360° - φ и θ += 180°
  7. При θ >= 360°: θ -= 360°
  8. При θ < 0°: θ += 360°
  9. Возврат {r, φ, θ}

В географии долгота иногда нормализуется до -180° < θ <= 180°, что изменило бы шаги 7 и 8 на:

Пока θ > 180°: θ -= 360° Пока θ <= -180°: θ += 360°

Здесь у вас есть ссылка Playground с добавленными классами с методами нормализации и преобразования для Cartesian, Spherical и Geograpical (a Spherical, но он создан из и печатает широту и долготу вместо наклона и азимута).

...