step one
This commit is contained in:
parent
7a8d5d13fa
commit
9e663db9dc
68 changed files with 5647 additions and 2958 deletions
50
internal/engine/state.go
Normal file
50
internal/engine/state.go
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
package engine
|
||||
|
||||
import "math"
|
||||
|
||||
// pymod returns a % b with Python semantics: the result has the sign of b,
|
||||
// so for b > 0 the result is always in [0, b).
|
||||
func pymod(a, b float64) float64 {
|
||||
r := math.Mod(a, b)
|
||||
if r < 0 {
|
||||
r += b
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
// stateAdd is the RK4 integrator's update operation y + k*dy, with longitude
|
||||
// kept wrapped to [0, 360).
|
||||
//
|
||||
// Time is not stored in State — it is tracked separately by the integrator
|
||||
// and passed to Model.
|
||||
func stateAdd(y State, k float64, dy State) State {
|
||||
return State{
|
||||
Lat: y.Lat + k*dy.Lat,
|
||||
Lng: pymod(y.Lng+k*dy.Lng, 360),
|
||||
Altitude: y.Altitude + k*dy.Altitude,
|
||||
}
|
||||
}
|
||||
|
||||
// stateLerp computes the linear interpolation of two states by parameter l
|
||||
// in [0, 1]. Longitude uses lngLerp so that wrap-around is handled.
|
||||
func stateLerp(a, b State, l float64) State {
|
||||
return State{
|
||||
Lat: (1-l)*a.Lat + l*b.Lat,
|
||||
Lng: lngLerp(a.Lng, b.Lng, l),
|
||||
Altitude: (1-l)*a.Altitude + l*b.Altitude,
|
||||
}
|
||||
}
|
||||
|
||||
// lngLerp interpolates between two longitudes in [0, 360), choosing the
|
||||
// shorter great-circle arc.
|
||||
func lngLerp(a, b, l float64) float64 {
|
||||
l2 := 1 - l
|
||||
if a > b {
|
||||
a, b = b, a
|
||||
l, l2 = l2, l
|
||||
}
|
||||
if b-a < 180 {
|
||||
return l2*a + l*b
|
||||
}
|
||||
return pymod(l2*(a+360)+l*b, 360)
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue