-
Notifications
You must be signed in to change notification settings - Fork 73
/
Copy pathhorizon.cs
155 lines (134 loc) · 5.92 KB
/
horizon.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
using System;
using CosineKitty;
using demo_helper;
namespace horizon
{
class Program
{
static int Main(string[] args)
{
Observer observer;
AstroTime time;
DemoHelper.ParseArgs("horizon", args, out observer, out time);
return FindEclipticCrossings(observer, time);
}
static int HorizontalCoords(
out Spherical hor,
double ecliptic_longitude,
AstroTime time,
RotationMatrix rot_ecl_hor)
{
var eclip = new Spherical(
0.0, /* being "on the ecliptic plane" means ecliptic latitude is zero. */
ecliptic_longitude,
1.0 /* any positive distance value will work fine. */
);
/* Convert ecliptic angular coordinates to ecliptic vector. */
AstroVector ecl_vec = Astronomy.VectorFromSphere(eclip, time);
/* Use the rotation matrix to convert ecliptic vector to horizontal vector. */
AstroVector hor_vec = Astronomy.RotateVector(rot_ecl_hor, ecl_vec);
/* Find horizontal angular coordinates, correcting for atmospheric refraction. */
hor = Astronomy.HorizonFromVector(hor_vec, Refraction.Normal);
return 0; /* success */
}
static int Search(
out double ecliptic_longitude_crossing,
out Spherical hor_crossing,
AstroTime time,
RotationMatrix rot_ecl_hor,
double e1, double e2)
{
int error;
double e3;
Spherical h3;
const double tolerance = 1.0e-6; /* one-millionth of a degree is close enough! */
/*
Binary search: find the ecliptic longitude such that the horizontal altitude
ascends through a zero value. The caller must pass e1, e2 such that the altitudes
bound zero in ascending order.
*/
ecliptic_longitude_crossing = 1.0e+99; // initialize with impossible value
hor_crossing = new Spherical();
for(;;)
{
e3 = (e1 + e2) / 2.0;
error = HorizontalCoords(out h3, e3, time, rot_ecl_hor);
if (error != 0)
return error;
if (Math.Abs(e2-e1) < tolerance)
{
/* We have found the horizon crossing within tolerable limits. */
ecliptic_longitude_crossing = e3;
hor_crossing = h3;
return 0;
}
if (h3.lat < 0.0)
e1 = e3;
else
e2 = e3;
}
}
const int NUM_SAMPLES = 4;
static double ECLIPLON(int i) => ((360.0 * i) / NUM_SAMPLES);
static int FindEclipticCrossings(Observer observer, AstroTime time)
{
int i;
var hor = new Spherical[NUM_SAMPLES];
/*
The ecliptic is a celestial circle that describes the mean plane of
the Earth's orbit around the Sun. We use J2000 ecliptic coordinates,
meaning the x-axis is defined to where the plane of the Earth's
equator on January 1, 2000 at noon UTC intersects the ecliptic plane.
The positive x-axis points toward the March equinox.
Calculate a rotation matrix that converts J2000 ecliptic vectors
to horizontal vectors for this observer and time.
*/
RotationMatrix rot = Astronomy.Rotation_ECL_HOR(time, observer);
/*
Sample several points around the ecliptic.
Remember the horizontal coordinates for each sample.
*/
for (i=0; i<NUM_SAMPLES; ++i)
if (0 != HorizontalCoords(out hor[i], ECLIPLON(i), time, rot))
return 1; /* failure */
for (i=0; i < NUM_SAMPLES; ++i)
{
double a1 = hor[i].lat;
double a2 = hor[(i+1) % NUM_SAMPLES].lat;
double e1 = ECLIPLON(i);
double e2 = ECLIPLON(i+1);
double ex;
Spherical hx;
int error;
if (a1*a2 <= 0.0)
{
/* Looks like a horizon crossing. Is altitude going up with longitude or down? */
if (a2 > a1)
{
/* Search for the ecliptic longitude and azimuth where altitude ascends through zero. */
error = Search(out ex, out hx, time, rot, e1, e2);
}
else
{
/* Search for the ecliptic longitude and azimuth where altitude descends through zero. */
error = Search(out ex, out hx, time, rot, e2, e1);
}
if (error != 0)
return error;
string direction;
if (hx.lon > 0.0 && hx.lon < 180.0)
direction = "ascends "; /* azimuth is more toward the east than the west */
else
direction = "descends"; /* azimuth is more toward the west than the east */
Console.WriteLine("Ecliptic longitude {0,9:0.0000} {1} through horizon at azimuth {2,9:0.0000}", ex, direction, hx.lon);
if (Math.Abs(hx.lat) > 5.0e-7)
{
Console.Error.WriteLine("FindEclipticCrossings: Excessive altitude = {0}", hx.lat);
return 1;
}
}
}
return 0;
}
}
}