```'Astro-functions
'Keith@xylem.demon.co.uk
'http://www.xylem.demon.co.uk/kepler/

'This text file contains the current set of User defined functions
'for Microsoft Excel 5, 95 and 97 versions. The functions are written
'in Visual Basic for Applications, and may be useable from other
'Office97 applications.

'RA and time UT and all angles measured in degrees, all instants
'defined by the decimal fraction of days after J2000.0

'Value of daily change in Pluto's Longitude corrected 19990227

Public Const pi As Double = 3.14159265358979
Public Const tpi As Double = 6.28318530717958
Public Const degs  As Double = 57.2957795130823
Public Const rads As Double = 1.74532925199433E-02

' Trig functions working in degrees
Function DegSin(x As Double) As Double
End Function

Function DegCos(x As Double) As Double
End Function

Function DegTan(x As Double) As Double
End Function

Function DegArcsin(x As Double) As Double
DegArcsin = degs * Application.Asin(x)
End Function

Function DegArccos(x As Double) As Double
DegArccos = degs * Application.Acos(x)
End Function

Function DegArctan(x As Double) As Double
DegArctan = degs * Atn(x)
End Function

' modified arctan function - returns tangent in right quadrant
Function DegAtan2(y As Double, x As Double) As Double
DegAtan2 = degs * Application.Atan2(x, y)
If DegAtan2 < 0 Then DegAtan2 = DegAtan2 + 360
End Function

' functions below return argument in range 0 to 2 pi or 0 to 360
Private Function range2pi(x)
range2pi = x - tpi * Int(x / tpi)
End Function

Private Function range360(x)
range360 = x - 360 * Int(x / 360)
End Function

' converts degs min sec to decimal deg
Function degdecimal(d, m, s)
degdecimal = d + m / 60 + s / 3600
End Function

' returns Julian day number, greg is switch for Gregorian
' or Julian calendars. Default is gregorian.
Function jday(year As Integer, month As Integer, day As Integer, _
hour As Integer, min As Integer, sec As Double, Optional greg) _
As Double
Dim a As Double
Dim b As Integer
a = 10000# * year + 100# * month + day
If (a < -47120101) Then
MsgBox "Warning: date too early for algorithm"
End If
If (IsMissing(greg)) Then greg = 1
If (month <= 2) Then
month = month + 12
year = year - 1
End If
If (greg = 0) Then
b = -2 + Fix((year + 4716) / 4) - 1179
Else
b = Fix(year / 400) - Fix(year / 100) + Fix(year / 4)
End If
a = 365# * year + 1720996.5
jday = a + b + Fix(30.6001 * (month + 1))
jday = jday + day + (hour + min / 60 + sec / 3600) / 24
End Function

' Returns days after J2000, greg switch for Gregorian or
' Julian calendar - default is Gregorian.
Function day2000(year As Integer, month As Integer, day As Integer, _
hour As Integer, min As Integer, sec As Double, Optional greg) _
As Double
Dim a As Double
Dim b As Integer
If (IsMissing(greg)) Then greg = 1
a = 10000# * year + 100# * month + day
If (month <= 2) Then
month = month + 12
year = year - 1
End If
If (greg = 0) Then
b = -2 + Fix((year + 4716) / 4) - 1179
Else
b = Fix(year / 400) - Fix(year / 100) + Fix(year / 4)
End If
a = 365# * year - 730548.5
day2000 = a + b + Fix(30.6001 * (month + 1))
day2000 = day2000 + day + (hour + min / 60 + sec / 3600) / 24
End Function

' Given polar coords, returns cartesian coords
' r is radius vector, theta is declination like angle, phi is
' RA like angle. Index = 1 returns x coord and so on
Function rectangular(r As Double, theta As Double, phi As Double, _
index As Integer) As Double
Dim r_cos_theta As Double
r_cos_theta = r * DegCos(theta)
Select Case index
Case 1
rectangular = r_cos_theta * DegCos(phi) 'returns x coord
Case 2
rectangular = r_cos_theta * DegSin(phi) 'returns y coord
Case 3
rectangular = r * DegSin(theta)         'returns z coord
End Select
End Function

' given cartesian coords, returns distance
Function rlength(x As Double, y As Double, z As Double) As Double
rlength = Sqr(x * x + y * y + z * z)
End Function

' returns spherical coord given cartesian coords
Function spherical(x As Double, y As Double, z As Double, _
index As Integer) As Double
Dim rho As Double
rho = x * x + y * y
Select Case index
Case 1
spherical = Sqr(rho + z * z)    'returns r
Case 2
rho = Sqr(rho)
spherical = DegArctan(z / rho)    'returns theta
Case 3
rho = Sqr(rho)
spherical = DegAtan2(y, x)      'returns phi
End Select
End Function

' returns obliquity of equator given date in days after J2000.0
Function obliquity(d As Double) As Double
Dim t As Double
t = d / 36525   'julian centuries since J2000.0
obliquity = -(46.815 + (0.00059 - 0.001813 * t) * t) * t / 3600#
obliquity = obliquity + 23.43929111
End Function

' given geocentric ecliptic coordinates, returns geocentric
' equatorial coordinates - all cartesian. NB, d is epoch of
' frame, use d = 0 if working in J2000.0 frame
Function requatorial(x As Double, y As Double, z As Double, _
d As Double, index As Integer) As Double
Dim obl As Double
obl = obliquity(d)
Select Case index
Case 1
requatorial = x
Case 2
requatorial = y * DegCos(obl) - z * DegSin(obl)
Case 3
requatorial = y * DegSin(obl) + z * DegCos(obl)
End Select
End Function

' given geocentric equatorial coords, returns geocentric
' ecliptic coords - all cartesian. NB, d is epoch of
' frame, use d = 0 if working in J2000.0 frame
Function recliptic(x As Double, y As Double, z As Double, _
d As Double, index As Integer) As Double
Dim obl As Double
obl = obliquity(d)
Select Case index
Case 1
recliptic = x
Case 2
recliptic = y * DegCos(obl) + z * DegSin(obl)
Case 3
recliptic = -y * DegSin(obl) + z * DegCos(obl)
End Select
End Function

' returns equatorial coords given geocentric ecliptic coords
Function sequatorial(r As Double, theta As Double, phi As Double, _
d As Double, index As Integer) As Double
Dim x As Double, y As Double, z As Double
x = rectangular(r, theta, phi, 1)
y = rectangular(r, theta, phi, 2)
z = rectangular(r, theta, phi, 3)
sequatorial = spherical(requatorial(x, y, z, d, 1), _
requatorial(x, y, z, d, 2), _
requatorial(x, y, z, d, 3), index)
End Function

' returns ecliptic coords given geocentric equatorial coords
Function secliptic(r As Double, theta As Double, phi As Double, _
d As Double, index As Integer) As Double
Dim x As Double, y As Double, z As Double
x = rectangular(r, theta, phi, 1)
y = rectangular(r, theta, phi, 2)
z = rectangular(r, theta, phi, 3)
secliptic = spherical(recliptic(x, y, z, d, 1), _
recliptic(x, y, z, d, 2), _
recliptic(x, y, z, d, 3), index)
End Function

' approximate presession from one epoch d2 to another d1
Function precess(d1 As Double, d2 As Double, dec As Double, _
ra As Double, index As Integer, _
Optional ddec, Optional dra) As Double
Dim m As Double, n As Double, t As Double
If (IsMissing(dra)) Then dra = 0
If (IsMissing(ddec)) Then ddec = 0
t = d1 / 36525          'years since J2000
m = 0.01281233333333 + 0.00000775 * t
n = 0.005567527777778 - 2.361111111111E-06 * t
t = (d2 - d1) / 365.25
Select Case index
Case 1      'dec
precess = dec + (n * DegCos(ra) + ddec / 3600) * t
Case 2      'ra
precess = ra + (m + n * DegSin(ra) * DegTan(dec) + dra / 3600) * t
End Select
End Function

' returns ecliptic longitude and distance of Sun given
' days after J2000.0. Based on method in AA
Function ssun(d As Double, index As Integer) As Double
Dim G As Double
Dim L As Double
Dim lambda As Double
G = range360(357.528 + 0.9856003 * d)
L = range360(280.461 + 0.9856474 * d)
Select Case index
Case 1
ssun = 1.00014 - 0.01671 * DegCos(G) - 0.00014 * DegCos(2 * G)
Case 2
ssun = 0    'ecliptic latitude of Sun is zero
Case 3
ssun = range360(L + 1.915 * DegSin(G) + 0.02 * DegSin(2 * G))
Case 4  'equation of time
lambda = range360(L + 1.915 * DegSin(G) + 0.02 * DegSin(2 * G))
ssun = -1.915 * DegSin(G) - 0.02 * DegSin(2 * G)
ssun = ssun + 2.466 * DegSin(2 * lambda)
ssun = ssun - 0.053 * DegSin(4 * lambda)
End Select
End Function

' caretsian version of above
Function rsun(d As Double, index As Integer) As Double
Dim x As Double
Dim y As Double
Dim z As Double
rsun = rectangular(ssun(d, 1), ssun(d, 2), ssun(d, 3), index)
End Function

Function sun(d As Double, index As Integer) As Double
sun = sequatorial(ssun(d, 1), ssun(d, 2), ssun(d, 3), d, index)
End Function

' returns ecliptic longitide, latitude and distance of Moon
' (geocentric) given days after J2000.0
Function smoon(ByVal d As Double, index As Integer) As Double
Dim Nm As Double, im As Double, wm As Double, _
am As Double, ecm As Double, _
Mm As Double, em As Double, Ms As Double, _
ws As Double, xv As Double, _
yv As Double, vm As Double, rm As Double, x As Double, _
y As Double, z As Double, lon As Double, lat As Double, _
ls As Double, lm As Double, _
dm As Double, F As Double, dlong As Double, dlat As Double
d = d + 1.5     'epoch of theory is not same as J2000.0
Nm = range360(125.1228 - 0.0529538083 * d) * rads
wm = range360(318.0634 + 0.1643573223 * d) * rads
ecm = 0.0549
Mm = range360(115.3654 + 13.0649929509 * d) * rads
em = Mm + ecm * Sin(Mm) * (1# + ecm * Cos(Mm))
xv = am * (Cos(em) - ecm)
yv = am * (Sqr(1# - ecm * ecm) * Sin(em))
vm = Application.Atan2(xv, yv)
rm = Sqr(xv * xv + yv * yv)
x = Cos(Nm) * Cos(vm + wm) - Sin(Nm) * Sin(vm + wm) * Cos(im)
x = rm * x
y = Sin(Nm) * Cos(vm + wm) + Cos(Nm) * Sin(vm + wm) * Cos(im)
y = rm * y
z = rm * (Sin(vm + wm) * Sin(im))
lon = Application.Atan2(x, y)
If lon < 0 Then lon = tpi + lon
lat = Atn(z / Sqr(x * x + y * y))
ws = range360(282.9404 + 0.0000470935 * d) * rads
Ms = range360(356.047 + 0.9856002585 * d) * rads
ls = Ms + ws       'Mean Longitude of the Sun  (Ns=0)
lm = Mm + wm + Nm  'Mean longitude of the Moon
dm = lm - ls        'Mean elongation of the Moon
F = lm - Nm        'Argument of latitude for the Moon
Select Case index
Case 1  '   distance terms earth radii
rm = rm - 0.58 * Cos(Mm - 2 * dm)
rm = rm - 0.46 * Cos(2 * dm)
smoon = rm
Case 2  '   latitude terms
dlat = -0.173 * Sin(F - 2 * dm)
dlat = dlat - 0.055 * Sin(Mm - F - 2 * dm)
dlat = dlat - 0.046 * Sin(Mm + F - 2 * dm)
dlat = dlat + 0.033 * Sin(F + 2 * dm)
dlat = dlat + 0.017 * Sin(2 * Mm + F)
smoon = lat * degs + dlat
Case 3  '   longitude terms
dlon = -1.274 * Sin(Mm - 2 * dm)        '(the Evection)
dlon = dlon + 0.658 * Sin(2 * dm)       '(the Variation)
dlon = dlon - 0.186 * Sin(Ms)     '(the Yearly Equation)
dlon = dlon - 0.059 * Sin(2 * Mm - 2 * dm)
dlon = dlon - 0.057 * Sin(Mm - 2 * dm + Ms)
dlon = dlon + 0.053 * Sin(Mm + 2 * dm)
dlon = dlon + 0.046 * Sin(2 * dm - Ms)
dlon = dlon + 0.041 * Sin(Mm - Ms)
dlon = dlon - 0.035 * Sin(dm) '(the Parallactic Equation)
dlon = dlon - 0.031 * Sin(Mm + Ms)
dlon = dlon - 0.015 * Sin(2 * F - 2 * dm)
dlon = dlon + 0.011 * Sin(Mm - 4 * dm)
smoon = lon * degs + dlon
End Select
End Function

' rectangular version of above
Function rmoon(d As Double, index As Integer) As Double
rmoon = rectangular(smoon(d, 1), smoon(d, 2), smoon(d, 3), index)
End Function

' returns spherical equatorial coords of moon given days
' after J2000.0
Function moon(d As Double, index As Integer) As Double
Dim nigel As Double
If index = 4 Then
nigel = smoon(d, 2)
moon = d
Else
moon = sequatorial(smoon(d, 1), smoon(d, 2), smoon(d, 3), d, index)
End If
End Function

' returns true anomaly given eccentricity of orbit, mean anomaly
' and optional precision parameter. Default precision is 10^-8 rads
Function kepler(m As Double, ecc As Double, Optional eps) As Double
Dim delta As Double, E As Double, v As Double
E = m               'first guess
delta = 0.05        'set delta equal to a dummy value
If (IsMissing(eps)) Then eps = 8 'if no eps then assume 10^-8
Do While Abs(delta) >= 10 ^ -eps           'converged?
delta = E - ecc * Sin(E) - m           'new error
E = E - delta / (1 - ecc * Cos(E))     'corrected guess
Loop
v = 2 * Atn(((1 + ecc) / (1 - ecc)) ^ 0.5 * Tan(0.5 * E))
If v < 0 Then v = v + tpi
kepler = v
End Function

' returns heliocentric rectangular coords of planet
' given days after J2000.o and planet number
Function rplanet(d As Double, pnumber As Integer, _
index As Integer) As Double
Dim x As Double, y As Double, z As Double, v As Double, _
m As Double, i As Double, o As Double, p As Double, _
a As Double, E As Double, _
L As Double, r As Double
element i, o, p, a, E, L, d, pnumber 'calls the sub element
m = range2pi(L - p)
v = kepler(m, E, 8)
r = a * (1 - E * E) / (1 + E * Cos(v))
Select Case index
Case 1      'x coordinate
rplanet = Cos(o) * Cos(v + p - o) - Sin(o) * Sin(v + p - o) * Cos(i)
rplanet = rplanet * r
Case 2      'y coordinate
rplanet = Sin(o) * Cos(v + p - o) + Cos(o) * Sin(v + p - o) * Cos(i)
rplanet = rplanet * r
Case 3      'z coordinate
rplanet = r * (Sin(v + p - o) * Sin(i))
End Select
End Function

' gives equatorial spherical coords of planet given
' days after J2000.0 and planet number. Refeered to
' equinox of date
Function planet(d As Double, pnumber As Integer, _
index As Integer) As Double
Dim x As Double, y As Double, z As Double, v As Double, _
m As Double, i As Double, o As Double, p As Double, _
a As Double, E As Double, L As Double, r As Double, _
xe As Double, ye As Double, ze As Double, s1 As Double, _
si As Double, so As Double, c1 As Double, ci As Double, _
co As Double
element i, o, p, a, E, L, d, pnumber
m = range2pi(L - p)
v = kepler(m, E, 8)
r = a * (1 - E * E) / (1 + E * Cos(v))
s1 = Sin(v + p - o)
si = Sin(i)
so = Sin(o)
c1 = Cos(v + p - o)
ci = Cos(i)
co = Cos(o)
x = r * (co * c1 - so * s1 * ci)
y = r * (so * c1 + co * s1 * ci)
z = r * (s1 * si)
element i, o, p, a, E, L, d, 3
m = range2pi(L - p)
v = kepler(m, E, 8)
r = a * (1 - E * E) / (1 + E * Cos(v))
s1 = Sin(v + p - o)
si = Sin(i)
so = Sin(o)
c1 = Cos(v + p - o)
ci = Cos(i)
co = Cos(o)
xe = r * (co * c1 - so * s1 * ci)
ye = r * (so * c1 + co * s1 * ci)
ze = r * (s1 * si)
x = x - xe
y = y - ye
ecl = 23.429292 * rads      'value for J2000.0 frame
xe = x
ye = y * Cos(ecl) - z * Sin(ecl)
ze = y * Sin(ecl) + z * Cos(ecl)
Select Case index
Case 3
planet = Application.Atan2(xe, ye) * degs
If planet < 0 Then planet = 360 + planet
Case 2
planet = Atn(ze / Sqr(xe * xe + ye * ye)) * degs
Case 1
planet = Sqr(xe * xe + ye * ye + ze * ze)
End Select
End Function

' not accesible as user defined function
' returns elements of orbits of planets given days after
' J2000.0 and planet number
Sub element(i As Double, o As Double, p As Double, _
a As Double, E As Double, L As Double, _
ByVal d As Double, ByVal pnum As Integer)
Select Case pnum
Case 1          'mercury
i = (7.00487 - 0.000000178797 * d) * rads
o = (48.33167 - 0.0000033942 * d) * rads
p = (77.45645 + 0.00000436208 * d) * rads
a = 0.38709893 + 1.80698E-11 * d
E = 0.20563069 + 0.000000000691855 * d
L = range2pi(rads * (252.25084 + 4.092338796 * d))
Case 2          'venus
i = (3.39471 - 0.0000000217507 * d) * rads
o = (76.68069 - 0.0000075815 * d) * rads
p = (131.53298 - 0.000000827439 * d) * rads
a = 0.72333199 + 2.51882E-11 * d
E = 0.00677323 - 0.00000000135195 * d
L = range2pi(rads * (181.97973 + 1.602130474 * d))
Case 3          'earth
i = (0.00005 - 0.000000356985 * d) * rads
o = (-11.26064 - 0.00013863 * d) * rads
p = (102.94719 + 0.00000911309 * d) * rads
a = 1.00000011 - 1.36893E-12 * d
E = 0.01671022 - 0.00000000104148 * d
L = range2pi(rads * (100.46435 + 0.985609101 * d))
Case 4          'mars
i = (1.85061 - 0.000000193703 * d) * rads
o = (49.57854 - 0.0000077587 * d) * rads
p = (336.04084 + 0.00001187 * d) * rads
a = 1.52366231 - 0.000000001977 * d
E = 0.09341233 - 0.00000000325859 * d
L = range2pi(rads * (355.45332 + 0.524033035 * d))
Case 5          'jupiter
i = (1.3053 - 0.0000000315613 * d) * rads
o = (100.55615 + 0.00000925675 * d) * rads
p = (14.75385 + 0.00000638779 * d) * rads
a = 5.20336301 + 0.0000000166289 * d
E = 0.04839266 - 0.00000000352635 * d
L = range2pi(rads * (34.40438 + 0.083086762 * d))
Case 6          'saturn
i = (2.48446 + 0.0000000464674 * d) * rads
o = (113.71504 - 0.0000121 * d) * rads
p = (92.43194 - 0.0000148216 * d) * rads
a = 9.53707032 - 0.0000000825544 * d
E = 0.0541506 - 0.0000000100649 * d
L = range2pi(rads * (49.94432 + 0.033470629 * d))
Case 7          'uranus
i = (0.76986 - 0.0000000158947 * d) * rads
o = (74.22988 + 0.0000127873 * d) * rads
p = (170.96424 + 0.0000099822 * d) * rads
a = 19.19126393 + 0.0000000416222 * d
E = 0.04716771 - 0.00000000524298 * d
L = range2pi(rads * (313.23218 + 0.011731294 * d))
Case 8          'neptune
i = (1.76917 - 0.0000000276827 * d) * rads
o = (131.72169 - 0.0000011503 * d) * rads
p = (44.97135 - 0.00000642201 * d) * rads
a = 30.06896348 - 0.0000000342768 * d
E = 0.00858587 + 0.000000000688296 * d
L = range2pi(rads * (304.88003 + 0.0059810572 * d))
Case 9          'pluto
i = (17.14175 + 0.0000000841889 * d) * rads
o = (110.30347 - 0.0000002839 * d) * rads
p = (224.06676 - 0.00000100578 * d) * rads
a = 39.48168677 - 0.0000000210574 * d
E = 0.24880766 + 0.00000000177002 * d
L = range2pi(rads * (238.92881 + 3.97557152635181E-03 * d))
End Select
End Sub

' returns time of sunrise/set or twilights as angles
' given days after J2000.0, longitude and latitude of observer
' and an optional altitude required for the Sun. default altitude
' corresponds to upper limb on mathematical horizon
Function Sunrise(ByVal day As Double, _
glat As Double, glong As Double, index As Integer, _
Optional altitude) As Double
Dim sinalt As Double, gha As Double, lambda As Double, _
delta As Double, t As Double, c As Double, days As Double, _
utold As Double, utnew As Double, sinphi As Double, _
cosphi As Double, L As Double, G As Double, E As Double, _
obl As Double, signt As Double, act As Double
If (IsMissing(altitude)) Then altitude = -0.833
utold = 180
utnew = 0
sinphi = DegSin(glat)
cosphi = DegCos(glat)
If index = 1 Then signt = 1 Else signt = -1
Do While Abs(utold - utnew) > 0.1
utold = utnew   'carry forward the iteration
days = day + utold / 360
t = days / 36525
L = range360(280.46 + 36000.77 * t)
G = 357.528 + 35999.05 * t
lambda = L + 1.915 * DegSin(G) + 0.02 * DegSin(2 * G)
E = -1.915 * DegSin(G) - 0.02 * DegSin(2 * G) _
+ 2.466 * DegSin(2 * lambda) - 0.053 * DegSin(4 * lambda)
obl = 23.4393 - 0.13 * t
gha = utold - 180 + E
delta = DegArcsin(DegSin(obl) * DegSin(lambda))
c = (sinalt - sinphi * DegSin(delta)) / (cosphi * DegCos(delta))
act = DegArccos(c)
If c > 1 Then act = 0
If c < -1 Then act = 180
utnew = range360(utold - (gha + glong + signt * act))
Loop
Sunrise = utnew
End Function

' returns topocentric coords of moon given days after J2000.0
' observer's latitude and longitude.
Function tmoon(days As Double, glat As Double, _
glong As Double, index As Integer) As Double
Dim x As Double, y As Double, z As Double, xt As Double, _
yt As Double, zt As Double, r As Double, xe As Double, _
ye As Double, ze As Double, lst As Double
x = rmoon(days, 1)
y = rmoon(days, 2)
z = rmoon(days, 3)
xe = requatorial(x, y, z, days, 1)
ye = requatorial(x, y, z, days, 2)
ze = requatorial(x, y, z, days, 3)
r = rlength(x, y, z)
lst = gst(days) + glong
xt = xe - DegCos(glat) * DegCos(lst)
yt = ye - DegCos(glat) * DegSin(lst)
zt = ze - DegSin(glat)
tmoon = spherical(xt, yt, zt, index)
End Function

' returns siderial time at longitude zero given days
' after J2000.0
Function gst(days As Double) As Double
Dim t As Double
t = days / 36525
gst = 280.46061837 + 360.98564736629 * days
gst = gst + 0.000387933 * t ^ 2 - t ^ 3 / 38710000
gst = range360(gst)
End Function

' returns time of rise or set of object given RA and DEC
' of object, latitude and longitude of observer and days
' before J2000.0
Function riset(d As Double, dec As Double, ra As Double, _
glat As Double, glong As Double, index As Integer) As Double
Dim lst As Double, tau As Double
lst = gst(d) + glong
tau = DegSin(-34 / 60) - DegSin(glat) * DegSin(dec)
tau = tau / (DegCos(glat) * DegCos(dec))
tau = DegArccos(tau)
Select Case index
Case 1  'rising, degrees on day after midnight chosen
riset = range360(360 - 0.9972696 * (lst - ra + tau))
Case 2  'transit on day after or after
If ra > lst Then
riset = Abs(0.9972696 * (lst - ra))
Else
riset = 360 - 0.9972696 * (lst - ra)
End If
Case 3  'setting, degrees UT after midnight chosen
riset = range360(0.9972696 * (ra + tau - lst))
End Select
End Function

' returns altitude and azimuth of object given RA and DEC of
' object, latitude and longitude of observer and days after
' J2000.0
Function altaz(d As Double, dec As Double, ra As Double, _
glat As Double, glong As Double, index As Integer) As Double
Dim h As Double, lst As Double, a As Double, z As Double, _
sa As Double, cz As Double
h = gst(d) + glong - ra
sa = DegSin(dec) * DegSin(glat)
sa = sa + DegCos(dec) * DegCos(glat) * DegCos(h)
a = DegArcsin(sa)
cz = DegSin(dec) - DegSin(glat) * sa
cz = cz / (DegCos(glat) * DegCos(a))
Select Case index
Case 1  'altitude
altaz = a
Case 2  'azimuth
If DegSin(h) < 0 Then
altaz = DegArccos(cz)
Else
altaz = 360 - DegArccos(cz)
End If
End Select
End Function

' calculates the time of rise and set of the planets given
' days after J2000.0, planet number and longitude and latitude
' of observer
Function prise(d As Double, p As Integer, glat As Double, _
glong As Double, index As Integer) As Double
Dim lst As Double, tau As Double, ra As Double, dec As Double, _
ut0 As Double, ut1 As Double, slt As Double, clt As Double, _
flag As Integer, count As Integer
count = 0
flag = 2 - index
ut0 = 0
ut1 = 180
slt = DegSin(glat)
clt = DegCos(glat)
Do While Abs(ut0 - ut1) > 0.1 And count < 10
count = count + 1
ut0 = ut1
dec = planet(d + ut0 / 360, p, 2)
ra = planet(d + ut0 / 360, p, 3)
tau = (-0.009890037858741 - slt * DegSin(dec)) / (clt * DegCos(dec))
Select Case tau
Case Is >= 1
tau = 180
Case Is <= -1
tau = -180
Case Else
tau = DegArccos(tau)
End Select
lst = gst(d + ut0 / 360) + glong
ut1 = range360(ut0 - 0.9972696 * (lst - ra + flag * tau))
Loop
prise = ut1
End Function
```