feat: polish & windviz & deploy

This commit is contained in:
Anatoly Antonov 2026-05-30 06:29:39 +09:00
parent 81b8e763bd
commit 465ad00f7b
78 changed files with 20622 additions and 2154 deletions

View file

@ -46,13 +46,13 @@ func TestConstantAscentToBurst(t *testing.T) {
t.Errorf("RefinedState not populated")
}
last := results[0].Points[len(results[0].Points)-1]
lastT, last := results[0].Path.Last()
if math.Abs(last.Altitude-burst) > 5 {
t.Errorf("burst altitude = %v, want within 5m of %v", last.Altitude, burst)
}
wantTime := burst / rate
if math.Abs(last.Time-wantTime) > 1 {
t.Errorf("burst time = %v, want within 1s of %v", last.Time, wantTime)
if math.Abs(lastT-wantTime) > 1 {
t.Errorf("burst time = %v, want within 1s of %v", lastT, wantTime)
}
}
@ -87,7 +87,7 @@ func TestProfileWithFallback(t *testing.T) {
t.Errorf("second outcome = %v, want OutcomeStopped", results[1].Outcome)
}
last := results[1].Points[len(results[1].Points)-1]
_, last := results[1].Path.Last()
if math.Abs(last.Altitude) > 5 {
t.Errorf("final altitude = %v, want within 5m of 0", last.Altitude)
}
@ -103,12 +103,12 @@ func TestReverseDirection(t *testing.T) {
prof := Profile{Stages: []*Propagator{desc}, Direction: Reverse}
results := prof.Run(0, State{Altitude: 100}, NewEventSink())
last := results[0].Points[len(results[0].Points)-1]
lastT, last := results[0].Path.Last()
if math.Abs(last.Altitude-200) > 1 {
t.Errorf("reverse final altitude = %v, want ~200", last.Altitude)
}
if last.Time >= 0 {
t.Errorf("reverse final time = %v, want < 0", last.Time)
if lastT >= 0 {
t.Errorf("reverse final time = %v, want < 0", lastT)
}
}
@ -206,15 +206,25 @@ func TestWindTransportEmitsAboveModel(t *testing.T) {
}
}
func TestStateAddWrapsLongitude(t *testing.T) {
s := stateAdd(State{Lat: 0, Lng: 350, Altitude: 0}, 1, State{Lng: 20})
if math.Abs(s.Lng-10) > 1e-9 {
t.Errorf("addState wrap: lng = %v, want 10", s.Lng)
func TestNoTerminatorStopsAtStepCap(t *testing.T) {
// A stage that ascends forever with no constraint must not loop endlessly;
// the integrator's step backstop stops it and records a max_steps event.
sink := NewEventSink()
prof := Profile{
Stages: []*Propagator{{Name: "runaway", Step: 60, Model: ConstantRate(5)}},
Direction: Forward,
}
results := prof.Run(0, State{}, sink)
mid := stateLerp(State{Lng: 350}, State{Lng: 10}, 0.5)
if math.Abs(mid.Lng-0) > 1e-9 && math.Abs(mid.Lng-360) > 1e-9 {
t.Errorf("lerpState lng wrap: %v, want 0 or 360", mid.Lng)
if results[0].Outcome != OutcomeContinued {
t.Errorf("outcome = %v, want OutcomeContinued (step cap)", results[0].Outcome)
}
if results[0].Path.Len() != DefaultMaxSteps+1 {
t.Errorf("path len = %d, want %d", results[0].Path.Len(), DefaultMaxSteps+1)
}
ev := sink.Snapshot()
if len(ev) != 1 || ev[0].Type != "max_steps" {
t.Errorf("expected a max_steps event, got %+v", ev)
}
}
@ -226,7 +236,7 @@ func TestPolygonInside(t *testing.T) {
{Lat: 1, Lng: 1},
{Lat: 1, Lng: -1},
}
c := Polygon{Vertices: square, Mode: PolygonInside, On: ActionStop}
c := NewPolygon(square, PolygonInside, ActionStop, "")
if !c.Violated(0, State{Lat: 0, Lng: 0}) {
t.Errorf("origin should be inside the square")
}
@ -244,7 +254,7 @@ func TestPolygonOutsideAntimeridian(t *testing.T) {
{Lat: 10, Lng: 190},
{Lat: 10, Lng: 170},
}
c := Polygon{Vertices: poly, Mode: PolygonInside, On: ActionStop}
c := NewPolygon(poly, PolygonInside, ActionStop, "")
// A point at the antimeridian.
if !c.Violated(0, State{Lat: 0, Lng: 180}) {
t.Errorf("(0, 180) should be inside the antimeridian polygon")