This commit is contained in:
Anatoly Antonov 2026-05-18 03:17:17 +09:00
parent 7a8d5d13fa
commit 9e663db9dc
68 changed files with 5647 additions and 2958 deletions

50
internal/engine/state.go Normal file
View 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)
}