Files
Halcyon/world/world_test.go
T
2026-09-19 20:21:47 +02:00

79 lines
2.3 KiB
Go

package world
import (
"math"
"testing"
"wh/config"
"wh/fixed"
)
func TestOrbitsAreCirclesAtCommonSpeed(t *testing.T) {
cfg := config.Default()
asts, _ := Generate(cfg)
want := cfg.OrbitSpeed.Float64()
for _, a := range asts {
o := a.Orbit
for _, ts := range []int64{0, 100_000, 777_777, o.Period / 3, o.Period - 1} {
p, v := o.State(ts)
if r := p.Len().Float64(); math.Abs(r-o.A.Float64()) > 1e-3 {
t.Fatalf("asteroid %d t=%d: radius %g, want %g", a.ID, ts, r, o.A.Float64())
}
if s := v.Len().Float64(); math.Abs(s-want)/want > 1e-5 {
t.Fatalf("asteroid %d t=%d: speed %g, want %g", a.ID, ts, s, want)
}
if d := p.Dot(v).Float64() / (p.Len().Float64() * want); math.Abs(d) > 1e-4 {
t.Fatalf("asteroid %d: velocity not tangent (cos=%g)", a.ID, d)
}
// Inclination bounds the height above the ecliptic.
if z := p.Z.Abs().Float64(); z > o.A.Float64()*math.Sin(o.Inc.Float64())*1.001+1e-3 {
t.Fatalf("asteroid %d: |z|=%g exceeds inclination bound", a.ID, z)
}
}
// Periodic.
p1, _ := o.State(12345)
p2, _ := o.State(12345 + o.Period)
if d := p1.Sub(p2).Len().Float64(); d > 1 {
t.Fatalf("asteroid %d not periodic, off by %g km", a.ID, d)
}
}
}
func TestOrbitPlaneMatchesInclination(t *testing.T) {
o := Orbit{A: fixed.FromInt(2_000_000), Inc: fixed.FromRatio(3, 10), Node: fixed.FromInt(2)}
o.Period = PeriodFor(o.A, fixed.FromInt(3))
// The orbit normal is Rz(Node)Rx(Inc) applied to +Z; positions must be
// perpendicular to it, and the maximum height is A*sin(Inc).
n := fixed.Vec{Z: fixed.One}.RotateX(o.Inc).RotateZ(o.Node)
var maxZ float64
for k := int64(0); k < 50; k++ {
p, _ := o.State(k * o.Period / 50)
if d := p.Dot(n).Float64(); math.Abs(d) > 1e-2 {
t.Fatalf("position not in the orbital plane: p.n = %g", d)
}
maxZ = math.Max(maxZ, p.Z.Float64())
}
if want := o.A.Float64() * math.Sin(0.3); math.Abs(maxZ-want)/want > 0.01 {
t.Fatalf("max z = %g, want %g", maxZ, want)
}
}
func TestGenerateDeterministic(t *testing.T) {
cfg := config.Default()
a1, s1 := Generate(cfg)
a2, s2 := Generate(cfg)
if len(a1) != cfg.AsteroidCount || s1 != s2 {
t.Fatal("mismatch")
}
for i := range a1 {
if a1[i] != a2[i] {
t.Fatalf("asteroid %d differs", i)
}
}
cfg.Seed = 2
a3, _ := Generate(cfg)
if a3[0] == a1[0] {
t.Fatal("different seeds should differ")
}
}