1 |
// Upgraded to Delphi 2009: Sebastian Zierer
|
2 |
|
3 |
(* ***** BEGIN LICENSE BLOCK *****
|
4 |
* Version: MPL 1.1
|
5 |
*
|
6 |
* The contents of this file are subject to the Mozilla Public License Version
|
7 |
* 1.1 (the "License"); you may not use this file except in compliance with
|
8 |
* the License. You may obtain a copy of the License at
|
9 |
* http://www.mozilla.org/MPL/
|
10 |
*
|
11 |
* Software distributed under the License is distributed on an "AS IS" basis,
|
12 |
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
13 |
* for the specific language governing rights and limitations under the
|
14 |
* License.
|
15 |
*
|
16 |
* The Original Code is TurboPower SysTools
|
17 |
*
|
18 |
* The Initial Developer of the Original Code is
|
19 |
* TurboPower Software
|
20 |
*
|
21 |
* Portions created by the Initial Developer are Copyright (C) 1996-2002
|
22 |
* the Initial Developer. All Rights Reserved.
|
23 |
*
|
24 |
* Contributor(s):
|
25 |
*
|
26 |
* ***** END LICENSE BLOCK ***** *)
|
27 |
|
28 |
{*********************************************************}
|
29 |
{* SysTools: StEclpse.pas 4.04 *}
|
30 |
{*********************************************************}
|
31 |
{* SysTools: Lunar/Solar Eclipses *}
|
32 |
{*********************************************************}
|
33 |
|
34 |
{$I StDefine.inc}
|
35 |
|
36 |
{ ************************************************************** }
|
37 |
{ Sources: }
|
38 |
{ 1. Astronomical Algorithms, Jean Meeus, Willmann-Bell, 1991. }
|
39 |
{ }
|
40 |
{ 2. Planetary and Lunar Coordinates (1984-2000), U.S. Govt, }
|
41 |
{ 1983. }
|
42 |
{ }
|
43 |
{ 3. Supplement to the American Ephemeris and Nautical Almanac,}
|
44 |
{ U.S. Govt, 1964. }
|
45 |
{ }
|
46 |
{ 4. MPO96-98 source files, Brian D. Warner, 1995-98. }
|
47 |
{ }
|
48 |
{ ************************************************************** }
|
49 |
|
50 |
|
51 |
unit StEclpse;
|
52 |
|
53 |
interface
|
54 |
|
55 |
uses
|
56 |
{$IFDEF UseMathUnit} Math, {$ENDIF}
|
57 |
StBase, StList, StDate, StAstro, StMath;
|
58 |
|
59 |
type
|
60 |
TStEclipseType = (etLunarPenumbral, etLunarPartial, etLunarTotal,
|
61 |
etSolarPartial, etSolarAnnular, etSolarTotal,
|
62 |
etSolarAnnularTotal);
|
63 |
|
64 |
TStHemisphereType = (htNone, htNorthern, htSouthern);
|
65 |
|
66 |
TStContactTimes = packed record
|
67 |
UT1, {start of lunar penumbral phase}
|
68 |
UT2, {end of lunar penumbral phase}
|
69 |
FirstContact, {start of partial eclipse}
|
70 |
SecondContact, {start of totality}
|
71 |
MidEclipse, {mid-eclipse}
|
72 |
ThirdContact, {end of totality}
|
73 |
FourthContact : TDateTime; {end of partial phase}
|
74 |
end;
|
75 |
|
76 |
TStLongLat = packed record
|
77 |
JD : TDateTime;
|
78 |
Longitude,
|
79 |
Latitude,
|
80 |
Duration : Double;
|
81 |
end;
|
82 |
PStLongLat = ^TStLongLat;
|
83 |
|
84 |
TStEclipseRecord = packed record
|
85 |
EType : TStEclipseType; {type of Eclipse}
|
86 |
Magnitude : Double; {magnitude of eclipse}
|
87 |
Hemisphere : TStHemisphereType; {favored hemisphere - solar}
|
88 |
LContacts : TStContactTimes; {Universal Times of critical points}
|
89 |
{ in lunar eclipses}
|
90 |
Path : TStList; {longitude/latitude of moon's shadow}
|
91 |
end; { during solar eclipse}
|
92 |
PStEclipseRecord = ^TStEclipseRecord;
|
93 |
|
94 |
TStBesselianRecord = packed record
|
95 |
JD : TDateTime;
|
96 |
Delta,
|
97 |
Angle,
|
98 |
XAxis,
|
99 |
YAxis,
|
100 |
L1,
|
101 |
L2 : Double;
|
102 |
end;
|
103 |
|
104 |
TStEclipses = class(TStList)
|
105 |
{.Z+}
|
106 |
protected {private}
|
107 |
FBesselianElements : array[1..25] of TStBesselianRecord;
|
108 |
F0,
|
109 |
FUPrime,
|
110 |
FDPrime : Double;
|
111 |
|
112 |
function GetEclipse(Idx : longint) : PStEclipseRecord;
|
113 |
procedure CentralEclipseTime(JD, K, J2,
|
114 |
SunAnom, MoonAnom,
|
115 |
ArgLat, AscNode, EFac : Double;
|
116 |
var F1, A1, CentralTime : Double);
|
117 |
procedure CheckForEclipse(K : Double);
|
118 |
procedure TotalLunarEclipse(CentralJD, MoonAnom, Mu,
|
119 |
PMag, UMag, Gamma : Double);
|
120 |
procedure PartialLunarEclipse(CentralJD, MoonAnom, Mu,
|
121 |
PMag, UMag, Gamma : Double);
|
122 |
procedure PenumbralLunarEclipse(CentralJD, MoonAnom, Mu,
|
123 |
PMag, UMag, Gamma : Double);
|
124 |
|
125 |
procedure GetBesselianElements(CentralJD : Double);
|
126 |
procedure GetShadowPath(I1, I2 : Integer; Path : TStList);
|
127 |
procedure NonPartialSolarEclipse(CentralJD, Mu, Gamma : Double);
|
128 |
procedure PartialSolarEclipse(CentralJD, Mu, Gamma : Double);
|
129 |
{.Z-}
|
130 |
public
|
131 |
constructor Create(NodeClass : TStNodeClass);
|
132 |
override;
|
133 |
procedure FindEclipses(Year : integer);
|
134 |
|
135 |
property Eclipses[Idx : longint] : PStEclipseRecord
|
136 |
read GetEclipse;
|
137 |
end;
|
138 |
|
139 |
|
140 |
implementation
|
141 |
|
142 |
procedure DisposePathData(Data : Pointer); far;
|
143 |
begin
|
144 |
Dispose(PStLongLat(Data));
|
145 |
end;
|
146 |
|
147 |
procedure DisposeEclipseRecord(Data : Pointer); far;
|
148 |
var
|
149 |
EcData : TStEclipseRecord;
|
150 |
begin
|
151 |
EcData := TStEclipseRecord(Data^);
|
152 |
if (Assigned(EcData.Path)) then
|
153 |
EcData.Path.Free;
|
154 |
Dispose(PStEclipseRecord(Data));
|
155 |
end;
|
156 |
|
157 |
constructor TStEclipses.Create(NodeClass : TStNodeClass);
|
158 |
begin
|
159 |
inherited Create(NodeClass);
|
160 |
|
161 |
DisposeData := DisposeEclipseRecord;
|
162 |
end;
|
163 |
|
164 |
function TStEclipses.GetEclipse(Idx : longint) : PStEclipseRecord;
|
165 |
begin
|
166 |
if (Idx < 0) or (Idx > pred(Count)) then
|
167 |
Result := nil
|
168 |
else
|
169 |
Result := PStEclipseRecord(Items[Idx].Data);
|
170 |
end;
|
171 |
|
172 |
procedure TStEclipses.FindEclipses(Year : integer);
|
173 |
var
|
174 |
K,
|
175 |
MeanJD,
|
176 |
JDofFirst,
|
177 |
JDofLast : Double;
|
178 |
|
179 |
begin
|
180 |
JDofFirst := AstJulianDatePrim(Year, 1, 1, 0);
|
181 |
JDofLast := AstJulianDatePrim(Year, 12, 31, pred(SecondsInDay));
|
182 |
K := Int((Year - 2000) * 12.3685 - 1);
|
183 |
repeat
|
184 |
MeanJD := 2451550.09765 + 29.530588853 * K;
|
185 |
if (MeanJD < JDofFirst) then
|
186 |
K := K + 0.5;
|
187 |
until (MeanJD >= JDofFirst);
|
188 |
|
189 |
while (MeanJD < JDofLast) do begin
|
190 |
CheckForEclipse(K);
|
191 |
K := K + 0.5;
|
192 |
MeanJD := 2451550.09765 + 29.530588853 * K;
|
193 |
end;
|
194 |
end;
|
195 |
|
196 |
procedure TStEclipses.CentralEclipseTime(JD, K, J2,
|
197 |
SunAnom, MoonAnom,
|
198 |
ArgLat, AscNode, EFac : Double;
|
199 |
var F1, A1, CentralTime : Double);
|
200 |
{the mean error of this routine is 0.36 minutes in a test between}
|
201 |
{1951 through 2050 with a maximum of 1.1 - Meeus}
|
202 |
begin
|
203 |
F1 := ArgLat - (0.02665/radcor) * sin(AscNode);
|
204 |
A1 := (299.77/radcor)
|
205 |
+ (0.107408/radcor) * K
|
206 |
- (0.009173/radcor) * J2;
|
207 |
|
208 |
if (Frac(K) > 0.1) then
|
209 |
{correction at Full Moon - Lunar eclipse}
|
210 |
CentralTime := JD
|
211 |
- 0.4065 * sin(MoonAnom)
|
212 |
+ 0.1727 * EFac * sin(SunAnom)
|
213 |
else
|
214 |
{correction at New Moon - solar eclipse}
|
215 |
CentralTime := JD
|
216 |
- 0.4075 * sin(MoonAnom)
|
217 |
+ 0.1721 * EFac * sin(SunAnom);
|
218 |
|
219 |
CentralTime := CentralTime
|
220 |
+ 0.0161 * sin(2 * MoonAnom)
|
221 |
- 0.0097 * sin(2 * F1)
|
222 |
+ 0.0073 * sin(MoonAnom - SunAnom) * EFac
|
223 |
- 0.0050 * sin(MoonAnom + SunAnom) * EFac
|
224 |
- 0.0023 * sin(MoonAnom - 2*F1)
|
225 |
+ 0.0021 * sin(2*SunAnom) * EFac
|
226 |
+ 0.0012 * sin(MoonAnom + 2*F1)
|
227 |
+ 0.0006 * sin(2*MoonAnom + SunAnom) * EFac
|
228 |
- 0.0004 * sin(3*MoonAnom)
|
229 |
- 0.0003 * sin(SunAnom + 2*F1) * EFac
|
230 |
+ 0.0003 * sin(A1)
|
231 |
- 0.0002 * sin(SunAnom - 2*F1) * EFac
|
232 |
- 0.0002 * sin(2*MoonAnom - SunAnom) * EFac
|
233 |
- 0.0002 * sin(AscNode);
|
234 |
end;
|
235 |
|
236 |
procedure TStEclipses.CheckForEclipse(K : Double);
|
237 |
var
|
238 |
MeanJD,
|
239 |
J1, J2, J3,
|
240 |
PMag, UMag,
|
241 |
CentralJD,
|
242 |
SunAnom,
|
243 |
MoonAnom,
|
244 |
ArgLat,
|
245 |
AscNode,
|
246 |
EFac,
|
247 |
DeltaT,
|
248 |
F1, A1,
|
249 |
P, Q, W,
|
250 |
Gamma, Mu : Double;
|
251 |
begin
|
252 |
{compute Julian Centuries}
|
253 |
J1 := K / 1236.85;
|
254 |
J2 := Sqr(J1);
|
255 |
J3 := J2 * J1;
|
256 |
|
257 |
{mean Julian Date for phase}
|
258 |
MeanJD := 2451550.09765
|
259 |
+ 29.530588853 * K
|
260 |
+ 0.0001337 * J2
|
261 |
- 0.000000150 * J3
|
262 |
+ 0.00000000073 * J2 * J2;
|
263 |
|
264 |
{solar mean anomaly}
|
265 |
SunAnom := 2.5534
|
266 |
+ 29.1053569 * K
|
267 |
- 0.0000218 * J2
|
268 |
- 0.00000011 * J3;
|
269 |
SunAnom := Frac(SunAnom / 360.0) * 360;
|
270 |
if (SunAnom < 0) then
|
271 |
SunAnom := SunAnom + 360.0;
|
272 |
|
273 |
{lunar mean anomaly}
|
274 |
MoonAnom := 201.5643
|
275 |
+ 385.81693528 * K
|
276 |
+ 0.0107438 * J2
|
277 |
+ 0.00001239 * J3
|
278 |
- 0.000000058 * J2 * J2;
|
279 |
MoonAnom := Frac(MoonAnom / 360.0) * 360;
|
280 |
if (MoonAnom < 0) then
|
281 |
MoonAnom := MoonAnom + 360.0;
|
282 |
|
283 |
{lunar argument of latitude}
|
284 |
ArgLat := 160.7108
|
285 |
+ 390.67050274 * K
|
286 |
- 0.0016341 * J2
|
287 |
- 0.00000227 * J3
|
288 |
+ 0.000000011 * J2 * J2;
|
289 |
ArgLat := Frac(ArgLat / 360.0) * 360;
|
290 |
if (ArgLat < 0) then
|
291 |
ArgLat := ArgLat + 360.0;
|
292 |
|
293 |
{lunar ascending node}
|
294 |
AscNode := 124.7746
|
295 |
- 1.56375580 * K
|
296 |
+ 0.0020691 * J2
|
297 |
+ 0.00000215 * J3;
|
298 |
AscNode := Frac(AscNode / 360.0) * 360;
|
299 |
if (AscNode < 0) then
|
300 |
AscNode := AscNode + 360.0;
|
301 |
|
302 |
{convert to radians}
|
303 |
SunAnom := SunAnom/radcor;
|
304 |
MoonAnom := MoonAnom/radcor;
|
305 |
ArgLat := ArgLat/radcor;
|
306 |
AscNode := AscNode/radcor;
|
307 |
|
308 |
{correction factor}
|
309 |
EFac := 1.0 - 0.002516 * J1 - 0.0000074 * J2;
|
310 |
|
311 |
{if AscNode > 21 deg. from 0 or 180 then no eclipse}
|
312 |
if (abs(sin(ArgLat)) > (sin(21.0/radcor))) then Exit;
|
313 |
|
314 |
{there is probably an eclipse - what kind? when?}
|
315 |
|
316 |
CentralEclipseTime(MeanJD, K, J2, SunAnom, MoonAnom,
|
317 |
ArgLat, AscNode, EFac,
|
318 |
F1, A1, CentralJD);
|
319 |
|
320 |
{Central JD is in Dynamical Time. Sun/Moon Positions are based on UT}
|
321 |
{An APPROXIMATE conversion is made to UT. This has limited accuracy}
|
322 |
|
323 |
DeltaT := (-15 + (sqr(CentralJD - 2382148) / 41048480)) / 86400;
|
324 |
CentralJD := CentralJD - DeltaT;
|
325 |
|
326 |
P := 0.2070 * sin(SunAnom) * EFac
|
327 |
+ 0.0024 * sin(2*SunAnom) * EFac
|
328 |
- 0.0392 * sin(MoonAnom)
|
329 |
+ 0.0116 * sin(2*MoonAnom)
|
330 |
- 0.0073 * sin(SunAnom + MoonAnom) * EFac
|
331 |
+ 0.0067 * sin(MoonAnom - SunAnom) * EFac
|
332 |
+ 0.0118 * sin(2*F1);
|
333 |
|
334 |
Q := 5.2207
|
335 |
- 0.0048 * cos(SunAnom) * EFac
|
336 |
+ 0.0020 * cos(2*SunAnom) * EFac
|
337 |
- 0.3299 * cos(MoonAnom)
|
338 |
- 0.0060 * cos(SunAnom + MoonAnom) * EFac
|
339 |
+ 0.0041 * cos(MoonAnom - SunAnom) * EFac;
|
340 |
|
341 |
W := abs(cos(F1));
|
342 |
|
343 |
Gamma := (P * cos(F1) + Q * sin(F1)) * (1 - 0.0048 * W);
|
344 |
|
345 |
Mu := 0.0059
|
346 |
+ 0.0046 * cos(SunAnom) * EFac
|
347 |
- 0.0182 * cos(MoonAnom)
|
348 |
+ 0.0004 * cos(2*MoonAnom)
|
349 |
- 0.0005 * cos(SunAnom + MoonAnom);
|
350 |
|
351 |
if (Frac(abs(K)) > 0.1) then begin
|
352 |
{Check for Lunar Eclipse possibilities}
|
353 |
PMag := (1.5573 + Mu - abs(Gamma)) / 0.5450;
|
354 |
UMag := (1.0128 - Mu - abs(Gamma)) / 0.5450;
|
355 |
|
356 |
if (UMag >= 1.0) then
|
357 |
TotalLunarEclipse(CentralJD, MoonAnom, Mu, PMag, UMag, Gamma)
|
358 |
else if (UMag > 0) then
|
359 |
PartialLunarEclipse(CentralJD, MoonAnom, Mu, PMag, UMag, Gamma)
|
360 |
else if ((UMag < 0) and (PMag > 0)) then
|
361 |
PenumbralLunarEclipse(CentralJD, MoonAnom, Mu, PMag, UMag, Gamma);
|
362 |
end else begin
|
363 |
{Check for Solar Eclipse possibilities}
|
364 |
{
|
365 |
Non-partial eclipses
|
366 |
--------------------
|
367 |
central Axis of moon's umbral shadow touches earth's surface
|
368 |
Can be total, annular, or both
|
369 |
|
370 |
non-central Axis of moon's umbral shadow does not touch earth's surface
|
371 |
Eclipse is usually partial but can be one of possibilities
|
372 |
for central eclipse if very near one of the earth's poles
|
373 |
|
374 |
Partial eclipses
|
375 |
----------------
|
376 |
partial None of the moon's umbral shadow touches the earth's surface
|
377 |
}
|
378 |
|
379 |
if (abs(Gamma) <= (0.9972 + abs(Mu))) then
|
380 |
NonPartialSolarEclipse(CentralJD, Mu, Gamma)
|
381 |
else begin
|
382 |
if (abs(Gamma) < 1.5433 + Mu) then
|
383 |
PartialSolarEclipse(CentralJD, Mu, Gamma);
|
384 |
end;
|
385 |
end;
|
386 |
end;
|
387 |
|
388 |
procedure TStEclipses.TotalLunarEclipse(CentralJD, MoonAnom, Mu,
|
389 |
PMag, UMag, Gamma : Double);
|
390 |
var
|
391 |
TLE : PStEclipseRecord;
|
392 |
PartialSemiDur,
|
393 |
TotalSemiDur,
|
394 |
Dbl1 : Double;
|
395 |
begin
|
396 |
New(TLE);
|
397 |
TLE^.Magnitude := UMag;
|
398 |
TLE^.Hemisphere := htNone;
|
399 |
TLE^.EType := etLunarTotal;
|
400 |
TLE^.Path := nil;
|
401 |
CentralJD := AJDToDateTime(CentralJD);
|
402 |
|
403 |
PartialSemiDur := 1.0128 - Mu;
|
404 |
TotalSemiDur := 0.4678 - Mu;
|
405 |
Dbl1 := 0.5458 + 0.0400 * cos(MoonAnom);
|
406 |
|
407 |
PartialSemiDur := 60/Dbl1 * sqrt(sqr(PartialSemiDur) - sqr(Gamma)) / 1440;
|
408 |
TotalSemiDur := 60/Dbl1 * sqrt(sqr(TotalSemiDur) - sqr(Gamma)) / 1440;
|
409 |
|
410 |
TLE^.LContacts.FirstContact := CentralJD - PartialSemiDur;
|
411 |
TLE^.LContacts.SecondContact := CentralJD - TotalSemiDur;
|
412 |
TLE^.LContacts.MidEclipse := CentralJD;
|
413 |
TLE^.LContacts.ThirdContact := CentralJD + TotalSemiDur;
|
414 |
TLE^.LContacts.FourthContact := CentralJD + PartialSemiDur;
|
415 |
|
416 |
PartialSemiDur := 60/Dbl1 * sqrt(sqr(1.5573 + Mu) - sqr(Gamma)) / 1440;
|
417 |
TLE^.LContacts.UT1 := CentralJD - PartialSemiDur;
|
418 |
TLE^.LContacts.UT2 := CentralJD + PartialSemiDur;
|
419 |
|
420 |
Self.Append(TLE);
|
421 |
end;
|
422 |
|
423 |
procedure TStEclipses.PartialLunarEclipse(CentralJD, MoonAnom, Mu,
|
424 |
PMag, UMag, Gamma : Double);
|
425 |
var
|
426 |
TLE : PStEclipseRecord;
|
427 |
PartialSemiDur,
|
428 |
Dbl1 : Double;
|
429 |
begin
|
430 |
New(TLE);
|
431 |
TLE^.Magnitude := UMag;
|
432 |
TLE^.Hemisphere := htNone;
|
433 |
TLE^.EType := etLunarPartial;
|
434 |
TLE^.Path := nil;
|
435 |
CentralJD := AJDToDateTime(CentralJD);
|
436 |
|
437 |
PartialSemiDur := 1.0128 - Mu;
|
438 |
Dbl1 := 0.5458 + 0.0400 * cos(MoonAnom);
|
439 |
|
440 |
PartialSemiDur := 60/Dbl1 * sqrt(sqr(PartialSemiDur) - sqr(Gamma)) / 1440;
|
441 |
|
442 |
TLE^.LContacts.FirstContact := CentralJD - PartialSemiDur;
|
443 |
TLE^.LContacts.SecondContact := 0;
|
444 |
TLE^.LContacts.MidEclipse := CentralJD;
|
445 |
TLE^.LContacts.ThirdContact := 0;
|
446 |
TLE^.LContacts.FourthContact := CentralJD + PartialSemiDur;
|
447 |
|
448 |
PartialSemiDur := 60/Dbl1 * sqrt(sqr(1.5573 + Mu) - sqr(Gamma)) / 1440;
|
449 |
TLE^.LContacts.UT1 := CentralJD - PartialSemiDur;
|
450 |
TLE^.LContacts.UT2 := CentralJD + PartialSemiDur;
|
451 |
|
452 |
Self.Append(TLE);
|
453 |
end;
|
454 |
|
455 |
procedure TStEclipses.PenumbralLunarEclipse(CentralJD, MoonAnom, Mu,
|
456 |
PMag, UMag, Gamma : Double);
|
457 |
var
|
458 |
TLE : PStEclipseRecord;
|
459 |
PartialSemiDur,
|
460 |
Dbl1 : Double;
|
461 |
begin
|
462 |
New(TLE);
|
463 |
TLE^.Magnitude := PMag;
|
464 |
TLE^.Hemisphere := htNone;
|
465 |
TLE^.EType := etLunarPenumbral;
|
466 |
TLE^.Path := nil;
|
467 |
CentralJD := AJDToDateTime(CentralJD);
|
468 |
|
469 |
TLE^.LContacts.FirstContact := 0;
|
470 |
TLE^.LContacts.SecondContact := 0;
|
471 |
TLE^.LContacts.MidEclipse := CentralJD;
|
472 |
TLE^.LContacts.ThirdContact := 0;
|
473 |
TLE^.LContacts.FourthContact := 0;
|
474 |
|
475 |
Dbl1 := 0.5458 + 0.0400 * cos(MoonAnom);
|
476 |
PartialSemiDur := 60/Dbl1 * sqrt(sqr(1.5573 + Mu) - sqr(Gamma)) / 1440;
|
477 |
TLE^.LContacts.UT1 := CentralJD - PartialSemiDur;
|
478 |
TLE^.LContacts.UT2 := CentralJD + PartialSemiDur;
|
479 |
|
480 |
Self.Append(TLE);
|
481 |
end;
|
482 |
|
483 |
procedure TStEclipses.GetBesselianElements(CentralJD : Double);
|
484 |
var
|
485 |
I,
|
486 |
Mins : LongInt;
|
487 |
CurJD,
|
488 |
SidTime,
|
489 |
SunDist,
|
490 |
MoonDist,
|
491 |
DistRatio,
|
492 |
Alpha,
|
493 |
Theta,
|
494 |
Sun1,
|
495 |
Sun2,
|
496 |
Moon1,
|
497 |
Moon2,
|
498 |
Dbl3,
|
499 |
F1, F2 : Double;
|
500 |
DTRec : TStDateTimeRec;
|
501 |
SunXYZ : TStSunXYZRec;
|
502 |
Sun : TStPosRec;
|
503 |
Moon : TStMoonPosRec;
|
504 |
begin
|
505 |
{compute BesselianElements every 10 minutes starting 2 hours prior to CentralJD}
|
506 |
{but forcing positions to be at multiple of ten minutes}
|
507 |
for I := 1 to 25 do begin
|
508 |
CurJD := CentralJD + ((I-13) * (10/1440));
|
509 |
DTRec.D := AstJulianDateToStDate(CurJD, True);
|
510 |
if ((Frac(CurJD) + 0.5) >= 1) then
|
511 |
Mins := Trunc(((Frac(CurJD) + 0.5)-1) * 1440)
|
512 |
else
|
513 |
Mins := Trunc((Frac(CurJD) + 0.5) * 1440);
|
514 |
{changed because, for example, both 25 and 35 rounded to 30}
|
515 |
Mins := ((Mins + 5) div 10) * 10;
|
516 |
if (Mins = 1440) then
|
517 |
Mins := 0;
|
518 |
DTRec.T := Mins * 60;
|
519 |
|
520 |
SidTime := SiderealTime(DTRec) / radcor;
|
521 |
SunXYZ := SunPosPrim(DTRec);
|
522 |
Sun := SunPos(DTRec);
|
523 |
Moon := MoonPos(DTRec);
|
524 |
|
525 |
Sun1 := Sun.RA/radcor;
|
526 |
Sun2 := Sun.DC/radcor;
|
527 |
Moon1 := Moon.RA/radcor;
|
528 |
Moon2 := Moon.DC/radcor;
|
529 |
|
530 |
FBesselianElements[I].JD := StDateToDateTime(DTRec.D)
|
531 |
+ StTimeToDateTime(DTRec.T);
|
532 |
|
533 |
SunDist := 1.0 / sin(8.794/SunXYZ.RV/3600.0/radcor);
|
534 |
MoonDist := 1.0 / sin(Moon.Plx/radcor);
|
535 |
DistRatio := MoonDist / SunDist;
|
536 |
|
537 |
Theta := DistRatio/cos(Sun2) * cos(Moon2) * (Moon1 - Sun1);
|
538 |
Theta := Theta/(1.0-DistRatio);
|
539 |
Alpha := Sun1 - Theta;
|
540 |
|
541 |
Theta := DistRatio/(1.0 - DistRatio) * (Moon2 - Sun2);
|
542 |
|
543 |
FBesselianElements[I].Delta := Sun2 - Theta;
|
544 |
FBesselianElements[I].Angle := SidTime - Alpha;
|
545 |
FBesselianElements[I].XAxis := MoonDist * cos(Moon2) * (sin(Moon1 - Alpha));
|
546 |
|
547 |
Dbl3 := FBesselianElements[I].Delta;
|
548 |
FBesselianElements[I].YAxis := MoonDist * (sin(Moon2) * cos(Dbl3)
|
549 |
- cos(Moon2) * sin(Dbl3) * cos(Moon1 - Alpha));
|
550 |
|
551 |
Theta := DistRatio * SunXYZ.RV;
|
552 |
Theta := SunXYZ.RV - Theta;
|
553 |
F1 := StInvSin(0.004664012/Theta);
|
554 |
F2 := StInvSin(0.004640787/Theta);
|
555 |
|
556 |
Theta := MoonDist * (sin(Moon2) * sin(Dbl3) + cos(Moon2)
|
557 |
* cos(Dbl3) * cos(Moon1 - Alpha));
|
558 |
FBesselianElements[I].L1 := (Theta + 0.272453/sin(F1)) * StTan(F1);
|
559 |
FBesselianElements[I].L2 := (Theta - 0.272453/sin(F2)) * StTan(F2);
|
560 |
|
561 |
if (I = 13) then
|
562 |
F0 := StTan(F2);
|
563 |
|
564 |
if (I = 16) then begin
|
565 |
FUPrime := FBesselianElements[16].Angle - FBesselianElements[10].Angle;
|
566 |
FDPrime := FBesselianElements[16].Delta - FBesselianElements[10].Delta;
|
567 |
end;
|
568 |
end;
|
569 |
end;
|
570 |
|
571 |
procedure TStEclipses.GetShadowPath(I1, I2 : Integer; Path : TStList);
|
572 |
var
|
573 |
J,
|
574 |
I3, I4,
|
575 |
I5, I6 : integer;
|
576 |
|
577 |
Delta,
|
578 |
Dbl1,
|
579 |
Dbl2,
|
580 |
P1,
|
581 |
XAxis,
|
582 |
YAxis,
|
583 |
Eta,
|
584 |
R1, R2,
|
585 |
D1, D2,
|
586 |
D3, D4,
|
587 |
V3, V4,
|
588 |
V5, V6, V7,
|
589 |
XPrime,
|
590 |
YPrime : Double;
|
591 |
|
592 |
Position : PStLongLat;
|
593 |
begin
|
594 |
for J := I1 to I2 do begin
|
595 |
Eta := 0.00669454;
|
596 |
Delta := FBesselianElements[J].Delta;
|
597 |
XAxis := FBesselianElements[J].XAxis;
|
598 |
YAxis := FBesselianElements[J].YAxis;
|
599 |
|
600 |
R1 := sqrt(1.0 - Eta * sqr(cos(Delta)));
|
601 |
R2 := sqrt(1.0 - Eta * sqr(sin(Delta)));
|
602 |
|
603 |
D1 := sin(Delta) / R1;
|
604 |
D2 := sqrt(1.0 - Eta) * cos(Delta) / R1;
|
605 |
D3 := Eta * sin(Delta) * cos(Delta) / R1 / R2;
|
606 |
D4 := sqrt(1.0 - Eta) / R1 / R2;
|
607 |
|
608 |
V3 := YAxis / R1;
|
609 |
V4 := sqrt(1.0 - sqr(XAxis) - sqr(V3));
|
610 |
V5 := R2 * (V4 * D4 - V3 * D3);
|
611 |
V6 := FUPrime * (-YAxis * sin(Delta) + V5 * cos(Delta));
|
612 |
V7 := FUPrime * XAxis * sin(Delta) - FDPrime * V5;
|
613 |
|
614 |
if ((I2-I1) div 2) >= 4 then begin
|
615 |
I3 := (I2-I1) div 2;
|
616 |
I4 := I1 + I3;
|
617 |
I5 := I4 - 3;
|
618 |
I6 := I4 + 3;
|
619 |
XPrime := FBesselianElements[I6].XAxis
|
620 |
- FBesselianElements[I5].XAxis;
|
621 |
YPrime := FBesselianElements[I6].YAxis
|
622 |
- FBesselianElements[I5].YAxis;
|
623 |
end else begin
|
624 |
XPrime := (FBesselianElements[J+1].XAxis -
|
625 |
FBesselianElements[J-1].XAxis) * 3;
|
626 |
YPrime := (FBesselianElements[J+1].YAxis -
|
627 |
FBesselianElements[J-1].YAxis) * 3;
|
628 |
end;
|
629 |
|
630 |
New(Position);
|
631 |
Dbl1 := sqrt(sqr(XPrime - V6) + sqr(YPrime - V7));
|
632 |
Position^.JD := FBesselianElements[J].JD;
|
633 |
|
634 |
Dbl2 := (FBesselianElements[J].L2 - V5 * F0) / Dbl1;
|
635 |
Dbl2 := abs(Dbl2 * 120);
|
636 |
Position^.Duration := int(Dbl2) + frac(Dbl2) * 0.6;
|
637 |
|
638 |
Dbl1 := -V3 * D1 + V4 * D2;
|
639 |
P1 := StInvTan2(Dbl1, XAxis);
|
640 |
|
641 |
Dbl2 := (FBesselianElements[J].Angle - P1) * radcor;
|
642 |
Dbl2 := frac(Dbl2 / 360.0) * 360;
|
643 |
if (Dbl2 < 0) then
|
644 |
Dbl2 := Dbl2 + 360.0;
|
645 |
if (Dbl2 > 180.0) and (Dbl2 < 360.0) then
|
646 |
Dbl2 := Dbl2 - 360.0;
|
647 |
Position^.Longitude := Dbl2;
|
648 |
|
649 |
Dbl1 := StInvSin(V3 * D2 + V4 * D1);
|
650 |
Dbl2 := ArcTan(1.003364 * StTan(Dbl1)) * radcor;
|
651 |
Position^.Latitude := Dbl2;
|
652 |
|
653 |
Path.Append(Position);
|
654 |
end;
|
655 |
end;
|
656 |
|
657 |
procedure TStEclipses.NonPartialSolarEclipse(CentralJD, Mu, Gamma : Double);
|
658 |
var
|
659 |
SolEc : PStEclipseRecord;
|
660 |
I1, I2 : Integer;
|
661 |
begin
|
662 |
New(SolEc);
|
663 |
if (Mu < 0) then
|
664 |
SolEc^.EType := etSolarTotal
|
665 |
else if (Mu > 0.0047) then
|
666 |
SolEc^.EType := etSolarAnnular
|
667 |
else begin
|
668 |
if (Mu < (0.00464 * sqrt(1 - sqr(Gamma)))) then
|
669 |
SolEc^.EType := etSolarAnnularTotal
|
670 |
else
|
671 |
SolEc^.EType := etSolarTotal;
|
672 |
end;
|
673 |
|
674 |
SolEc^.Magnitude := -1;
|
675 |
if (Gamma > 0) then
|
676 |
SolEc^.Hemisphere := htNorthern
|
677 |
else
|
678 |
SolEc^.Hemisphere := htSouthern;
|
679 |
FillChar(SolEc^.LContacts, SizeOf(TStContactTimes), #0);
|
680 |
SolEc^.LContacts.MidEclipse := AJDtoDateTime(CentralJD);
|
681 |
|
682 |
GetBesselianElements(CentralJD);
|
683 |
|
684 |
{find limits - then go one step inside at each end}
|
685 |
I1 := 1;
|
686 |
while (sqr(FBesselianElements[I1].XAxis) +
|
687 |
sqr(FBesselianElements[I1].YAxis) >= 1.0) and (I1 < 25) do
|
688 |
Inc(I1);
|
689 |
Inc(I1);
|
690 |
|
691 |
I2 := I1;
|
692 |
repeat
|
693 |
if (I2 < 25) then begin
|
694 |
if (sqr(FBesselianElements[I2+1].XAxis) +
|
695 |
sqr(FBesselianElements[I2+1].YAxis) < 1) then
|
696 |
Inc(I2)
|
697 |
else
|
698 |
break;
|
699 |
end;
|
700 |
until (sqr(FBesselianElements[I2].XAxis) +
|
701 |
sqr(FBesselianElements[I2].YAxis) >= 1) or (I2 >= 25);
|
702 |
Dec(I2);
|
703 |
|
704 |
{this test accounts for non-central eclipses, i.e., those that are total}
|
705 |
{and/or annular but the axis of the moon's shadow does not touch the earth}
|
706 |
if (I1 <> I2) and (I1 < 26) and (I2 < 26) then begin
|
707 |
SolEc^.Path := TStList.Create(TStListNode);
|
708 |
SolEc^.Path.DisposeData := DisposePathData;
|
709 |
GetShadowPath(I1, I2, SolEc^.Path);
|
710 |
end else
|
711 |
SolEc^.Path := nil;
|
712 |
Self.Append(SolEc);
|
713 |
end;
|
714 |
|
715 |
procedure TStEclipses.PartialSolarEclipse(CentralJD, Mu, Gamma : Double);
|
716 |
var
|
717 |
SolEc : PStEclipseRecord;
|
718 |
begin
|
719 |
New(SolEc);
|
720 |
SolEc^.EType := etSolarPartial;
|
721 |
SolEc^.Magnitude := (1.5433 + Mu - abs(Gamma)) / (0.5461 + 2*Mu);
|
722 |
if (Gamma > 0) then
|
723 |
SolEc^.Hemisphere := htNorthern
|
724 |
else
|
725 |
SolEc^.Hemisphere := htSouthern;
|
726 |
FillChar(SolEc^.LContacts, SizeOf(TStContactTimes), #0);
|
727 |
SolEc^.LContacts.MidEclipse := AJDToDateTime(CentralJD);
|
728 |
SolEc^.Path := nil;
|
729 |
Self.Append(SolEc);
|
730 |
end;
|
731 |
|
732 |
|
733 |
end.
|