Esempio n. 1
0
// Vertical computes data for a vertical sundial.
//
// Argument φ is geographic latitude at which the sundial will be located.
// D is gnomonic declination, the azimuth of the perpendicular to the plane
// of the sundial, measured from the southern meridian towards the west.
// Argument a is the length of a straight stylus perpendicular to the plane
// of the sundial.
//
// Results consist of a set of lines, a center point, and u, the length of a
// polar stylus.  They are in units of a, the stylus length.
func Vertical(φ, D unit.Angle, a float64) (lines []Line, center Point, u float64) {
	sφ, cφ := φ.Sincos()
	tφ := sφ / cφ
	sD, cD := D.Sincos()
	for i := 0; i < 24; i++ {
		l := Line{Hour: i}
		H := float64(i-12) * 15 * math.Pi / 180
		aH := math.Abs(H)
		sH, cH := math.Sincos(H)
		for _, d := range m {
			tδ := math.Tan(d * math.Pi / 180)
			H0 := math.Acos(-tφ * tδ)
			if aH > H0 {
				continue // sun below horizon
			}
			Q := sD*sH + sφ*cD*cH - cφ*cD*tδ
			if Q < 0 {
				continue // sun below plane of sundial
			}
			x := a * (cD*sH - sφ*sD*cH + cφ*sD*tδ) / Q
			y := -a * (cφ*cH + sφ*tδ) / Q
			l.Points = append(l.Points, Point{x, y})
		}
		if len(l.Points) > 0 {
			lines = append(lines, l)
		}
	}
	center.X = -a * sD / cD
	center.Y = a * tφ / cD
	u = a / math.Abs(cφ*cD)
	return
}
Esempio n. 2
0
// Kepler1 solves Kepler's equation by iteration.
//
// The iterated formula is
//
//	E1 = M + e * sin(E0)
//
// Argument e is eccentricity, M is mean anomaly,
// places is the desired number of decimal places in the result.
//
// Result E is eccentric anomaly.
//
// For some vaues of e and M it will fail to converge and the
// function will return an error.
func Kepler1(e float64, M unit.Angle, places int) (E unit.Angle, err error) {
	f := func(E0 float64) float64 {
		return M.Rad() + e*math.Sin(E0) // (30.5) p. 195
	}
	ea, err := iterate.DecimalPlaces(f, M.Rad(), places, places*5)
	return unit.Angle(ea), err
}
Esempio n. 3
0
func (m *moon) physical(A, bʹ unit.Angle) (lʺ, bʺ unit.Angle) {
	// (53.2) p. 373
	sA, cA := A.Sincos()
	lʺ = -m.τ + (m.ρ.Mul(cA) + m.σ.Mul(sA)).Mul(bʹ.Tan())
	bʺ = m.σ.Mul(cA) - m.ρ.Mul(sA)
	return
}
Esempio n. 4
0
// Kepler2 solves Kepler's equation by iteration.
//
// The iterated formula is
//
//	E1 = E0 + (M + e * sin(E0) - E0) / (1 - e * cos(E0))
//
// Argument e is eccentricity, M is mean anomaly,
// places is the desired number of decimal places in the result.
//
// Result E is eccentric anomaly.
//
// The function converges over a wider range of inputs than does Kepler1
// but it also fails to converge for some values of e and M.
func Kepler2(e float64, M unit.Angle, places int) (E unit.Angle, err error) {
	f := func(E0 float64) float64 {
		se, ce := math.Sincos(E0)
		return E0 + (M.Rad()+e*se-E0)/(1-e*ce) // (30.7) p. 199
	}
	ea, err := iterate.DecimalPlaces(f, M.Rad(), places, places)
	return unit.Angle(ea), err
}
Esempio n. 5
0
// SepPauwels returns the angular separation between two celestial bodies.
//
// The algorithm is a numerically stable form of that used in Sep.
func SepPauwels(r1, d1, r2, d2 unit.Angle) unit.Angle {
	sd1, cd1 := d1.Sincos()
	sd2, cd2 := d2.Sincos()
	cdr := (r2 - r1).Cos()
	x := cd1*sd2 - sd1*cd2*cdr
	y := cd2 * (r2 - r1).Sin()
	z := sd1*sd2 + cd1*cd2*cdr
	return unit.Angle(math.Atan2(math.Hypot(x, y), z))
}
Esempio n. 6
0
// GalToEq converts galactic coordinates to equatorial coordinates.
//
// Resulting equatorial coordinates will be referred to the standard equinox of
// B1950.0.  For subsequent conversion to other epochs, see package precess and
// utility functions in package meeus.
func GalToEq(l, b unit.Angle) (α unit.RA, δ unit.Angle) {
	sdLon, cdLon := (l - galacticLon0).Sincos()
	sgδ, cgδ := galacticNorth.Dec.Sincos()
	sb, cb := b.Sincos()
	y := math.Atan2(sdLon, cdLon*sgδ-(sb/cb)*cgδ)
	α = unit.RAFromRad(y + galacticNorth.RA.Rad())
	δ = unit.Angle(math.Asin(sb*sgδ + cb*cgδ*cdLon))
	return
}
Esempio n. 7
0
// HzToEq transforms horizontal coordinates to equatorial coordinates.
//
//	A: azimuth
//	h: elevation
//	φ: latitude of observer on Earth
//	ψ: longitude of observer on Earth
//	st: sidereal time at Greenwich at time of observation.
//
// Sidereal time must be consistent with the equatorial coordinates
// in the sense that tf coordinates are apparent, sidereal time must be
// apparent as well.
//
// Results:
//
//	α: right ascension
//	δ: declination
func HzToEq(A, h, φ, ψ unit.Angle, st unit.Time) (α unit.RA, δ unit.Angle) {
	sA, cA := A.Sincos()
	sh, ch := h.Sincos()
	sφ, cφ := φ.Sincos()
	H := math.Atan2(sA, cA*sφ+sh/ch*cφ)
	α = unit.RAFromRad(st.Rad() - ψ.Rad() - H)
	δ = unit.Angle(math.Asin(sφ*sh - cφ*ch*cA))
	return
}
Esempio n. 8
0
// Kepler2a solves Kepler's equation by iteration.
//
// The iterated formula is the same as in Kepler2 but a limiting function
// avoids divergence.
//
// Argument e is eccentricity, M is mean anomaly,
// places is the desired number of decimal places in the result.
//
// Result E is eccentric anomaly.
func Kepler2a(e float64, M unit.Angle, places int) (E unit.Angle, err error) {
	f := func(E0 float64) float64 {
		se, ce := math.Sincos(E0)
		// method of Leingärtner, p. 205
		return E0 + math.Asin(math.Sin((M.Rad()+e*se-E0)/(1-e*ce)))
	}
	ea, err := iterate.DecimalPlaces(f, M.Rad(), places, places*5)
	return unit.Angle(ea), err
}
Esempio n. 9
0
// 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))
}
Esempio n. 10
0
// Sep returns the angular separation between two celestial bodies.
//
// The algorithm is numerically naïve, and while patched up a bit for
// small separations, remains unstable for separations near π.
func Sep(r1, d1, r2, d2 unit.Angle) unit.Angle {
	sd1, cd1 := d1.Sincos()
	sd2, cd2 := d2.Sincos()
	cd := sd1*sd2 + cd1*cd2*(r1-r2).Cos() // (17.1) p. 109
	if cd < base.CosSmallAngle {
		return unit.Angle(math.Acos(cd))
	}
	// (17.2) p. 109
	return unit.Angle(math.Hypot((r2-r1).Rad()*cd1, (d2 - d1).Rad()))
}
Esempio n. 11
0
// Times computes UT rise, transit and set times for a celestial object on
// a day of interest.
//
// The function argurments do not actually include the day, but do include
// a number of values computed from the day.
//
//	p is geographic coordinates of observer.
//	ΔT is delta T.
//	h0 is "standard altitude" of the body.
//	Th0 is apparent sidereal time at 0h UT at Greenwich.
//	α3, δ3 are slices of three right ascensions and declinations.
//
// h0 unit is radians.
//
// Th0 must be the time on the day of interest, in seconds.
// See sidereal.Apparent0UT.
//
// α3, δ3 must be values at 0h dynamical time for the day before, the day of,
// and the day after the day of interest.  Units are radians.
//
// Result units are seconds of day and are in the range [0,86400).
func Times(p globe.Coord, ΔT unit.Time, h0 unit.Angle, Th0 unit.Time, α3 []unit.RA, δ3 []unit.Angle) (tRise, tTransit, tSet unit.Time, err error) {
	tRise, tTransit, tSet, err = ApproxTimes(p, h0, Th0, α3[1], δ3[1])
	if err != nil {
		return
	}
	αf := make([]float64, 3)
	for i, α := range α3 {
		αf[i] = α.Rad()
	}
	δf := make([]float64, 3)
	for i, δ := range δ3 {
		δf[i] = δ.Rad()
	}
	var d3α, d3δ *interp.Len3
	d3α, err = interp.NewLen3(-86400, 86400, αf)
	if err != nil {
		return
	}
	d3δ, err = interp.NewLen3(-86400, 86400, δf)
	if err != nil {
		return
	}
	// adjust tTransit
	{
		th0 := (Th0 + tTransit.Mul(360.985647/360)).Mod1()
		α := d3α.InterpolateX((tTransit + ΔT).Sec())
		// local hour angle as Time
		H := th0 - unit.TimeFromRad(p.Lon.Rad()+α)
		tTransit -= H
	}
	// adjust tRise, tSet
	sLat, cLat := p.Lat.Sincos()
	adjustRS := func(m unit.Time) (unit.Time, error) {
		th0 := (Th0 + m.Mul(360.985647/360)).Mod1()
		ut := (m + ΔT).Sec()
		α := d3α.InterpolateX(ut)
		δ := d3δ.InterpolateX(ut)
		Hrad := th0.Rad() - p.Lon.Rad() - α
		sδ, cδ := math.Sincos(δ)
		sH, cH := math.Sincos(Hrad)
		h := math.Asin(sLat*sδ + cLat*cδ*cH)
		md := (unit.TimeFromRad(h) - h0.Time()).Div(cδ * cLat * sH)
		return m + md, nil
	}
	tRise, err = adjustRS(tRise)
	if err != nil {
		return
	}
	tSet, err = adjustRS(tSet)
	return
}
Esempio n. 12
0
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
}
Esempio n. 13
0
// Kepler2b solves Kepler's equation by iteration.
//
// The iterated formula is the same as in Kepler2 but a (different) limiting
// function avoids divergence.
//
// Argument e is eccentricity, M is mean anomaly,
// places is the desired number of decimal places in the result.
//
// Result E is eccentric anomaly.
func Kepler2b(e float64, M unit.Angle, places int) (E unit.Angle, err error) {
	f := func(E0 float64) float64 {
		se, ce := math.Sincos(E0)
		d := (M.Rad() + e*se - E0) / (1 - e*ce)
		// method of Steele, p. 205
		if d > .5 {
			d = .5
		} else if d < -.5 {
			d = -.5
		}
		return E0 + d
	}
	ea, err := iterate.DecimalPlaces(f, M.Rad(), places, places)
	return unit.Angle(ea), err
}
Esempio n. 14
0
// TopocentricEcliptical returns topocentric ecliptical coordinates including parallax.
//
// Arguments λ, β are geocentric ecliptical longitude and latitude of a body,
// s is its geocentric semidiameter. φ, h are the observer's latitude and
// and height above the ellipsoid in meters.  ε is the obliquity of the
// ecliptic, θ is local sidereal time, π is equatorial horizontal parallax
// of the body (see Horizonal()).
//
// Results are observed topocentric coordinates and semidiameter.
func TopocentricEcliptical(λ, β, s, φ unit.Angle, h float64, ε unit.Angle, θ unit.Time, π unit.Angle) (λʹ, βʹ, sʹ unit.Angle) {
	S, C := globe.Earth76.ParallaxConstants(φ, h)
	sλ, cλ := λ.Sincos()
	sβ, cβ := β.Sincos()
	sε, cε := ε.Sincos()
	sθ, cθ := θ.Angle().Sincos()
	sπ := π.Sin()
	N := cλ*cβ - C*sπ*cθ
	λʹ = unit.Angle(math.Atan2(sλ*cβ-sπ*(S*sε+C*cε*sθ), N))
	if λʹ < 0 {
		λʹ += 2 * math.Pi
	}
	cλʹ := λʹ.Cos()
	βʹ = unit.Angle(math.Atan(cλʹ * (sβ - sπ*(S*cε-C*sε*sθ)) / N))
	sʹ = unit.Angle(math.Asin(cλʹ * βʹ.Cos() * s.Sin() / N))
	return
}
Esempio n. 15
0
// Time computes the time at which a moving body is on a straight line (great
// circle) between two fixed points, such as stars.
//
// Coordinates may be right ascensions and declinations or longitudes and
// latitudes.  Fixed points are r1, d1, r2, d2.  Moving body is an ephemeris
// of 5 rows, r3, d3, starting at time t1 and ending at time t5.  Time scale
// is arbitrary.
//
// Result is time of alignment.
func Time(r1, d1, r2, d2 unit.Angle, r3, d3 []unit.Angle, t1, t5 float64) (float64, error) {
	if len(r3) != 5 || len(d3) != 5 {
		return 0, errors.New("r3, d3 must be length 5")
	}
	gc := make([]float64, 5)
	for i, r3i := range r3 {
		// (19.1) p. 121
		gc[i] = d1.Tan()*(r2-r3i).Sin() +
			d2.Tan()*(r3i-r1).Sin() +
			d3[i].Tan()*(r1-r2).Sin()
	}
	l5, err := interp.NewLen5(t1, t5, gc)
	if err != nil {
		return 0, err
	}
	return l5.Zero(false)
}
Esempio n. 16
0
// 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
}
Esempio n. 17
0
// ApproxTimes computes approximate UT rise, transit and set times for
// a celestial object on a day of interest.
//
// The function argurments do not actually include the day, but do include
// values computed from the day.
//
//	p is geographic coordinates of observer.
//	h0 is "standard altitude" of the body.
//	Th0 is apparent sidereal time at 0h UT at Greenwich.
//	α, δ are right ascension and declination of the body.
//
// Th0 must be the time on the day of interest.
// See sidereal.Apparent0UT.
//
// α, δ must be values at 0h dynamical time for the day of interest.
func ApproxTimes(p globe.Coord, h0 unit.Angle, Th0 unit.Time, α unit.RA, δ unit.Angle) (tRise, tTransit, tSet unit.Time, err error) {
	// approximate local hour angle
	sLat, cLat := p.Lat.Sincos()
	sδ1, cδ1 := δ.Sincos()
	cH0 := (h0.Sin() - sLat*sδ1) / (cLat * cδ1) // (15.1) p. 102
	if cH0 < -1 || cH0 > 1 {
		err = ErrorCircumpolar
		return
	}
	H0 := unit.TimeFromRad(math.Acos(cH0))

	// approximate transit, rise, set times.
	// (15.2) p. 102.
	mt := unit.TimeFromRad(α.Rad()+p.Lon.Rad()) - Th0
	tTransit = mt.Mod1()
	tRise = (mt - H0).Mod1()
	tSet = (mt + H0).Mod1()
	return
}
Esempio n. 18
0
// Angle returns the angle between great circles defined by three points.
//
// Coordinates may be right ascensions and declinations or longitudes and
// latitudes.  If r1, d1, r2, d2 defines one line and r2, d2, r3, d3 defines
// another, the result is the angle between the two lines.
//
// Algorithm by Meeus.
func Angle(r1, d1, r2, d2, r3, d3 unit.Angle) unit.Angle {
	sd2, cd2 := d2.Sincos()
	sr21, cr21 := (r2 - r1).Sincos()
	sr32, cr32 := (r3 - r2).Sincos()
	C1 := math.Atan2(sr21, cd2*d1.Tan()-sd2*cr21)
	C2 := math.Atan2(sr32, cd2*d3.Tan()-sd2*cr32)
	return unit.Angle(C1 + C2)
}
Esempio n. 19
0
// Kepler3 solves Kepler's equation by binary search.
//
// Argument e is eccentricity, M is mean anomaly.
//
// Result E is eccentric anomaly.
func Kepler3(e float64, M unit.Angle) (E unit.Angle) {
	// adapted from BASIC, p. 206
	MR := M.Mod1().Rad()
	f := 1
	if MR > math.Pi {
		f = -1
		MR = 2*math.Pi - MR
	}
	E0 := math.Pi * .5
	d := math.Pi * .25
	for i := 0; i < 53; i++ {
		M1 := E0 - e*math.Sin(E0)
		if MR-M1 < 0 {
			E0 -= d
		} else {
			E0 += d
		}
		d *= .5
	}
	if f < 0 {
		E0 = -E0
	}
	return unit.Angle(E0)
}
Esempio n. 20
0
// General computes data for the general case of a planar sundial.
//
// Argument φ is geographic latitude at which the sundial will be located.
// D is gnomonic declination, the azimuth of the perpendicular to the plane
// of the sundial, measured from the southern meridian towards the west.
// Argument a is the length of a straight stylus perpendicular to the plane
// of the sundial, z is zenithal distance of the direction defined by the
// stylus.  Units of stylus length a are arbitrary.
//
// Results consist of a set of lines, a center point, u, the length of a
// polar stylus, and ψ, the angle which the polar stylus makes with the plane
// of the sundial.  The center point, the points defining the hour lines, and
// u are in units of a, the stylus length.
func General(φ, D unit.Angle, a float64, z unit.Angle) (lines []Line, center Point, u float64, ψ unit.Angle) {
	sφ, cφ := φ.Sincos()
	tφ := sφ / cφ
	sD, cD := D.Sincos()
	sz, cz := z.Sincos()
	P := sφ*cz - cφ*sz*cD
	for i := 0; i < 24; i++ {
		l := Line{Hour: i}
		H := float64(i-12) * 15 * math.Pi / 180
		aH := math.Abs(H)
		sH, cH := math.Sincos(H)
		for _, d := range m {
			tδ := math.Tan(d * math.Pi / 180)
			H0 := math.Acos(-tφ * tδ)
			if aH > H0 {
				continue // sun below horizon
			}
			Q := sD*sz*sH + (cφ*cz+sφ*sz*cD)*cH + P*tδ
			if Q < 0 {
				continue // sun below plane of sundial
			}
			Nx := cD*sH - sD*(sφ*cH-cφ*tδ)
			Ny := cz*sD*sH - (cφ*sz-sφ*cz*cD)*cH - (sφ*sz+cφ*cz*cD)*tδ
			l.Points = append(l.Points, Point{a * Nx / Q, a * Ny / Q})
		}
		if len(l.Points) > 0 {
			lines = append(lines, l)
		}
	}
	center.X = a / P * cφ * sD
	center.Y = -a / P * (sφ*sz + cφ*cz*cD)
	aP := math.Abs(P)
	u = a / aP
	ψ = unit.Angle(math.Asin(aP))
	return
}
Esempio n. 21
0
// 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
}
Esempio n. 22
0
// Physical computes quantities for physical observations of Jupiter.
//
// Results:
//	DS  Planetocentric declination of the Sun.
//	DE  Planetocentric declination of the Earth.
//	ω1  Longitude of the System I central meridian of the illuminated disk,
//	    as seen from Earth.
//	ω2  Longitude of the System II central meridian of the illuminated disk,
//	    as seen from Earth.
//	P   Geocentric position angle of Jupiter's northern rotation pole.
func Physical(jde float64, earth, jupiter *pp.V87Planet) (DS, DE, ω1, ω2, P unit.Angle) {
	// Step 1.
	d := jde - 2433282.5
	T1 := d / base.JulianCentury
	const p = math.Pi / 180
	α0 := 268*p + .1061*p*T1
	δ0 := 64.5*p - .0164*p*T1
	// Step 2.
	W1 := 17.71*p + 877.90003539*p*d
	W2 := 16.838*p + 870.27003539*p*d
	// Step 3.
	l0, b0, R := earth.Position(jde)
	l0, b0 = pp.ToFK5(l0, b0, jde)
	// Steps 4-7.
	sl0, cl0 := l0.Sincos()
	sb0 := b0.Sin()
	Δ := 4. // surely better than 0.
	var l, b unit.Angle
	var r, x, y, z float64
	f := func() {
		τ := base.LightTime(Δ)
		l, b, r = jupiter.Position(jde - τ)
		l, b = pp.ToFK5(l, b, jde)
		sb, cb := b.Sincos()
		sl, cl := l.Sincos()
		// (42.2) p. 289
		x = r*cb*cl - R*cl0
		y = r*cb*sl - R*sl0
		z = r*sb - R*sb0
		// (42.3) p. 289
		Δ = math.Sqrt(x*x + y*y + z*z)
	}
	f()
	f()
	// Step 8.
	ε0 := nutation.MeanObliquity(jde)
	// Step 9.
	sε0, cε0 := ε0.Sincos()
	sl, cl := l.Sincos()
	sb, cb := b.Sincos()
	αs := math.Atan2(cε0*sl-sε0*sb/cb, cl)
	δs := math.Asin(cε0*sb + sε0*cb*sl)
	// Step 10.
	sδs, cδs := math.Sincos(δs)
	sδ0, cδ0 := math.Sincos(δ0)
	DS = unit.Angle(math.Asin(-sδ0*sδs - cδ0*cδs*math.Cos(α0-αs)))
	// Step 11.
	u := y*cε0 - z*sε0
	v := y*sε0 + z*cε0
	α := math.Atan2(u, x)
	δ := math.Atan(v / math.Hypot(x, u))
	sδ, cδ := math.Sincos(δ)
	sα0α, cα0α := math.Sincos(α0 - α)
	ζ := math.Atan2(sδ0*cδ*cα0α-sδ*cδ0, cδ*sα0α)
	// Step 12.
	DE = unit.Angle(math.Asin(-sδ0*sδ - cδ0*cδ*math.Cos(α0-α)))
	// Step 13.
	ω1 = unit.Angle(W1 - ζ - 5.07033*p*Δ)
	ω2 = unit.Angle(W2 - ζ - 5.02626*p*Δ)
	// Step 14.
	C := unit.Angle((2*r*Δ + R*R - r*r - Δ*Δ) / (4 * r * Δ))
	if (l - l0).Sin() < 0 {
		C = -C
	}
	ω1 = (ω1 + C).Mod1()
	ω2 = (ω2 + C).Mod1()
	// Step 15.
	Δψ, Δε := nutation.Nutation(jde)
	ε := ε0 + Δε
	// Step 16.
	sε, cε := ε.Sincos()
	sα, cα := math.Sincos(α)
	α += .005693 * p * (cα*cl0*cε + sα*sl0) / cδ
	δ += .005693 * p * (cl0*cε*(sε/cε*cδ-sα*sδ) + cα*sδ*sl0)
	// Step 17.
	tδ := sδ / cδ
	Δα := (cε+sε*sα*tδ)*Δψ.Rad() - cα*tδ*Δε.Rad()
	Δδ := sε*cα*Δψ.Rad() + sα*Δε.Rad()
	αʹ := α + Δα
	δʹ := δ + Δδ
	sα0, cα0 := math.Sincos(α0)
	tδ0 := sδ0 / cδ0
	Δα0 := (cε+sε*sα0*tδ0)*Δψ.Rad() - cα0*tδ0*Δε.Rad()
	Δδ0 := sε*cα0*Δψ.Rad() + sα0*Δε.Rad()
	α0ʹ := α0 + Δα0
	δ0ʹ := δ0 + Δδ0
	// Step 18.
	sδʹ, cδʹ := math.Sincos(δʹ)
	sδ0ʹ, cδ0ʹ := math.Sincos(δ0ʹ)
	sα0ʹαʹ, cα0ʹαʹ := math.Sincos(α0ʹ - αʹ)
	// (42.4) p. 290
	P = unit.Angle(math.Atan2(cδ0ʹ*sα0ʹαʹ, sδ0ʹ*cδʹ-cδ0ʹ*sδʹ*cα0ʹαʹ))
	if P < 0 {
		P += 2 * math.Pi
	}
	return
}
Esempio n. 23
0
// 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
}
Esempio n. 24
0
// SunAltitude returns altitude of the Sun above the lunar horizon.
//
// Arguments η, θ are selenographic longitude and latitude of a site on the
// Moon, l0, b0 are selenographic coordinates of the Sun, as returned by
// Physical(), for example.
func SunAltitude(η, θ, l0, b0 unit.Angle) unit.Angle {
	c0 := math.Pi/2 - l0
	sb0, cb0 := b0.Sincos()
	sθ, cθ := θ.Sincos()
	return unit.Angle(math.Asin(sb0*sθ + cb0*cθ*(c0+η).Sin()))
}
Esempio n. 25
0
// 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())
}
Esempio n. 26
0
// True returns true anomaly ν for given eccentric anomaly E.
//
// Argument e is eccentricity.  E must be in radians.
func True(E unit.Angle, e float64) unit.Angle {
	// (30.1) p. 195
	return unit.Angle(2 * math.Atan(math.Sqrt((1+e)/(1-e))*E.Mul(.5).Tan()))
}
Esempio n. 27
0
// Kepler4 returns an approximate solution to Kepler's equation.
//
// It is valid only for small values of e.
//
// Argument e is eccentricity, M is mean anomaly.
//
// Result E is eccentric anomaly.
func Kepler4(e float64, M unit.Angle) (E unit.Angle) {
	sm, cm := M.Sincos()
	return unit.Angle(math.Atan2(sm, cm-e)) // (30.8) p. 206
}
Esempio n. 28
0
// 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))))
}
Esempio n. 29
0
// 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())
}
Esempio n. 30
0
// RelativePosition returns the position angle of one body with respect to
// another.
//
// The position angle result is measured counter-clockwise from North.
func RelativePosition(r1, d1, r2, d2 unit.Angle) unit.Angle {
	sΔr, cΔr := (r2 - r1).Sincos()
	sd2, cd2 := d2.Sincos()
	return unit.Angle(math.Atan2(sΔr, cd2*d1.Tan()-sd2*cΔr))
}