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

View file

@ -0,0 +1,55 @@
package engine
// Profile is an ordered chain of propagators executed sequentially. Each
// propagator picks up where the previous one finished.
type Profile struct {
// Stages are run in order. For Direction=Reverse they are still iterated
// from index 0 onwards, but each propagator integrates with negative dt.
Stages []*Propagator
// Direction controls the sign of dt across the whole profile.
Direction Direction
// Globals are constraints evaluated alongside each stage's local Constraints.
// Useful for profile-wide bounds like "stop after N hours total".
Globals []Constraint
}
// Run executes the profile from the given launch point. Returns one Result
// per executed stage, including any Fallback chains that were activated.
func (p *Profile) Run(t0 float64, launch State) []Result {
if p.Direction == 0 {
p.Direction = Forward
}
results := make([]Result, 0, len(p.Stages))
t, s := t0, launch
for i := 0; i < len(p.Stages); i++ {
stage := p.Stages[i]
res := stage.run(t, s, p.Direction, p.Globals)
results = append(results, res)
last := res.Points[len(res.Points)-1]
t = last.Time
s = State{Lat: last.Lat, Lng: last.Lng, Altitude: last.Altitude}
// Follow Fallback chains until none remains. Each fallback consumes
// from the same point the previous stage stopped at.
for res.Outcome == OutcomeFallback && stage.Fallback != nil {
stage = stage.Fallback
res = stage.run(t, s, p.Direction, p.Globals)
results = append(results, res)
last = res.Points[len(res.Points)-1]
t = last.Time
s = State{Lat: last.Lat, Lng: last.Lng, Altitude: last.Altitude}
}
// If a propagator's stop fired (not a fallback), end the profile.
if res.Outcome == OutcomeStopped {
continue
}
}
return results
}