// ApparentEccentricity returns apparent eccenticity of a binary star // given true orbital elements. // // e is eccentricity of the true orbit // i is inclination relative to the line of sight // ω is longitude of periastron func ApparentEccentricity(e float64, i, ω unit.Angle) float64 { ci := i.Cos() sω, cω := ω.Sincos() A := (1 - e*e*cω*cω) * ci * ci B := e * e * sω * cω * ci C := 1 - e*e*sω*sω d := A - C sD := math.Sqrt(d*d + 4*B*B) return math.Sqrt(2 * sD / (A + C + sD)) }
// Position computes apparent position angle and angular distance of // components of a binary star. // // e is eccentricity of the true orbit // a is angular apparent semimajor axis // i is inclination relative to the line of sight // Ω is position angle of the ascending node // ω is longitude of periastron // E is eccentric anomaly, computed for example with package kepler // and the mean anomaly as returned by function M in this package. // // Return value θ is the apparent position angle, ρ is the angular distance. func Position(e float64, a, i, Ω, ω, E unit.Angle) (θ, ρ unit.Angle) { r := a.Mul(1 - e*E.Cos()) ν := unit.Angle(2 * math.Atan(math.Sqrt((1+e)/(1-e))*E.Div(2).Tan())) sνω, cνω := (ν + ω).Sincos() ci := i.Cos() num := sνω * ci θ = (unit.Angle(math.Atan2(num, cνω)) + Ω).Mod1() ρ = r.Mul(math.Sqrt(num*num + cνω*cνω)) return }
func (m *moon) pa(λ, β, b unit.Angle) unit.Angle { V := m.Ω + m.Δψ + m.σ.Div(sI) sV, cV := V.Sincos() sIρ, cIρ := (_I + m.ρ).Sincos() X := sIρ * sV Y := sIρ*cV*m.cε - cIρ*m.sε ω := math.Atan2(X, Y) α, _ := coord.EclToEq(λ+m.Δψ, β, m.sε, m.cε) P := unit.Angle(math.Asin(math.Hypot(X, Y) * math.Cos(α.Rad()-ω) / b.Cos())) if P < 0 { P += 2 * math.Pi } return P }
// Error returns an error angle of three nearly co-linear points. // // For the line defined by r1, d1, r2, d2, the result is the anglular distance // between that line and r0, d0. // // Algorithm by Meeus. func Error(r1, d1, r2, d2, r0, d0 unit.Angle) unit.Angle { sr1, cr1 := r1.Sincos() sd1, cd1 := d1.Sincos() sr2, cr2 := r2.Sincos() sd2, cd2 := d2.Sincos() X1 := cd1 * cr1 X2 := cd2 * cr2 Y1 := cd1 * sr1 Y2 := cd2 * sr2 Z1 := sd1 Z2 := sd2 A := Y1*Z2 - Z1*Y2 B := Z1*X2 - X1*Z2 C := X1*Y2 - Y1*X2 m := r0.Tan() n := d0.Tan() / r0.Cos() return unit.Angle(math.Asin((A + B*m + C*n) / (math.Sqrt(A*A+B*B+C*C) * math.Sqrt(1+m*m+n*n)))) }
// Smallest finds the smallest circle containing three points. // // Arguments should represent coordinates in right ascension and declination // or longitude and latitude. Result Δ is the diameter of the circle, typeI // is true if solution is of type I. // // type I Two points on circle, one interior. // type II All three points on circle. func Smallest(r1, d1, r2, d2, r3, d3 unit.Angle) (Δ unit.Angle, typeI bool) { // Using haversine formula, but reimplementing SepHav here to reuse // the computed cosines. cd1 := d1.Cos() cd2 := d2.Cos() cd3 := d3.Cos() a := 2 * math.Asin(math.Sqrt(base.Hav(d2-d1)+cd1*cd2*base.Hav(r2-r1))) b := 2 * math.Asin(math.Sqrt(base.Hav(d3-d2)+cd2*cd3*base.Hav(r3-r2))) c := 2 * math.Asin(math.Sqrt(base.Hav(d1-d3)+cd3*cd1*base.Hav(r1-r3))) if b > a { a, b = b, a } if c > a { a, c = c, a } if a*a >= b*b+c*c { return unit.Angle(a), true } // (20.1) p. 128 return unit.Angle(2 * a * b * c / math.Sqrt((a+b+c)*(a+b-c)*(b+c-a)*(a+c-b))), false }
// Radius returns radius distance r for given eccentric anomaly E. // // Argument e is eccentricity, a is semimajor axis. // // Result unit is the unit of semimajor axis a (typically AU.) func Radius(E unit.Angle, e, a float64) float64 { // (30.2) p. 195 return a * (1 - e*E.Cos()) }
// Hav implements the haversine trigonometric function. // // See https://en.wikipedia.org/wiki/Haversine_formula. func Hav(a unit.Angle) float64 { // (17.5) p. 115 return .5 * (1 - a.Cos()) }
// SepHav returns the angular separation between two celestial bodies. // // The algorithm uses the haversine function and is superior to the naïve // algorithm of the Sep function. func SepHav(r1, d1, r2, d2 unit.Angle) unit.Angle { // using (17.5) p. 115 return unit.Angle(2 * math.Asin(math.Sqrt(base.Hav(d2-d1)+ d1.Cos()*d2.Cos()*base.Hav(r2-r1)))) }
// Illuminated returns the illuminated fraction of a body's disk. // // The illuminated body can be the Moon or a planet. // // Argument i is the phase angle. func Illuminated(i unit.Angle) float64 { // (41.1) p. 283, also (48.1) p. 345. return (1 + i.Cos()) * .5 }
// SaturnApparentPolar returns apparent polar semidiameter of Saturn // at specified distance. // // Argument Δ must be observer-Saturn distance in AU. Argument B is // Saturnicentric latitude of the observer as given by function saturnring.UB() // for example. func SaturnApparentPolar(Δ float64, B unit.Angle) unit.Angle { k := (SaturnPolar.Rad() / SaturnEquatorial.Rad()) k = 1 - k*k cB := B.Cos() return SaturnEquatorial.Mul(math.Sqrt(1-k*cB*cB) / Δ) }
// PhaseAngle2 computes the phase angle of a planet. // // Arguments L, B, R are heliocentric ecliptical coordinates of the planet. // L0, R0 are longitude and radius for Earth, Δ is distance from Earth to // the planet. All distances in AU. func PhaseAngle2(L, B unit.Angle, R float64, L0 unit.Angle, R0, Δ float64) unit.Angle { // (41.3) p. 283 return unit.Angle(math.Acos((R - R0*B.Cos()*(L-L0).Cos()) / Δ)) }