// Package world defines the static shape of the belt: bodies on analytic // (on-rails) orbits and the procedural generation that creates them. // // The star pulls with acceleration v^2/r (v = config OrbitSpeed), so a circular // orbit at any radius has the same speed v. Every body on rails is therefore // on a circle traversed at speed v; only the period (2*pi*r/v) varies. package world import "wh/fixed" // Orbit is a circular orbit around the origin (the star). type Orbit struct { A fixed.F // radius, km Period int64 // seconds M0 fixed.F // phase at t=0, radians Inc fixed.F // inclination to the ecliptic (XY plane), radians Node fixed.F // longitude of the ascending node, radians } // PeriodFor returns the period in seconds of a circle of radius a at speed v. func PeriodFor(a, v fixed.F) int64 { return fixed.TwoPi.Mul(a).Div(v).Int() } // State returns position (km) and velocity (km/s) at absolute time t seconds. func (o Orbit) State(t int64) (pos, vel fixed.Vec) { frac := fixed.FromInt(t % o.Period).Div(fixed.FromInt(o.Period)) s, c := fixed.SinCos(o.M0 + fixed.TwoPi.Mul(frac)) k := fixed.TwoPi.Mul(o.A).Div(fixed.FromInt(o.Period)) // speed pos = fixed.Vec{X: o.A.Mul(c), Y: o.A.Mul(s)} vel = fixed.Vec{X: -k.Mul(s), Y: k.Mul(c)} return o.orient(pos), o.orient(vel) } // orient rotates a vector from the orbital plane into the ecliptic frame: // Rz(Node) * Rx(Inc). func (o Orbit) orient(v fixed.Vec) fixed.Vec { return v.RotateX(o.Inc).RotateZ(o.Node) }