Gergely POLONKAI (W00d5t0ck)
449e26259b
!!!WARNING!!! The build system is not updated to reflect this! The !!!WARNING!!! whole point is to subtree the swe-glib/ directory, !!!WARNING!!! making SWE-Glib a separate project as it intended to be.
5309 lines
194 KiB
C
5309 lines
194 KiB
C
|
|
/* SWISSEPH
|
|
$Header: /home/dieter/sweph/RCS/swecl.c,v 1.75 2008/08/26 07:23:27 dieter Exp $
|
|
|
|
Ephemeris computations
|
|
Author: Dieter Koch
|
|
|
|
************************************************************/
|
|
|
|
/* Copyright (C) 1997 - 2008 Astrodienst AG, Switzerland. All rights reserved.
|
|
|
|
License conditions
|
|
------------------
|
|
|
|
This file is part of Swiss Ephemeris.
|
|
|
|
Swiss Ephemeris is distributed with NO WARRANTY OF ANY KIND. No author
|
|
or distributor accepts any responsibility for the consequences of using it,
|
|
or for whether it serves any particular purpose or works at all, unless he
|
|
or she says so in writing.
|
|
|
|
Swiss Ephemeris is made available by its authors under a dual licensing
|
|
system. The software developer, who uses any part of Swiss Ephemeris
|
|
in his or her software, must choose between one of the two license models,
|
|
which are
|
|
a) GNU public license version 2 or later
|
|
b) Swiss Ephemeris Professional License
|
|
|
|
The choice must be made before the software developer distributes software
|
|
containing parts of Swiss Ephemeris to others, and before any public
|
|
service using the developed software is activated.
|
|
|
|
If the developer choses the GNU GPL software license, he or she must fulfill
|
|
the conditions of that license, which includes the obligation to place his
|
|
or her whole software project under the GNU GPL or a compatible license.
|
|
See http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
If the developer choses the Swiss Ephemeris Professional license,
|
|
he must follow the instructions as found in http://www.astro.com/swisseph/
|
|
and purchase the Swiss Ephemeris Professional Edition from Astrodienst
|
|
and sign the corresponding license contract.
|
|
|
|
The License grants you the right to use, copy, modify and redistribute
|
|
Swiss Ephemeris, but only under certain conditions described in the License.
|
|
Among other things, the License requires that the copyright notices and
|
|
this notice be preserved on all copies.
|
|
|
|
Authors of the Swiss Ephemeris: Dieter Koch and Alois Treindl
|
|
|
|
The authors of Swiss Ephemeris have no control or influence over any of
|
|
the derived works, i.e. over software or services created by other
|
|
programmers which use Swiss Ephemeris functions.
|
|
|
|
The names of the authors or of the copyright holder (Astrodienst) must not
|
|
be used for promoting any software, product or service which uses or contains
|
|
the Swiss Ephemeris. This copyright notice is the ONLY place where the
|
|
names of the authors can legally appear, except in cases where they have
|
|
given special permission in writing.
|
|
|
|
The trademarks 'Swiss Ephemeris' and 'Swiss Ephemeris inside' may be used
|
|
for promoting such software, products or services.
|
|
*/
|
|
|
|
#include "swejpl.h"
|
|
#include "swephexp.h"
|
|
#include "sweph.h"
|
|
#include "swephlib.h"
|
|
|
|
#define SEFLG_EPHMASK (SEFLG_JPLEPH|SEFLG_SWIEPH|SEFLG_MOSEPH)
|
|
static int find_maximum(double y00, double y11, double y2, double dx,
|
|
double *dxret, double *yret);
|
|
static int find_zero(double y00, double y11, double y2, double dx,
|
|
double *dxret, double *dxret2);
|
|
static double calc_dip(double geoalt, double atpress, double attemp,
|
|
double lapse_rate);
|
|
static double calc_astronomical_refr(double geoalt, double atpress,
|
|
double attemp);
|
|
static double const_lapse_rate = SE_LAPSE_RATE; /* for refraction */
|
|
|
|
#if 0
|
|
#define DSUN (1391978489.9 / AUNIT) /* this value is consistent with
|
|
* 959.63 arcsec at AU distance (Astr. Alm.) */
|
|
#else
|
|
#define DSUN (1392000000.0 / AUNIT)
|
|
#endif
|
|
#define DMOON (3476300.0 / AUNIT)
|
|
#define DEARTH (6378140.0 * 2 / AUNIT)
|
|
#define RSUN (DSUN / 2)
|
|
#define RMOON (DMOON / 2)
|
|
#define REARTH (DEARTH / 2)
|
|
|
|
/*#define SEI_OCC_FAST (16 * 1024L)*/
|
|
static int32 eclipse_where(double tjd_ut, int32 ipl, char *starname,
|
|
int32 ifl, double *geopos, double *dcore,
|
|
char *serr);
|
|
static int32 eclipse_how(double tjd_ut, int32 ipl, char *starname, int32 ifl,
|
|
double geolon, double geolat, double geohgt,
|
|
double *attr, char *serr);
|
|
static int32 eclipse_when_loc(double tjd_start, int32 ifl, double *geopos,
|
|
double *tret, double *attr, AS_BOOL backward,
|
|
char *serr);
|
|
static int32 occult_when_loc(double tjd_start, int32 ipl, char *starname,
|
|
int32 ifl, double *geopos, double *tret,
|
|
double *attr, AS_BOOL backward, char *serr);
|
|
static int32 lun_eclipse_how(double tjd_ut, int32 ifl, double *attr,
|
|
double *dcore, char *serr);
|
|
static int32 calc_mer_trans(double tjd_ut, int32 ipl, int32 epheflag,
|
|
int32 rsmi, double *geopos, char *starname,
|
|
double *tret, char *serr);
|
|
static int32 calc_planet_star(double tjd_et, int32 ipl, char *starname,
|
|
int32 iflag, double *x, char *serr);
|
|
|
|
struct saros_data
|
|
{
|
|
int series_no;
|
|
double tstart;
|
|
};
|
|
|
|
#define SAROS_CYCLE 6585.3213
|
|
#define NSAROS_SOLAR 181
|
|
struct saros_data saros_data_solar[NSAROS_SOLAR] = {
|
|
{0, 641886.5}, /* 23 May -2955 */
|
|
{1, 672214.5}, /* 04 Jun -2872 */
|
|
{2, 676200.5}, /* 04 May -2861 */
|
|
{3, 693357.5}, /* 24 Apr -2814 */
|
|
{4, 723685.5}, /* 06 May -2731 */
|
|
{5, 727671.5}, /* 04 Apr -2720 */
|
|
{6, 744829.5}, /* 27 Mar -2673 */
|
|
{7, 775157.5}, /* 08 Apr -2590 */
|
|
{8, 779143.5}, /* 07 Mar -2579 */
|
|
{9, 783131.5}, /* 06 Feb -2568 */
|
|
{10, 820044.5}, /* 28 Feb -2467 */
|
|
{11, 810859.5}, /* 06 Jan -2492 */
|
|
{12, 748993.5}, /* 20 Aug -2662 */
|
|
{13, 792492.5}, /* 23 Sep -2543 */
|
|
{14, 789892.5}, /* 11 Aug -2550 */
|
|
{15, 787294.5}, /* 01 Jul -2557 */
|
|
{16, 824207.5}, /* 23 Jul -2456 */
|
|
{17, 834779.5}, /* 03 Jul -2427 */
|
|
{18, 838766.5}, /* 02 Jun -2416 */
|
|
{19, 869094.5}, /* 15 Jun -2333 */
|
|
{20, 886251.5}, /* 05 Jun -2286 */
|
|
{21, 890238.5}, /* 05 May -2275 */
|
|
{22, 927151.5}, /* 28 May -2174 */
|
|
{23, 937722.5}, /* 07 May -2145 */
|
|
{24, 941709.5}, /* 06 Apr -2134 */
|
|
{25, 978623.5}, /* 30 Apr -2033 */
|
|
{26, 989194.5}, /* 08 Apr -2004 */
|
|
{27, 993181.5}, /* 09 Mar -1993 */
|
|
{28, 1023510.5}, /* 22 Mar -1910 */
|
|
{29, 1034081.5}, /* 01 Mar -1881 */
|
|
{30, 972214.5}, /* 12 Oct -2051 */
|
|
{31, 1061811.5}, /* 31 Jan -1805 */
|
|
{32, 1006529.5}, /* 24 Sep -1957 */
|
|
{33, 997345.5}, /* 02 Aug -1982 */
|
|
{34, 1021088.5}, /* 04 Aug -1917 */
|
|
{35, 1038245.5}, /* 25 Jul -1870 */
|
|
{36, 1042231.5}, /* 23 Jun -1859 */
|
|
{37, 1065974.5}, /* 25 Jun -1794 */
|
|
{38, 1089716.5}, /* 26 Jun -1729 */
|
|
{39, 1093703.5}, /* 26 May -1718 */
|
|
{40, 1117446.5}, /* 28 May -1653 */
|
|
{41, 1141188.5}, /* 28 May -1588 */
|
|
{42, 1145175.5}, /* 28 Apr -1577 */
|
|
{43, 1168918.5}, /* 29 Apr -1512 */
|
|
{44, 1192660.5}, /* 30 Apr -1447 */
|
|
{45, 1196647.5}, /* 30 Mar -1436 */
|
|
{46, 1220390.5}, /* 01 Apr -1371 */
|
|
{47, 1244132.5}, /* 02 Apr -1306 */
|
|
{48, 1234948.5}, /* 08 Feb -1331 */
|
|
{49, 1265277.5}, /* 22 Feb -1248 */
|
|
{50, 1282433.5}, /* 11 Feb -1201 */
|
|
{51, 1207395.5}, /* 02 Sep -1407 */
|
|
{52, 1217968.5}, /* 14 Aug -1378 */
|
|
{53, 1254881.5}, /* 06 Sep -1277 */
|
|
{54, 1252282.5}, /* 25 Jul -1284 */
|
|
{55, 1262855.5}, /* 06 Jul -1255 */
|
|
{56, 1293182.5}, /* 17 Jul -1172 */
|
|
{57, 1297169.5}, /* 17 Jun -1161 */
|
|
{58, 1314326.5}, /* 07 Jun -1114 */
|
|
{59, 1344654.5}, /* 19 Jun -1031 */
|
|
{60, 1348640.5}, /* 18 May -1020 */
|
|
{61, 1365798.5}, /* 10 May -0973 */
|
|
{62, 1396126.5}, /* 22 May -0890 */
|
|
{63, 1400112.5}, /* 20 Apr -0879 */
|
|
{64, 1417270.5}, /* 11 Apr -0832 */
|
|
{65, 1447598.5}, /* 24 Apr -0749 */
|
|
{66, 1444999.5}, /* 12 Mar -0756 */
|
|
{67, 1462157.5}, /* 04 Mar -0709 */
|
|
{68, 1492485.5}, /* 16 Mar -0626 */
|
|
{69, 1456959.5}, /* 09 Dec -0724 */
|
|
{70, 1421434.5}, /* 05 Sep -0821 */
|
|
{71, 1471518.5}, /* 19 Oct -0684 */
|
|
{72, 1455748.5}, /* 16 Aug -0727 */
|
|
{73, 1466320.5}, /* 27 Jul -0698 */
|
|
{74, 1496648.5}, /* 08 Aug -0615 */
|
|
{75, 1500634.5}, /* 07 Jul -0604 */
|
|
{76, 1511207.5}, /* 18 Jun -0575 */
|
|
{77, 1548120.5}, /* 11 Jul -0474 */
|
|
{78, 1552106.5}, /* 09 Jun -0463 */
|
|
{79, 1562679.5}, /* 21 May -0434 */
|
|
{80, 1599592.5}, /* 13 Jun -0333 */
|
|
{81, 1603578.5}, /* 12 May -0322 */
|
|
{82, 1614150.5}, /* 22 Apr -0293 */
|
|
{83, 1644479.5}, /* 05 May -0210 */
|
|
{84, 1655050.5}, /* 14 Apr -0181 */
|
|
{85, 1659037.5}, /* 14 Mar -0170 */
|
|
{86, 1695950.5}, /* 06 Apr -0069 */
|
|
{87, 1693351.5}, /* 23 Feb -0076 */
|
|
{88, 1631484.5}, /* 06 Oct -0246 */
|
|
{89, 1727666.5}, /* 04 Feb 0018 */
|
|
{90, 1672384.5}, /* 28 Sep -0134 */
|
|
{91, 1663200.5}, /* 06 Aug -0159 */
|
|
{92, 1693529.5}, /* 19 Aug -0076 */
|
|
{93, 1710685.5}, /* 09 Aug -0029 */
|
|
{94, 1714672.5}, /* 09 Jul -0018 */
|
|
{95, 1738415.5}, /* 11 Jul 0047 */
|
|
{96, 1755572.5}, /* 01 Jul 0094 */
|
|
{97, 1766144.5}, /* 11 Jun 0123 */
|
|
{98, 1789887.5}, /* 12 Jun 0188 */
|
|
{99, 1807044.5}, /* 03 Jun 0235 */
|
|
{100, 1817616.5}, /* 13 May 0264 */
|
|
{101, 1841359.5}, /* 15 May 0329 */
|
|
{102, 1858516.5}, /* 05 May 0376 */
|
|
{103, 1862502.5}, /* 04 Apr 0387 */
|
|
{104, 1892831.5}, /* 17 Apr 0470 */
|
|
{105, 1903402.5}, /* 27 Mar 0499 */
|
|
{106, 1887633.5}, /* 23 Jan 0456 */
|
|
{107, 1924547.5}, /* 15 Feb 0557 */
|
|
{108, 1921948.5}, /* 04 Jan 0550 */
|
|
{109, 1873251.5}, /* 07 Sep 0416 */
|
|
{110, 1890409.5}, /* 30 Aug 0463 */
|
|
{111, 1914151.5}, /* 30 Aug 0528 */
|
|
{112, 1918138.5}, /* 31 Jul 0539 */
|
|
{113, 1935296.5}, /* 22 Jul 0586 */
|
|
{114, 1959038.5}, /* 23 Jul 0651 */
|
|
{115, 1963024.5}, /* 21 Jun 0662 */
|
|
{116, 1986767.5}, /* 23 Jun 0727 */
|
|
{117, 2010510.5}, /* 24 Jun 0792 */
|
|
{118, 2014496.5}, /* 24 May 0803 */
|
|
{119, 2031654.5}, /* 15 May 0850 */
|
|
{120, 2061982.5}, /* 27 May 0933 */
|
|
{121, 2065968.5}, /* 25 Apr 0944 */
|
|
{122, 2083126.5}, /* 17 Apr 0991 */
|
|
{123, 2113454.5}, /* 29 Apr 1074 */
|
|
{124, 2104269.5}, /* 06 Mar 1049 */
|
|
{125, 2108256.5}, /* 04 Feb 1060 */
|
|
{126, 2151755.5}, /* 10 Mar 1179 */
|
|
{127, 2083302.5}, /* 10 Oct 0991 */
|
|
{128, 2080704.5}, /* 29 Aug 0984 */
|
|
{129, 2124203.5}, /* 03 Oct 1103 */
|
|
{130, 2121603.5}, /* 20 Aug 1096 */
|
|
{131, 2132176.5}, /* 01 Aug 1125 */
|
|
{132, 2162504.5}, /* 13 Aug 1208 */
|
|
{133, 2166490.5}, /* 13 Jul 1219 */
|
|
{134, 2177062.5}, /* 22 Jun 1248 */
|
|
{135, 2207390.5}, /* 05 Jul 1331 */
|
|
{136, 2217962.5}, /* 14 Jun 1360 */
|
|
{137, 2228534.5}, /* 25 May 1389 */
|
|
{138, 2258862.5}, /* 06 Jun 1472 */
|
|
{139, 2269434.5}, /* 17 May 1501 */
|
|
{140, 2273421.5}, /* 16 Apr 1512 */
|
|
{141, 2310334.5}, /* 19 May 1613 */
|
|
{142, 2314320.5}, /* 17 Apr 1624 */
|
|
{143, 2311722.5}, /* 07 Mar 1617 */
|
|
{144, 2355221.5}, /* 11 Apr 1736 */
|
|
{145, 2319695.5}, /* 04 Jan 1639 */
|
|
{146, 2284169.5}, /* 19 Sep 1541 */
|
|
{147, 2314498.5}, /* 12 Oct 1624 */
|
|
{148, 2325069.5}, /* 21 Sep 1653 */
|
|
{149, 2329056.5}, /* 21 Aug 1664 */
|
|
{150, 2352799.5}, /* 24 Aug 1729 */
|
|
{151, 2369956.5}, /* 14 Aug 1776 */
|
|
{152, 2380528.5}, /* 26 Jul 1805 */
|
|
{153, 2404271.5}, /* 28 Jul 1870 */
|
|
{154, 2421428.5}, /* 19 Jul 1917 */
|
|
{155, 2425414.5}, /* 17 Jun 1928 */
|
|
{156, 2455743.5}, /* 01 Jul 2011 */
|
|
{157, 2472900.5}, /* 21 Jun 2058 */
|
|
{158, 2476886.5}, /* 20 May 2069 */
|
|
{159, 2500629.5}, /* 23 May 2134 */
|
|
{160, 2517786.5}, /* 13 May 2181 */
|
|
{161, 2515187.5}, /* 01 Apr 2174 */
|
|
{162, 2545516.5}, /* 15 Apr 2257 */
|
|
{163, 2556087.5}, /* 25 Mar 2286 */
|
|
{164, 2487635.5}, /* 24 Oct 2098 */
|
|
{165, 2504793.5}, /* 16 Oct 2145 */
|
|
{166, 2535121.5}, /* 29 Oct 2228 */
|
|
{167, 2525936.5}, /* 06 Sep 2203 */
|
|
{168, 2543094.5}, /* 28 Aug 2250 */
|
|
{169, 2573422.5}, /* 10 Sep 2333 */
|
|
{170, 2577408.5}, /* 09 Aug 2344 */
|
|
{171, 2594566.5}, /* 01 Aug 2391 */
|
|
{172, 2624894.5}, /* 13 Aug 2474 */
|
|
{173, 2628880.5}, /* 12 Jul 2485 */
|
|
{174, 2646038.5}, /* 04 Jul 2532 */
|
|
{175, 2669780.5}, /* 05 Jul 2597 */
|
|
{176, 2673766.5}, /* 04 Jun 2608 */
|
|
{177, 2690924.5}, /* 27 May 2655 */
|
|
{178, 2721252.5}, /* 09 Jun 2738 */
|
|
{179, 2718653.5}, /* 28 Apr 2731 */
|
|
{180, 2729226.5}, /* 08 Apr 2760 */
|
|
};
|
|
|
|
#define NSAROS_LUNAR 180
|
|
struct saros_data saros_data_lunar[NSAROS_LUNAR] = {
|
|
{1, 782437.5}, /* 14 Mar -2570 */
|
|
{2, 799593.5}, /* 03 Mar -2523 */
|
|
{3, 783824.5}, /* 30 Dec -2567 */
|
|
{4, 754884.5}, /* 06 Oct -2646 */
|
|
{5, 824724.5}, /* 22 Dec -2455 */
|
|
{6, 762857.5}, /* 04 Aug -2624 */
|
|
{7, 773430.5}, /* 16 Jul -2595 */
|
|
{8, 810343.5}, /* 08 Aug -2494 */
|
|
{9, 807743.5}, /* 26 Jun -2501 */
|
|
{10, 824901.5}, /* 17 Jun -2454 */
|
|
{11, 855229.5}, /* 29 Jun -2371 */
|
|
{12, 859215.5}, /* 28 May -2360 */
|
|
{13, 876373.5}, /* 20 May -2313 */
|
|
{14, 906701.5}, /* 01 Jun -2230 */
|
|
{15, 910687.5}, /* 30 Apr -2219 */
|
|
{16, 927845.5}, /* 21 Apr -2172 */
|
|
{17, 958173.5}, /* 04 May -2089 */
|
|
{18, 962159.5}, /* 02 Apr -2078 */
|
|
{19, 979317.5}, /* 24 Mar -2031 */
|
|
{20, 1009645.5}, /* 05 Apr -1948 */
|
|
{21, 1007046.5}, /* 22 Feb -1955 */
|
|
{22, 1017618.5}, /* 02 Feb -1926 */
|
|
{23, 1054531.5}, /* 25 Feb -1825 */
|
|
{24, 979493.5}, /* 16 Sep -2031 */
|
|
{25, 976895.5}, /* 06 Aug -2038 */
|
|
{26, 1020394.5}, /* 09 Sep -1919 */
|
|
{27, 1017794.5}, /* 28 Jul -1926 */
|
|
{28, 1028367.5}, /* 09 Jul -1897 */
|
|
{29, 1058695.5}, /* 21 Jul -1814 */
|
|
{30, 1062681.5}, /* 19 Jun -1803 */
|
|
{31, 1073253.5}, /* 30 May -1774 */
|
|
{32, 1110167.5}, /* 23 Jun -1673 */
|
|
{33, 1114153.5}, /* 22 May -1662 */
|
|
{34, 1131311.5}, /* 13 May -1615 */
|
|
{35, 1161639.5}, /* 25 May -1532 */
|
|
{36, 1165625.5}, /* 24 Apr -1521 */
|
|
{37, 1176197.5}, /* 03 Apr -1492 */
|
|
{38, 1213111.5}, /* 27 Apr -1391 */
|
|
{39, 1217097.5}, /* 26 Mar -1380 */
|
|
{40, 1221084.5}, /* 24 Feb -1369 */
|
|
{41, 1257997.5}, /* 18 Mar -1268 */
|
|
{42, 1255398.5}, /* 04 Feb -1275 */
|
|
{43, 1186946.5}, /* 07 Sep -1463 */
|
|
{44, 1283128.5}, /* 06 Jan -1199 */
|
|
{45, 1227845.5}, /* 29 Aug -1351 */
|
|
{46, 1225247.5}, /* 19 Jul -1358 */
|
|
{47, 1255575.5}, /* 31 Jul -1275 */
|
|
{48, 1272732.5}, /* 21 Jul -1228 */
|
|
{49, 1276719.5}, /* 21 Jun -1217 */
|
|
{50, 1307047.5}, /* 03 Jul -1134 */
|
|
{51, 1317619.5}, /* 13 Jun -1105 */
|
|
{52, 1328191.5}, /* 23 May -1076 */
|
|
{53, 1358519.5}, /* 05 Jun -0993 */
|
|
{54, 1375676.5}, /* 26 May -0946 */
|
|
{55, 1379663.5}, /* 25 Apr -0935 */
|
|
{56, 1409991.5}, /* 07 May -0852 */
|
|
{57, 1420562.5}, /* 16 Apr -0823 */
|
|
{58, 1424549.5}, /* 16 Mar -0812 */
|
|
{59, 1461463.5}, /* 09 Apr -0711 */
|
|
{60, 1465449.5}, /* 08 Mar -0700 */
|
|
{61, 1436509.5}, /* 13 Dec -0780 */
|
|
{62, 1493179.5}, /* 08 Feb -0624 */
|
|
{63, 1457653.5}, /* 03 Nov -0722 */
|
|
{64, 1435298.5}, /* 20 Aug -0783 */
|
|
{65, 1452456.5}, /* 11 Aug -0736 */
|
|
{66, 1476198.5}, /* 12 Aug -0671 */
|
|
{67, 1480184.5}, /* 11 Jul -0660 */
|
|
{68, 1503928.5}, /* 14 Jul -0595 */
|
|
{69, 1527670.5}, /* 15 Jul -0530 */
|
|
{70, 1531656.5}, /* 13 Jun -0519 */
|
|
{71, 1548814.5}, /* 04 Jun -0472 */
|
|
{72, 1579142.5}, /* 17 Jun -0389 */
|
|
{73, 1583128.5}, /* 16 May -0378 */
|
|
{74, 1600286.5}, /* 07 May -0331 */
|
|
{75, 1624028.5}, /* 08 May -0266 */
|
|
{76, 1628015.5}, /* 07 Apr -0255 */
|
|
{77, 1651758.5}, /* 09 Apr -0190 */
|
|
{78, 1675500.5}, /* 10 Apr -0125 */
|
|
{79, 1672901.5}, /* 27 Feb -0132 */
|
|
{80, 1683474.5}, /* 07 Feb -0103 */
|
|
{81, 1713801.5}, /* 19 Feb -0020 */
|
|
{82, 1645349.5}, /* 21 Sep -0208 */
|
|
{83, 1649336.5}, /* 22 Aug -0197 */
|
|
{84, 1686249.5}, /* 13 Sep -0096 */
|
|
{85, 1683650.5}, /* 02 Aug -0103 */
|
|
{86, 1694222.5}, /* 13 Jul -0074 */
|
|
{87, 1731136.5}, /* 06 Aug 0027 */
|
|
{88, 1735122.5}, /* 05 Jul 0038 */
|
|
{89, 1745694.5}, /* 15 Jun 0067 */
|
|
{90, 1776022.5}, /* 27 Jun 0150 */
|
|
{91, 1786594.5}, /* 07 Jun 0179 */
|
|
{92, 1797166.5}, /* 17 May 0208 */
|
|
{93, 1827494.5}, /* 30 May 0291 */
|
|
{94, 1838066.5}, /* 09 May 0320 */
|
|
{95, 1848638.5}, /* 19 Apr 0349 */
|
|
{96, 1878966.5}, /* 01 May 0432 */
|
|
{97, 1882952.5}, /* 31 Mar 0443 */
|
|
{98, 1880354.5}, /* 18 Feb 0436 */
|
|
{99, 1923853.5}, /* 24 Mar 0555 */
|
|
{100, 1881741.5}, /* 06 Dec 0439 */
|
|
{101, 1852801.5}, /* 11 Sep 0360 */
|
|
{102, 1889715.5}, /* 05 Oct 0461 */
|
|
{103, 1893701.5}, /* 03 Sep 0472 */
|
|
{104, 1897688.5}, /* 04 Aug 0483 */
|
|
{105, 1928016.5}, /* 16 Aug 0566 */
|
|
{106, 1938588.5}, /* 27 Jul 0595 */
|
|
{107, 1942575.5}, /* 26 Jun 0606 */
|
|
{108, 1972903.5}, /* 08 Jul 0689 */
|
|
{109, 1990059.5}, /* 27 Jun 0736 */
|
|
{110, 1994046.5}, /* 28 May 0747 */
|
|
{111, 2024375.5}, /* 10 Jun 0830 */
|
|
{112, 2034946.5}, /* 20 May 0859 */
|
|
{113, 2045518.5}, /* 29 Apr 0888 */
|
|
{114, 2075847.5}, /* 13 May 0971 */
|
|
{115, 2086418.5}, /* 21 Apr 1000 */
|
|
{116, 2083820.5}, /* 11 Mar 0993 */
|
|
{117, 2120733.5}, /* 03 Apr 1094 */
|
|
{118, 2124719.5}, /* 02 Mar 1105 */
|
|
{119, 2062852.5}, /* 14 Oct 0935 */
|
|
{120, 2086596.5}, /* 16 Oct 1000 */
|
|
{121, 2103752.5}, /* 06 Oct 1047 */
|
|
{122, 2094568.5}, /* 14 Aug 1022 */
|
|
{123, 2118311.5}, /* 16 Aug 1087 */
|
|
{124, 2142054.5}, /* 17 Aug 1152 */
|
|
{125, 2146040.5}, /* 17 Jul 1163 */
|
|
{126, 2169783.5}, /* 18 Jul 1228 */
|
|
{127, 2186940.5}, /* 09 Jul 1275 */
|
|
{128, 2197512.5}, /* 18 Jun 1304 */
|
|
{129, 2214670.5}, /* 10 Jun 1351 */
|
|
{130, 2238412.5}, /* 10 Jun 1416 */
|
|
{131, 2242398.5}, /* 10 May 1427 */
|
|
{132, 2266142.5}, /* 12 May 1492 */
|
|
{133, 2289884.5}, /* 13 May 1557 */
|
|
{134, 2287285.5}, /* 01 Apr 1550 */
|
|
{135, 2311028.5}, /* 13 Apr 1615 */
|
|
{136, 2334770.5}, /* 13 Apr 1680 */
|
|
{137, 2292659.5}, /* 17 Dec 1564 */
|
|
{138, 2276890.5}, /* 15 Oct 1521 */
|
|
{139, 2326974.5}, /* 09 Dec 1658 */
|
|
{140, 2304619.5}, /* 25 Sep 1597 */
|
|
{141, 2308606.5}, /* 25 Aug 1608 */
|
|
{142, 2345520.5}, /* 19 Sep 1709 */
|
|
{143, 2349506.5}, /* 18 Aug 1720 */
|
|
{144, 2360078.5}, /* 29 Jul 1749 */
|
|
{145, 2390406.5}, /* 11 Aug 1832 */
|
|
{146, 2394392.5}, /* 11 Jul 1843 */
|
|
{147, 2411550.5}, /* 02 Jul 1890 */
|
|
{148, 2441878.5}, /* 15 Jul 1973 */
|
|
{149, 2445864.5}, /* 13 Jun 1984 */
|
|
{150, 2456437.5}, /* 25 May 2013 */
|
|
{151, 2486765.5}, /* 06 Jun 2096 */
|
|
{152, 2490751.5}, /* 07 May 2107 */
|
|
{153, 2501323.5}, /* 16 Apr 2136 */
|
|
{154, 2538236.5}, /* 10 May 2237 */
|
|
{155, 2529052.5}, /* 18 Mar 2212 */
|
|
{156, 2473771.5}, /* 08 Nov 2060 */
|
|
{157, 2563367.5}, /* 01 Mar 2306 */
|
|
{158, 2508085.5}, /* 21 Oct 2154 */
|
|
{159, 2505486.5}, /* 09 Sep 2147 */
|
|
{160, 2542400.5}, /* 03 Oct 2248 */
|
|
{161, 2546386.5}, /* 02 Sep 2259 */
|
|
{162, 2556958.5}, /* 12 Aug 2288 */
|
|
{163, 2587287.5}, /* 27 Aug 2371 */
|
|
{164, 2597858.5}, /* 05 Aug 2400 */
|
|
{165, 2601845.5}, /* 06 Jul 2411 */
|
|
{166, 2632173.5}, /* 18 Jul 2494 */
|
|
{167, 2649330.5}, /* 09 Jul 2541 */
|
|
{168, 2653317.5}, /* 08 Jun 2552 */
|
|
{169, 2683645.5}, /* 22 Jun 2635 */
|
|
{170, 2694217.5}, /* 01 Jun 2664 */
|
|
{171, 2698203.5}, /* 01 May 2675 */
|
|
{172, 2728532.5}, /* 15 May 2758 */
|
|
{173, 2739103.5}, /* 24 Apr 2787 */
|
|
{174, 2683822.5}, /* 16 Dec 2635 */
|
|
{175, 2740492.5}, /* 11 Feb 2791 */
|
|
{176, 2724722.5}, /* 09 Dec 2747 */
|
|
{177, 2708952.5}, /* 05 Oct 2704 */
|
|
{178, 2732695.5}, /* 07 Oct 2769 */
|
|
{179, 2749852.5}, /* 27 Sep 2816 */
|
|
{180, 2753839.5}, /* 28 Aug 2827 */
|
|
};
|
|
|
|
/* Computes geographic location and type of solar eclipse
|
|
* for a given tjd
|
|
* iflag: to indicate ephemeris to be used
|
|
* (SEFLG_JPLEPH, SEFLG_SWIEPH, SEFLG_MOSEPH)
|
|
*
|
|
* Algorithms for the central line is taken from Montenbruck, pp. 179ff.,
|
|
* with the exception, that we consider refraction for the maxima of
|
|
* partial and noncentral eclipses.
|
|
* Geographical positions are referred to sea level / the mean ellipsoid.
|
|
*
|
|
* Errors:
|
|
* - from uncertainty of JPL-ephemerides (0.01 arcsec):
|
|
* about 40 meters
|
|
* - from displacement of shadow points by atmospheric refraction:
|
|
* a few meters
|
|
* - from deviation of the geoid from the ellipsoid
|
|
* a few meters
|
|
* - from polar motion
|
|
* a few meters
|
|
* For geographical locations that are interesting for observation,
|
|
* the error is always < 100 m.
|
|
* However, if the sun is close to the horizon,
|
|
* all of these errors can grow up to a km or more.
|
|
*
|
|
* Function returns:
|
|
* -1 (ERR) on error (e.g. if swe_calc() for sun or moon fails)
|
|
* 0 if there is no solar eclipse at tjd
|
|
* SE_ECL_TOTAL
|
|
* SE_ECL_ANNULAR
|
|
* SE_ECL_TOTAL | SE_ECL_CENTRAL
|
|
* SE_ECL_TOTAL | SE_ECL_NONCENTRAL
|
|
* SE_ECL_ANNULAR | SE_ECL_CENTRAL
|
|
* SE_ECL_ANNULAR | SE_ECL_NONCENTRAL
|
|
* SE_ECL_PARTIAL
|
|
*
|
|
* geopos[0]: geographic longitude of central line
|
|
* geopos[1]: geographic latitude of central line
|
|
*
|
|
* not implemented so far:
|
|
*
|
|
* geopos[2]: geographic longitude of northern limit of umbra
|
|
* geopos[3]: geographic latitude of northern limit of umbra
|
|
* geopos[4]: geographic longitude of southern limit of umbra
|
|
* geopos[5]: geographic latitude of southern limit of umbra
|
|
* geopos[6]: geographic longitude of northern limit of penumbra
|
|
* geopos[7]: geographic latitude of northern limit of penumbra
|
|
* geopos[8]: geographic longitude of southern limit of penumbra
|
|
* geopos[9]: geographic latitude of southern limit of penumbra
|
|
*
|
|
* Attention: "northern" and "southern" limits of umbra do not
|
|
* necessarily correspond to the northernmost or southernmost
|
|
* geographic position, where the total, annular, or partial
|
|
* phase is visible at a given time.
|
|
* Imagine a situation in northern summer, when the sun illuminates
|
|
* the northern polar circle. The southernmost point of the core
|
|
* shadow may then touch the north pole, and therefore the
|
|
* northernmost point will be more in the south.
|
|
* Note also that with annular eclipses, the northern edge is
|
|
* usually geographically the southern one. With annular-total
|
|
* ones, the two lines cross, usually twice. The maximum is always
|
|
* total in such cases.
|
|
*
|
|
* attr[0] fraction of solar diameter covered by moon (magnitude)
|
|
* attr[1] ratio of lunar diameter to solar one
|
|
* attr[2] fraction of solar disc covered by moon (obscuration)
|
|
* attr[3] diameter of core shadow in km
|
|
* attr[4] azimuth of sun at tjd
|
|
* attr[5] true altitude of sun above horizon at tjd
|
|
* attr[6] apparent altitude of sun above horizon at tjd
|
|
* attr[7] angular distance of moon from sun in degrees
|
|
* declare as attr[20] at least !
|
|
*/
|
|
int32 FAR PASCAL_CONV
|
|
swe_sol_eclipse_where(double tjd_ut, int32 ifl, double *geopos, double *attr,
|
|
char *serr)
|
|
{
|
|
int32 retflag, retflag2;
|
|
double dcore[10];
|
|
ifl &= SEFLG_EPHMASK;
|
|
if ((retflag =
|
|
eclipse_where(tjd_ut, SE_SUN, NULL, ifl, geopos, dcore, serr)) < 0)
|
|
return retflag;
|
|
if ((retflag2 =
|
|
eclipse_how(tjd_ut, SE_SUN, NULL, ifl, geopos[0], geopos[1], 0, attr,
|
|
serr)) == ERR)
|
|
return retflag2;
|
|
attr[3] = dcore[0];
|
|
return retflag;
|
|
}
|
|
|
|
int32 FAR PASCAL_CONV
|
|
swe_lun_occult_where(double tjd_ut, int32 ipl, char *starname, int32 ifl,
|
|
double *geopos, double *attr, char *serr)
|
|
{
|
|
int32 retflag, retflag2;
|
|
double dcore[10];
|
|
ifl &= SEFLG_EPHMASK;
|
|
/* function calls for Pluto with asteroid number 134340
|
|
* are treated as calls for Pluto as main body SE_PLUTO */
|
|
if (ipl == SE_AST_OFFSET + 134340)
|
|
ipl = SE_PLUTO;
|
|
if ((retflag =
|
|
eclipse_where(tjd_ut, ipl, starname, ifl, geopos, dcore, serr)) < 0)
|
|
return retflag;
|
|
if ((retflag2 =
|
|
eclipse_how(tjd_ut, ipl, starname, ifl, geopos[0], geopos[1], 0,
|
|
attr, serr)) == ERR)
|
|
return retflag2;
|
|
attr[3] = dcore[0];
|
|
return retflag;
|
|
}
|
|
|
|
/* Used by several swe_sol_eclipse_ functions.
|
|
* Like swe_sol_eclipse_where(), but instead of attr[0], it returns:
|
|
*
|
|
* dcore[0]: core shadow width in km
|
|
* dcore[2]: distance of shadow axis from geocenter r0
|
|
* dcore[3]: diameter of core shadow on fundamental plane d0
|
|
* dcore[4]: diameter of half-shadow on fundamental plane D0
|
|
*/
|
|
static int32
|
|
eclipse_where(double tjd_ut, int32 ipl, char *starname, int32 ifl,
|
|
double *geopos, double *dcore, char *serr)
|
|
{
|
|
int i;
|
|
int32 retc = 0, niter = 0;
|
|
double e[6], et[6], rm[6], rs[6], rmt[6], rst[6], xs[6], xst[6];
|
|
#if 0
|
|
double erm[6];
|
|
#endif
|
|
double x[6];
|
|
double lm[6], ls[6], lx[6];
|
|
double dsm, dsmt, d0, D0, s0, r0, d, s, dm;
|
|
double de = 6378140.0 / AUNIT;
|
|
double earthobl = 1 - EARTH_OBLATENESS;
|
|
double deltat, tjd, sidt;
|
|
double drad;
|
|
double sinf1, sinf2, cosf1, cosf2;
|
|
double rmoon = RMOON;
|
|
double dmoon = 2 * rmoon;
|
|
int32 iflag, iflag2;
|
|
/* double ecce = sqrt(2 * EARTH_OBLATENESS - EARTH_OBLATENESS * EARTH_OBLATENESS); */
|
|
AS_BOOL no_eclipse = FALSE;
|
|
struct epsilon *oe = &swed.oec;
|
|
for (i = 0; i < 10; i++)
|
|
dcore[i] = 0;
|
|
/* nutation need not be in lunar and solar positions,
|
|
* if mean sidereal time will be used */
|
|
iflag = SEFLG_SPEED | SEFLG_EQUATORIAL | ifl;
|
|
iflag2 = iflag | SEFLG_RADIANS;
|
|
iflag = iflag | SEFLG_XYZ;
|
|
deltat = swe_deltat(tjd_ut);
|
|
tjd = tjd_ut + deltat;
|
|
/* moon in cartesian coordinates */
|
|
if ((retc = swe_calc(tjd, SE_MOON, iflag, rm, serr)) == ERR)
|
|
return retc;
|
|
/* moon in polar coordinates */
|
|
if ((retc = swe_calc(tjd, SE_MOON, iflag2, lm, serr)) == ERR)
|
|
return retc;
|
|
/* sun in cartesian coordinates */
|
|
if ((retc = calc_planet_star(tjd, ipl, starname, iflag, rs, serr)) == ERR)
|
|
return retc;
|
|
/* sun in polar coordinates */
|
|
if ((retc =
|
|
calc_planet_star(tjd, ipl, starname, iflag2, ls, serr)) == ERR)
|
|
return retc;
|
|
/* save sun position */
|
|
for (i = 0; i <= 2; i++)
|
|
rst[i] = rs[i];
|
|
/* save moon position */
|
|
for (i = 0; i <= 2; i++)
|
|
rmt[i] = rm[i];
|
|
if (iflag & SEFLG_NONUT)
|
|
sidt = swe_sidtime0(tjd_ut, oe->eps * RADTODEG, 0) * 15 * DEGTORAD;
|
|
else
|
|
sidt = swe_sidtime(tjd_ut) * 15 * DEGTORAD;
|
|
/*
|
|
* radius of planet disk in AU
|
|
*/
|
|
if (starname != NULL && *starname != '\0')
|
|
drad = 0;
|
|
else if (ipl < NDIAM)
|
|
drad = pla_diam[ipl] / 2 / AUNIT;
|
|
else if (ipl > SE_AST_OFFSET)
|
|
drad = swed.ast_diam / 2 * 1000 / AUNIT; /* km -> m -> AU */
|
|
else
|
|
drad = 0;
|
|
iter_where:
|
|
for (i = 0; i <= 2; i++) {
|
|
rs[i] = rst[i];
|
|
rm[i] = rmt[i];
|
|
}
|
|
/* Account for oblateness of earth:
|
|
* Instead of flattening the earth, we apply the
|
|
* correction to the z coordinate of the moon and
|
|
* the sun. This makes the calculation easier.
|
|
*/
|
|
for (i = 0; i <= 2; i++)
|
|
lx[i] = lm[i];
|
|
swi_polcart(lx, rm);
|
|
rm[2] /= earthobl;
|
|
/* distance of moon from geocenter */
|
|
dm = sqrt(square_sum(rm));
|
|
/* Account for oblateness of earth */
|
|
for (i = 0; i <= 2; i++)
|
|
lx[i] = ls[i];
|
|
swi_polcart(lx, rs);
|
|
rs[2] /= earthobl;
|
|
/* sun - moon vector */
|
|
for (i = 0; i <= 2; i++) {
|
|
e[i] = (rm[i] - rs[i]);
|
|
et[i] = (rmt[i] - rst[i]);
|
|
}
|
|
/* distance sun - moon */
|
|
dsm = sqrt(square_sum(e));
|
|
dsmt = sqrt(square_sum(et));
|
|
/* sun - moon unit vector */
|
|
for (i = 0; i <= 2; i++) {
|
|
e[i] /= dsm;
|
|
et[i] /= dsmt;
|
|
#if 0
|
|
erm[i] = rm[i] / dm;
|
|
#endif
|
|
}
|
|
sinf1 = ((drad - rmoon) / dsm);
|
|
cosf1 = sqrt(1 - sinf1 * sinf1);
|
|
sinf2 = ((drad + rmoon) / dsm);
|
|
cosf2 = sqrt(1 - sinf2 * sinf2);
|
|
/* distance of moon from fundamental plane */
|
|
s0 = -dot_prod(rm, e);
|
|
/* distance of shadow axis from geocenter */
|
|
r0 = sqrt(dm * dm - s0 * s0);
|
|
/* diameter of core shadow on fundamental plane */
|
|
d0 = (s0 / dsm * (drad * 2 - dmoon) - dmoon) / cosf1;
|
|
/* diameter of half-shadow on fundamental plane */
|
|
D0 = (s0 / dsm * (drad * 2 + dmoon) + dmoon) / cosf2;
|
|
dcore[2] = r0;
|
|
dcore[3] = d0;
|
|
dcore[4] = D0;
|
|
dcore[5] = cosf1;
|
|
dcore[6] = cosf2;
|
|
for (i = 2; i < 5; i++)
|
|
dcore[i] *= AUNIT / 1000.0;
|
|
|
|
/**************************
|
|
* central (total or annular) phase
|
|
**************************/
|
|
retc = 0;
|
|
if (de * cosf1 >= r0) {
|
|
retc |= SE_ECL_CENTRAL;
|
|
}
|
|
else if (r0 <= de * cosf1 + fabs(d0) / 2) {
|
|
retc |= SE_ECL_NONCENTRAL;
|
|
}
|
|
else if (r0 <= de * cosf2 + D0 / 2) {
|
|
retc |= (SE_ECL_PARTIAL | SE_ECL_NONCENTRAL);
|
|
}
|
|
else {
|
|
if (serr != NULL)
|
|
sprintf(serr, "no solar eclipse at tjd = %f", tjd);
|
|
for (i = 0; i < 10; i++)
|
|
geopos[i] = 0;
|
|
*dcore = 0;
|
|
retc = 0;
|
|
d = 0;
|
|
no_eclipse = TRUE;
|
|
/*return retc; */
|
|
}
|
|
/* distance of shadow point from fundamental plane */
|
|
d = s0 * s0 + de * de - dm * dm;
|
|
if (d > 0)
|
|
d = sqrt(d);
|
|
else
|
|
d = 0;
|
|
/* distance of moon from shadow point on earth */
|
|
s = s0 - d;
|
|
/* next: geographic position of eclipse center.
|
|
* if shadow axis does not touch the earth,
|
|
* place on earth with maximum occultation is computed.
|
|
*/
|
|
#if 0 /* the following stuff is meaningless for observations */
|
|
/*
|
|
* account for refraction at horizon
|
|
*/
|
|
if (d == 0) {
|
|
double ds, a, b;
|
|
/* distance of sun from geocenter */
|
|
ds = sqrt(square_sum(rs));
|
|
a = PI - acos(swi_dot_prod_unit(e, erm));
|
|
/* refraction at horizon + sun radius = about 0.83 degrees */
|
|
b = 34.4556 / 60.0 * DEGTORAD + asin(drad / ds);
|
|
#if 0
|
|
/* at edge of umbra and penumbra
|
|
* light rays are not parallel to shadow axis.
|
|
* for a short time close to contact of umbra and
|
|
* penumbra, an angle < 0.27 degrees would have
|
|
* to be subtracted from b;
|
|
*/
|
|
if (retc & SE_ECL_PARTIAL) {
|
|
d = d0;
|
|
sinf = sinf1;
|
|
}
|
|
else {
|
|
d = D0;
|
|
sinf = sinf2;
|
|
}
|
|
c = (r0 - de) / d * 2 * sinf;
|
|
if (c > sinf1) {
|
|
b -= .....;
|
|
}
|
|
printf("%f %f %f", a * RADTODEG, b * RADTODEG, s);
|
|
printf(" %f\n", s);
|
|
#else
|
|
if (retc & SE_ECL_PARTIAL)
|
|
b -= asin(sinf2); /* maximum! */
|
|
else
|
|
b -= asin(sinf1);
|
|
#endif
|
|
s += tan(b) * cos(PI / 2 - a) * dm;
|
|
}
|
|
#endif
|
|
/* geographic position of eclipse center (maximum) */
|
|
for (i = 0; i <= 2; i++)
|
|
xs[i] = rm[i] + s * e[i];
|
|
/* we need geographic position with correct z, as well */
|
|
for (i = 0; i <= 2; i++)
|
|
xst[i] = xs[i];
|
|
xst[2] *= earthobl;
|
|
swi_cartpol(xst, xst);
|
|
if (niter <= 0) {
|
|
double cosfi = cos(xst[1]);
|
|
double sinfi = sin(xst[1]);
|
|
double eobl = EARTH_OBLATENESS;
|
|
double cc =
|
|
1 / sqrt(cosfi * cosfi + (1 - eobl) * (1 - eobl) * sinfi * sinfi);
|
|
double ss = (1 - eobl) * (1 - eobl) * cc;
|
|
earthobl = ss;
|
|
niter++;
|
|
goto iter_where;
|
|
}
|
|
swi_polcart(xst, xst);
|
|
/* to longitude and latitude */
|
|
swi_cartpol(xs, xs);
|
|
/* measure from sidereal time at greenwich */
|
|
xs[0] -= sidt;
|
|
xs[0] *= RADTODEG;
|
|
xs[1] *= RADTODEG;
|
|
xs[0] = swe_degnorm(xs[0]);
|
|
/* west is negative */
|
|
if (xs[0] > 180)
|
|
xs[0] -= 360;
|
|
geopos[0] = xs[0];
|
|
geopos[1] = xs[1];
|
|
/* diameter of core shadow:
|
|
* first, distance moon - place of eclipse on earth */
|
|
for (i = 0; i <= 2; i++)
|
|
x[i] = rmt[i] - xst[i];
|
|
s = sqrt(square_sum(x));
|
|
/* diameter of core shadow at place of maximum eclipse */
|
|
*dcore = (s / dsmt * (drad * 2 - dmoon) - dmoon) * cosf1;
|
|
*dcore *= AUNIT / 1000.0;
|
|
/* diameter of penumbra at place of maximum eclipse */
|
|
dcore[1] = (s / dsmt * (drad * 2 + dmoon) + dmoon) * cosf2;
|
|
dcore[1] *= AUNIT / 1000.0;
|
|
if (!(retc & SE_ECL_PARTIAL) && !no_eclipse) {
|
|
if (*dcore > 0) {
|
|
/*printf("annular\n"); */
|
|
retc |= SE_ECL_ANNULAR;
|
|
}
|
|
else {
|
|
/*printf("total\n"); */
|
|
retc |= SE_ECL_TOTAL;
|
|
}
|
|
}
|
|
return retc;
|
|
}
|
|
|
|
static int32
|
|
calc_planet_star(double tjd_et, int32 ipl, char *starname, int32 iflag,
|
|
double *x, char *serr)
|
|
{
|
|
int i;
|
|
int retc = OK;
|
|
if (starname == NULL || *starname == '\0') {
|
|
retc = swe_calc(tjd_et, ipl, iflag, x, serr);
|
|
}
|
|
else {
|
|
if ((retc = swe_fixstar(starname, tjd_et, iflag, x, serr)) == OK) {
|
|
/* fixstars have the standard distance 1.
|
|
* in the occultation routines, this might lead to errors
|
|
* if interpreted as AU distance. To avoid this, we make it very high.
|
|
*/
|
|
if (iflag & SEFLG_XYZ) {
|
|
for (i = 0; i < 3; i++)
|
|
x[i] *= 100000000;
|
|
}
|
|
else {
|
|
x[2] *= 100000000;
|
|
}
|
|
}
|
|
}
|
|
return retc;
|
|
}
|
|
|
|
/* Computes attributes of a solar eclipse for given tjd, geo. longitude,
|
|
* geo. latitude, and geo. height.
|
|
*
|
|
* retflag SE_ECL_TOTAL or SE_ECL_ANNULAR or SE_ECL_PARTIAL
|
|
* SE_ECL_NONCENTRAL
|
|
* if 0, no eclipse is visible at geogr. position.
|
|
*
|
|
* attr[0] fraction of solar diameter covered by moon;
|
|
* with total/annular eclipses, it results in magnitude acc. to IMCCE.
|
|
* attr[1] ratio of lunar diameter to solar one
|
|
* attr[2] fraction of solar disc covered by moon (obscuration)
|
|
* attr[3] diameter of core shadow in km
|
|
* attr[4] azimuth of sun at tjd
|
|
* attr[5] true altitude of sun above horizon at tjd
|
|
* attr[6] apparent altitude of sun above horizon at tjd
|
|
* attr[7] elongation of moon in degrees
|
|
* attr[8] magnitude acc. to NASA;
|
|
* = attr[0] for partial and attr[1] for annular and total eclipses
|
|
* attr[9] saros series number
|
|
* attr[10] saros series member number
|
|
* declare as attr[20] at least !
|
|
*
|
|
*/
|
|
int32 FAR PASCAL_CONV
|
|
swe_sol_eclipse_how(double tjd_ut, int32 ifl, double *geopos, double *attr,
|
|
char *serr)
|
|
{
|
|
int32 retflag, retflag2;
|
|
double dcore[10], ls[6], xaz[6];
|
|
double geopos2[20];
|
|
ifl &= SEFLG_EPHMASK;
|
|
if ((retflag =
|
|
eclipse_how(tjd_ut, SE_SUN, NULL, ifl, geopos[0], geopos[1],
|
|
geopos[2], attr, serr)) == ERR)
|
|
return retflag;
|
|
if ((retflag2 =
|
|
eclipse_where(tjd_ut, SE_SUN, NULL, ifl, geopos2, dcore,
|
|
serr)) == ERR)
|
|
return retflag2;
|
|
if (retflag)
|
|
retflag |= (retflag2 & (SE_ECL_CENTRAL | SE_ECL_NONCENTRAL));
|
|
attr[3] = dcore[0];
|
|
swe_set_topo(geopos[0], geopos[1], geopos[2]);
|
|
if (swe_calc_ut
|
|
(tjd_ut, SE_SUN, ifl | SEFLG_TOPOCTR | SEFLG_EQUATORIAL, ls,
|
|
serr) == ERR)
|
|
return ERR;
|
|
swe_azalt(tjd_ut, SE_EQU2HOR, geopos, 0, 10, ls, xaz);
|
|
attr[4] = xaz[0];
|
|
attr[5] = xaz[1];
|
|
attr[6] = xaz[2];
|
|
if (xaz[2] <= 0)
|
|
retflag = 0;
|
|
return retflag;
|
|
}
|
|
|
|
#define USE_AZ_NAV 0
|
|
static int32
|
|
eclipse_how(double tjd_ut, int32 ipl, char *starname, int32 ifl,
|
|
double geolon, double geolat, double geohgt, double *attr,
|
|
char *serr)
|
|
{
|
|
int i, j, k;
|
|
int32 retc = 0;
|
|
double te, d;
|
|
double xs[6], xm[6], ls[6], lm[6], x1[6], x2[6];
|
|
double rmoon, rsun, rsplusrm, rsminusrm;
|
|
double dctr;
|
|
double drad;
|
|
int32 iflag = SEFLG_EQUATORIAL | SEFLG_TOPOCTR | ifl;
|
|
int32 iflagcart = iflag | SEFLG_XYZ;
|
|
#if USE_AZ_NAV
|
|
double mdd, eps, sidt, armc;
|
|
#endif
|
|
double xh[6], hmin_appr;
|
|
double lsun, lmoon, lctr, lsunleft, a, b, sc1, sc2;
|
|
double geopos[3];
|
|
for (i = 0; i < 10; i++)
|
|
attr[i] = 0;
|
|
geopos[0] = geolon;
|
|
geopos[1] = geolat;
|
|
geopos[2] = geohgt;
|
|
te = tjd_ut + swe_deltat(tjd_ut);
|
|
swe_set_topo(geolon, geolat, geohgt);
|
|
if (calc_planet_star(te, ipl, starname, iflag, ls, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(te, SE_MOON, iflag, lm, serr) == ERR)
|
|
return ERR;
|
|
if (calc_planet_star(te, ipl, starname, iflagcart, xs, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(te, SE_MOON, iflagcart, xm, serr) == ERR)
|
|
return ERR;
|
|
/*
|
|
* radius of planet disk in AU
|
|
*/
|
|
if (starname != NULL && *starname != '\0')
|
|
drad = 0;
|
|
else if (ipl < NDIAM)
|
|
drad = pla_diam[ipl] / 2 / AUNIT;
|
|
else if (ipl > SE_AST_OFFSET)
|
|
drad = swed.ast_diam / 2 * 1000 / AUNIT; /* km -> m -> AU */
|
|
else
|
|
drad = 0;
|
|
/*
|
|
* azimuth and altitude of sun or planet
|
|
*/
|
|
#if USE_AZ_NAV /* old */
|
|
eps = swi_epsiln(te);
|
|
if (iflag & SEFLG_NONUT)
|
|
sidt = swe_sidtime0(tjd_ut, eps * RADTODEG, 0) * 15;
|
|
else
|
|
sidt = swe_sidtime(tjd_ut) * 15;
|
|
armc = sidt + geolon;
|
|
mdd = swe_degnorm(ls[0] - armc);
|
|
xh[0] = swe_degnorm(mdd - 90);
|
|
xh[1] = ls[1];
|
|
xh[2] = ls[2];
|
|
swe_cotrans(xh, xh, 90 - geolat); /* azimuth from east, counterclock, via north */
|
|
#else
|
|
swe_azalt(tjd_ut, SE_EQU2HOR, geopos, 0, 10, ls, xh); /* azimuth from south, clockwise, via west */
|
|
#endif
|
|
/* eclipse description */
|
|
rmoon = asin(RMOON / lm[2]) * RADTODEG;
|
|
rsun = asin(drad / ls[2]) * RADTODEG;
|
|
rsplusrm = rsun + rmoon;
|
|
rsminusrm = rsun - rmoon;
|
|
for (i = 0; i < 3; i++) {
|
|
x1[i] = xs[i] / ls[2];
|
|
x2[i] = xm[i] / lm[2];
|
|
}
|
|
dctr = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
|
|
/*
|
|
* phase
|
|
*/
|
|
if (dctr < rsminusrm)
|
|
retc = SE_ECL_ANNULAR;
|
|
else if (dctr < fabs(rsminusrm))
|
|
retc = SE_ECL_TOTAL;
|
|
else if (dctr < rsplusrm)
|
|
retc = SE_ECL_PARTIAL;
|
|
else {
|
|
retc = 0;
|
|
if (serr != NULL)
|
|
sprintf(serr, "no solar eclipse at tjd = %f", tjd_ut);
|
|
}
|
|
/*
|
|
* ratio of diameter of moon to that of sun
|
|
*/
|
|
if (rsun > 0)
|
|
attr[1] = rmoon / rsun;
|
|
else
|
|
attr[1] = 0;
|
|
/*
|
|
* eclipse magnitude:
|
|
* fraction of solar diameter covered by moon
|
|
*/
|
|
lsun = asin(rsun / 2 * DEGTORAD) * 2;
|
|
lsunleft = (-dctr + rsun + rmoon);
|
|
if (lsun > 0) {
|
|
attr[0] = lsunleft / rsun / 2;
|
|
}
|
|
else {
|
|
attr[0] = 100;
|
|
}
|
|
/*if (retc == SE_ECL_ANNULAR || retc == SE_ECL_TOTAL)
|
|
* attr[0] = attr[1]; */
|
|
/*
|
|
* obscuration:
|
|
* fraction of solar disc obscured by moon
|
|
*/
|
|
lsun = rsun;
|
|
lmoon = rmoon;
|
|
lctr = dctr;
|
|
if (retc == 0 || lsun == 0) {
|
|
attr[2] = 100;
|
|
}
|
|
else if (retc == SE_ECL_TOTAL || retc == SE_ECL_ANNULAR) {
|
|
attr[2] = lmoon * lmoon / lsun / lsun;
|
|
}
|
|
else {
|
|
a = 2 * lctr * lmoon;
|
|
b = 2 * lctr * lsun;
|
|
if (a < 1e-9) {
|
|
attr[2] = lmoon * lmoon / lsun / lsun;
|
|
}
|
|
else {
|
|
a = (lctr * lctr + lmoon * lmoon - lsun * lsun) / a;
|
|
if (a > 1)
|
|
a = 1;
|
|
if (a < -1)
|
|
a = -1;
|
|
b = (lctr * lctr + lsun * lsun - lmoon * lmoon) / b;
|
|
if (b > 1)
|
|
b = 1;
|
|
if (b < -1)
|
|
b = -1;
|
|
a = acos(a);
|
|
b = acos(b);
|
|
sc1 = a * lmoon * lmoon / 2;
|
|
sc2 = b * lsun * lsun / 2;
|
|
sc1 -= (cos(a) * sin(a)) * lmoon * lmoon / 2;
|
|
sc2 -= (cos(b) * sin(b)) * lsun * lsun / 2;
|
|
attr[2] = (sc1 + sc2) * 2 / PI / lsun / lsun;
|
|
}
|
|
}
|
|
attr[7] = dctr;
|
|
/* approximate minimum height for visibility, considering
|
|
* refraction and dip
|
|
* 34.4556': refraction at horizon, from Bennets formulae
|
|
* 1.75' / sqrt(geohgt): dip of horizon
|
|
* 0.37' / sqrt(geohgt): refraction between horizon and observer */
|
|
hmin_appr = -(34.4556 + (1.75 + 0.37) * sqrt(geohgt)) / 60;
|
|
if (xh[1] + rsun + fabs(hmin_appr) >= 0 && retc)
|
|
retc |= SE_ECL_VISIBLE; /* eclipse visible */
|
|
#if USE_AZ_NAV /* old */
|
|
attr[4] = swe_degnorm(90 - xh[0]); /* azimuth, from north, clockwise, via east */
|
|
#else
|
|
attr[4] = xh[0]; /* azimuth, from south, clockwise, via west */
|
|
#endif
|
|
attr[5] = xh[1]; /* height */
|
|
attr[6] = xh[2]; /* height */
|
|
if (ipl == SE_SUN && (starname == NULL || *starname == '\0')) {
|
|
/* magnitude of solar eclipse according to NASA */
|
|
attr[8] = attr[0]; /* fraction of diameter occulted */
|
|
if (retc & (SE_ECL_TOTAL | SE_ECL_ANNULAR))
|
|
attr[8] = attr[1]; /* ratio between diameters of sun and moon */
|
|
/* saros series and member */
|
|
for (i = 0; i < NSAROS_SOLAR; i++) {
|
|
d = (tjd_ut - saros_data_solar[i].tstart) / SAROS_CYCLE;
|
|
if (d < 0)
|
|
continue;
|
|
j = (int)d;
|
|
if ((d - j) * SAROS_CYCLE < 2) {
|
|
attr[9] = (double)saros_data_solar[i].series_no;
|
|
attr[10] = (double)j + 1;
|
|
break;
|
|
}
|
|
k = j + 1;
|
|
if ((k - d) * SAROS_CYCLE < 2) {
|
|
attr[9] = (double)saros_data_solar[i].series_no;
|
|
attr[10] = (double)k + 1;
|
|
break;
|
|
}
|
|
}
|
|
if (i == NSAROS_SOLAR) {
|
|
attr[9] = attr[10] = -99999999;
|
|
}
|
|
}
|
|
return retc;
|
|
}
|
|
|
|
/* When is the next solar eclipse anywhere on earth?
|
|
*
|
|
* input parameters:
|
|
*
|
|
* tjd_start start time for search (UT)
|
|
* ifl ephemeris to be used (SEFLG_SWIEPH, etc.)
|
|
* ifltype eclipse type to be searched (SE_ECL_TOTAL, etc.)
|
|
* 0, if any type of eclipse is wanted
|
|
*
|
|
* return values:
|
|
*
|
|
* retflag SE_ECL_TOTAL or SE_ECL_ANNULAR or SE_ECL_PARTIAL
|
|
* or SE_ECL_ANNULAR_TOTAL
|
|
* SE_ECL_CENTRAL
|
|
* SE_ECL_NONCENTRAL
|
|
*
|
|
* tret[0] time of maximum eclipse
|
|
* tret[1] time, when eclipse takes place at local apparent noon
|
|
* tret[2] time of eclipse begin
|
|
* tret[3] time of eclipse end
|
|
* tret[4] time of totality begin
|
|
* tret[5] time of totality end
|
|
* tret[6] time of center line begin
|
|
* tret[7] time of center line end
|
|
* tret[8] time when annular-total eclipse becomes total
|
|
* not implemented so far
|
|
* tret[9] time when annular-total eclipse becomes annular again
|
|
* not implemented so far
|
|
* declare as tret[10] at least!
|
|
*
|
|
*/
|
|
int32 FAR PASCAL_CONV
|
|
swe_sol_eclipse_when_glob(double tjd_start, int32 ifl, int32 ifltype,
|
|
double *tret, int32 backward, char *serr)
|
|
{
|
|
int i, j, k, m, n, o, i1 = 0, i2 = 0;
|
|
int32 retflag = 0, retflag2 = 0;
|
|
double de = 6378.140, a;
|
|
double t, tt, tjd, tjds, dt, dtint, dta, dtb;
|
|
double T, T2, T3, T4, K, M, Mm;
|
|
double E, Ff;
|
|
double xs[6], xm[6], ls[6], lm[6];
|
|
double rmoon, rsun, dcore[10];
|
|
double dc[3], dctr;
|
|
double twohr = 2.0 / 24.0;
|
|
double tenmin = 10.0 / 24.0 / 60.0;
|
|
double dt1, dt2;
|
|
double geopos[20], attr[20];
|
|
double dtstart, dtdiv;
|
|
double xa[6], xb[6];
|
|
int direction = 1;
|
|
AS_BOOL dont_times = FALSE;
|
|
int32 iflag, iflagcart;
|
|
ifl &= SEFLG_EPHMASK;
|
|
iflag = SEFLG_EQUATORIAL | ifl;
|
|
iflagcart = iflag | SEFLG_XYZ;
|
|
if (ifltype == (SE_ECL_PARTIAL | SE_ECL_CENTRAL)) {
|
|
if (serr != NULL)
|
|
strcpy(serr, "central partial eclipses do not exist");
|
|
return ERR;
|
|
}
|
|
if (ifltype == 0)
|
|
ifltype =
|
|
SE_ECL_TOTAL | SE_ECL_ANNULAR | SE_ECL_PARTIAL |
|
|
SE_ECL_ANNULAR_TOTAL | SE_ECL_NONCENTRAL | SE_ECL_CENTRAL;
|
|
if (backward)
|
|
direction = -1;
|
|
K = (int)((tjd_start - J2000) / 365.2425 * 12.3685);
|
|
K -= direction;
|
|
next_try:
|
|
retflag = 0;
|
|
dont_times = FALSE;
|
|
for (i = 0; i <= 9; i++)
|
|
tret[i] = 0;
|
|
T = K / 1236.85;
|
|
T2 = T * T;
|
|
T3 = T2 * T;
|
|
T4 = T3 * T;
|
|
Ff = swe_degnorm(160.7108 + 390.67050274 * K - 0.0016341 * T2 -
|
|
0.00000227 * T3 + 0.000000011 * T4);
|
|
if (Ff > 180)
|
|
Ff -= 180;
|
|
if (Ff > 21 && Ff < 159) { /* no eclipse possible */
|
|
K += direction;
|
|
goto next_try;
|
|
}
|
|
/* approximate time of geocentric maximum eclipse
|
|
* formula from Meeus, German, p. 381 */
|
|
tjd =
|
|
2451550.09765 + 29.530588853 * K + 0.0001337 * T2 - 0.000000150 * T3 +
|
|
0.00000000073 * T4;
|
|
M = swe_degnorm(2.5534 + 29.10535669 * K - 0.0000218 * T2 -
|
|
0.00000011 * T3);
|
|
Mm = swe_degnorm(201.5643 + 385.81693528 * K + 0.1017438 * T2 +
|
|
0.00001239 * T3 + 0.000000058 * T4);
|
|
E = 1 - 0.002516 * T - 0.0000074 * T2;
|
|
M *= DEGTORAD;
|
|
Mm *= DEGTORAD;
|
|
tjd = tjd - 0.4075 * sin(Mm)
|
|
+ 0.1721 * E * sin(M);
|
|
/*
|
|
* time of maximum eclipse (if eclipse) =
|
|
* minimum geocentric angle between sun and moon edges.
|
|
* After this time has been determined, check
|
|
* whether or not an eclipse is taking place with
|
|
* the functions eclipse_where() and _how().
|
|
*/
|
|
dtstart = 1;
|
|
if (tjd < 2000000)
|
|
dtstart = 5;
|
|
dtdiv = 4;
|
|
for (dt = dtstart; dt > 0.0001; dt /= dtdiv) {
|
|
for (i = 0, t = tjd - dt; i <= 2; i++, t += dt) {
|
|
if (swe_calc(t, SE_SUN, iflag, ls, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(t, SE_MOON, iflag, lm, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(t, SE_SUN, iflagcart, xs, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(t, SE_MOON, iflagcart, xm, serr) == ERR)
|
|
return ERR;
|
|
for (m = 0; m < 3; m++) {
|
|
xa[m] = xs[m] / ls[2];
|
|
xb[m] = xm[m] / lm[2];
|
|
}
|
|
dc[i] = acos(swi_dot_prod_unit(xa, xb)) * RADTODEG;
|
|
rmoon = asin(RMOON / lm[2]) * RADTODEG;
|
|
rsun = asin(RSUN / ls[2]) * RADTODEG;
|
|
dc[i] -= (rmoon + rsun);
|
|
}
|
|
find_maximum(dc[0], dc[1], dc[2], dt, &dtint, &dctr);
|
|
tjd += dtint + dt;
|
|
}
|
|
tjds = tjd = tjd - swe_deltat(tjd);
|
|
if ((retflag =
|
|
eclipse_where(tjd, SE_SUN, NULL, ifl, geopos, dcore, serr)) == ERR)
|
|
return retflag;
|
|
retflag2 = retflag;
|
|
/* in extreme cases _where() returns no eclipse, where there is
|
|
* actually a very small one, therefore call _how() with the
|
|
* coordinates returned by _where(): */
|
|
if ((retflag2 =
|
|
eclipse_how(tjd, SE_SUN, NULL, ifl, geopos[0], geopos[1], 0, attr,
|
|
serr)) == ERR)
|
|
return retflag2;
|
|
if (retflag2 == 0) {
|
|
K += direction;
|
|
goto next_try;
|
|
}
|
|
tret[0] = tjd;
|
|
if ((backward && tret[0] >= tjd_start - 0.0001)
|
|
|| (!backward && tret[0] <= tjd_start + 0.0001)) {
|
|
K += direction;
|
|
goto next_try;
|
|
}
|
|
/*
|
|
* eclipse type, SE_ECL_TOTAL, _ANNULAR, etc.
|
|
* SE_ECL_ANNULAR_TOTAL will be discovered later
|
|
*/
|
|
if ((retflag =
|
|
eclipse_where(tjd, SE_SUN, NULL, ifl, geopos, dcore, serr)) == ERR)
|
|
return retflag;
|
|
if (retflag == 0) { /* can happen with extremely small percentage */
|
|
retflag = SE_ECL_PARTIAL | SE_ECL_NONCENTRAL;
|
|
tret[4] = tret[5] = tjd; /* fix this ???? */
|
|
dont_times = TRUE;
|
|
}
|
|
/*
|
|
* check whether or not eclipse type found is wanted
|
|
*/
|
|
/* non central eclipse is wanted: */
|
|
if (!(ifltype & SE_ECL_NONCENTRAL) && (retflag & SE_ECL_NONCENTRAL)) {
|
|
K += direction;
|
|
goto next_try;
|
|
}
|
|
/* central eclipse is wanted: */
|
|
if (!(ifltype & SE_ECL_CENTRAL) && (retflag & SE_ECL_CENTRAL)) {
|
|
K += direction;
|
|
goto next_try;
|
|
}
|
|
/* non annular eclipse is wanted: */
|
|
if (!(ifltype & SE_ECL_ANNULAR) && (retflag & SE_ECL_ANNULAR)) {
|
|
K += direction;
|
|
goto next_try;
|
|
}
|
|
/* non partial eclipse is wanted: */
|
|
if (!(ifltype & SE_ECL_PARTIAL) && (retflag & SE_ECL_PARTIAL)) {
|
|
K += direction;
|
|
goto next_try;
|
|
}
|
|
/* annular-total eclipse will be discovered later */
|
|
if (!(ifltype & (SE_ECL_TOTAL | SE_ECL_ANNULAR_TOTAL))
|
|
&& (retflag & SE_ECL_TOTAL)) {
|
|
K += direction;
|
|
goto next_try;
|
|
}
|
|
if (dont_times)
|
|
goto end_search_global;
|
|
/*
|
|
* n = 0: times of eclipse begin and end
|
|
* n = 1: times of totality begin and end
|
|
* n = 2: times of center line begin and end
|
|
*/
|
|
if (retflag & SE_ECL_PARTIAL)
|
|
o = 0;
|
|
else if (retflag & SE_ECL_NONCENTRAL)
|
|
o = 1;
|
|
else
|
|
o = 2;
|
|
dta = twohr;
|
|
dtb = tenmin / 3.0;
|
|
for (n = 0; n <= o; n++) {
|
|
if (n == 0) {
|
|
/*dc[1] = dcore[3] / 2 + de - dcore[1]; */
|
|
i1 = 2;
|
|
i2 = 3;
|
|
}
|
|
else if (n == 1) {
|
|
if (retflag & SE_ECL_PARTIAL)
|
|
continue;
|
|
i1 = 4;
|
|
i2 = 5;
|
|
}
|
|
else if (n == 2) {
|
|
if (retflag & SE_ECL_NONCENTRAL)
|
|
continue;
|
|
i1 = 6;
|
|
i2 = 7;
|
|
}
|
|
for (i = 0, t = tjd - dta; i <= 2; i += 1, t += dta) {
|
|
if ((retflag2 =
|
|
eclipse_where(t, SE_SUN, NULL, ifl, geopos, dcore,
|
|
serr)) == ERR)
|
|
return retflag2;
|
|
if (n == 0)
|
|
dc[i] = dcore[4] / 2 + de / dcore[5] - dcore[2];
|
|
else if (n == 1)
|
|
dc[i] = fabs(dcore[3]) / 2 + de / dcore[6] - dcore[2];
|
|
else if (n == 2)
|
|
dc[i] = de / dcore[6] - dcore[2];
|
|
}
|
|
find_zero(dc[0], dc[1], dc[2], dta, &dt1, &dt2);
|
|
tret[i1] = tjd + dt1 + dta;
|
|
tret[i2] = tjd + dt2 + dta;
|
|
for (m = 0, dt = dtb; m < 3; m++, dt /= 3) {
|
|
for (j = i1; j <= i2; j += (i2 - i1)) {
|
|
for (i = 0, t = tret[j] - dt; i < 2; i++, t += dt) {
|
|
if ((retflag2 =
|
|
eclipse_where(t, SE_SUN, NULL, ifl, geopos, dcore,
|
|
serr)) == ERR)
|
|
return retflag2;
|
|
if (n == 0)
|
|
dc[i] = dcore[4] / 2 + de / dcore[5] - dcore[2];
|
|
else if (n == 1)
|
|
dc[i] = fabs(dcore[3]) / 2 + de / dcore[6] - dcore[2];
|
|
else if (n == 2)
|
|
dc[i] = de / dcore[6] - dcore[2];
|
|
}
|
|
dt1 = dc[1] / ((dc[1] - dc[0]) / dt);
|
|
tret[j] -= dt1;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* annular-total eclipses
|
|
*/
|
|
if (retflag & SE_ECL_TOTAL) {
|
|
if ((retflag2 =
|
|
eclipse_where(tret[0], SE_SUN, NULL, ifl, geopos, dcore,
|
|
serr)) == ERR)
|
|
return retflag2;
|
|
dc[0] = *dcore;
|
|
if ((retflag2 =
|
|
eclipse_where(tret[4], SE_SUN, NULL, ifl, geopos, dcore,
|
|
serr)) == ERR)
|
|
return retflag2;
|
|
dc[1] = *dcore;
|
|
if ((retflag2 =
|
|
eclipse_where(tret[5], SE_SUN, NULL, ifl, geopos, dcore,
|
|
serr)) == ERR)
|
|
return retflag2;
|
|
dc[2] = *dcore;
|
|
/* the maximum is always total, and there is either one or
|
|
* to times before and after, when the core shadow becomes
|
|
* zero and totality changes into annularity or vice versa.
|
|
*/
|
|
if (dc[0] * dc[1] < 0 || dc[0] * dc[2] < 0) {
|
|
retflag |= SE_ECL_ANNULAR_TOTAL;
|
|
retflag &= ~SE_ECL_TOTAL;
|
|
}
|
|
}
|
|
/* if eclipse is given but not wanted: */
|
|
if (!(ifltype & SE_ECL_TOTAL) && (retflag & SE_ECL_TOTAL)) {
|
|
K += direction;
|
|
goto next_try;
|
|
}
|
|
/* if annular_total eclipse is given but not wanted: */
|
|
if (!(ifltype & SE_ECL_ANNULAR_TOTAL) && (retflag & SE_ECL_ANNULAR_TOTAL)) {
|
|
K += direction;
|
|
goto next_try;
|
|
}
|
|
/*
|
|
* time of maximum eclipse at local apparent noon
|
|
*/
|
|
/* first, find out, if there is a solar transit
|
|
* between begin and end of eclipse */
|
|
k = 2;
|
|
for (i = 0; i < 2; i++) {
|
|
j = i + k;
|
|
tt = tret[j] + swe_deltat(tret[j]);
|
|
if (swe_calc(tt, SE_SUN, iflag, ls, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(tt, SE_MOON, iflag, lm, serr) == ERR)
|
|
return ERR;
|
|
dc[i] = swe_degnorm(ls[0] - lm[0]);
|
|
if (dc[i] > 180)
|
|
dc[i] -= 360;
|
|
}
|
|
if (dc[0] * dc[1] >= 0) /* no transit */
|
|
tret[1] = 0;
|
|
else {
|
|
tjd = tjds;
|
|
dt = 0.1;
|
|
dt1 = (tret[3] - tret[2]) / 2.0;
|
|
if (dt1 < dt)
|
|
dt = dt1 / 2.0;
|
|
for (j = 0; dt > 0.01; j++, dt /= 3) {
|
|
for (i = 0, t = tjd; i <= 1; i++, t -= dt) {
|
|
tt = t + swe_deltat(t);
|
|
if (swe_calc(tt, SE_SUN, iflag, ls, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(tt, SE_MOON, iflag, lm, serr) == ERR)
|
|
return ERR;
|
|
dc[i] = swe_degnorm(ls[0] - lm[0]);
|
|
if (dc[i] > 180)
|
|
dc[i] -= 360;
|
|
if (dc[i] > 180)
|
|
dc[i] -= 360;
|
|
}
|
|
a = (dc[1] - dc[0]) / dt;
|
|
if (a < 1e-10)
|
|
break;
|
|
dt1 = dc[0] / a;
|
|
tjd += dt1;
|
|
}
|
|
tret[1] = tjd;
|
|
}
|
|
end_search_global:
|
|
return retflag;
|
|
/*
|
|
* the time of maximum occultation is practically identical
|
|
* with the time of maximum core shadow diameter.
|
|
*
|
|
* the time, when duration of totality is maximal,
|
|
* is not an interesting computation either. Near the maximum
|
|
* occulation, the time of totality can be the same by
|
|
* a second for hundreds of kilometers (for 10 minutes
|
|
* or more).
|
|
*
|
|
* for annular eclipses the maximum duration is close to the
|
|
* beginning and the end of the center lines, where is also
|
|
* the minimum of core shadow diameter.
|
|
*/
|
|
}
|
|
|
|
/* When is the next lunar occultation anywhere on earth?
|
|
* This function also finds solar eclipses, but is less efficient
|
|
* than swe_sol_eclipse_when_glob().
|
|
*
|
|
* input parameters:
|
|
*
|
|
* tjd_start start time for search (UT)
|
|
* ipl planet number of occulted body
|
|
* starname name of occulted star. Must be NULL or "", if a planetary
|
|
* occultation is to be calculated. For the use of this
|
|
* field, also see swe_fixstar().
|
|
* ifl ephemeris to be used (SEFLG_SWIEPH, etc.)
|
|
* ephemeris flag.
|
|
*
|
|
* ifltype eclipse type to be searched (SE_ECL_TOTAL, etc.)
|
|
* 0, if any type of eclipse is wanted
|
|
* this functionality also works with occultations
|
|
*
|
|
* backward if 1, causes search backward in time
|
|
*
|
|
* If you want to have only one conjunction
|
|
* of the moon with the body tested, add the following flag:
|
|
* backward |= SE_ECL_ONE_TRY. If this flag is not set,
|
|
* the function will search for an occultation until it
|
|
* finds one. For bodies with ecliptical latitudes > 5,
|
|
* the function may search successlessly until it reaches
|
|
* the end of the ephemeris.
|
|
* (Note: we do not add SE_ECL_ONE_TRY to ifl, because
|
|
* ifl may contain SEFLG_TOPOCTR (=SE_ECL_ONE_TRY) from
|
|
* the parameter iflag of swe_calc() etc. Although the
|
|
* topocentric flag is irrelevant here, it might cause
|
|
* confusion.)
|
|
*
|
|
* return values:
|
|
*
|
|
* retflag SE_ECL_TOTAL or SE_ECL_ANNULAR or SE_ECL_PARTIAL
|
|
* or SE_ECL_ANNULAR_TOTAL
|
|
* SE_ECL_CENTRAL
|
|
* SE_ECL_NONCENTRAL
|
|
*
|
|
* tret[0] time of maximum eclipse
|
|
* tret[1] time, when eclipse takes place at local apparent noon
|
|
* tret[2] time of eclipse begin
|
|
* tret[3] time of eclipse end
|
|
* tret[4] time of totality begin
|
|
* tret[5] time of totality end
|
|
* tret[6] time of center line begin
|
|
* tret[7] time of center line end
|
|
* tret[8] time when annular-total eclipse becomes total
|
|
* not implemented so far
|
|
* tret[9] time when annular-total eclipse becomes annular again
|
|
* not implemented so far
|
|
* declare as tret[10] at least!
|
|
*
|
|
*/
|
|
int32 FAR PASCAL_CONV
|
|
swe_lun_occult_when_glob(double tjd_start, int32 ipl, char *starname,
|
|
int32 ifl, int32 ifltype, double *tret,
|
|
int32 backward, char *serr)
|
|
{
|
|
int i, j, k, m, n, o, i1, i2;
|
|
int32 retflag = 0, retflag2 = 0;
|
|
double de = 6378.140, a;
|
|
double t, tt, tjd = 0, tjds, dt, dtint, dta, dtb;
|
|
double drad;
|
|
double xs[6], xm[6], ls[6], lm[6];
|
|
double rmoon, rsun, dcore[10];
|
|
double dc[20], dctr;
|
|
double twohr = 2.0 / 24.0;
|
|
double tenmin = 10.0 / 24.0 / 60.0;
|
|
double dt1, dt2, dadd = 10, dadd2 = 6;
|
|
int nstartpos = 10;
|
|
double geopos[20];
|
|
double dtstart, dtdiv;
|
|
int direction = 1;
|
|
char s[AS_MAXCH];
|
|
int32 iflag, iflagcart;
|
|
AS_BOOL dont_times = FALSE;
|
|
int32 one_try = backward & SE_ECL_ONE_TRY;
|
|
|
|
/*if (backward & SEI_OCC_FAST)
|
|
dont_times = TRUE; */
|
|
/* function calls for Pluto with asteroid number 134340
|
|
* are treated as calls for Pluto as main body SE_PLUTO */
|
|
if (ipl == SE_AST_OFFSET + 134340)
|
|
ipl = SE_PLUTO;
|
|
ifl &= SEFLG_EPHMASK;
|
|
iflag = SEFLG_EQUATORIAL | ifl;
|
|
iflagcart = iflag | SEFLG_XYZ;
|
|
backward &= 1L;
|
|
/*
|
|
* initializations
|
|
*/
|
|
if (ifltype == (SE_ECL_PARTIAL | SE_ECL_CENTRAL)) {
|
|
if (serr != NULL)
|
|
strcpy(serr, "central partial eclipses do not exist");
|
|
return ERR;
|
|
}
|
|
if (ifltype == 0)
|
|
ifltype =
|
|
SE_ECL_TOTAL | SE_ECL_ANNULAR | SE_ECL_PARTIAL |
|
|
SE_ECL_ANNULAR_TOTAL | SE_ECL_NONCENTRAL | SE_ECL_CENTRAL;
|
|
retflag = 0;
|
|
for (i = 0; i <= 9; i++)
|
|
tret[i] = 0;
|
|
if (backward)
|
|
direction = -1;
|
|
t = tjd_start - direction * 0.001;
|
|
next_try:
|
|
for (i = 0; i < nstartpos; i++, t += direction * dadd2) {
|
|
if (calc_planet_star(t, ipl, starname, iflagcart, xs, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(t, SE_MOON, iflagcart, xm, serr) == ERR)
|
|
return ERR;
|
|
dc[i] = acos(swi_dot_prod_unit(xs, xm)) * RADTODEG;
|
|
if (i > 1 && dc[i] > dc[i - 1] && dc[i - 2] > dc[i - 1]) {
|
|
tjd = t - direction * dadd2;
|
|
break;
|
|
}
|
|
else if (i == nstartpos - 1) {
|
|
/*for (j = 0; j < nstartpos; j++)
|
|
* printf("%f ", dc[j]); */
|
|
if (serr != NULL) {
|
|
if (starname != NULL && *starname != '\0')
|
|
strcpy(s, starname);
|
|
else
|
|
swe_get_planet_name(ipl, s);
|
|
sprintf(serr,
|
|
"error in swe_lun_occult_when_glob(): conjunction of moon with planet %s not found\n",
|
|
s);
|
|
}
|
|
return ERR;
|
|
}
|
|
}
|
|
/*
|
|
* radius of planet disk in AU
|
|
*/
|
|
if (starname != NULL && *starname != '\0')
|
|
drad = 0;
|
|
else if (ipl < NDIAM)
|
|
drad = pla_diam[ipl] / 2 / AUNIT;
|
|
else if (ipl > SE_AST_OFFSET)
|
|
drad = swed.ast_diam / 2 * 1000 / AUNIT; /* km -> m -> AU */
|
|
else
|
|
drad = 0;
|
|
/*
|
|
* time of maximum eclipse (if eclipse) =
|
|
* minimum geocentric angle between sun and moon edges.
|
|
* After this time has been determined, check
|
|
* whether or not an eclipse is taking place with
|
|
* the functions eclipse_where() and _how().
|
|
*/
|
|
dtstart = dadd2; /* originally 1 */
|
|
dtdiv = 3;
|
|
for (dt = dtstart; dt > 0.0001; dt /= dtdiv) {
|
|
for (i = 0, t = tjd - dt; i <= 2; i++, t += dt) {
|
|
if (calc_planet_star(t, ipl, starname, iflag, ls, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(t, SE_MOON, iflag, lm, serr) == ERR)
|
|
return ERR;
|
|
if (calc_planet_star(t, ipl, starname, iflagcart, xs, serr) ==
|
|
ERR)
|
|
return ERR;
|
|
if (swe_calc(t, SE_MOON, iflagcart, xm, serr) == ERR)
|
|
return ERR;
|
|
dc[i] = acos(swi_dot_prod_unit(xs, xm)) * RADTODEG;
|
|
rmoon = asin(RMOON / lm[2]) * RADTODEG;
|
|
rsun = asin(drad / ls[2]) * RADTODEG;
|
|
dc[i] -= (rmoon + rsun);
|
|
}
|
|
find_maximum(dc[0], dc[1], dc[2], dt, &dtint, &dctr);
|
|
tjd += dtint + dt;
|
|
}
|
|
tjd -= swe_deltat(tjd);
|
|
tjds = tjd;
|
|
if ((retflag =
|
|
eclipse_where(tjd, ipl, starname, ifl, geopos, dcore, serr)) == ERR)
|
|
return retflag;
|
|
retflag2 = retflag;
|
|
/* in extreme cases _where() returns no eclipse, where there is
|
|
* actually a very small one, therefore call _how() with the
|
|
* coordinates returned by _where(): */
|
|
/* if ((retflag2 = eclipse_how(tjd, ipl, starname, ifl, geopos[0], geopos[1], 0, attr, serr)) == ERR)
|
|
* return retflag2; */
|
|
if (retflag2 == 0) {
|
|
/* only one try! */
|
|
if (one_try) {
|
|
tret[0] = tjd;
|
|
return 0;
|
|
}
|
|
t = tjd + direction * dadd;
|
|
goto next_try;
|
|
}
|
|
tret[0] = tjd;
|
|
if ((backward && tret[0] >= tjd_start - 0.0001)
|
|
|| (!backward && tret[0] <= tjd_start + 0.0001)) {
|
|
t = tjd + direction * dadd;
|
|
goto next_try;
|
|
}
|
|
/*
|
|
* eclipse type, SE_ECL_TOTAL, _ANNULAR, etc.
|
|
* SE_ECL_ANNULAR_TOTAL will be discovered later
|
|
*/
|
|
if ((retflag =
|
|
eclipse_where(tjd, ipl, starname, ifl, geopos, dcore, serr)) == ERR)
|
|
return retflag;
|
|
if (retflag == 0) { /* can happen with extremely small percentage */
|
|
retflag = SE_ECL_PARTIAL | SE_ECL_NONCENTRAL;
|
|
tret[4] = tret[5] = tjd; /* fix this ???? */
|
|
dont_times = TRUE;
|
|
}
|
|
/*
|
|
* check whether or not eclipse type found is wanted
|
|
*/
|
|
/* non central eclipse is wanted: */
|
|
if (!(ifltype & SE_ECL_NONCENTRAL) && (retflag & SE_ECL_NONCENTRAL)) {
|
|
t = tjd + direction * dadd;
|
|
goto next_try;
|
|
}
|
|
/* central eclipse is wanted: */
|
|
if (!(ifltype & SE_ECL_CENTRAL) && (retflag & SE_ECL_CENTRAL)) {
|
|
t = tjd + direction * dadd;
|
|
goto next_try;
|
|
}
|
|
/* non annular eclipse is wanted: */
|
|
if (!(ifltype & SE_ECL_ANNULAR) && (retflag & SE_ECL_ANNULAR)) {
|
|
t = tjd + direction * dadd;
|
|
goto next_try;
|
|
}
|
|
/* non partial eclipse is wanted: */
|
|
if (!(ifltype & SE_ECL_PARTIAL) && (retflag & SE_ECL_PARTIAL)) {
|
|
t = tjd + direction * dadd;
|
|
goto next_try;
|
|
}
|
|
/* annular-total eclipse will be discovered later */
|
|
if (!(ifltype & (SE_ECL_TOTAL | SE_ECL_ANNULAR_TOTAL))
|
|
&& (retflag & SE_ECL_TOTAL)) {
|
|
t = tjd + direction * dadd;
|
|
goto next_try;
|
|
}
|
|
if (dont_times)
|
|
goto end_search_global;
|
|
/*
|
|
* n = 0: times of eclipse begin and end
|
|
* n = 1: times of totality begin and end
|
|
* n = 2: times of center line begin and end
|
|
*/
|
|
if (retflag & SE_ECL_PARTIAL)
|
|
o = 0;
|
|
else if (retflag & SE_ECL_NONCENTRAL)
|
|
o = 1;
|
|
else
|
|
o = 2;
|
|
dta = twohr;
|
|
dtb = tenmin;
|
|
for (n = 0; n <= o; n++) {
|
|
if (n == 0) {
|
|
/*dc[1] = dcore[3] / 2 + de - dcore[1]; */
|
|
i1 = 2;
|
|
i2 = 3;
|
|
}
|
|
else if (n == 1) {
|
|
if (retflag & SE_ECL_PARTIAL)
|
|
continue;
|
|
i1 = 4;
|
|
i2 = 5;
|
|
}
|
|
else if (n == 2) {
|
|
if (retflag & SE_ECL_NONCENTRAL)
|
|
continue;
|
|
i1 = 6;
|
|
i2 = 7;
|
|
}
|
|
for (i = 0, t = tjd - dta; i <= 2; i += 1, t += dta) {
|
|
if ((retflag2 =
|
|
eclipse_where(t, ipl, starname, ifl, geopos, dcore,
|
|
serr)) == ERR)
|
|
return retflag2;
|
|
if (n == 0)
|
|
dc[i] = dcore[4] / 2 + de / dcore[5] - dcore[2];
|
|
else if (n == 1)
|
|
dc[i] = fabs(dcore[3]) / 2 + de / dcore[6] - dcore[2];
|
|
else if (n == 2)
|
|
dc[i] = de / dcore[6] - dcore[2];
|
|
}
|
|
find_zero(dc[0], dc[1], dc[2], dta, &dt1, &dt2);
|
|
tret[i1] = tjd + dt1 + dta;
|
|
tret[i2] = tjd + dt2 + dta;
|
|
for (m = 0, dt = dtb; m < 3; m++, dt /= 3) {
|
|
for (j = i1; j <= i2; j += (i2 - i1)) {
|
|
for (i = 0, t = tret[j] - dt; i < 2; i++, t += dt) {
|
|
if ((retflag2 =
|
|
eclipse_where(t, ipl, starname, ifl, geopos, dcore,
|
|
serr)) == ERR)
|
|
return retflag2;
|
|
if (n == 0)
|
|
dc[i] = dcore[4] / 2 + de / dcore[5] - dcore[2];
|
|
else if (n == 1)
|
|
dc[i] = fabs(dcore[3]) / 2 + de / dcore[6] - dcore[2];
|
|
else if (n == 2)
|
|
dc[i] = de / dcore[6] - dcore[2];
|
|
}
|
|
dt1 = dc[1] / ((dc[1] - dc[0]) / dt);
|
|
tret[j] -= dt1;
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* annular-total eclipses
|
|
*/
|
|
if (retflag & SE_ECL_TOTAL) {
|
|
if ((retflag2 =
|
|
eclipse_where(tret[0], ipl, starname, ifl, geopos, dcore,
|
|
serr)) == ERR)
|
|
return retflag2;
|
|
dc[0] = *dcore;
|
|
if ((retflag2 =
|
|
eclipse_where(tret[4], ipl, starname, ifl, geopos, dcore,
|
|
serr)) == ERR)
|
|
return retflag2;
|
|
dc[1] = *dcore;
|
|
if ((retflag2 =
|
|
eclipse_where(tret[5], ipl, starname, ifl, geopos, dcore,
|
|
serr)) == ERR)
|
|
return retflag2;
|
|
dc[2] = *dcore;
|
|
/* the maximum is always total, and there is either one or
|
|
* to times before and after, when the core shadow becomes
|
|
* zero and totality changes into annularity or vice versa.
|
|
*/
|
|
if (dc[0] * dc[1] < 0 || dc[0] * dc[2] < 0) {
|
|
retflag |= SE_ECL_ANNULAR_TOTAL;
|
|
retflag &= ~SE_ECL_TOTAL;
|
|
}
|
|
}
|
|
/* if eclipse is given but not wanted: */
|
|
if (!(ifltype & SE_ECL_TOTAL) && (retflag & SE_ECL_TOTAL)) {
|
|
t = tjd + direction * dadd;
|
|
goto next_try;
|
|
}
|
|
/* if annular_total eclipse is given but not wanted: */
|
|
if (!(ifltype & SE_ECL_ANNULAR_TOTAL) && (retflag & SE_ECL_ANNULAR_TOTAL)) {
|
|
t = tjd + direction * dadd;
|
|
goto next_try;
|
|
}
|
|
/*
|
|
* time of maximum eclipse at local apparent noon
|
|
*/
|
|
/* first, find out, if there is a solar transit
|
|
* between begin and end of eclipse */
|
|
k = 2;
|
|
for (i = 0; i < 2; i++) {
|
|
j = i + k;
|
|
tt = tret[j] + swe_deltat(tret[j]);
|
|
if (calc_planet_star(tt, ipl, starname, iflag, ls, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(tt, SE_MOON, iflag, lm, serr) == ERR)
|
|
return ERR;
|
|
dc[i] = swe_degnorm(ls[0] - lm[0]);
|
|
if (dc[i] > 180)
|
|
dc[i] -= 360;
|
|
}
|
|
if (dc[0] * dc[1] >= 0) /* no transit */
|
|
tret[1] = 0;
|
|
else {
|
|
tjd = tjds;
|
|
dt = 0.1;
|
|
dt1 = (tret[3] - tret[2]) / 2.0;
|
|
if (dt1 < dt)
|
|
dt = dt1 / 2.0;
|
|
for (j = 0; dt > 0.01; j++, dt /= 3) {
|
|
for (i = 0, t = tjd; i <= 1; i++, t -= dt) {
|
|
tt = t + swe_deltat(t);
|
|
if (calc_planet_star(tt, ipl, starname, iflag, ls, serr) ==
|
|
ERR)
|
|
return ERR;
|
|
if (swe_calc(tt, SE_MOON, iflag, lm, serr) == ERR)
|
|
return ERR;
|
|
dc[i] = swe_degnorm(ls[0] - lm[0]);
|
|
if (dc[i] > 180)
|
|
dc[i] -= 360;
|
|
if (dc[i] > 180)
|
|
dc[i] -= 360;
|
|
}
|
|
a = (dc[1] - dc[0]) / dt;
|
|
if (a < 1e-10)
|
|
break;
|
|
dt1 = dc[0] / a;
|
|
tjd += dt1;
|
|
}
|
|
tret[1] = tjd;
|
|
}
|
|
end_search_global:
|
|
return retflag;
|
|
/*
|
|
* the time of maximum occultation is practically identical
|
|
* with the time of maximum core shadow diameter.
|
|
*
|
|
* the time, when duration of totality is maximal,
|
|
* is not an interesting computation either. Near the maximum
|
|
* occulation, the time of totality can be the same by
|
|
* a second for hundreds of kilometers (for 10 minutes
|
|
* or more).
|
|
*
|
|
* for annular eclipses the maximum duration is close to the
|
|
* beginning and the end of the center lines, where is also
|
|
* the minimum of core shadow diameter.
|
|
*/
|
|
}
|
|
|
|
/* When is the next solar eclipse at a given geographical position?
|
|
* Note the uncertainty of Delta T for the remote past and for
|
|
* the future.
|
|
*
|
|
* retflag SE_ECL_TOTAL or SE_ECL_ANNULAR or SE_ECL_PARTIAL
|
|
* SE_ECL_VISIBLE,
|
|
* SE_ECL_MAX_VISIBLE,
|
|
* SE_ECL_1ST_VISIBLE, SE_ECL_2ND_VISIBLE
|
|
* SE_ECL_3ST_VISIBLE, SE_ECL_4ND_VISIBLE
|
|
*
|
|
* tret[0] time of maximum eclipse
|
|
* tret[1] time of first contact
|
|
* tret[2] time of second contact
|
|
* tret[3] time of third contact
|
|
* tret[4] time of forth contact
|
|
* tret[5] time of sun rise between first and forth contact
|
|
* tret[6] time of sun set beween first and forth contact
|
|
*
|
|
* attr[0] fraction of solar diameter covered by moon;
|
|
* with total/annular eclipses, it results in magnitude acc. to IMCCE.
|
|
* attr[1] ratio of lunar diameter to solar one
|
|
* attr[2] fraction of solar disc covered by moon (obscuration)
|
|
* attr[3] diameter of core shadow in km
|
|
* attr[4] azimuth of sun at tjd
|
|
* attr[5] true altitude of sun above horizon at tjd
|
|
* attr[6] apparent altitude of sun above horizon at tjd
|
|
* attr[7] elongation of moon in degrees
|
|
* attr[8] magnitude acc. to NASA;
|
|
* = attr[0] for partial and attr[1] for annular and total eclipses
|
|
* attr[9] saros series number
|
|
* attr[10] saros series member number
|
|
* declare as attr[20] at least !
|
|
*/
|
|
int32 FAR PASCAL_CONV
|
|
swe_sol_eclipse_when_loc(double tjd_start, int32 ifl, double *geopos,
|
|
double *tret, double *attr, int32 backward,
|
|
char *serr)
|
|
{
|
|
int32 retflag = 0, retflag2 = 0;
|
|
double geopos2[20], dcore[10];
|
|
ifl &= SEFLG_EPHMASK;
|
|
if ((retflag =
|
|
eclipse_when_loc(tjd_start, ifl, geopos, tret, attr, backward,
|
|
serr)) <= 0)
|
|
return retflag;
|
|
/*
|
|
* diameter of core shadow
|
|
*/
|
|
if ((retflag2 =
|
|
eclipse_where(tret[0], SE_SUN, NULL, ifl, geopos2, dcore,
|
|
serr)) == ERR)
|
|
return retflag2;
|
|
retflag |= (retflag2 & SE_ECL_NONCENTRAL);
|
|
attr[3] = dcore[0];
|
|
return retflag;
|
|
}
|
|
|
|
/* Same declaration as swe_sol_eclipse_when_loc().
|
|
* In addition:
|
|
* int32 ipl planet number of occulted body
|
|
* char* starname name of occulted star. Must be NULL or "", if a planetary
|
|
* occultation is to be calculated. For the use of this
|
|
* field, also see swe_fixstar().
|
|
* int32 ifl ephemeris flag. If you want to have only one conjunction
|
|
* of the moon with the body tested, add the following flag:
|
|
* backward |= SE_ECL_ONE_TRY. If this flag is not set,
|
|
* the function will search for an occultation until it
|
|
* finds one. For bodies with ecliptical latitudes > 5,
|
|
* the function may search unsuccessfully until it reaches
|
|
* the end of the ephemeris.
|
|
*/
|
|
int32 FAR PASCAL_CONV
|
|
swe_lun_occult_when_loc(double tjd_start, int32 ipl, char *starname,
|
|
int32 ifl, double *geopos, double *tret, double *attr,
|
|
int32 backward, char *serr)
|
|
{
|
|
int32 retflag = 0, retflag2 = 0;
|
|
double geopos2[20], dcore[10];
|
|
/* function calls for Pluto with asteroid number 134340
|
|
* are treated as calls for Pluto as main body SE_PLUTO */
|
|
if (ipl == SE_AST_OFFSET + 134340)
|
|
ipl = SE_PLUTO;
|
|
ifl &= SEFLG_EPHMASK;
|
|
if ((retflag =
|
|
occult_when_loc(tjd_start, ipl, starname, ifl, geopos, tret, attr,
|
|
backward, serr)) <= 0)
|
|
return retflag;
|
|
/*
|
|
* diameter of core shadow
|
|
*/
|
|
if ((retflag2 =
|
|
eclipse_where(tret[0], ipl, starname, ifl, geopos2, dcore,
|
|
serr)) == ERR)
|
|
return retflag2;
|
|
retflag |= (retflag2 & SE_ECL_NONCENTRAL);
|
|
attr[3] = dcore[0];
|
|
return retflag;
|
|
}
|
|
|
|
static int32
|
|
eclipse_when_loc(double tjd_start, int32 ifl, double *geopos, double *tret,
|
|
double *attr, int32 backward, char *serr)
|
|
{
|
|
int i, j, k, m;
|
|
int32 retflag = 0, retc;
|
|
double t, tjd, dt, dtint, K, T, T2, T3, T4, F, M, Mm;
|
|
double tjdr, tjds;
|
|
double E, Ff, A1, Om;
|
|
double xs[6], xm[6], ls[6], lm[6], x1[6], x2[6], dm, ds;
|
|
double rmoon, rsun, rsplusrm, rsminusrm;
|
|
double dc[3], dctr, dctrmin;
|
|
double twomin = 2.0 / 24.0 / 60.0;
|
|
double tensec = 10.0 / 24.0 / 60.0 / 60.0;
|
|
double twohr = 2.0 / 24.0;
|
|
double tenmin = 10.0 / 24.0 / 60.0;
|
|
double dt1, dt2, dtdiv, dtstart;
|
|
int32 iflag = SEFLG_EQUATORIAL | SEFLG_TOPOCTR | ifl;
|
|
int32 iflagcart = iflag | SEFLG_XYZ;
|
|
swe_set_topo(geopos[0], geopos[1], geopos[2]);
|
|
K = (int)((tjd_start - J2000) / 365.2425 * 12.3685);
|
|
if (backward)
|
|
K++;
|
|
else
|
|
K--;
|
|
next_try:
|
|
T = K / 1236.85;
|
|
T2 = T * T;
|
|
T3 = T2 * T;
|
|
T4 = T3 * T;
|
|
Ff = F =
|
|
swe_degnorm(160.7108 + 390.67050274 * K - 0.0016341 * T2 -
|
|
0.00000227 * T3 + 0.000000011 * T4);
|
|
if (Ff > 180)
|
|
Ff -= 180;
|
|
if (Ff > 21 && Ff < 159) { /* no eclipse possible */
|
|
if (backward)
|
|
K--;
|
|
else
|
|
K++;
|
|
goto next_try;
|
|
}
|
|
/* approximate time of geocentric maximum eclipse.
|
|
* formula from Meeus, German, p. 381 */
|
|
tjd =
|
|
2451550.09765 + 29.530588853 * K + 0.0001337 * T2 - 0.000000150 * T3 +
|
|
0.00000000073 * T4;
|
|
M = swe_degnorm(2.5534 + 29.10535669 * K - 0.0000218 * T2 -
|
|
0.00000011 * T3);
|
|
Mm = swe_degnorm(201.5643 + 385.81693528 * K + 0.1017438 * T2 +
|
|
0.00001239 * T3 + 0.000000058 * T4);
|
|
Om = swe_degnorm(124.7746 - 1.56375580 * K + 0.0020691 * T2 +
|
|
0.00000215 * T3);
|
|
E = 1 - 0.002516 * T - 0.0000074 * T2;
|
|
A1 = swe_degnorm(299.77 + 0.107408 * K - 0.009173 * T2);
|
|
M *= DEGTORAD;
|
|
Mm *= DEGTORAD;
|
|
F *= DEGTORAD;
|
|
Om *= DEGTORAD;
|
|
A1 *= DEGTORAD;
|
|
tjd = tjd - 0.4075 * sin(Mm)
|
|
+ 0.1721 * E * sin(M);
|
|
swe_set_topo(geopos[0], geopos[1], geopos[2]);
|
|
dtdiv = 2;
|
|
dtstart = 0.5;
|
|
if (tjd < 1900000) /* because above formula is not good (delta t?) */
|
|
dtstart = 2;
|
|
for (dt = dtstart; dt > 0.00001; dt /= dtdiv) {
|
|
if (dt < 0.1)
|
|
dtdiv = 3;
|
|
for (i = 0, t = tjd - dt; i <= 2; i++, t += dt) {
|
|
/* this takes some time, but is necessary to avoid
|
|
* missing an eclipse */
|
|
if (swe_calc(t, SE_SUN, iflagcart, xs, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(t, SE_SUN, iflag, ls, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(t, SE_MOON, iflagcart, xm, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(t, SE_MOON, iflag, lm, serr) == ERR)
|
|
return ERR;
|
|
dm = sqrt(square_sum(xm));
|
|
ds = sqrt(square_sum(xs));
|
|
for (k = 0; k < 3; k++) {
|
|
x1[k] = xs[k] / ds /*ls[2] */ ;
|
|
x2[k] = xm[k] / dm /*lm[2] */ ;
|
|
}
|
|
dc[i] = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
|
|
}
|
|
find_maximum(dc[0], dc[1], dc[2], dt, &dtint, &dctr);
|
|
tjd += dtint + dt;
|
|
}
|
|
if (swe_calc(tjd, SE_SUN, iflagcart, xs, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(tjd, SE_SUN, iflag, ls, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(tjd, SE_MOON, iflagcart, xm, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(tjd, SE_MOON, iflag, lm, serr) == ERR)
|
|
return ERR;
|
|
dctr = acos(swi_dot_prod_unit(xs, xm)) * RADTODEG;
|
|
rmoon = asin(RMOON / lm[2]) * RADTODEG;
|
|
rsun = asin(RSUN / ls[2]) * RADTODEG;
|
|
rsplusrm = rsun + rmoon;
|
|
rsminusrm = rsun - rmoon;
|
|
if (dctr > rsplusrm) {
|
|
if (backward)
|
|
K--;
|
|
else
|
|
K++;
|
|
goto next_try;
|
|
}
|
|
tret[0] = tjd - swe_deltat(tjd);
|
|
if ((backward && tret[0] >= tjd_start - 0.0001)
|
|
|| (!backward && tret[0] <= tjd_start + 0.0001)) {
|
|
if (backward)
|
|
K--;
|
|
else
|
|
K++;
|
|
goto next_try;
|
|
}
|
|
if (dctr < rsminusrm)
|
|
retflag = SE_ECL_ANNULAR;
|
|
else if (dctr < fabs(rsminusrm))
|
|
retflag = SE_ECL_TOTAL;
|
|
else if (dctr <= rsplusrm)
|
|
retflag = SE_ECL_PARTIAL;
|
|
dctrmin = dctr;
|
|
/* contacts 2 and 3 */
|
|
if (dctr > fabs(rsminusrm)) /* partial, no 2nd and 3rd contact */
|
|
tret[2] = tret[3] = 0;
|
|
else {
|
|
dc[1] = fabs(rsminusrm) - dctrmin;
|
|
for (i = 0, t = tjd - twomin; i <= 2; i += 2, t = tjd + twomin) {
|
|
if (swe_calc(t, SE_SUN, iflagcart, xs, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(t, SE_MOON, iflagcart, xm, serr) == ERR)
|
|
return ERR;
|
|
dm = sqrt(square_sum(xm));
|
|
ds = sqrt(square_sum(xs));
|
|
rmoon = asin(RMOON / dm) * RADTODEG;
|
|
rmoon *= 0.99916; /* gives better accuracy for 2nd/3rd contacts */
|
|
rsun = asin(RSUN / ds) * RADTODEG;
|
|
rsminusrm = rsun - rmoon;
|
|
for (k = 0; k < 3; k++) {
|
|
x1[k] = xs[k] / ds /*ls[2] */ ;
|
|
x2[k] = xm[k] / dm /*lm[2] */ ;
|
|
}
|
|
dctr = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
|
|
dc[i] = fabs(rsminusrm) - dctr;
|
|
}
|
|
find_zero(dc[0], dc[1], dc[2], twomin, &dt1, &dt2);
|
|
tret[2] = tjd + dt1 + twomin;
|
|
tret[3] = tjd + dt2 + twomin;
|
|
for (m = 0, dt = tensec; m < 2; m++, dt /= 10) {
|
|
for (j = 2; j <= 3; j++) {
|
|
if (swe_calc
|
|
(tret[j], SE_SUN, iflagcart | SEFLG_SPEED, xs,
|
|
serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc
|
|
(tret[j], SE_MOON, iflagcart | SEFLG_SPEED, xm,
|
|
serr) == ERR)
|
|
return ERR;
|
|
for (i = 0; i < 2; i++) {
|
|
if (i == 1) {
|
|
for (k = 0; k < 3; k++) {
|
|
xs[k] -= xs[k + 3] * dt;
|
|
xm[k] -= xm[k + 3] * dt;
|
|
}
|
|
}
|
|
dm = sqrt(square_sum(xm));
|
|
ds = sqrt(square_sum(xs));
|
|
rmoon = asin(RMOON / dm) * RADTODEG;
|
|
rmoon *= 0.99916; /* gives better accuracy for 2nd/3rd contacts */
|
|
rsun = asin(RSUN / ds) * RADTODEG;
|
|
rsminusrm = rsun - rmoon;
|
|
for (k = 0; k < 3; k++) {
|
|
x1[k] = xs[k] / ds /*ls[2] */ ;
|
|
x2[k] = xm[k] / dm /*lm[2] */ ;
|
|
}
|
|
dctr = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
|
|
dc[i] = fabs(rsminusrm) - dctr;
|
|
}
|
|
dt1 = -dc[0] / ((dc[0] - dc[1]) / dt);
|
|
tret[j] += dt1;
|
|
}
|
|
}
|
|
tret[2] -= swe_deltat(tret[2]);
|
|
tret[3] -= swe_deltat(tret[3]);
|
|
}
|
|
/* contacts 1 and 4 */
|
|
dc[1] = rsplusrm - dctrmin;
|
|
for (i = 0, t = tjd - twohr; i <= 2; i += 2, t = tjd + twohr) {
|
|
if (swe_calc(t, SE_SUN, iflagcart, xs, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(t, SE_MOON, iflagcart, xm, serr) == ERR)
|
|
return ERR;
|
|
dm = sqrt(square_sum(xm));
|
|
ds = sqrt(square_sum(xs));
|
|
rmoon = asin(RMOON / dm) * RADTODEG;
|
|
rsun = asin(RSUN / ds) * RADTODEG;
|
|
rsplusrm = rsun + rmoon;
|
|
for (k = 0; k < 3; k++) {
|
|
x1[k] = xs[k] / ds /*ls[2] */ ;
|
|
x2[k] = xm[k] / dm /*lm[2] */ ;
|
|
}
|
|
dctr = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
|
|
dc[i] = rsplusrm - dctr;
|
|
}
|
|
find_zero(dc[0], dc[1], dc[2], twohr, &dt1, &dt2);
|
|
tret[1] = tjd + dt1 + twohr;
|
|
tret[4] = tjd + dt2 + twohr;
|
|
for (m = 0, dt = tenmin; m < 3; m++, dt /= 10) {
|
|
for (j = 1; j <= 4; j += 3) {
|
|
if (swe_calc(tret[j], SE_SUN, iflagcart | SEFLG_SPEED, xs, serr)
|
|
== ERR)
|
|
return ERR;
|
|
if (swe_calc(tret[j], SE_MOON, iflagcart | SEFLG_SPEED, xm, serr)
|
|
== ERR)
|
|
return ERR;
|
|
for (i = 0; i < 2; i++) {
|
|
if (i == 1) {
|
|
for (k = 0; k < 3; k++) {
|
|
xs[k] -= xs[k + 3] * dt;
|
|
xm[k] -= xm[k + 3] * dt;
|
|
}
|
|
}
|
|
dm = sqrt(square_sum(xm));
|
|
ds = sqrt(square_sum(xs));
|
|
rmoon = asin(RMOON / dm) * RADTODEG;
|
|
rsun = asin(RSUN / ds) * RADTODEG;
|
|
rsplusrm = rsun + rmoon;
|
|
for (k = 0; k < 3; k++) {
|
|
x1[k] = xs[k] / ds /*ls[2] */ ;
|
|
x2[k] = xm[k] / dm /*lm[2] */ ;
|
|
}
|
|
dctr = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
|
|
dc[i] = fabs(rsplusrm) - dctr;
|
|
}
|
|
dt1 = -dc[0] / ((dc[0] - dc[1]) / dt);
|
|
tret[j] += dt1;
|
|
}
|
|
}
|
|
tret[1] -= swe_deltat(tret[1]);
|
|
tret[4] -= swe_deltat(tret[4]);
|
|
/*
|
|
* visibility of eclipse phases
|
|
*/
|
|
for (i = 4; i >= 0; i--) { /* attr for i = 0 must be kept !!! */
|
|
if (tret[i] == 0)
|
|
continue;
|
|
if (eclipse_how
|
|
(tret[i], SE_SUN, NULL, ifl, geopos[0], geopos[1], geopos[2],
|
|
attr, serr) == ERR)
|
|
return ERR;
|
|
/*if (retflag2 & SE_ECL_VISIBLE) { could be wrong for 1st/4th contact */
|
|
if (attr[6] > 0) { /* this is save, sun above horizon, using app. alt. */
|
|
retflag |= SE_ECL_VISIBLE;
|
|
switch (i) {
|
|
case 0:
|
|
retflag |= SE_ECL_MAX_VISIBLE;
|
|
break;
|
|
case 1:
|
|
retflag |= SE_ECL_1ST_VISIBLE;
|
|
break;
|
|
case 2:
|
|
retflag |= SE_ECL_2ND_VISIBLE;
|
|
break;
|
|
case 3:
|
|
retflag |= SE_ECL_3RD_VISIBLE;
|
|
break;
|
|
case 4:
|
|
retflag |= SE_ECL_4TH_VISIBLE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#if 1
|
|
if (!(retflag & SE_ECL_VISIBLE)) {
|
|
if (backward)
|
|
K--;
|
|
else
|
|
K++;
|
|
goto next_try;
|
|
}
|
|
#endif
|
|
if (swe_rise_trans
|
|
(tret[1] - 0.1, SE_SUN, NULL, iflag,
|
|
SE_CALC_RISE | SE_BIT_DISC_BOTTOM, geopos, 0, 0, &tjdr, serr) == ERR)
|
|
return ERR;
|
|
if (swe_rise_trans
|
|
(tret[1] - 0.1, SE_SUN, NULL, iflag, SE_CALC_SET | SE_BIT_DISC_BOTTOM,
|
|
geopos, 0, 0, &tjds, serr) == ERR)
|
|
return ERR;
|
|
if (tjdr > tret[1] && tjdr < tret[4]) {
|
|
tret[5] = tjdr;
|
|
if (!(retflag & SE_ECL_MAX_VISIBLE)) {
|
|
tret[0] = tjdr;
|
|
if ((retc =
|
|
eclipse_how(tret[5], SE_SUN, NULL, ifl, geopos[0], geopos[1],
|
|
geopos[2], attr, serr)) == ERR)
|
|
return ERR;
|
|
retflag &= ~(SE_ECL_TOTAL | SE_ECL_ANNULAR | SE_ECL_PARTIAL);
|
|
retflag |=
|
|
(retc & (SE_ECL_TOTAL | SE_ECL_ANNULAR | SE_ECL_PARTIAL));
|
|
}
|
|
}
|
|
if (tjds > tret[1] && tjds < tret[4]) {
|
|
tret[6] = tjds;
|
|
if (!(retflag & SE_ECL_MAX_VISIBLE)) {
|
|
tret[0] = tjds;
|
|
if ((retc =
|
|
eclipse_how(tret[6], SE_SUN, NULL, ifl, geopos[0], geopos[1],
|
|
geopos[2], attr, serr)) == ERR)
|
|
return ERR;
|
|
retflag &= ~(SE_ECL_TOTAL | SE_ECL_ANNULAR | SE_ECL_PARTIAL);
|
|
retflag |=
|
|
(retc & (SE_ECL_TOTAL | SE_ECL_ANNULAR | SE_ECL_PARTIAL));
|
|
}
|
|
}
|
|
return retflag;
|
|
}
|
|
|
|
static int32
|
|
occult_when_loc(double tjd_start, int32 ipl, char *starname, int32 ifl,
|
|
double *geopos, double *tret, double *attr, int32 backward,
|
|
char *serr)
|
|
{
|
|
int i, j, k, m;
|
|
int32 retflag = 0;
|
|
double t, tjd, dt, dtint;
|
|
double tjdr, tjds;
|
|
double xs[6], xm[6], ls[6], lm[6], x1[6], x2[6], dm, ds;
|
|
double rmoon, rsun, rsplusrm, rsminusrm;
|
|
double dc[20], dctr, dctrmin;
|
|
double twomin = 2.0 / 24.0 / 60.0;
|
|
double tensec = 10.0 / 24.0 / 60.0 / 60.0;
|
|
double twohr = 2.0 / 24.0;
|
|
double tenmin = 10.0 / 24.0 / 60.0;
|
|
double dt1, dt2, dtdiv, dtstart;
|
|
double dadd2 = 6;
|
|
int nstartpos = 10;
|
|
double drad;
|
|
int32 iflag = SEFLG_TOPOCTR | ifl;
|
|
int32 iflaggeo = iflag & ~SEFLG_TOPOCTR;
|
|
int32 iflagcart = iflag | SEFLG_XYZ;
|
|
int32 iflagcartgeo = iflaggeo | SEFLG_XYZ;
|
|
int direction = 1;
|
|
int32 one_try = backward & SE_ECL_ONE_TRY;
|
|
AS_BOOL stop_after_this = FALSE;
|
|
backward &= 1L;
|
|
retflag = 0;
|
|
swe_set_topo(geopos[0], geopos[1], geopos[2]);
|
|
for (i = 0; i <= 9; i++)
|
|
tret[i] = 0;
|
|
if (backward)
|
|
direction = -1;
|
|
t = tjd_start - direction * 0.1;
|
|
tjd = tjd_start;
|
|
next_try:
|
|
for (i = 0; i < nstartpos; i++, t += direction * dadd2) {
|
|
if (calc_planet_star(t, ipl, starname, iflagcartgeo, xs, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(t, SE_MOON, iflagcartgeo, xm, serr) == ERR)
|
|
return ERR;
|
|
dc[i] = acos(swi_dot_prod_unit(xs, xm)) * RADTODEG;
|
|
if (i > 1 && dc[i] > dc[i - 1] && dc[i - 2] > dc[i - 1]) {
|
|
tjd = t - direction * dadd2;
|
|
break;
|
|
}
|
|
else if (i == nstartpos - 1) {
|
|
for (j = 0; j < nstartpos; j++)
|
|
printf("%f ", dc[j]);
|
|
printf("swe_lun_occult_when_loc(): problem planet\n");
|
|
return ERR;
|
|
}
|
|
}
|
|
/*
|
|
* radius of planet disk in AU
|
|
*/
|
|
if (starname != NULL && *starname != '\0')
|
|
drad = 0;
|
|
else if (ipl < NDIAM)
|
|
drad = pla_diam[ipl] / 2 / AUNIT;
|
|
else if (ipl > SE_AST_OFFSET)
|
|
drad = swed.ast_diam / 2 * 1000 / AUNIT; /* km -> m -> AU */
|
|
else
|
|
drad = 0;
|
|
/* now find out, if there is an occultation at our geogr. location */
|
|
dtdiv = 3;
|
|
dtstart = dadd2; /* formerly 0.2 */
|
|
for (dt = dtstart; dt > 0.00001; dt /= dtdiv) {
|
|
if (dt < 0.01)
|
|
dtdiv = 3;
|
|
for (i = 0, t = tjd - dt; i <= 2; i++, t += dt) {
|
|
/* this takes some time, but is necessary to avoid
|
|
* missing an eclipse */
|
|
if (calc_planet_star(t, ipl, starname, iflagcart, xs, serr) ==
|
|
ERR)
|
|
return ERR;
|
|
if (calc_planet_star(t, ipl, starname, iflag, ls, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(t, SE_MOON, iflagcart, xm, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(t, SE_MOON, iflag, lm, serr) == ERR)
|
|
return ERR;
|
|
if (dt < 1 && fabs(ls[1] - lm[1]) > 2) {
|
|
if (one_try) {
|
|
stop_after_this = TRUE;
|
|
}
|
|
else {
|
|
t = tjd + direction * 2;
|
|
goto next_try;
|
|
}
|
|
}
|
|
dc[i] = acos(swi_dot_prod_unit(xs, xm)) * RADTODEG;
|
|
rmoon = asin(RMOON / lm[2]) * RADTODEG;
|
|
rsun = asin(drad / ls[2]) * RADTODEG;
|
|
dc[i] -= (rmoon + rsun);
|
|
}
|
|
find_maximum(dc[0], dc[1], dc[2], dt, &dtint, &dctr);
|
|
tjd += dtint + dt;
|
|
}
|
|
if (stop_after_this) { /* has one_try = TRUE */
|
|
tret[0] = tjd;
|
|
return 0;
|
|
}
|
|
if (calc_planet_star(tjd, ipl, starname, iflagcart, xs, serr) == ERR)
|
|
return ERR;
|
|
if (calc_planet_star(tjd, ipl, starname, iflag, ls, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(tjd, SE_MOON, iflagcart, xm, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(tjd, SE_MOON, iflag, lm, serr) == ERR)
|
|
return ERR;
|
|
dctr = acos(swi_dot_prod_unit(xs, xm)) * RADTODEG;
|
|
rmoon = asin(RMOON / lm[2]) * RADTODEG;
|
|
rsun = asin(drad / ls[2]) * RADTODEG;
|
|
rsplusrm = rsun + rmoon;
|
|
rsminusrm = rsun - rmoon;
|
|
if (dctr > rsplusrm) {
|
|
if (one_try) {
|
|
tret[0] = tjd;
|
|
return 0;
|
|
}
|
|
t = tjd + direction;
|
|
goto next_try;
|
|
}
|
|
tret[0] = tjd - swe_deltat(tjd);
|
|
if ((backward && tret[0] >= tjd_start - 0.0001)
|
|
|| (!backward && tret[0] <= tjd_start + 0.0001)) {
|
|
t = tjd + direction;
|
|
goto next_try;
|
|
}
|
|
if (dctr < rsminusrm)
|
|
retflag = SE_ECL_ANNULAR;
|
|
else if (dctr < fabs(rsminusrm))
|
|
retflag = SE_ECL_TOTAL;
|
|
else if (dctr <= rsplusrm)
|
|
retflag = SE_ECL_PARTIAL;
|
|
dctrmin = dctr;
|
|
/* contacts 2 and 3 */
|
|
if (dctr > fabs(rsminusrm)) /* partial, no 2nd and 3rd contact */
|
|
tret[2] = tret[3] = 0;
|
|
else {
|
|
dc[1] = fabs(rsminusrm) - dctrmin;
|
|
for (i = 0, t = tjd - twomin; i <= 2; i += 2, t = tjd + twomin) {
|
|
if (calc_planet_star(t, ipl, starname, iflagcart, xs, serr) ==
|
|
ERR)
|
|
return ERR;
|
|
if (swe_calc(t, SE_MOON, iflagcart, xm, serr) == ERR)
|
|
return ERR;
|
|
dm = sqrt(square_sum(xm));
|
|
ds = sqrt(square_sum(xs));
|
|
rmoon = asin(RMOON / dm) * RADTODEG;
|
|
rmoon *= 0.99916; /* gives better accuracy for 2nd/3rd contacts */
|
|
rsun = asin(drad / ds) * RADTODEG;
|
|
rsminusrm = rsun - rmoon;
|
|
for (k = 0; k < 3; k++) {
|
|
x1[k] = xs[k] / ds /*ls[2] */ ;
|
|
x2[k] = xm[k] / dm /*lm[2] */ ;
|
|
}
|
|
dctr = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
|
|
dc[i] = fabs(rsminusrm) - dctr;
|
|
}
|
|
find_zero(dc[0], dc[1], dc[2], twomin, &dt1, &dt2);
|
|
tret[2] = tjd + dt1 + twomin;
|
|
tret[3] = tjd + dt2 + twomin;
|
|
for (m = 0, dt = tensec; m < 2; m++, dt /= 10) {
|
|
for (j = 2; j <= 3; j++) {
|
|
if (calc_planet_star
|
|
(tret[j], ipl, starname, iflagcart | SEFLG_SPEED, xs,
|
|
serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc
|
|
(tret[j], SE_MOON, iflagcart | SEFLG_SPEED, xm,
|
|
serr) == ERR)
|
|
return ERR;
|
|
for (i = 0; i < 2; i++) {
|
|
if (i == 1) {
|
|
for (k = 0; k < 3; k++) {
|
|
xs[k] -= xs[k + 3] * dt;
|
|
xm[k] -= xm[k + 3] * dt;
|
|
}
|
|
}
|
|
dm = sqrt(square_sum(xm));
|
|
ds = sqrt(square_sum(xs));
|
|
rmoon = asin(RMOON / dm) * RADTODEG;
|
|
rmoon *= 0.99916; /* gives better accuracy for 2nd/3rd contacts */
|
|
rsun = asin(drad / ds) * RADTODEG;
|
|
rsminusrm = rsun - rmoon;
|
|
for (k = 0; k < 3; k++) {
|
|
x1[k] = xs[k] / ds /*ls[2] */ ;
|
|
x2[k] = xm[k] / dm /*lm[2] */ ;
|
|
}
|
|
dctr = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
|
|
dc[i] = fabs(rsminusrm) - dctr;
|
|
}
|
|
dt1 = -dc[0] / ((dc[0] - dc[1]) / dt);
|
|
tret[j] += dt1;
|
|
}
|
|
}
|
|
tret[2] -= swe_deltat(tret[2]);
|
|
tret[3] -= swe_deltat(tret[3]);
|
|
}
|
|
/* contacts 1 and 4 */
|
|
dc[1] = rsplusrm - dctrmin;
|
|
for (i = 0, t = tjd - twohr; i <= 2; i += 2, t = tjd + twohr) {
|
|
if (calc_planet_star(t, ipl, starname, iflagcart, xs, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(t, SE_MOON, iflagcart, xm, serr) == ERR)
|
|
return ERR;
|
|
dm = sqrt(square_sum(xm));
|
|
ds = sqrt(square_sum(xs));
|
|
rmoon = asin(RMOON / dm) * RADTODEG;
|
|
rsun = asin(drad / ds) * RADTODEG;
|
|
rsplusrm = rsun + rmoon;
|
|
for (k = 0; k < 3; k++) {
|
|
x1[k] = xs[k] / ds /*ls[2] */ ;
|
|
x2[k] = xm[k] / dm /*lm[2] */ ;
|
|
}
|
|
dctr = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
|
|
dc[i] = rsplusrm - dctr;
|
|
}
|
|
find_zero(dc[0], dc[1], dc[2], twohr, &dt1, &dt2);
|
|
tret[1] = tjd + dt1 + twohr;
|
|
tret[4] = tjd + dt2 + twohr;
|
|
for (m = 0, dt = tenmin; m < 3; m++, dt /= 10) {
|
|
for (j = 1; j <= 4; j += 3) {
|
|
if (calc_planet_star
|
|
(tret[j], ipl, starname, iflagcart | SEFLG_SPEED, xs,
|
|
serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(tret[j], SE_MOON, iflagcart | SEFLG_SPEED, xm, serr)
|
|
== ERR)
|
|
return ERR;
|
|
for (i = 0; i < 2; i++) {
|
|
if (i == 1) {
|
|
for (k = 0; k < 3; k++) {
|
|
xs[k] -= xs[k + 3] * dt;
|
|
xm[k] -= xm[k + 3] * dt;
|
|
}
|
|
}
|
|
dm = sqrt(square_sum(xm));
|
|
ds = sqrt(square_sum(xs));
|
|
rmoon = asin(RMOON / dm) * RADTODEG;
|
|
rsun = asin(drad / ds) * RADTODEG;
|
|
rsplusrm = rsun + rmoon;
|
|
for (k = 0; k < 3; k++) {
|
|
x1[k] = xs[k] / ds /*ls[2] */ ;
|
|
x2[k] = xm[k] / dm /*lm[2] */ ;
|
|
}
|
|
dctr = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
|
|
dc[i] = fabs(rsplusrm) - dctr;
|
|
}
|
|
dt1 = -dc[0] / ((dc[0] - dc[1]) / dt);
|
|
tret[j] += dt1;
|
|
}
|
|
}
|
|
tret[1] -= swe_deltat(tret[1]);
|
|
tret[4] -= swe_deltat(tret[4]);
|
|
/*
|
|
* visibility of eclipse phases
|
|
*/
|
|
for (i = 4; i >= 0; i--) { /* attr for i = 0 must be kept !!! */
|
|
if (tret[i] == 0)
|
|
continue;
|
|
if (eclipse_how
|
|
(tret[i], ipl, starname, ifl, geopos[0], geopos[1], geopos[2],
|
|
attr, serr) == ERR)
|
|
return ERR;
|
|
/*if (retflag2 & SE_ECL_VISIBLE) { could be wrong for 1st/4th contact */
|
|
if (attr[6] > 0) { /* this is save, sun above horizon (using app. alt.) */
|
|
retflag |= SE_ECL_VISIBLE;
|
|
switch (i) {
|
|
case 0:
|
|
retflag |= SE_ECL_MAX_VISIBLE;
|
|
break;
|
|
case 1:
|
|
retflag |= SE_ECL_1ST_VISIBLE;
|
|
break;
|
|
case 2:
|
|
retflag |= SE_ECL_2ND_VISIBLE;
|
|
break;
|
|
case 3:
|
|
retflag |= SE_ECL_3RD_VISIBLE;
|
|
break;
|
|
case 4:
|
|
retflag |= SE_ECL_4TH_VISIBLE;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
#if 1
|
|
if (!(retflag & SE_ECL_VISIBLE)) {
|
|
t = tjd + direction;
|
|
goto next_try;
|
|
}
|
|
#endif
|
|
if (swe_rise_trans
|
|
(tret[1] - 0.1, ipl, starname, iflag,
|
|
SE_CALC_RISE | SE_BIT_DISC_BOTTOM, geopos, 0, 0, &tjdr, serr) == ERR)
|
|
return ERR;
|
|
if (swe_rise_trans
|
|
(tret[1] - 0.1, ipl, starname, iflag,
|
|
SE_CALC_SET | SE_BIT_DISC_BOTTOM, geopos, 0, 0, &tjds, serr) == ERR)
|
|
return ERR;
|
|
if (tjdr > tret[1] && tjdr < tret[4])
|
|
tret[5] = tjdr;
|
|
if (tjds > tret[1] && tjds < tret[4])
|
|
tret[6] = tjds;
|
|
return retflag;
|
|
}
|
|
|
|
/*
|
|
* swe_azalt()
|
|
* Computes azimut and height, from either ecliptic or
|
|
* equatorial coordinates
|
|
*
|
|
* input:
|
|
* tjd_ut
|
|
* iflag either SE_ECL2HOR or SE_EQU2HOR
|
|
* geopos[3] geograph. longitude, latitude, height above sea
|
|
* atpress atmospheric pressure at geopos in millibars (hPa)
|
|
* attemp atmospheric temperature in degrees C
|
|
* xin[2] input coordinates polar, in degrees
|
|
*
|
|
* Horizontal coordinates are returned in
|
|
* xaz[3] xaz[0] = azimuth
|
|
* xaz[1] = true altitude
|
|
* xaz[2] = apparent altitude
|
|
*
|
|
* If atpress is not given (= 0), the programm assumes 1013.25 mbar;
|
|
* if a non-zero height above sea is given, atpress is estimated.
|
|
* geohgt height of observer above sea (optional)
|
|
*/
|
|
void FAR PASCAL_CONV
|
|
swe_azalt(double tjd_ut, int32 calc_flag, double *geopos, double atpress,
|
|
double attemp, double *xin, double *xaz)
|
|
{
|
|
int i;
|
|
double x[6], xra[3];
|
|
double armc = swe_degnorm(swe_sidtime(tjd_ut) * 15 + geopos[0]);
|
|
double mdd, eps_true, tjd_et;
|
|
for (i = 0; i < 2; i++)
|
|
xra[i] = xin[i];
|
|
xra[2] = 1;
|
|
if (calc_flag == SE_ECL2HOR) {
|
|
tjd_et = tjd_ut + swe_deltat(tjd_ut);
|
|
swe_calc(tjd_et, SE_ECL_NUT, 0, x, NULL);
|
|
eps_true = x[0];
|
|
swe_cotrans(xra, xra, -eps_true);
|
|
}
|
|
mdd = swe_degnorm(xra[0] - armc);
|
|
x[0] = swe_degnorm(mdd - 90);
|
|
x[1] = xra[1];
|
|
x[2] = 1;
|
|
/* azimuth from east, counterclock */
|
|
swe_cotrans(x, x, 90 - geopos[1]);
|
|
/* azimuth from south to west */
|
|
x[0] = swe_degnorm(x[0] + 90);
|
|
xaz[0] = 360 - x[0];
|
|
xaz[1] = x[1]; /* true height */
|
|
if (atpress == 0) {
|
|
/* estimate atmospheric pressure */
|
|
atpress = 1013.25 * pow(1 - 0.0065 * geopos[2] / 288, 5.255);
|
|
}
|
|
xaz[2] =
|
|
swe_refrac_extended(x[1], geopos[2], atpress, attemp,
|
|
const_lapse_rate, SE_TRUE_TO_APP, NULL);
|
|
/* xaz[2] = swe_refrac_extended(xaz[2], geopos[2], atpress, attemp, const_lapse_rate, SE_APP_TO_TRUE, NULL); */
|
|
}
|
|
|
|
/*
|
|
* swe_azalt_rev()
|
|
* computes either ecliptical or equatorial coordinates from
|
|
* azimuth and true altitude in degrees.
|
|
* For conversion between true and apparent altitude, there is
|
|
* the function swe_refrac().
|
|
*
|
|
* input:
|
|
* tjd_ut
|
|
* iflag either SE_HOR2ECL or SE_HOR2EQU
|
|
* xin[2] azimut and true altitude, in degrees
|
|
*/
|
|
void FAR PASCAL_CONV
|
|
swe_azalt_rev(double tjd_ut, int32 calc_flag, double *geopos, double *xin,
|
|
double *xout)
|
|
{
|
|
int i;
|
|
double x[6], xaz[3];
|
|
double geolon = geopos[0];
|
|
double geolat = geopos[1];
|
|
double armc = swe_degnorm(swe_sidtime(tjd_ut) * 15 + geolon);
|
|
double eps_true, tjd_et, dang;
|
|
for (i = 0; i < 2; i++)
|
|
xaz[i] = xin[i];
|
|
xaz[2] = 1;
|
|
/* azimuth is from south, clockwise.
|
|
* we need it from east, counterclock */
|
|
xaz[0] = 360 - xaz[0];
|
|
xaz[0] = swe_degnorm(xaz[0] - 90);
|
|
/* equatorial positions */
|
|
dang = geolat - 90;
|
|
swe_cotrans(xaz, xaz, dang);
|
|
xaz[0] = swe_degnorm(xaz[0] + armc + 90);
|
|
xout[0] = xaz[0];
|
|
xout[1] = xaz[1];
|
|
/* ecliptic positions */
|
|
if (calc_flag == SE_HOR2ECL) {
|
|
tjd_et = tjd_ut + swe_deltat(tjd_ut);
|
|
swe_calc(tjd_et, SE_ECL_NUT, 0, x, NULL);
|
|
eps_true = x[0];
|
|
swe_cotrans(xaz, x, eps_true);
|
|
xout[0] = x[0];
|
|
xout[1] = x[1];
|
|
}
|
|
}
|
|
|
|
/* swe_refrac()
|
|
* Transforms apparent to true altitude and vice-versa.
|
|
* These formulae do not handle the case when the
|
|
* sun is visible below the geometrical horizon
|
|
* (from a mountain top or an air plane)
|
|
* input:
|
|
* double inalt; * altitude of object in degrees *
|
|
* double atpress; * millibars (hectopascal) *
|
|
* double attemp; * degrees C *
|
|
* int32 calc_flag; * either SE_CALC_APP_TO_TRUE or
|
|
* * SE_CALC_TRUE_TO_APP
|
|
*/
|
|
double FAR PASCAL_CONV
|
|
swe_refrac(double inalt, double atpress, double attemp, int32 calc_flag)
|
|
{
|
|
double a, refr;
|
|
double pt_factor = atpress / 1010.0 * 283.0 / (273.0 + attemp);
|
|
double trualt, appalt;
|
|
#if 0
|
|
/*
|
|
* -- S. L. Moshier */
|
|
double y, yy0, D0, N, D, P, Q;
|
|
int i;
|
|
if (calc_flag == SE_TRUE_TO_APP) {
|
|
trualt = inalt;
|
|
if ((trualt < -2.0) || (trualt >= 90.0))
|
|
return (trualt);
|
|
/* For high altitude angle, AA page B61
|
|
* Accuracy "usually about 0.1' ".
|
|
*/
|
|
if (trualt > 15.0) {
|
|
D = 0.00452 * atpress / ((273.0 + attemp) *
|
|
tan(DEGTORAD * trualt));
|
|
return (trualt + D);
|
|
}
|
|
/* Formula for low altitude is from the Almanac for Computers.
|
|
* It gives the correction for observed altitude, so has
|
|
* to be inverted numerically to get the observed from the true.
|
|
* Accuracy about 0.2' for -20C < T < +40C and 970mb < P < 1050mb.
|
|
*/
|
|
/* Start iteration assuming correction = 0
|
|
*/
|
|
y = trualt;
|
|
D = 0.0;
|
|
/* Invert Almanac for Computers formula numerically
|
|
*/
|
|
P = (atpress - 80.0) / 930.0;
|
|
Q = 4.8e-3 * (attemp - 10.0);
|
|
yy0 = y;
|
|
D0 = D;
|
|
for (i = 0; i < 4; i++) {
|
|
N = y + (7.31 / (y + 4.4));
|
|
N = 1.0 / tan(DEGTORAD * N);
|
|
D = N * P / (60.0 + Q * (N + 39.0));
|
|
N = y - yy0;
|
|
yy0 = D - D0 - N; /* denominator of derivative */
|
|
if ((N != 0.0) && (yy0 != 0.0))
|
|
/* Newton iteration with numerically estimated derivative */
|
|
N = y - N * (trualt + D - y) / yy0;
|
|
else
|
|
/* Can't do it on first pass */
|
|
N = trualt + D;
|
|
yy0 = y;
|
|
D0 = D;
|
|
y = N;
|
|
}
|
|
return (trualt + D);
|
|
}
|
|
else {
|
|
#else
|
|
/* another algorithm, from Meeus, German, p. 114ff.
|
|
*/
|
|
if (calc_flag == SE_TRUE_TO_APP) {
|
|
trualt = inalt;
|
|
if (trualt > 15) {
|
|
a = tan((90 - trualt) * DEGTORAD);
|
|
refr = (58.276 * a - 0.0824 * a * a * a);
|
|
refr *= pt_factor / 3600.0;
|
|
}
|
|
else if (trualt > -5) {
|
|
/* the following tan is not defined for a value
|
|
* of trualt near -5.00158 and 89.89158 */
|
|
a = trualt + 10.3 / (trualt + 5.11);
|
|
if (a + 1e-10 >= 90)
|
|
refr = 0;
|
|
else
|
|
refr = 1.02 / tan(a * DEGTORAD);
|
|
refr *= pt_factor / 60.0;
|
|
}
|
|
else
|
|
refr = 0;
|
|
appalt = trualt;
|
|
if (appalt + refr > 0)
|
|
appalt += refr;
|
|
return appalt;
|
|
}
|
|
else {
|
|
#endif
|
|
/* apparent to true */
|
|
appalt = inalt;
|
|
/* the following tan is not defined for a value
|
|
* of inalt near -4.3285 and 89.9225 */
|
|
a = appalt + 7.31 / (appalt + 4.4);
|
|
if (a + 1e-10 >= 90)
|
|
refr = 0;
|
|
else {
|
|
refr = 1.00 / tan(a * DEGTORAD);
|
|
refr -= 0.06 * sin(14.7 * refr + 13);
|
|
}
|
|
refr *= pt_factor / 60.0;
|
|
trualt = appalt;
|
|
if (appalt - refr > 0)
|
|
trualt = appalt - refr;
|
|
return trualt;
|
|
}
|
|
}
|
|
|
|
void FAR PASCAL_CONV
|
|
swe_set_lapse_rate(double lapse_rate)
|
|
{
|
|
const_lapse_rate = lapse_rate;
|
|
}
|
|
|
|
/* swe_refrac_extended()
|
|
*
|
|
* This function was created thanks to and with the help of the
|
|
* archaeoastronomer Victor Reijs.
|
|
* It is more correct and more skilled than the old function swe_refrac():
|
|
* - it allows correct calculation of refraction for altitudes above sea > 0,
|
|
* where the ideal horizon and planets that are visible may have a
|
|
* negative height. (for swe_refrac(), negative apparent heights do not
|
|
* exist!)
|
|
* - it allows to manipulate the refraction constant
|
|
*
|
|
* Transforms apparent to true altitude and vice-versa.
|
|
* input:
|
|
* double inalt; * altitude of object above geometric horizon in degrees*
|
|
* * geometric horizon = plane perpendicular to gravity *
|
|
* double geoalt; * altitude of observer above sea level in meters *
|
|
* double atpress; * millibars (hectopascal) *
|
|
* double lapse_rate; * (dT/dh) [deg K/m]
|
|
* double attemp; * degrees C *
|
|
* int32 calc_flag; * either SE_CALC_APP_TO_TRUE or
|
|
* * SE_CALC_TRUE_TO_APP
|
|
*
|
|
* function returns:
|
|
* case 1, conversion from true altitude to apparent altitude
|
|
* - apparent altitude, if body appears above is observable above ideal horizon
|
|
* - true altitude (the input value), otherwise
|
|
* "ideal horizon" is the horizon as seen above an ideal sphere (as seen
|
|
* from a plane over the ocean with a clear sky)
|
|
* case 2, conversion from apparent altitude to true altitude
|
|
* - the true altitude resulting from the input apparent altitude, if this value
|
|
* is a plausible apparent altitude, i.e. if it is a position above the ideal
|
|
* horizon
|
|
* - the input altitude otherwise
|
|
*
|
|
* in addition the array dret[] is given the following values
|
|
* - dret[0] true altitude, if possible; otherwise input value
|
|
* - dret[1] apparent altitude, if possible; otherwise input value
|
|
* - dret[2] refraction
|
|
* - dret[3] dip of the horizon
|
|
*
|
|
* The body is above the horizon if the dret[0] != dret[1]
|
|
*/
|
|
double FAR PASCAL_CONV
|
|
swe_refrac_extended(double inalt, double geoalt, double atpress,
|
|
double attemp, double lapse_rate, int32 calc_flag,
|
|
double *dret)
|
|
{
|
|
double refr;
|
|
double trualt;
|
|
double dip = calc_dip(geoalt, atpress, attemp, lapse_rate);
|
|
double D, D0, N, y, yy0;
|
|
int i;
|
|
/* make sure that inalt <=90 */
|
|
if ((inalt > 90))
|
|
inalt = 180 - inalt;
|
|
if (calc_flag == SE_TRUE_TO_APP) {
|
|
if (inalt < -10) {
|
|
if (dret != NULL) {
|
|
dret[0] = inalt;
|
|
dret[1] = inalt;
|
|
dret[2] = 0;
|
|
dret[3] = dip;
|
|
}
|
|
return inalt;
|
|
}
|
|
/* by iteration */
|
|
y = inalt;
|
|
D = 0.0;
|
|
yy0 = 0;
|
|
D0 = D;
|
|
for (i = 0; i < 5; i++) {
|
|
D = calc_astronomical_refr(y, atpress, attemp);
|
|
N = y - yy0;
|
|
yy0 = D - D0 - N; /* denominator of derivative */
|
|
if (N != 0.0 && yy0 != 0.0) /* sic !!! code by Moshier */
|
|
N = y - N * (inalt + D - y) / yy0; /* Newton iteration with numerically estimated derivative */
|
|
else /* Can't do it on first pass */
|
|
N = inalt + D;
|
|
yy0 = y;
|
|
D0 = D;
|
|
y = N;
|
|
}
|
|
refr = D;
|
|
if ((inalt + refr < dip)) {
|
|
if (dret != NULL) {
|
|
dret[0] = inalt;
|
|
dret[1] = inalt;
|
|
dret[2] = 0;
|
|
dret[3] = dip;
|
|
}
|
|
return inalt;
|
|
}
|
|
if (dret != NULL) {
|
|
dret[0] = inalt;
|
|
dret[1] = inalt + refr;
|
|
dret[2] = refr;
|
|
dret[3] = dip;
|
|
}
|
|
return inalt + refr;
|
|
}
|
|
else {
|
|
refr = calc_astronomical_refr(inalt, atpress, attemp);
|
|
trualt = inalt - refr;
|
|
if (dret != NULL) {
|
|
if (inalt > dip) {
|
|
dret[0] = trualt;
|
|
dret[1] = inalt;
|
|
dret[2] = refr;
|
|
dret[3] = dip;
|
|
}
|
|
else {
|
|
dret[0] = inalt;
|
|
dret[1] = inalt;
|
|
dret[2] = 0;
|
|
dret[3] = dip;
|
|
}
|
|
}
|
|
if (trualt > dip)
|
|
return trualt;
|
|
else
|
|
return inalt;
|
|
}
|
|
}
|
|
|
|
/* calculate the astronomical refraction
|
|
* input parameters:
|
|
* double inalt * apparent altitude of object
|
|
* double atpress * atmospheric pressure millibars (hectopascal) *
|
|
* double attemp * atmospheric temperature degrees C *
|
|
* returns double r in degrees
|
|
*/
|
|
static double
|
|
calc_astronomical_refr(double inalt, double atpress, double attemp)
|
|
{
|
|
#if 0
|
|
/* formula based on G.G. Bennett, The calculation of astronomical refraction in marine navigation,
|
|
* Journal of Inst. Navigation, No. 35, page 255-259, 1982,
|
|
* page 257 for refraction formula: formula H
|
|
* and page 259 for atmospheric compensation
|
|
*/
|
|
double refractaccent = 1 / tan(DEGTORAD * (inalt + 7.31 / (inalt + 4.4)));
|
|
double r =
|
|
(refractaccent - 0.06 * sin(DEGTORAD * (14.7 * refractaccent + 13)));
|
|
r = ((atpress - 80) / 930 / (1 +
|
|
0.00008 * (r + 39) * (attemp -
|
|
10)) * r) / 60;
|
|
return r;
|
|
#else
|
|
/* Formula by Sinclair, see article mentioned above, p. 256. Better for
|
|
* apparent altitudes < 0; */
|
|
double r;
|
|
if (inalt > 17.904104638432) { /* for continuous function, instead of '>15' */
|
|
r = 0.97 / tan(inalt * DEGTORAD);
|
|
}
|
|
else {
|
|
r = (34.46 + 4.23 * inalt + 0.004 * inalt * inalt) / (1 +
|
|
0.505 * inalt +
|
|
0.0845 * inalt *
|
|
inalt);
|
|
}
|
|
r = ((atpress - 80) / 930 / (1 +
|
|
0.00008 * (r + 39) * (attemp -
|
|
10)) * r) / 60.0;
|
|
return r;
|
|
#endif
|
|
}
|
|
|
|
/* calculate dip of the horizon
|
|
* input parameters:
|
|
* double geoalt * altitude of observer above sea level in meters *
|
|
* double atpress * atmospheric pressure millibars (hectopascal) *
|
|
* double attemp * atmospheric temperature degrees C *
|
|
* double lapse_rate * (dT/dh) [deg K/m]
|
|
* returns dip in degrees
|
|
*/
|
|
static double
|
|
calc_dip(double geoalt, double atpress, double attemp, double lapse_rate)
|
|
{
|
|
/* below formula is based on A. Thom, Megalithic lunar observations, 1973 (page 32).
|
|
* conversion to metric has been done by
|
|
* V. Reijs, 2000, http://www.iol.ie/~geniet/eng/refract.htm
|
|
*/
|
|
double krefr = (0.0342 + lapse_rate) / (0.154 * 0.0238);
|
|
double d =
|
|
1 - 1.8480 * krefr * atpress / (273.16 + attemp) / (273.16 + attemp);
|
|
/* return -0.03203*sqrt(geoalt)*sqrt(d); */
|
|
/* double a = acos(1/(1+geoalt/EARTH_RADIUS)); */
|
|
return -180.0 / PI * acos(1 / (1 + geoalt / EARTH_RADIUS)) * sqrt(d);
|
|
}
|
|
|
|
|
|
/* Computes attributes of a lunar eclipse for given tjd and geopos
|
|
*
|
|
* retflag SE_ECL_TOTAL or SE_ECL_PARTIAL
|
|
* SE_ECL_PENUMBRAL
|
|
* if 0, there is no eclipse
|
|
*
|
|
* attr[0] umbral magnitude at tjd
|
|
* attr[1] penumbral magnitude
|
|
* attr[4] azimuth of moon at tjd
|
|
* attr[5] true altitude of moon above horizon at tjd
|
|
* attr[6] apparent altitude of moon above horizon at tjd
|
|
* attr[7] distance of moon from opposition in degrees
|
|
* attr[8] umbral magnitude at tjd (= attr[0])
|
|
* attr[9] saros series number
|
|
* attr[10] saros series member number
|
|
* declare as attr[20] at least !
|
|
*
|
|
*/
|
|
int32 FAR PASCAL_CONV
|
|
swe_lun_eclipse_how(double tjd_ut, int32 ifl, double *geopos, double *attr,
|
|
char *serr)
|
|
{
|
|
double dcore[10];
|
|
double lm[6], xaz[6];
|
|
int32 retc;
|
|
/* attention: geopos[] is not used so far; may be NULL */
|
|
if (geopos != NULL)
|
|
geopos[0] = geopos[0]; /* to shut up mint */
|
|
ifl = ifl & ~SEFLG_TOPOCTR;
|
|
retc = lun_eclipse_how(tjd_ut, ifl, attr, dcore, serr);
|
|
if (geopos == NULL)
|
|
return retc;
|
|
/*
|
|
* azimuth and altitude of moon
|
|
*/
|
|
swe_set_topo(geopos[0], geopos[1], geopos[2]);
|
|
if (swe_calc_ut
|
|
(tjd_ut, SE_MOON, ifl | SEFLG_TOPOCTR | SEFLG_EQUATORIAL, lm,
|
|
serr) == ERR)
|
|
return ERR;
|
|
swe_azalt(tjd_ut, SE_EQU2HOR, geopos, 0, 10, lm, xaz);
|
|
attr[4] = xaz[0];
|
|
attr[5] = xaz[1];
|
|
attr[6] = xaz[2];
|
|
if (xaz[2] <= 0)
|
|
retc = 0;
|
|
return retc;
|
|
}
|
|
|
|
/*
|
|
* attr[]: see swe_lun_eclipse_how()
|
|
*
|
|
* dcore[0]: distance of shadow axis from geocenter r0
|
|
* dcore[1]: diameter of core shadow on fundamental plane d0
|
|
* dcore[2]: diameter of half-shadow on fundamental plane D0
|
|
*/
|
|
static int32
|
|
lun_eclipse_how(double tjd_ut, int32 ifl, double *attr, double *dcore,
|
|
char *serr)
|
|
{
|
|
int i, j, k;
|
|
int32 retc = 0;
|
|
double e[6], rm[6], rs[6];
|
|
double dsm, d0, D0, s0, r0, ds, dm;
|
|
double dctr, x1[6], x2[6];
|
|
double f1, f2;
|
|
double deltat, tjd, d;
|
|
double cosf1, cosf2;
|
|
double rmoon = RMOON;
|
|
double dmoon = 2 * rmoon;
|
|
int32 iflag;
|
|
for (i = 0; i < 10; i++)
|
|
dcore[i] = 0;
|
|
for (i = 0; i < 20; i++)
|
|
attr[i] = 0;
|
|
/* nutation need not be in lunar and solar positions,
|
|
* if mean sidereal time will be used */
|
|
iflag = SEFLG_SPEED | SEFLG_EQUATORIAL | ifl;
|
|
iflag = iflag | SEFLG_XYZ;
|
|
deltat = swe_deltat(tjd_ut);
|
|
tjd = tjd_ut + deltat;
|
|
/* moon in cartesian coordinates */
|
|
if (swe_calc(tjd, SE_MOON, iflag, rm, serr) == ERR)
|
|
return ERR;
|
|
/* distance of moon from geocenter */
|
|
dm = sqrt(square_sum(rm));
|
|
/* sun in cartesian coordinates */
|
|
if (swe_calc(tjd, SE_SUN, iflag, rs, serr) == ERR)
|
|
return ERR;
|
|
/* distance of sun from geocenter */
|
|
ds = sqrt(square_sum(rs));
|
|
for (i = 0; i < 3; i++) {
|
|
x1[i] = rs[i] / ds;
|
|
x2[i] = rm[i] / dm;
|
|
}
|
|
dctr = acos(swi_dot_prod_unit(x1, x2)) * RADTODEG;
|
|
/* selenocentric sun */
|
|
for (i = 0; i <= 2; i++)
|
|
rs[i] -= rm[i];
|
|
/* selenocentric earth */
|
|
for (i = 0; i <= 2; i++)
|
|
rm[i] = -rm[i];
|
|
/* sun - earth vector */
|
|
for (i = 0; i <= 2; i++)
|
|
e[i] = (rm[i] - rs[i]);
|
|
/* distance sun - earth */
|
|
dsm = sqrt(square_sum(e));
|
|
/* sun - earth unit vector */
|
|
for (i = 0; i <= 2; i++)
|
|
e[i] /= dsm;
|
|
f1 = ((RSUN - REARTH) / dsm);
|
|
cosf1 = sqrt(1 - f1 * f1);
|
|
f2 = ((RSUN + REARTH) / dsm);
|
|
cosf2 = sqrt(1 - f2 * f2);
|
|
/* distance of earth from fundamental plane */
|
|
s0 = -dot_prod(rm, e);
|
|
/* distance of shadow axis from selenocenter */
|
|
r0 = sqrt(dm * dm - s0 * s0);
|
|
/* diameter of core shadow on fundamental plane */
|
|
/* one 50th is added for effect of atmosphere, AA98, L4 */
|
|
d0 = fabs(s0 / dsm * (DSUN - DEARTH) - DEARTH) * (1 + 1.0 / 50.0) / cosf1;
|
|
/* diameter of half-shadow on fundamental plane */
|
|
D0 = (s0 / dsm * (DSUN + DEARTH) + DEARTH) * (1 + 1.0 / 50.0) / cosf2;
|
|
d0 /= cosf1;
|
|
D0 /= cosf2;
|
|
/* for better agreement with NASA: */
|
|
d0 *= 0.99405;
|
|
D0 *= 0.98813;
|
|
dcore[0] = r0;
|
|
dcore[1] = d0;
|
|
dcore[2] = D0;
|
|
dcore[3] = cosf1;
|
|
dcore[4] = cosf2;
|
|
|
|
/**************************
|
|
* phase and umbral magnitude
|
|
**************************/
|
|
retc = 0;
|
|
if (d0 / 2 >= r0 + rmoon / cosf1) {
|
|
retc = SE_ECL_TOTAL;
|
|
attr[0] = (d0 / 2 - r0 + rmoon) / dmoon;
|
|
}
|
|
else if (d0 / 2 >= r0 - rmoon / cosf1) {
|
|
retc = SE_ECL_PARTIAL;
|
|
attr[0] = (d0 / 2 - r0 + rmoon) / dmoon;
|
|
}
|
|
else if (D0 / 2 >= r0 - rmoon / cosf2) {
|
|
retc = SE_ECL_PENUMBRAL;
|
|
attr[0] = 0;
|
|
}
|
|
else {
|
|
if (serr != NULL)
|
|
sprintf(serr, "no lunar eclipse at tjd = %f", tjd);
|
|
}
|
|
attr[8] = attr[0];
|
|
|
|
/**************************
|
|
* penumbral magnitude
|
|
**************************/
|
|
attr[1] = (D0 / 2 - r0 + rmoon) / dmoon;
|
|
if (retc != 0)
|
|
attr[7] = 180 - fabs(dctr);
|
|
/* saros series and member */
|
|
for (i = 0; i < NSAROS_LUNAR; i++) {
|
|
d = (tjd_ut - saros_data_lunar[i].tstart) / SAROS_CYCLE;
|
|
if (d < 0)
|
|
continue;
|
|
j = (int)d;
|
|
if ((d - j) * SAROS_CYCLE < 2) {
|
|
attr[9] = (double)saros_data_lunar[i].series_no;
|
|
attr[10] = (double)j + 1;
|
|
break;
|
|
}
|
|
k = j + 1;
|
|
if ((k - d) * SAROS_CYCLE < 2) {
|
|
attr[9] = (double)saros_data_lunar[i].series_no;
|
|
attr[10] = (double)k + 1;
|
|
break;
|
|
}
|
|
}
|
|
if (i == NSAROS_LUNAR) {
|
|
attr[9] = attr[10] = -99999999;
|
|
}
|
|
return retc;
|
|
}
|
|
|
|
/* When is the next lunar eclipse?
|
|
*
|
|
* retflag SE_ECL_TOTAL or SE_ECL_PENUMBRAL or SE_ECL_PARTIAL
|
|
*
|
|
* tret[0] time of maximum eclipse
|
|
* tret[1]
|
|
* tret[2] time of partial phase begin (indices consistent with solar eclipses)
|
|
* tret[3] time of partial phase end
|
|
* tret[4] time of totality begin
|
|
* tret[5] time of totality end
|
|
* tret[6] time of penumbral phase begin
|
|
* tret[7] time of penumbral phase end
|
|
*/
|
|
int32 FAR PASCAL_CONV
|
|
swe_lun_eclipse_when(double tjd_start, int32 ifl, int32 ifltype, double *tret,
|
|
int32 backward, char *serr)
|
|
{
|
|
int i, j, m, n, o, i1 = 0, i2 = 0;
|
|
int32 retflag = 0, retflag2 = 0;
|
|
double t, tjd, dt, dtint, dta, dtb;
|
|
double T, T2, T3, T4, K, F, M, Mm;
|
|
double E, Ff, F1, A1, Om;
|
|
double xs[6], xm[6], dm, ds;
|
|
double rsun, rearth, dcore[10];
|
|
double dc[3], dctr;
|
|
double twohr = 2.0 / 24.0;
|
|
double tenmin = 10.0 / 24.0 / 60.0;
|
|
double dt1, dt2;
|
|
double kk;
|
|
double attr[20];
|
|
double dtstart, dtdiv;
|
|
double xa[6], xb[6];
|
|
int direction = 1;
|
|
int32 iflag;
|
|
int32 iflagcart;
|
|
ifl &= SEFLG_EPHMASK;
|
|
iflag = SEFLG_EQUATORIAL | ifl;
|
|
iflagcart = iflag | SEFLG_XYZ;
|
|
if (ifltype == 0)
|
|
ifltype = SE_ECL_TOTAL | SE_ECL_PENUMBRAL | SE_ECL_PARTIAL;
|
|
if (backward)
|
|
direction = -1;
|
|
K = (int)((tjd_start - J2000) / 365.2425 * 12.3685);
|
|
K -= direction;
|
|
next_try:
|
|
retflag = 0;
|
|
for (i = 0; i <= 9; i++)
|
|
tret[i] = 0;
|
|
kk = K + 0.5;
|
|
T = kk / 1236.85;
|
|
T2 = T * T;
|
|
T3 = T2 * T;
|
|
T4 = T3 * T;
|
|
Ff = F =
|
|
swe_degnorm(160.7108 + 390.67050274 * kk - 0.0016341 * T2 -
|
|
0.00000227 * T3 + 0.000000011 * T4);
|
|
if (Ff > 180)
|
|
Ff -= 180;
|
|
if (Ff > 21 && Ff < 159) { /* no eclipse possible */
|
|
K += direction;
|
|
goto next_try;
|
|
}
|
|
/* approximate time of geocentric maximum eclipse
|
|
* formula from Meeus, German, p. 381 */
|
|
tjd =
|
|
2451550.09765 + 29.530588853 * kk + 0.0001337 * T2 -
|
|
0.000000150 * T3 + 0.00000000073 * T4;
|
|
M = swe_degnorm(2.5534 + 29.10535669 * kk - 0.0000218 * T2 -
|
|
0.00000011 * T3);
|
|
Mm = swe_degnorm(201.5643 + 385.81693528 * kk + 0.1017438 * T2 +
|
|
0.00001239 * T3 + 0.000000058 * T4);
|
|
Om = swe_degnorm(124.7746 - 1.56375580 * kk + 0.0020691 * T2 +
|
|
0.00000215 * T3);
|
|
E = 1 - 0.002516 * T - 0.0000074 * T2;
|
|
A1 = swe_degnorm(299.77 + 0.107408 * kk - 0.009173 * T2);
|
|
M *= DEGTORAD;
|
|
Mm *= DEGTORAD;
|
|
F *= DEGTORAD;
|
|
Om *= DEGTORAD;
|
|
F1 = F - 0.02665 * sin(Om) * DEGTORAD;
|
|
A1 *= DEGTORAD;
|
|
tjd = tjd - 0.4075 * sin(Mm)
|
|
+ 0.1721 * E * sin(M)
|
|
+ 0.0161 * sin(2 * Mm)
|
|
- 0.0097 * sin(2 * F1)
|
|
+ 0.0073 * E * sin(Mm - M)
|
|
- 0.0050 * E * sin(Mm + M)
|
|
- 0.0023 * sin(Mm - 2 * F1)
|
|
+ 0.0021 * E * sin(2 * M)
|
|
+ 0.0012 * sin(Mm + 2 * F1)
|
|
+ 0.0006 * E * sin(2 * Mm + M)
|
|
- 0.0004 * sin(3 * Mm)
|
|
- 0.0003 * E * sin(M + 2 * F1)
|
|
+ 0.0003 * sin(A1)
|
|
- 0.0002 * E * sin(M - 2 * F1)
|
|
- 0.0002 * E * sin(2 * Mm - M)
|
|
- 0.0002 * sin(Om);
|
|
/*
|
|
* precise computation:
|
|
* time of maximum eclipse (if eclipse) =
|
|
* minimum selenocentric angle between sun and earth edges.
|
|
* After this time has been determined, check
|
|
* whether or not an eclipse is taking place with
|
|
* the function lun_eclipse_how().
|
|
*/
|
|
dtstart = 0.1;
|
|
if (tjd < 2000000)
|
|
dtstart = 5;
|
|
dtdiv = 4;
|
|
for (j = 0, dt = dtstart; dt > 0.001; j++, dt /= dtdiv) {
|
|
for (i = 0, t = tjd - dt; i <= 2; i++, t += dt) {
|
|
if (swe_calc(t, SE_SUN, iflagcart, xs, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(t, SE_MOON, iflagcart, xm, serr) == ERR)
|
|
return ERR;
|
|
for (m = 0; m < 3; m++) {
|
|
xs[m] -= xm[m]; /* selenocentric sun */
|
|
xm[m] = -xm[m]; /* selenocentric earth */
|
|
}
|
|
ds = sqrt(square_sum(xs));
|
|
dm = sqrt(square_sum(xm));
|
|
for (m = 0; m < 3; m++) {
|
|
xa[m] = xs[m] / ds;
|
|
xb[m] = xm[m] / dm;
|
|
}
|
|
dc[i] = acos(swi_dot_prod_unit(xa, xb)) * RADTODEG;
|
|
rearth = asin(REARTH / dm) * RADTODEG;
|
|
rsun = asin(RSUN / ds) * RADTODEG;
|
|
dc[i] -= (rearth + rsun);
|
|
}
|
|
find_maximum(dc[0], dc[1], dc[2], dt, &dtint, &dctr);
|
|
tjd += dtint + dt;
|
|
}
|
|
tjd = tjd - swe_deltat(tjd);
|
|
if ((retflag = swe_lun_eclipse_how(tjd, ifl, NULL, attr, serr)) == ERR)
|
|
return retflag;
|
|
if (retflag == 0) {
|
|
K += direction;
|
|
goto next_try;
|
|
}
|
|
tret[0] = tjd;
|
|
if ((backward && tret[0] >= tjd_start - 0.0001)
|
|
|| (!backward && tret[0] <= tjd_start + 0.0001)) {
|
|
K += direction;
|
|
goto next_try;
|
|
}
|
|
/*
|
|
* check whether or not eclipse type found is wanted
|
|
*/
|
|
/* non penumbral eclipse is wanted: */
|
|
if (!(ifltype & SE_ECL_PENUMBRAL) && (retflag & SE_ECL_PENUMBRAL)) {
|
|
K += direction;
|
|
goto next_try;
|
|
}
|
|
/* non partial eclipse is wanted: */
|
|
if (!(ifltype & SE_ECL_PARTIAL) && (retflag & SE_ECL_PARTIAL)) {
|
|
K += direction;
|
|
goto next_try;
|
|
}
|
|
/* annular-total eclipse will be discovered later */
|
|
if (!(ifltype & (SE_ECL_TOTAL)) && (retflag & SE_ECL_TOTAL)) {
|
|
K += direction;
|
|
goto next_try;
|
|
}
|
|
/*
|
|
* n = 0: times of eclipse begin and end
|
|
* n = 1: times of totality begin and end
|
|
* n = 2: times of center line begin and end
|
|
*/
|
|
if (retflag & SE_ECL_PENUMBRAL)
|
|
o = 0;
|
|
else if (retflag & SE_ECL_PARTIAL)
|
|
o = 1;
|
|
else
|
|
o = 2;
|
|
dta = twohr;
|
|
dtb = tenmin;
|
|
for (n = 0; n <= o; n++) {
|
|
if (n == 0) {
|
|
i1 = 6;
|
|
i2 = 7;
|
|
}
|
|
else if (n == 1) {
|
|
i1 = 2;
|
|
i2 = 3;
|
|
}
|
|
else if (n == 2) {
|
|
i1 = 4;
|
|
i2 = 5;
|
|
}
|
|
#if 1
|
|
for (i = 0, t = tjd - dta; i <= 2; i += 1, t += dta) {
|
|
if ((retflag2 =
|
|
lun_eclipse_how(t, ifl, attr, dcore, serr)) == ERR)
|
|
return retflag2;
|
|
if (n == 0)
|
|
dc[i] = dcore[2] / 2 + RMOON / dcore[4] - dcore[0];
|
|
else if (n == 1)
|
|
dc[i] = dcore[1] / 2 + RMOON / dcore[3] - dcore[0];
|
|
else if (n == 2)
|
|
dc[i] = dcore[1] / 2 - RMOON / dcore[3] - dcore[0];
|
|
}
|
|
find_zero(dc[0], dc[1], dc[2], dta, &dt1, &dt2);
|
|
dtb = (dt1 + dta) / 2;
|
|
tret[i1] = tjd + dt1 + dta;
|
|
tret[i2] = tjd + dt2 + dta;
|
|
#else
|
|
tret[i1] = tjd - dtb;
|
|
tret[i2] = tjd + dtb;
|
|
#endif
|
|
for (m = 0, dt = dtb / 2; m < 3; m++, dt /= 2) {
|
|
for (j = i1; j <= i2; j += (i2 - i1)) {
|
|
for (i = 0, t = tret[j] - dt; i < 2; i++, t += dt) {
|
|
if ((retflag2 =
|
|
lun_eclipse_how(t, ifl, attr, dcore, serr)) == ERR)
|
|
return retflag2;
|
|
if (n == 0)
|
|
dc[i] = dcore[2] / 2 + RMOON / dcore[4] - dcore[0];
|
|
else if (n == 1)
|
|
dc[i] = dcore[1] / 2 + RMOON / dcore[3] - dcore[0];
|
|
else if (n == 2)
|
|
dc[i] = dcore[1] / 2 - RMOON / dcore[3] - dcore[0];
|
|
}
|
|
dt1 = dc[1] / ((dc[1] - dc[0]) / dt);
|
|
tret[j] -= dt1;
|
|
}
|
|
}
|
|
}
|
|
return retflag;
|
|
}
|
|
|
|
/*
|
|
* function calculates planetary phenomena
|
|
*
|
|
* attr[0] = phase angle (earth-planet-sun)
|
|
* attr[1] = phase (illumined fraction of disc)
|
|
* attr[2] = elongation of planet
|
|
* attr[3] = apparent diameter of disc
|
|
* attr[4] = apparent magnitude
|
|
* attr[5] = geocentric horizontal parallax (Moon)
|
|
* declare as attr[20] at least !
|
|
*
|
|
* Note: the lunar magnitude is quite a complicated thing,
|
|
* but our algorithm is very simple.
|
|
* The phase of the moon, its distance from the earth and
|
|
* the sun is considered, but no other factors.
|
|
*
|
|
*/
|
|
#define EULER 2.718281828459
|
|
#define NMAG_ELEM (SE_VESTA + 1)
|
|
static double mag_elem[NMAG_ELEM][4] = {
|
|
/* DTV-Atlas Astronomie, p. 32 */
|
|
{-26.86, 0, 0, 0},
|
|
{-12.55, 0, 0, 0},
|
|
/* IAU 1986 */
|
|
{-0.42, 3.80, -2.73, 2.00},
|
|
{-4.40, 0.09, 2.39, -0.65},
|
|
{-1.52, 1.60, 0, 0}, /* Mars */
|
|
{-9.40, 0.5, 0, 0}, /* Jupiter */
|
|
{-8.88, -2.60, 1.25, 0.044}, /* Saturn */
|
|
{-7.19, 0.0, 0, 0}, /* Uranus */
|
|
{-6.87, 0.0, 0, 0}, /* Neptune */
|
|
{-1.00, 0.0, 0, 0}, /* Pluto */
|
|
{99, 0, 0, 0}, /* nodes and apogees */
|
|
{99, 0, 0, 0},
|
|
{99, 0, 0, 0},
|
|
{99, 0, 0, 0},
|
|
{99, 0, 0, 0}, /* Earth */
|
|
/* from Bowell data base */
|
|
{6.5, 0.15, 0, 0}, /* Chiron */
|
|
{7.0, 0.15, 0, 0}, /* Pholus */
|
|
{3.34, 0.12, 0, 0}, /* Ceres */
|
|
{4.13, 0.11, 0, 0}, /* Pallas */
|
|
{5.33, 0.32, 0, 0}, /* Juno */
|
|
{3.20, 0.32, 0, 0}, /* Vesta */
|
|
};
|
|
|
|
int32 FAR PASCAL_CONV
|
|
swe_pheno(double tjd, int32 ipl, int32 iflag, double *attr, char *serr)
|
|
{
|
|
int i;
|
|
double xx[6], xx2[6], xxs[6], lbr[6], lbr2[6], dt = 0, dd;
|
|
double fac;
|
|
double T, in, om, sinB, u1, u2, du;
|
|
double ph1, ph2, me[2];
|
|
int32 iflagp, epheflag;
|
|
/* function calls for Pluto with asteroid number 134340
|
|
* are treated as calls for Pluto as main body SE_PLUTO */
|
|
if (ipl == SE_AST_OFFSET + 134340)
|
|
ipl = SE_PLUTO;
|
|
for (i = 0; i < 20; i++)
|
|
attr[i] = 0;
|
|
/* Ceres - Vesta must be SE_CERES etc., not 10001 etc. */
|
|
if (ipl > SE_AST_OFFSET && ipl <= SE_AST_OFFSET + 4)
|
|
ipl = ipl - SE_AST_OFFSET - 1 + SE_CERES;
|
|
iflag =
|
|
iflag & (SEFLG_EPHMASK | SEFLG_TRUEPOS | SEFLG_J2000 | SEFLG_NONUT |
|
|
SEFLG_NOGDEFL | SEFLG_NOABERR | SEFLG_TOPOCTR);
|
|
iflagp =
|
|
iflag & (SEFLG_EPHMASK | SEFLG_TRUEPOS | SEFLG_J2000 | SEFLG_NONUT |
|
|
SEFLG_NOABERR);
|
|
iflagp |= SEFLG_HELCTR;
|
|
epheflag = iflag & SEFLG_EPHMASK;
|
|
/*
|
|
* geocentric planet
|
|
*/
|
|
if (swe_calc(tjd, (int)ipl, iflag | SEFLG_XYZ, xx, serr) == ERR)
|
|
/* int cast can be removed when swe_calc() gets int32 ipl definition */
|
|
return ERR;
|
|
if (swe_calc(tjd, (int)ipl, iflag, lbr, serr) == ERR)
|
|
/* int cast can be removed when swe_calc() gets int32 ipl definition */
|
|
return ERR;
|
|
/* if moon, we need sun as well, for magnitude */
|
|
if (ipl == SE_MOON)
|
|
if (swe_calc(tjd, SE_SUN, iflag | SEFLG_XYZ, xxs, serr) == ERR)
|
|
return ERR;
|
|
if (ipl != SE_SUN && ipl != SE_EARTH && ipl != SE_MEAN_NODE
|
|
&& ipl != SE_TRUE_NODE && ipl != SE_MEAN_APOG
|
|
&& ipl != SE_OSCU_APOG) {
|
|
/*
|
|
* light time planet - earth
|
|
*/
|
|
dt = lbr[2] * AUNIT / CLIGHT / 86400.0;
|
|
if (iflag & SEFLG_TRUEPOS)
|
|
dt = 0;
|
|
/*
|
|
* heliocentric planet at tjd - dt
|
|
*/
|
|
if (swe_calc(tjd - dt, (int)ipl, iflagp | SEFLG_XYZ, xx2, serr) ==
|
|
ERR)
|
|
/* int cast can be removed when swe_calc() gets int32 ipl definition */
|
|
return ERR;
|
|
if (swe_calc(tjd - dt, (int)ipl, iflagp, lbr2, serr) == ERR)
|
|
/* int cast can be removed when swe_calc() gets int32 ipl definition */
|
|
return ERR;
|
|
/*
|
|
* phase angle
|
|
*/
|
|
attr[0] = acos(swi_dot_prod_unit(xx, xx2)) * RADTODEG;
|
|
/*
|
|
* phase
|
|
*/
|
|
attr[1] = (1 + cos(attr[0] * DEGTORAD)) / 2;
|
|
}
|
|
/*
|
|
* apparent diameter of disk
|
|
*/
|
|
if (ipl < NDIAM)
|
|
dd = pla_diam[ipl];
|
|
else if (ipl > SE_AST_OFFSET)
|
|
dd = swed.ast_diam * 1000; /* km -> m */
|
|
else
|
|
dd = 0;
|
|
if (lbr[2] < dd / 2 / AUNIT)
|
|
attr[3] = 180; /* assume position on surface of earth */
|
|
else
|
|
attr[3] = asin(dd / 2 / AUNIT / lbr[2]) * 2 * RADTODEG;
|
|
/*
|
|
* apparent magnitude
|
|
*/
|
|
if (ipl > SE_AST_OFFSET || (ipl < NMAG_ELEM && mag_elem[ipl][0] < 99)) {
|
|
if (ipl == SE_SUN) {
|
|
/* ratio apparent diameter : average diameter */
|
|
fac =
|
|
attr[3] / (asin(pla_diam[SE_SUN] / 2.0 / AUNIT) * 2 *
|
|
RADTODEG);
|
|
fac *= fac;
|
|
attr[4] = mag_elem[ipl][0] - 2.5 * log10(fac);
|
|
}
|
|
else if (ipl == SE_MOON) {
|
|
/* formula according to Allen, C.W., 1976, Astrophysical Quantities */
|
|
/*attr[4] = -21.62 + 5 * log10(384410497.8 / EARTH_RADIUS) / log10(10) + 0.026 * fabs(attr[0]) + 0.000000004 * pow(attr[0], 4); */
|
|
attr[4] =
|
|
-21.62 +
|
|
5 * log10(lbr[2] * AUNIT / EARTH_RADIUS) / log10(10) +
|
|
0.026 * fabs(attr[0]) + 0.000000004 * pow(attr[0], 4);
|
|
#if 0
|
|
/* ratio apparent diameter : average diameter */
|
|
fac =
|
|
attr[3] / (asin(pla_diam[SE_MOON] / 2.0 / 384400000.0) * 2 *
|
|
RADTODEG);
|
|
/* distance sun - moon */
|
|
for (i = 0; i < 3; i++)
|
|
xxs[i] -= xx[i];
|
|
dsm = sqrt(square_sum(xxs));
|
|
/* account for phase and distance of moon: */
|
|
fac *= fac * attr[1];
|
|
/* account for distance of sun from moon: */
|
|
fac *= dsm * dsm;
|
|
attr[4] = mag_elem[ipl][0] - 2.5 * log10(fac);
|
|
#endif
|
|
/*printf("1 = %f, 2 = %f\n", mag, mag2); */
|
|
}
|
|
else if (ipl == SE_SATURN) {
|
|
/* rings are considered according to Meeus, German, p. 329ff. */
|
|
T = (tjd - dt - J2000) / 36525.0;
|
|
in = (28.075216 - 0.012998 * T + 0.000004 * T * T) * DEGTORAD;
|
|
om = (169.508470 + 1.394681 * T + 0.000412 * T * T) * DEGTORAD;
|
|
sinB = fabs(sin(in) * cos(lbr[1] * DEGTORAD)
|
|
* sin(lbr[0] * DEGTORAD - om)
|
|
- cos(in) * sin(lbr[1] * DEGTORAD));
|
|
u1 = atan2(sin(in) * tan(lbr2[1] * DEGTORAD)
|
|
+ cos(in) * sin(lbr2[0] * DEGTORAD - om),
|
|
cos(lbr2[0] * DEGTORAD - om)) * RADTODEG;
|
|
u2 = atan2(sin(in) * tan(lbr[1] * DEGTORAD)
|
|
+ cos(in) * sin(lbr[0] * DEGTORAD - om),
|
|
cos(lbr[0] * DEGTORAD - om)) * RADTODEG;
|
|
du = swe_degnorm(u1 - u2);
|
|
if (du > 10)
|
|
du = 360 - du;
|
|
attr[4] = 5 * log10(lbr2[2] * lbr[2])
|
|
+ mag_elem[ipl][1] * sinB + mag_elem[ipl][2] * sinB * sinB +
|
|
mag_elem[ipl][3] * du + mag_elem[ipl][0];
|
|
}
|
|
else if (ipl < SE_CHIRON) {
|
|
attr[4] = 5 * log10(lbr2[2] * lbr[2])
|
|
+ mag_elem[ipl][1] * attr[0] / 100.0 +
|
|
mag_elem[ipl][2] * attr[0] * attr[0] / 10000.0 +
|
|
mag_elem[ipl][3] * attr[0] * attr[0] * attr[0] / 1000000.0 +
|
|
mag_elem[ipl][0];
|
|
}
|
|
else if (ipl < NMAG_ELEM || ipl > SE_AST_OFFSET) { /* asteroids */
|
|
ph1 = pow(EULER, -3.33 * pow(tan(attr[0] * DEGTORAD / 2), 0.63));
|
|
ph2 = pow(EULER, -1.87 * pow(tan(attr[0] * DEGTORAD / 2), 1.22));
|
|
if (ipl < NMAG_ELEM) { /* main asteroids */
|
|
me[0] = mag_elem[ipl][0];
|
|
me[1] = mag_elem[ipl][1];
|
|
}
|
|
else if (ipl == SE_AST_OFFSET + 1566) {
|
|
/* Icarus has elements from JPL database */
|
|
me[0] = 16.9;
|
|
me[1] = 0.15;
|
|
}
|
|
else { /* other asteroids */
|
|
me[0] = swed.ast_H;
|
|
me[1] = swed.ast_G;
|
|
}
|
|
attr[4] = 5 * log10(lbr2[2] * lbr[2])
|
|
+ me[0]
|
|
- 2.5 * log10((1 - me[1]) * ph1 + me[1] * ph2);
|
|
}
|
|
else { /* ficticious bodies */
|
|
attr[4] = 0;
|
|
}
|
|
}
|
|
if (ipl != SE_SUN && ipl != SE_EARTH) {
|
|
/*
|
|
* elongation of planet
|
|
*/
|
|
if (swe_calc(tjd, SE_SUN, iflag | SEFLG_XYZ, xx2, serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(tjd, SE_SUN, iflag, lbr2, serr) == ERR)
|
|
return ERR;
|
|
attr[2] = acos(swi_dot_prod_unit(xx, xx2)) * RADTODEG;
|
|
}
|
|
/* horizontal parallax */
|
|
if (ipl == SE_MOON) {
|
|
double sinhp, xm[6];
|
|
/* geocentric horizontal parallax */
|
|
/* Expl.Suppl. to the AA 1984, p.400 */
|
|
if (swe_calc
|
|
(tjd, (int)ipl,
|
|
epheflag | SEFLG_TRUEPOS | SEFLG_EQUATORIAL | SEFLG_RADIANS, xm,
|
|
serr) == ERR)
|
|
/* int cast can be removed when swe_calc() gets int32 ipl definition */
|
|
return ERR;
|
|
sinhp = EARTH_RADIUS / xm[2] / AUNIT;
|
|
attr[5] = asin(sinhp) / DEGTORAD;
|
|
/* topocentric horizontal parallax */
|
|
if (iflag & SEFLG_TOPOCTR) {
|
|
if (swe_calc
|
|
(tjd, (int)ipl, epheflag | SEFLG_XYZ | SEFLG_TOPOCTR, xm,
|
|
serr) == ERR)
|
|
return ERR;
|
|
if (swe_calc(tjd, (int)ipl, epheflag | SEFLG_XYZ, xx, serr) ==
|
|
ERR)
|
|
return ERR;
|
|
attr[5] = acos(swi_dot_prod_unit(xm, xx)) / DEGTORAD;
|
|
#if 0
|
|
{
|
|
/* Expl. Suppl. to the Astronomical Almanac 1984, p. 400;
|
|
* Does not take into account
|
|
* - the topocentric distance of the moon
|
|
* - the distance of the observer from the geocenter
|
|
*/
|
|
double tsid, h, e, f = EARTH_OBLATENESS;
|
|
double cosz, sinz, phi;
|
|
/* local apparent sidereal time */
|
|
tsid =
|
|
swe_sidtime(tjd - swe_deltat(tjd)) * 15 +
|
|
swed.topd.geolon;
|
|
/* local hour angle of the moon */
|
|
h = swe_degnorm(tsid - xm[0] / DEGTORAD);
|
|
/* geocentric latitude of the observer */
|
|
e = sqrt(f * (2 - f));
|
|
phi = atan((1 - e * e) * tan(swed.topd.geolat * DEGTORAD));
|
|
/* sine of geocentric zenith angle of moon */
|
|
cosz =
|
|
sin(xm[1]) * sin(phi) +
|
|
cos(xm[1]) * cos(phi) * cos(h * DEGTORAD);
|
|
sinz = sqrt(1 - cosz * cosz);
|
|
attr[5] = asin(sinz * sinhp / (1 - sinz * sinhp)) / DEGTORAD;
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
int32 FAR PASCAL_CONV
|
|
swe_pheno_ut(double tjd_ut, int32 ipl, int32 iflag, double *attr, char *serr)
|
|
{
|
|
return swe_pheno(tjd_ut + swe_deltat(tjd_ut), ipl, iflag, attr, serr);
|
|
}
|
|
|
|
static int
|
|
find_maximum(double y00, double y11, double y2, double dx, double *dxret,
|
|
double *yret)
|
|
{
|
|
double a, b, c, x, y;
|
|
c = y11;
|
|
b = (y2 - y00) / 2.0;
|
|
a = (y2 + y00) / 2.0 - c;
|
|
x = -b / 2 / a;
|
|
y = (4 * a * c - b * b) / 4 / a;
|
|
*dxret = (x - 1) * dx;
|
|
if (yret != NULL)
|
|
*yret = y;
|
|
return OK;
|
|
}
|
|
|
|
static int
|
|
find_zero(double y00, double y11, double y2, double dx, double *dxret,
|
|
double *dxret2)
|
|
{
|
|
double a, b, c, x1, x2;
|
|
c = y11;
|
|
b = (y2 - y00) / 2.0;
|
|
a = (y2 + y00) / 2.0 - c;
|
|
if (b * b - 4 * a * c < 0)
|
|
return ERR;
|
|
x1 = (-b + sqrt(b * b - 4 * a * c)) / 2 / a;
|
|
x2 = (-b - sqrt(b * b - 4 * a * c)) / 2 / a;
|
|
*dxret = (x1 - 1) * dx;
|
|
*dxret2 = (x2 - 1) * dx;
|
|
return OK;
|
|
}
|
|
|
|
double
|
|
rdi_twilight(int32 rsmi)
|
|
{
|
|
double rdi = 0;
|
|
if (rsmi & SE_BIT_CIVIL_TWILIGHT)
|
|
rdi = 6;
|
|
if (rsmi & SE_BIT_NAUTIC_TWILIGHT)
|
|
rdi = 12;
|
|
if (rsmi & SE_BIT_ASTRO_TWILIGHT)
|
|
rdi = 18;
|
|
return rdi;
|
|
}
|
|
|
|
/* rise, set, and meridian transits of sun, moon, planets, and stars
|
|
*
|
|
* tjd_ut universal time from when on search ought to start
|
|
* ipl planet number, neglected, if starname is given
|
|
* starname pointer to string. if a planet, not a star, is
|
|
* wanted, starname must be NULL or ""
|
|
* epheflag used for ephemeris only
|
|
* rsmi SE_CALC_RISE, SE_CALC_SET, SE_CALC_MTRANSIT, SE_CALC_ITRANSIT
|
|
* | SE_BIT_DISC_CENTER for rises of disc center of body
|
|
* | SE_BIT_DISC_BOTTOM for rises of disc bottom of body
|
|
* | SE_BIT_NO_REFRACTION to neglect refraction
|
|
* | SE_BIT_FIXED_DISC_SIZE neglect the effect of distance on disc size
|
|
* geopos array of doubles for geogr. long., lat. and height above sea
|
|
* atpress atmospheric pressure
|
|
* attemp atmospheric temperature
|
|
*
|
|
* return variables:
|
|
* tret time of rise, set, meridian transits
|
|
* serr[256] error string
|
|
* function return value -2 means that the body does not rise or set */
|
|
#define SEFLG_EPHMASK (SEFLG_JPLEPH|SEFLG_SWIEPH|SEFLG_MOSEPH)
|
|
int32 FAR PASCAL_CONV
|
|
swe_rise_trans(double tjd_ut, int32 ipl, char *starname, int32 epheflag,
|
|
int32 rsmi, double *geopos, double atpress, double attemp,
|
|
double *tret, char *serr)
|
|
{
|
|
return swe_rise_trans_true_hor(tjd_ut, ipl, starname, epheflag, rsmi,
|
|
geopos, atpress, attemp, 0, tret, serr);
|
|
}
|
|
|
|
/* same as swe_rise_trans(), but allows to define the height of the horizon
|
|
* at the point of the rising or setting (horhgt) */
|
|
int32 FAR PASCAL_CONV
|
|
swe_rise_trans_true_hor(double tjd_ut, int32 ipl, char *starname,
|
|
int32 epheflag, int32 rsmi, double *geopos,
|
|
double atpress, double attemp, double horhgt,
|
|
double *tret, char *serr)
|
|
{
|
|
int i, j, k, ii, calc_culm, nculm = -1;
|
|
double tjd_et = tjd_ut + swe_deltat(tjd_ut);
|
|
double xc[6], xh[20][6], ah[6], aha;
|
|
double tculm[4], tcu, tc[20], h[20], t2[6], dc[6], dtint, dx, rdi, dd = 0;
|
|
int32 iflag = epheflag;
|
|
int jmax = 14;
|
|
double t, te, tt, dt, twohrs = 1.0 / 12.0;
|
|
double curdist;
|
|
AS_BOOL do_fixstar = (starname != NULL && *starname != '\0');
|
|
/* function calls for Pluto with asteroid number 134340
|
|
* are treated as calls for Pluto as main body SE_PLUTO */
|
|
if (ipl == SE_AST_OFFSET + 134340)
|
|
ipl = SE_PLUTO;
|
|
xh[0][0] = 0; /* to shut up mint */
|
|
/* allowing SEFLG_NONUT and SEFLG_TRUEPOS speeds it up */
|
|
iflag &= (SEFLG_EPHMASK | SEFLG_NONUT | SEFLG_TRUEPOS);
|
|
*tret = 0;
|
|
iflag |= (SEFLG_EQUATORIAL | SEFLG_TOPOCTR);
|
|
swe_set_topo(geopos[0], geopos[1], geopos[2]);
|
|
if (rsmi & (SE_CALC_MTRANSIT | SE_CALC_ITRANSIT))
|
|
return calc_mer_trans(tjd_ut, ipl, epheflag, rsmi, geopos, starname,
|
|
tret, serr);
|
|
if (!(rsmi & (SE_CALC_RISE | SE_CALC_SET)))
|
|
rsmi |= SE_CALC_RISE;
|
|
/* twilight calculation */
|
|
if (ipl == SE_SUN
|
|
&& (rsmi &
|
|
(SE_BIT_CIVIL_TWILIGHT | SE_BIT_NAUTIC_TWILIGHT |
|
|
SE_BIT_ASTRO_TWILIGHT))) {
|
|
rsmi |= (SE_BIT_NO_REFRACTION | SE_BIT_DISC_CENTER);
|
|
horhgt = -rdi_twilight(rsmi);
|
|
/* note: twilight is not dependent on height of horizon, so we can
|
|
* use this parameter and define a fictitious height of horizon */
|
|
}
|
|
/* find culmination points within 28 hours from t0 - twohrs.
|
|
* culminations are required in case there are maxima or minima
|
|
* in height slightly above or below the horizon.
|
|
* we do not use meridian transits, because in polar regions
|
|
* the culmination points may considerably deviate from
|
|
* transits. also, there are cases where the moon rises in the
|
|
* western half of the sky for a short time.
|
|
*/
|
|
if (do_fixstar) {
|
|
if (swe_fixstar(starname, tjd_et, iflag, xc, serr) == ERR)
|
|
return ERR;
|
|
}
|
|
for (ii = 0, t = tjd_ut - twohrs; ii <= jmax; ii++, t += twohrs) {
|
|
tc[ii] = t;
|
|
if (!do_fixstar) {
|
|
te = t + swe_deltat(t);
|
|
if (swe_calc(te, ipl, iflag, xc, serr) == ERR)
|
|
return ERR;
|
|
}
|
|
/* diameter of object in km */
|
|
if (ii == 0) {
|
|
if (do_fixstar)
|
|
dd = 0;
|
|
else if (rsmi & SE_BIT_DISC_CENTER)
|
|
dd = 0;
|
|
else if (ipl < NDIAM)
|
|
dd = pla_diam[ipl];
|
|
else if (ipl > SE_AST_OFFSET)
|
|
dd = swed.ast_diam * 1000; /* km -> m */
|
|
else
|
|
dd = 0;
|
|
}
|
|
curdist = xc[2];
|
|
if (rsmi & SE_BIT_FIXED_DISC_SIZE) {
|
|
if (ipl == SE_SUN) {
|
|
curdist = 1.0;
|
|
}
|
|
else if (ipl == SE_MOON) {
|
|
curdist = 0.00257;
|
|
}
|
|
}
|
|
/* apparent radius of disc */
|
|
rdi = asin(dd / 2 / AUNIT / curdist) * RADTODEG;
|
|
/* true height of center of body */
|
|
swe_azalt(t, SE_EQU2HOR, geopos, atpress, attemp, xc, xh[ii]);
|
|
if (rsmi & SE_BIT_DISC_BOTTOM) {
|
|
/* true height of bottom point of body */
|
|
xh[ii][1] -= rdi;
|
|
}
|
|
else {
|
|
/* true height of uppermost point of body */
|
|
xh[ii][1] += rdi;
|
|
}
|
|
/* apparent height of uppermost point of body */
|
|
if (rsmi & SE_BIT_NO_REFRACTION) {
|
|
xh[ii][1] -= horhgt;
|
|
h[ii] = xh[ii][1];
|
|
}
|
|
else {
|
|
swe_azalt_rev(t, SE_HOR2EQU, geopos, xh[ii], xc);
|
|
swe_azalt(t, SE_EQU2HOR, geopos, atpress, attemp, xc, xh[ii]);
|
|
xh[ii][1] -= horhgt;
|
|
xh[ii][2] -= horhgt;
|
|
h[ii] = xh[ii][2];
|
|
}
|
|
calc_culm = 0;
|
|
if (ii > 1) {
|
|
dc[0] = xh[ii - 2][1];
|
|
dc[1] = xh[ii - 1][1];
|
|
dc[2] = xh[ii][1];
|
|
if (dc[1] > dc[0] && dc[1] > dc[2])
|
|
calc_culm = 1;
|
|
if (dc[1] < dc[0] && dc[1] < dc[2])
|
|
calc_culm = 2;
|
|
}
|
|
if (calc_culm) {
|
|
dt = twohrs;
|
|
tcu = t - dt;
|
|
find_maximum(dc[0], dc[1], dc[2], dt, &dtint, &dx);
|
|
tcu += dtint + dt;
|
|
dt /= 3;
|
|
for (; dt > 0.0001; dt /= 3) {
|
|
for (i = 0, tt = tcu - dt; i < 3; tt += dt, i++) {
|
|
te = tt + swe_deltat(tt);
|
|
if (!do_fixstar)
|
|
if (swe_calc(te, ipl, iflag, xc, serr) == ERR)
|
|
return ERR;
|
|
swe_azalt(tt, SE_EQU2HOR, geopos, atpress, attemp, xc,
|
|
ah);
|
|
ah[1] -= horhgt;
|
|
dc[i] = ah[1];
|
|
}
|
|
find_maximum(dc[0], dc[1], dc[2], dt, &dtint, &dx);
|
|
tcu += dtint + dt;
|
|
}
|
|
nculm++;
|
|
tculm[nculm] = tcu;
|
|
}
|
|
}
|
|
/* note: there can be a rise or set on the poles, even if
|
|
* there is no culmination. So, we must not leave here
|
|
* in any case. */
|
|
/* insert culminations into array of heights */
|
|
for (i = 0; i <= nculm; i++) {
|
|
for (j = 1; j <= jmax; j++) {
|
|
if (tculm[i] < tc[j]) {
|
|
for (k = jmax; k >= j; k--) {
|
|
tc[k + 1] = tc[k];
|
|
h[k + 1] = h[k];
|
|
}
|
|
tc[j] = tculm[i];
|
|
if (!do_fixstar) {
|
|
te = tc[j] + swe_deltat(tc[j]);
|
|
if (swe_calc(te, ipl, iflag, xc, serr) == ERR)
|
|
return ERR;
|
|
}
|
|
curdist = xc[2];
|
|
if (rsmi & SE_BIT_FIXED_DISC_SIZE) {
|
|
if (ipl == SE_SUN) {
|
|
curdist = 1.0;
|
|
}
|
|
else if (ipl == SE_MOON) {
|
|
curdist = 0.00257;
|
|
}
|
|
}
|
|
/* apparent radius of disc */
|
|
rdi = asin(dd / 2 / AUNIT / curdist) * RADTODEG;
|
|
/* true height of center of body */
|
|
swe_azalt(tc[j], SE_EQU2HOR, geopos, atpress, attemp, xc, ah);
|
|
if (rsmi & SE_BIT_DISC_BOTTOM) {
|
|
/* true height of bottom point of body */
|
|
ah[1] -= rdi;
|
|
}
|
|
else {
|
|
/* true height of uppermost point of body */
|
|
ah[1] += rdi;
|
|
}
|
|
/* apparent height of uppermost point of body */
|
|
if (rsmi & SE_BIT_NO_REFRACTION) {
|
|
ah[1] -= horhgt;
|
|
h[j] = ah[1];
|
|
}
|
|
else {
|
|
swe_azalt_rev(tc[j], SE_HOR2EQU, geopos, ah, xc);
|
|
swe_azalt(tc[j], SE_EQU2HOR, geopos, atpress, attemp, xc,
|
|
ah);
|
|
ah[1] -= horhgt;
|
|
ah[2] -= horhgt;
|
|
h[j] = ah[2];
|
|
}
|
|
jmax++;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
*tret = 0;
|
|
/* find points with zero height.
|
|
* binary search */
|
|
for (ii = 1; ii <= jmax; ii++) {
|
|
if (h[ii - 1] * h[ii] >= 0)
|
|
continue;
|
|
if (h[ii - 1] < h[ii] && !(rsmi & SE_CALC_RISE))
|
|
continue;
|
|
if (h[ii - 1] > h[ii] && !(rsmi & SE_CALC_SET))
|
|
continue;
|
|
dc[0] = h[ii - 1];
|
|
dc[1] = h[ii];
|
|
t2[0] = tc[ii - 1];
|
|
t2[1] = tc[ii];
|
|
for (i = 0; i < 20; i++) {
|
|
t = (t2[0] + t2[1]) / 2;
|
|
if (!do_fixstar) {
|
|
te = t + swe_deltat(t);
|
|
if (swe_calc(te, ipl, iflag, xc, serr) == ERR)
|
|
return ERR;
|
|
}
|
|
curdist = xc[2];
|
|
if (rsmi & SE_BIT_FIXED_DISC_SIZE) {
|
|
if (ipl == SE_SUN) {
|
|
curdist = 1.0;
|
|
}
|
|
else if (ipl == SE_MOON) {
|
|
curdist = 0.00257;
|
|
}
|
|
}
|
|
/* apparent radius of disc */
|
|
rdi = asin(dd / 2 / AUNIT / curdist) * RADTODEG;
|
|
/* true height of center of body */
|
|
swe_azalt(t, SE_EQU2HOR, geopos, atpress, attemp, xc, ah);
|
|
if (rsmi & SE_BIT_DISC_BOTTOM) {
|
|
/* true height of bottom point of body */
|
|
ah[1] -= rdi;
|
|
}
|
|
else {
|
|
/* true height of uppermost point of body */
|
|
ah[1] += rdi;
|
|
}
|
|
/* apparent height of uppermost point of body */
|
|
if (rsmi & SE_BIT_NO_REFRACTION) {
|
|
ah[1] -= horhgt;
|
|
aha = ah[1];
|
|
}
|
|
else {
|
|
swe_azalt_rev(t, SE_HOR2EQU, geopos, ah, xc);
|
|
swe_azalt(t, SE_EQU2HOR, geopos, atpress, attemp, xc, ah);
|
|
ah[1] -= horhgt;
|
|
ah[2] -= horhgt;
|
|
aha = ah[2];
|
|
}
|
|
if (aha * dc[0] <= 0) {
|
|
dc[1] = aha;
|
|
t2[1] = t;
|
|
}
|
|
else {
|
|
dc[0] = aha;
|
|
t2[0] = t;
|
|
}
|
|
}
|
|
if (t > tjd_ut) {
|
|
*tret = t;
|
|
return OK;
|
|
}
|
|
}
|
|
if (serr)
|
|
sprintf(serr, "rise or set not found for planet %d", ipl);
|
|
return -2; /* no t of rise or set found */
|
|
}
|
|
|
|
static int32
|
|
calc_mer_trans(double tjd_ut, int32 ipl, int32 epheflag, int32 rsmi,
|
|
double *geopos, char *starname, double *tret, char *serr)
|
|
{
|
|
int i;
|
|
double tjd_et = tjd_ut + swe_deltat(tjd_ut);
|
|
double armc, armc0, arxc, x0[6], x[6], t, te;
|
|
double mdd;
|
|
int32 iflag = epheflag;
|
|
AS_BOOL do_fixstar = (starname != NULL && *starname != '\0');
|
|
iflag &= SEFLG_EPHMASK;
|
|
*tret = 0;
|
|
iflag |= (SEFLG_EQUATORIAL | SEFLG_TOPOCTR);
|
|
armc0 = swe_sidtime(tjd_ut) + geopos[0] / 15;
|
|
if (armc0 >= 24)
|
|
armc0 -= 24;
|
|
if (armc0 < 0)
|
|
armc0 += 24;
|
|
armc0 *= 15;
|
|
if (do_fixstar) {
|
|
if (swe_fixstar(starname, tjd_et, iflag, x0, serr) == ERR)
|
|
return ERR;
|
|
}
|
|
else {
|
|
if (swe_calc(tjd_et, ipl, iflag, x0, serr) == ERR)
|
|
return ERR;
|
|
}
|
|
/*
|
|
* meridian transits
|
|
*/
|
|
x[0] = x0[0];
|
|
x[1] = x0[1];
|
|
t = tjd_ut;
|
|
arxc = armc0;
|
|
if (rsmi & SE_CALC_ITRANSIT)
|
|
arxc = swe_degnorm(arxc + 180);
|
|
for (i = 0; i < 4; i++) {
|
|
mdd = swe_degnorm(x[0] - arxc);
|
|
if (i > 0 && mdd > 180)
|
|
mdd -= 360;
|
|
t += mdd / 361;
|
|
armc = swe_sidtime(t) + geopos[0] / 15;
|
|
if (armc >= 24)
|
|
armc -= 24;
|
|
if (armc < 0)
|
|
armc += 24;
|
|
armc *= 15;
|
|
arxc = armc;
|
|
if (rsmi & SE_CALC_ITRANSIT)
|
|
arxc = swe_degnorm(arxc + 180);
|
|
if (!do_fixstar) {
|
|
te = t + swe_deltat(t);
|
|
if (swe_calc(te, ipl, iflag, x, serr) == ERR)
|
|
return ERR;
|
|
}
|
|
}
|
|
*tret = t;
|
|
return OK;
|
|
}
|
|
|
|
/*
|
|
Nodes and apsides of planets and moon
|
|
|
|
Planetary nodes can be defined in three different ways:
|
|
a) They can be understood as a direction or as an axis
|
|
defined by the intersection line of two orbital planes.
|
|
E.g., the nodes of Mars are defined by the intersection
|
|
line of Mars' orbital plane with the ecliptic (= the
|
|
Earths orbit heliocentrically or the solar orbit
|
|
geocentrically). However, as Michael Erlewine points
|
|
out in his elaborate web page on this topic
|
|
(http://thenewage.com/resources/articles/interface.html),
|
|
planetary nodes can be defined for any couple of
|
|
planets. E.g. there is also an intersection line for the
|
|
two orbital planes of Mars and Saturn.
|
|
Because such lines are, in principle, infinite, the
|
|
heliocentric and the geocentric positions of the
|
|
planetary nodes will be the same. There are astrologers
|
|
that use such heliocentric planetary nodes in geocentric
|
|
charts.
|
|
The ascending and the descending node will, in this
|
|
case, be in precise opposition.
|
|
|
|
b) The planetary nodes can also be understood in a
|
|
different way, not as an axis, but as the two points on a
|
|
planetary orbit that are located precisely on the
|
|
intersection line of the two planes.
|
|
This second definition makes no difference for the moon or
|
|
for heliocentric positions of planets, but it does so for
|
|
geocentric positions. There are two possibilities for
|
|
geocentric planetary nodes based on this definition.
|
|
1) The common solution is that the points on the
|
|
planets orbit are transformed to the geocenter. The
|
|
two points will not be in opposition anymore, or
|
|
they will only roughly be so with the outer planets. The
|
|
advantage of these nodes is that when a planet is in
|
|
conjunction with its node, then its ecliptic latitude
|
|
will be zero. This is not true when a planet is in
|
|
geocentric conjunction with its heliocentric node.
|
|
(And neither is it always true for the inner planets,
|
|
i.e. Mercury and Venus.)
|
|
2) The second possibility that nobody seems to have
|
|
thought of so far: One may compute the points of
|
|
the earth's orbit that lie exactly on another planet's
|
|
orbital plane and transform it to the geocenter. The two
|
|
points will always be in an approximate square.
|
|
|
|
c) Third, the planetary nodes could be defined as the
|
|
intersection points of the plane defined by their
|
|
momentary geocentric position and motion with the
|
|
plane of the ecliptic. Such points would move very fast
|
|
around the planetary stations. Here again, as in b)1),
|
|
the planet would cross the ecliptic and its ecliptic
|
|
latitude would be 0 exactly when it were in
|
|
conjunction with one of its nodes.
|
|
|
|
The Swiss Ephemeris supports the solutions a) and b) 1).
|
|
|
|
Possible definitions for apsides
|
|
|
|
a) The planetary apsides can be defined as the perihelion and
|
|
aphelion points on a planetary orbit. For a
|
|
geocentric chart, these points could be transformed
|
|
from the heliocenter to the geocenter.
|
|
b) However, one might consider these points as
|
|
astrologically relevant axes rather than as points on a
|
|
planetary orbit. Again, this would allow heliocentric
|
|
positions in a geocentric chart.
|
|
|
|
Note: For the "Dark Moon" or "Lilith", which I usually
|
|
define as the lunar apogee, some astrologers give a
|
|
different definition. They understand it as the second focal
|
|
point of the moon's orbital ellipse. This definition does not
|
|
make a difference for geocentric positions, because the
|
|
apogee and the second focus are in exactly the same geocentric
|
|
direction. However, it makes a difference with topocentric
|
|
positions, because the two points do not have same distance.
|
|
Analogous "black planets" have been proposed: they would be the
|
|
second focal points of the planets' orbital ellipses. The
|
|
heliocentric positions of these "black planets" are identical
|
|
with the heliocentric positions of the aphelia, but geocentric
|
|
positions are not identical, because the focal points are
|
|
much closer to the sun than the aphelia.
|
|
|
|
The Swiss Ephemeris allows to compute the "black planets" as well.
|
|
|
|
Mean positions
|
|
|
|
Mean nodes and apsides can be computed for the Moon, the
|
|
Earth and the planets Mercury - Neptune. They are taken
|
|
from the planetary theory VSOP87. Mean points can not be
|
|
calculated for Pluto and the asteroids, because there is no
|
|
planetary theory for them.
|
|
|
|
Osculating nodes and apsides
|
|
|
|
Nodes and apsides can also be derived from the osculating
|
|
orbital elements of a body, the paramaters that define an
|
|
ideal unperturbed elliptic (two-body) orbit.
|
|
For astrology, note that this is a simplification and
|
|
idealization.
|
|
Problem with Neptune: Neptune's orbit around the sun does not
|
|
have much in common with an ellipse. There are often two
|
|
perihelia and two aphelia within one revolution. As a result,
|
|
there is a wild oscillation of the osculating perihelion (and
|
|
aphelion).
|
|
In actuality, Neptune's orbit is not heliocentric orbit at all.
|
|
The twofold perihelia and aphelia are an effect of the motion of
|
|
the sun about the solar system barycenter. This motion is
|
|
much faster than the motion of Neptune, and Neptune
|
|
cannot react on such fast displacements of the Sun. As a
|
|
result, Neptune seems to move around the barycenter (or a
|
|
mean sun) rather than around the true sun. In fact,
|
|
Neptune's orbit around the barycenter is therefore closer to
|
|
an ellipse than the his orbit around the sun. The same
|
|
statement is also true for Saturn, Uranus and Pluto, but not
|
|
for Jupiter and the inner planets.
|
|
|
|
This fundamental problem about osculating ellipses of
|
|
planetary orbits does of course not only affect the apsides
|
|
but also the nodes.
|
|
|
|
Two solutions can be thought of for this problem:
|
|
1) The one would be to interpolate between actual
|
|
passages of the planets through their nodes and
|
|
apsides. However, this works only well with Mercury.
|
|
With all other planets, the supporting points are too far
|
|
apart as to make an accurate interpolation possible.
|
|
This solution is not implemented, here.
|
|
2) The other solution is to compute the apsides of the
|
|
orbit around the barycenter rather than around the sun.
|
|
This procedure makes sense for planets beyond Jupiter,
|
|
it comes closer to the mean apsides and nodes for
|
|
planets that have such points defined. For all other
|
|
transsaturnian planets and asteroids, this solution yields
|
|
a kind of "mean" nodes and apsides. On the other hand,
|
|
the barycentric ellipse does not make any sense for
|
|
inner planets and Jupiter.
|
|
|
|
The Swiss Ephemeris supports solution 2) for planets and
|
|
asteroids beyond Jupiter.
|
|
|
|
Anyway, neither the heliocentric nor the barycentric ellipse
|
|
is a perfect representation of the nature of a planetary orbit,
|
|
and it will not yield the degree of precision that today's
|
|
astrology is used to.
|
|
The best choice of method will probably be:
|
|
- For Mercury - Neptune: mean nodes and apsides
|
|
- For asteroids that belong to the inner asteroid belt:
|
|
osculating nodes/apsides from a heliocentric ellipse
|
|
- For Pluto and outer asteroids: osculating nodes/apsides
|
|
from a barycentric ellipse
|
|
|
|
The Moon is a special case: A "lunar true node" makes
|
|
more sense, because it can be defined without the idea of an
|
|
ellipse, e.g. as the intersection axis of the momentary lunar
|
|
orbital plane with the ecliptic. Or it can be said that the
|
|
momentary motion of the moon points to one of the two
|
|
ecliptic points that are called the "true nodes". So, these
|
|
points make sense. With planetary nodes, the situation is
|
|
somewhat different, at least if we make a difference
|
|
between heliocentric and geocentric positions. If so, the
|
|
planetary nodes are points on a heliocentric orbital ellipse,
|
|
which are transformed to the geocenter. An ellipse is
|
|
required here, because a solar distance is required. In
|
|
contrast to the planetary nodes, the lunar node does not
|
|
require a distance, therefore manages without the idea of an
|
|
ellipse and does not share its weaknesses.
|
|
On the other hand, the lunar apsides DO require the idea of
|
|
an ellipse. And because the lunar ellipse is actually
|
|
extremely distorted, even more than any other celestial
|
|
ellipse, the "true Lilith" (apogee), for which printed
|
|
ephemerides are available, does not make any sense at all.
|
|
(See the chapter on the lunar node and apogee.)
|
|
|
|
Special case: the Earth
|
|
|
|
The Earth is another special case. Instead of the motion of
|
|
the Earth herself, the heliocentric motion of the Earth-
|
|
Moon-Barycenter (EMB) is used to determine the
|
|
osculating perihelion.
|
|
There is no node of the earth orbit itself. However, there is
|
|
an axis around which the earth's orbital plane slowly rotates
|
|
due to planetary precession. The position points of this axis
|
|
are not calculated by the Swiss Ephemeris.
|
|
|
|
Special case: the Sun
|
|
|
|
In addition to the Earth (EMB) apsides, the function
|
|
computes so-to-say "apsides" of the sun, i.e. points on the
|
|
orbit of the Sun where it is closest to and where it is farthest
|
|
from the Earth. These points form an opposition and are
|
|
used by some astrologers, e.g. by the Dutch astrologer
|
|
George Bode or the Swiss astrologer Liduina Schmed. The
|
|
perigee, located at about 13 Capricorn, is called the
|
|
"Black Sun", the other one, in Cancer, the "Diamond".
|
|
So, for a complete set of apsides, one ought to calculate
|
|
them for the Sun and the Earth and all other planets.
|
|
|
|
The modes of the Swiss Ephemeris function
|
|
swe_nod_aps()
|
|
|
|
The function swe_nod_aps() can be run in the following
|
|
modes:
|
|
1) Mean positions are given for nodes and apsides of Sun,
|
|
Moon, Earth, and the up to Neptune. Osculating
|
|
positions are given with Pluto and all asteroids. This is
|
|
the default mode.
|
|
2) Osculating positions are returned for nodes and apsides
|
|
of all planets.
|
|
3) Same as 2), but for planets and asteroids beyond
|
|
Jupiter, a barycentric ellipse is used.
|
|
4) Same as 1), but for Pluto and asteroids beyond Jupiter,
|
|
a barycentric ellipse is used.
|
|
|
|
In all of these modes, the second focal point of the ellipse
|
|
can be computed instead of the aphelion.
|
|
Like the planetary function swe_calc(), swe_nod_aps() is
|
|
able to return geocentric, topocentric, heliocentric, or
|
|
barycentric position.
|
|
*
|
|
* tjd_ut julian day, ephemeris time
|
|
* ipl planet number
|
|
* iflag as usual, SEFLG_HELCTR, etc.
|
|
* xnasc an array of 6 doubles: ascending node
|
|
* xndsc an array of 6 doubles: ascending node
|
|
* xperi an array of 6 doubles: perihelion
|
|
* xaphe an array of 6 doubles: aphelion
|
|
* method see below
|
|
* serr error message
|
|
*
|
|
* method can have the following values:
|
|
* - 0 or SE_NODBIT_MEAN. MEAN positions are given for
|
|
* nodes and apsides of Sun, Moon, Earth, and the
|
|
* planets up to Neptune. Osculating positions are
|
|
* given with Pluto and all asteroids.
|
|
* - SE_NODBIT_OSCU. Osculating positions are given
|
|
* for all nodes and apsides.
|
|
* - SE_NODBIT_OSCU_BAR. Osculating nodes and apsides
|
|
* are computed from barycentric ellipses, for planets
|
|
* beyond Jupiter, but from heliocentric ones for
|
|
* ones for Jupiter and inner planets.
|
|
* - SE_NODBIT_MEAN and SE_NODBIT_OSCU_BAR can be combined.
|
|
* The program behaves the same way as with simple
|
|
* SE_NODBIT_MEAN, but uses barycentric ellipses for
|
|
* planets beyond Neptune and asteroids beyond Jupiter.
|
|
* - SE_NODBIT_FOCAL can be combined with any of the other
|
|
* bits. The second focal points of the ellipses will
|
|
* be returned instead of the aphelia.
|
|
*/
|
|
|
|
/* mean elements for Mercury - Neptune from VSOP87 (mean equinox of date) */
|
|
static double el_node[8][4] = { {48.330893, 1.1861890, 0.00017587, 0.000000211,}, /* Mercury */
|
|
{76.679920, 0.9011190, 0.00040665, -0.000000080,}, /* Venus */
|
|
{0, 0, 0, 0,}, /* Earth */
|
|
{49.558093, 0.7720923, 0.00001605, 0.000002325,}, /* Mars */
|
|
{100.464441, 1.0209550, 0.00040117, 0.000000569,}, /* Jupiter */
|
|
{113.665524, 0.8770970, -0.00012067, -0.000002380,}, /* Saturn */
|
|
{74.005947, 0.5211258, 0.00133982, 0.000018516,}, /* Uranus */
|
|
{131.784057, 1.1022057, 0.00026006, -0.000000636,}, /* Neptune */
|
|
};
|
|
static double el_peri[8][4] = { {77.456119, 1.5564775, 0.00029589, 0.000000056,}, /* Mercury */
|
|
{131.563707, 1.4022188, -0.00107337, -0.000005315,}, /* Venus */
|
|
{102.937348, 1.7195269, 0.00045962, 0.000000499,}, /* Earth */
|
|
{336.060234, 1.8410331, 0.00013515, 0.000000318,}, /* Mars */
|
|
{14.331309, 1.6126668, 0.00103127, -0.000004569,}, /* Jupiter */
|
|
{93.056787, 1.9637694, 0.00083757, 0.000004899,}, /* Saturn */
|
|
{173.005159, 1.4863784, 0.00021450, 0.000000433,}, /* Uranus */
|
|
{48.123691, 1.4262677, 0.00037918, -0.000000003,}, /* Neptune */
|
|
};
|
|
static double el_incl[8][4] = { {7.004986, 0.0018215, -0.00001809, 0.000000053,}, /* Mercury */
|
|
{3.394662, 0.0010037, -0.00000088, -0.000000007,}, /* Venus */
|
|
{0, 0, 0, 0,}, /* Earth */
|
|
{1.849726, -0.0006010, 0.00001276, -0.000000006,}, /* Mars */
|
|
{1.303270, -0.0054966, 0.00000465, -0.000000004,}, /* Jupiter */
|
|
{2.488878, -0.0037363, -0.00001516, 0.000000089,}, /* Saturn */
|
|
{0.773196, 0.0007744, 0.00003749, -0.000000092,}, /* Uranus */
|
|
{1.769952, -0.0093082, -0.00000708, 0.000000028,}, /* Neptune */
|
|
};
|
|
static double el_ecce[8][4] = { {0.20563175, 0.000020406, -0.0000000284, -0.00000000017,}, /* Mercury */
|
|
{0.00677188, -0.000047766, 0.0000000975, 0.00000000044,}, /* Venus */
|
|
{0.01670862, -0.000042037, -0.0000001236, 0.00000000004,}, /* Earth */
|
|
{0.09340062, 0.000090483, -0.0000000806, -0.00000000035,}, /* Mars */
|
|
{0.04849485, 0.000163244, -0.0000004719, -0.00000000197,}, /* Jupiter */
|
|
{0.05550862, -0.000346818, -0.0000006456, 0.00000000338,}, /* Saturn */
|
|
{0.04629590, -0.000027337, 0.0000000790, 0.00000000025,}, /* Uranus */
|
|
{0.00898809, 0.000006408, -0.0000000008, -0.00000000005,}, /* Neptune */
|
|
};
|
|
static double el_sema[8][4] = { {0.387098310, 0.0, 0.0, 0.0,}, /* Mercury */
|
|
{0.723329820, 0.0, 0.0, 0.0,}, /* Venus */
|
|
{1.000001018, 0.0, 0.0, 0.0,}, /* Earth */
|
|
{1.523679342, 0.0, 0.0, 0.0,}, /* Mars */
|
|
{5.202603191, 0.0000001913, 0.0, 0.0,}, /* Jupiter */
|
|
{9.554909596, 0.0000021389, 0.0, 0.0,}, /* Saturn */
|
|
{19.218446062, -0.0000000372, 0.00000000098, 0.0,}, /* Uranus */
|
|
{30.110386869, -0.0000001663, 0.00000000069, 0.0,}, /* Neptune */
|
|
};
|
|
|
|
/* Ratios of mass of Sun to masses of the planets */
|
|
static double plmass[9] = {
|
|
6023600, /* Mercury */
|
|
408523.5, /* Venus */
|
|
328900.5, /* Earth and Moon */
|
|
3098710, /* Mars */
|
|
1047.350, /* Jupiter */
|
|
3498.0, /* Saturn */
|
|
22960, /* Uranus */
|
|
19314, /* Neptune */
|
|
130000000, /* Pluto */
|
|
};
|
|
static int ipl_to_elem[15] = { 2, 0, 0, 1, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 2, };
|
|
|
|
int32 FAR PASCAL_CONV
|
|
swe_nod_aps(double tjd_et, int32 ipl, int32 iflag, int32 method,
|
|
double *xnasc, double *xndsc, double *xperi, double *xaphe,
|
|
char *serr)
|
|
{
|
|
int ij, i, j;
|
|
int32 iplx;
|
|
int32 ipli;
|
|
int istart, iend;
|
|
int32 iflJ2000;
|
|
double plm;
|
|
double t = (tjd_et - J2000) / 36525, dt;
|
|
double x[6], xx[24], *xp, xobs[6], x2000[6];
|
|
double xpos[3][6], xnorm[6];
|
|
double xposm[6];
|
|
double xn[3][6], xs[3][6];
|
|
double xq[3][6], xa[3][6];
|
|
double xobs2[6], x2[6];
|
|
double *xna, *xnd, *xpe, *xap;
|
|
double incl, sema, ecce, parg, ea, vincl, vsema, vecce, pargx, eax;
|
|
struct plan_data *pedp = &swed.pldat[SEI_EARTH];
|
|
struct plan_data *psbdp = &swed.pldat[SEI_SUNBARY];
|
|
struct plan_data pldat;
|
|
double *xsun = psbdp->x;
|
|
double *xear = pedp->x;
|
|
double *ep;
|
|
double Gmsm, dzmin;
|
|
double rxy, rxyz, fac, sgn;
|
|
double sinnode, cosnode, sinincl, cosincl, sinu, cosu, sinE, cosE, cosE2;
|
|
double uu, ny, ny2, c2, v2, pp, ro, ro2, rn, rn2;
|
|
struct epsilon *oe;
|
|
AS_BOOL is_true_nodaps = FALSE;
|
|
AS_BOOL do_aberr = !(iflag & (SEFLG_TRUEPOS | SEFLG_NOABERR));
|
|
AS_BOOL do_defl = !(iflag & SEFLG_TRUEPOS) && !(iflag & SEFLG_NOGDEFL);
|
|
AS_BOOL do_focal_point = method & SE_NODBIT_FOPOINT;
|
|
AS_BOOL ellipse_is_bary = FALSE;
|
|
int32 iflg0;
|
|
/* function calls for Pluto with asteroid number 134340
|
|
* are treated as calls for Pluto as main body SE_PLUTO */
|
|
if (ipl == SE_AST_OFFSET + 134340)
|
|
ipl = SE_PLUTO;
|
|
xna = xx;
|
|
xnd = xx + 6;
|
|
xpe = xx + 12;
|
|
xap = xx + 18;
|
|
xpos[0][0] = 0; /* to shut up mint */
|
|
/* to get control over the save area: */
|
|
swi_force_app_pos_etc();
|
|
method %= SE_NODBIT_FOPOINT;
|
|
ipli = ipl;
|
|
if (ipl == SE_SUN)
|
|
ipli = SE_EARTH;
|
|
if (ipl == SE_MOON) {
|
|
do_defl = FALSE;
|
|
if (!(iflag & SEFLG_HELCTR))
|
|
do_aberr = FALSE;
|
|
}
|
|
iflg0 =
|
|
(iflag & (SEFLG_EPHMASK | SEFLG_NONUT)) | SEFLG_SPEED | SEFLG_TRUEPOS;
|
|
if (ipli != SE_MOON)
|
|
iflg0 |= SEFLG_HELCTR;
|
|
if (ipl == SE_MEAN_NODE || ipl == SE_TRUE_NODE || ipl == SE_MEAN_APOG
|
|
|| ipl == SE_OSCU_APOG || ipl < 0 || (ipl >= SE_NPLANETS
|
|
&& ipl <= SE_AST_OFFSET)) {
|
|
/*(ipl >= SE_FICT_OFFSET && ipl - SE_FICT_OFFSET < SE_NFICT_ELEM)) */
|
|
if (serr != NULL)
|
|
sprintf(serr,
|
|
"nodes/apsides for planet %5.0f are not implemented",
|
|
(double)ipl);
|
|
if (xnasc != NULL)
|
|
for (i = 0; i <= 5; i++)
|
|
xnasc[i] = 0;
|
|
if (xndsc != NULL)
|
|
for (i = 0; i <= 5; i++)
|
|
xndsc[i] = 0;
|
|
if (xaphe != NULL)
|
|
for (i = 0; i <= 5; i++)
|
|
xaphe[i] = 0;
|
|
if (xperi != NULL)
|
|
for (i = 0; i <= 5; i++)
|
|
xperi[i] = 0;
|
|
return ERR;
|
|
}
|
|
for (i = 0; i < 24; i++)
|
|
xx[i] = 0;
|
|
|
|
/***************************************
|
|
* mean nodes and apsides
|
|
***************************************/
|
|
/* mean points only for Sun - Neptune */
|
|
if ((method == 0 || (method & SE_NODBIT_MEAN))
|
|
&& ((ipl >= SE_SUN && ipl <= SE_NEPTUNE) || ipl == SE_EARTH)) {
|
|
if (ipl == SE_MOON) {
|
|
swi_mean_lunar_elements(tjd_et, &xna[0], &xna[3], &xpe[0],
|
|
&xpe[3]);
|
|
incl = MOON_MEAN_INCL;
|
|
vincl = 0;
|
|
ecce = MOON_MEAN_ECC;
|
|
vecce = 0;
|
|
sema = MOON_MEAN_DIST / AUNIT;
|
|
vsema = 0;
|
|
}
|
|
else {
|
|
iplx = ipl_to_elem[ipl];
|
|
ep = el_incl[iplx];
|
|
incl = ep[0] + ep[1] * t + ep[2] * t * t + ep[3] * t * t * t;
|
|
vincl = ep[1] / 36525;
|
|
ep = el_sema[iplx];
|
|
sema = ep[0] + ep[1] * t + ep[2] * t * t + ep[3] * t * t * t;
|
|
vsema = ep[1] / 36525;
|
|
ep = el_ecce[iplx];
|
|
ecce = ep[0] + ep[1] * t + ep[2] * t * t + ep[3] * t * t * t;
|
|
vecce = ep[1] / 36525;
|
|
ep = el_node[iplx];
|
|
/* ascending node */
|
|
xna[0] = ep[0] + ep[1] * t + ep[2] * t * t + ep[3] * t * t * t;
|
|
xna[3] = ep[1] / 36525;
|
|
/* perihelion */
|
|
ep = el_peri[iplx];
|
|
xpe[0] = ep[0] + ep[1] * t + ep[2] * t * t + ep[3] * t * t * t;
|
|
xpe[3] = ep[1] / 36525;
|
|
}
|
|
/* descending node */
|
|
xnd[0] = swe_degnorm(xna[0] + 180);
|
|
xnd[3] = xna[3];
|
|
/* angular distance of perihelion from node */
|
|
parg = xpe[0] = swe_degnorm(xpe[0] - xna[0]);
|
|
pargx = xpe[3] = swe_degnorm(xpe[0] + xpe[3] - xna[3]);
|
|
/* transform from orbital plane to mean ecliptic of date */
|
|
swe_cotrans(xpe, xpe, -incl);
|
|
/* xpe+3 is aux. position, not speed!!! */
|
|
swe_cotrans(xpe + 3, xpe + 3, -incl - vincl);
|
|
/* add node again */
|
|
xpe[0] = swe_degnorm(xpe[0] + xna[0]);
|
|
/* xpe+3 is aux. position, not speed!!! */
|
|
xpe[3] = swe_degnorm(xpe[3] + xna[0] + xna[3]);
|
|
/* speed */
|
|
xpe[3] = swe_degnorm(xpe[3] - xpe[0]);
|
|
/* heliocentric distance of perihelion and aphelion */
|
|
xpe[2] = sema * (1 - ecce);
|
|
xpe[5] = (sema + vsema) * (1 - ecce - vecce) - xpe[2];
|
|
/* aphelion */
|
|
xap[0] = swe_degnorm(xpe[0] + 180);
|
|
xap[1] = -xpe[1];
|
|
xap[3] = xpe[3];
|
|
xap[4] = -xpe[4];
|
|
if (do_focal_point) {
|
|
xap[2] = sema * ecce * 2;
|
|
xap[5] = (sema + vsema) * (ecce + vecce) * 2 - xap[2];
|
|
}
|
|
else {
|
|
xap[2] = sema * (1 + ecce);
|
|
xap[5] = (sema + vsema) * (1 + ecce + vecce) - xap[2];
|
|
}
|
|
/* heliocentric distance of nodes */
|
|
ea = atan(tan(-parg * DEGTORAD / 2) * sqrt((1 - ecce) / (1 + ecce))) *
|
|
2;
|
|
eax =
|
|
atan(tan(-pargx * DEGTORAD / 2) *
|
|
sqrt((1 - ecce - vecce) / (1 + ecce + vecce))) * 2;
|
|
xna[2] = sema * (cos(ea) - ecce) / cos(parg * DEGTORAD);
|
|
xna[5] =
|
|
(sema + vsema) * (cos(eax) - ecce -
|
|
vecce) / cos(pargx * DEGTORAD);
|
|
xna[5] -= xna[2];
|
|
ea = atan(tan((180 - parg) * DEGTORAD / 2) *
|
|
sqrt((1 - ecce) / (1 + ecce))) * 2;
|
|
eax =
|
|
atan(tan((180 - pargx) * DEGTORAD / 2) *
|
|
sqrt((1 - ecce - vecce) / (1 + ecce + vecce))) * 2;
|
|
xnd[2] = sema * (cos(ea) - ecce) / cos((180 - parg) * DEGTORAD);
|
|
xnd[5] =
|
|
(sema + vsema) * (cos(eax) - ecce -
|
|
vecce) / cos((180 - pargx) * DEGTORAD);
|
|
xnd[5] -= xnd[2];
|
|
/* no light-time correction because speed is extremely small */
|
|
for (i = 0, xp = xx; i < 4; i++, xp += 6) {
|
|
/* to cartesian coordinates */
|
|
xp[0] *= DEGTORAD;
|
|
xp[1] *= DEGTORAD;
|
|
xp[3] *= DEGTORAD;
|
|
xp[4] *= DEGTORAD;
|
|
swi_polcart_sp(xp, xp);
|
|
}
|
|
|
|
/***************************************
|
|
* "true" or osculating nodes and apsides
|
|
***************************************/
|
|
}
|
|
else {
|
|
/* first, we need a heliocentric distance of the planet */
|
|
if (swe_calc(tjd_et, ipli, iflg0, x, serr) == ERR)
|
|
return ERR;
|
|
iflJ2000 =
|
|
(iflag & SEFLG_EPHMASK) | SEFLG_J2000 | SEFLG_EQUATORIAL |
|
|
SEFLG_XYZ | SEFLG_TRUEPOS | SEFLG_NONUT | SEFLG_SPEED;
|
|
ellipse_is_bary = FALSE;
|
|
if (ipli != SE_MOON) {
|
|
if ((method & SE_NODBIT_OSCU_BAR) && x[2] > 6) {
|
|
iflJ2000 |= SEFLG_BARYCTR; /* only planets beyond Jupiter */
|
|
ellipse_is_bary = TRUE;
|
|
}
|
|
else {
|
|
iflJ2000 |= SEFLG_HELCTR;
|
|
}
|
|
}
|
|
/* we need three positions and three speeds
|
|
* for three nodes/apsides. from the three node positions,
|
|
* the speed of the node will be computed. */
|
|
if (ipli == SE_MOON) {
|
|
dt = NODE_CALC_INTV;
|
|
dzmin = 1e-15;
|
|
Gmsm =
|
|
GEOGCONST * (1 +
|
|
1 / EARTH_MOON_MRAT) / AUNIT / AUNIT / AUNIT *
|
|
86400.0 * 86400.0;
|
|
}
|
|
else {
|
|
if ((ipli >= SE_MERCURY && ipli <= SE_PLUTO) || ipli == SE_EARTH)
|
|
plm = 1 / plmass[ipl_to_elem[ipl]];
|
|
else
|
|
plm = 0;
|
|
dt = NODE_CALC_INTV * 10 * x[2];
|
|
dzmin = 1e-15 * dt / NODE_CALC_INTV;
|
|
Gmsm =
|
|
HELGRAVCONST * (1 +
|
|
plm) / AUNIT / AUNIT / AUNIT * 86400.0 *
|
|
86400.0;
|
|
}
|
|
if (iflag & SEFLG_SPEED) {
|
|
istart = 0;
|
|
iend = 2;
|
|
}
|
|
else {
|
|
istart = iend = 0;
|
|
dt = 0;
|
|
}
|
|
for (i = istart, t = tjd_et - dt; i <= iend; i++, t += dt) {
|
|
if (istart == iend)
|
|
t = tjd_et;
|
|
if (swe_calc(t, ipli, iflJ2000, xpos[i], serr) == ERR)
|
|
return ERR;
|
|
/* the EMB is used instead of the earth */
|
|
if (ipli == SE_EARTH) {
|
|
if (swe_calc
|
|
(t, SE_MOON, iflJ2000 & ~(SEFLG_BARYCTR | SEFLG_HELCTR),
|
|
xposm, serr) == ERR)
|
|
return ERR;
|
|
for (j = 0; j <= 2; j++)
|
|
xpos[i][j] += xposm[j] / (EARTH_MOON_MRAT + 1.0);
|
|
}
|
|
swi_plan_for_osc_elem(iflg0, t, xpos[i]);
|
|
}
|
|
for (i = istart; i <= iend; i++) {
|
|
if (fabs(xpos[i][5]) < dzmin)
|
|
xpos[i][5] = dzmin;
|
|
fac = xpos[i][2] / xpos[i][5];
|
|
sgn = xpos[i][5] / fabs(xpos[i][5]);
|
|
for (j = 0; j <= 2; j++) {
|
|
xn[i][j] = (xpos[i][j] - fac * xpos[i][j + 3]) * sgn;
|
|
xs[i][j] = -xn[i][j];
|
|
}
|
|
}
|
|
for (i = istart; i <= iend; i++) {
|
|
/* node */
|
|
rxy = sqrt(xn[i][0] * xn[i][0] + xn[i][1] * xn[i][1]);
|
|
cosnode = xn[i][0] / rxy;
|
|
sinnode = xn[i][1] / rxy;
|
|
/* inclination */
|
|
swi_cross_prod(xpos[i], xpos[i] + 3, xnorm);
|
|
rxy = xnorm[0] * xnorm[0] + xnorm[1] * xnorm[1];
|
|
c2 = (rxy + xnorm[2] * xnorm[2]);
|
|
rxyz = sqrt(c2);
|
|
rxy = sqrt(rxy);
|
|
sinincl = rxy / rxyz;
|
|
cosincl = sqrt(1 - sinincl * sinincl);
|
|
if (xnorm[2] < 0)
|
|
cosincl = -cosincl; /* retrograde asteroid, e.g. 20461 Dioretsa */
|
|
/* argument of latitude */
|
|
cosu = xpos[i][0] * cosnode + xpos[i][1] * sinnode;
|
|
sinu = xpos[i][2] / sinincl;
|
|
uu = atan2(sinu, cosu);
|
|
/* semi-axis */
|
|
rxyz = sqrt(square_sum(xpos[i]));
|
|
v2 = square_sum((xpos[i] + 3));
|
|
sema = 1 / (2 / rxyz - v2 / Gmsm);
|
|
/* eccentricity */
|
|
pp = c2 / Gmsm;
|
|
ecce = sqrt(1 - pp / sema);
|
|
/* eccentric anomaly */
|
|
cosE = 1 / ecce * (1 - rxyz / sema);
|
|
sinE =
|
|
1 / ecce / sqrt(sema * Gmsm) * dot_prod(xpos[i],
|
|
(xpos[i] + 3));
|
|
/* true anomaly */
|
|
ny = 2 * atan(sqrt((1 + ecce) / (1 - ecce)) * sinE / (1 + cosE));
|
|
/* distance of perihelion from ascending node */
|
|
xq[i][0] = swi_mod2PI(uu - ny);
|
|
xq[i][1] = 0; /* latitude */
|
|
xq[i][2] = sema * (1 - ecce); /* distance of perihelion */
|
|
/* transformation to ecliptic coordinates */
|
|
swi_polcart(xq[i], xq[i]);
|
|
swi_coortrf2(xq[i], xq[i], -sinincl, cosincl);
|
|
swi_cartpol(xq[i], xq[i]);
|
|
/* adding node, we get perihelion in ecl. coord. */
|
|
xq[i][0] += atan2(sinnode, cosnode);
|
|
xa[i][0] = swi_mod2PI(xq[i][0] + PI);
|
|
xa[i][1] = -xq[i][1];
|
|
if (do_focal_point) {
|
|
xa[i][2] = sema * ecce * 2; /* distance of aphelion */
|
|
}
|
|
else {
|
|
xa[i][2] = sema * (1 + ecce); /* distance of aphelion */
|
|
}
|
|
swi_polcart(xq[i], xq[i]);
|
|
swi_polcart(xa[i], xa[i]);
|
|
/* new distance of node from orbital ellipse:
|
|
* true anomaly of node: */
|
|
ny = swi_mod2PI(ny - uu);
|
|
ny2 = swi_mod2PI(ny + PI);
|
|
/* eccentric anomaly */
|
|
cosE = cos(2 * atan(tan(ny / 2) / sqrt((1 + ecce) / (1 - ecce))));
|
|
cosE2 =
|
|
cos(2 * atan(tan(ny2 / 2) / sqrt((1 + ecce) / (1 - ecce))));
|
|
/* new distance */
|
|
rn = sema * (1 - ecce * cosE);
|
|
rn2 = sema * (1 - ecce * cosE2);
|
|
/* old node distance */
|
|
ro = sqrt(square_sum(xn[i]));
|
|
ro2 = sqrt(square_sum(xs[i]));
|
|
/* correct length of position vector */
|
|
for (j = 0; j <= 2; j++) {
|
|
xn[i][j] *= rn / ro;
|
|
xs[i][j] *= rn2 / ro2;
|
|
}
|
|
}
|
|
for (i = 0; i <= 2; i++) {
|
|
if (iflag & SEFLG_SPEED) {
|
|
xpe[i] = xq[1][i];
|
|
xpe[i + 3] = (xq[2][i] - xq[0][i]) / dt / 2;
|
|
xap[i] = xa[1][i];
|
|
xap[i + 3] = (xa[2][i] - xa[0][i]) / dt / 2;
|
|
xna[i] = xn[1][i];
|
|
xna[i + 3] = (xn[2][i] - xn[0][i]) / dt / 2;
|
|
xnd[i] = xs[1][i];
|
|
xnd[i + 3] = (xs[2][i] - xs[0][i]) / dt / 2;
|
|
}
|
|
else {
|
|
xpe[i] = xq[0][i];
|
|
xpe[i + 3] = 0;
|
|
xap[i] = xa[0][i];
|
|
xap[i + 3] = 0;
|
|
xna[i] = xn[0][i];
|
|
xna[i + 3] = 0;
|
|
xnd[i] = xs[0][i];
|
|
xnd[i + 3] = 0;
|
|
}
|
|
}
|
|
is_true_nodaps = TRUE;
|
|
}
|
|
/* to set the variables required in the save area,
|
|
* i.e. ecliptic, nutation, barycentric sun, earth
|
|
* we compute the planet */
|
|
if (ipli == SE_MOON && (iflag & (SEFLG_HELCTR | SEFLG_BARYCTR))) {
|
|
swi_force_app_pos_etc();
|
|
if (swe_calc(tjd_et, SE_SUN, iflg0, x, serr) == ERR)
|
|
return ERR;
|
|
}
|
|
else {
|
|
if (swe_calc(tjd_et, ipli, iflg0 | (iflag & SEFLG_TOPOCTR), x, serr)
|
|
== ERR)
|
|
return ERR;
|
|
}
|
|
|
|
/***********************
|
|
* position of observer
|
|
***********************/
|
|
if (iflag & SEFLG_TOPOCTR) {
|
|
/* geocentric position of observer */
|
|
if (swi_get_observer(tjd_et, iflag, FALSE, xobs, serr) != OK)
|
|
return ERR;
|
|
/*for (i = 0; i <= 5; i++)
|
|
* xobs[i] = swed.topd.xobs[i]; */
|
|
}
|
|
else {
|
|
for (i = 0; i <= 5; i++)
|
|
xobs[i] = 0;
|
|
}
|
|
if (iflag & (SEFLG_HELCTR | SEFLG_BARYCTR)) {
|
|
if ((iflag & SEFLG_HELCTR) && !(iflag & SEFLG_MOSEPH))
|
|
for (i = 0; i <= 5; i++)
|
|
xobs[i] = xsun[i];
|
|
}
|
|
else if (ipl == SE_SUN && !(iflag & SEFLG_MOSEPH)) {
|
|
for (i = 0; i <= 5; i++)
|
|
xobs[i] = xsun[i];
|
|
}
|
|
else {
|
|
/* barycentric position of observer */
|
|
for (i = 0; i <= 5; i++)
|
|
xobs[i] += xear[i];
|
|
}
|
|
/* ecliptic obliqity */
|
|
if (iflag & SEFLG_J2000)
|
|
oe = &swed.oec2000;
|
|
else
|
|
oe = &swed.oec;
|
|
|
|
/*************************************************
|
|
* conversions shared by mean and osculating points
|
|
*************************************************/
|
|
for (ij = 0, xp = xx; ij < 4; ij++, xp += 6) {
|
|
/* no nodes for earth */
|
|
if (ipli == SE_EARTH && ij <= 1) {
|
|
for (i = 0; i <= 5; i++)
|
|
xp[i] = 0;
|
|
continue;
|
|
}
|
|
|
|
/*********************
|
|
* to equator
|
|
*********************/
|
|
if (is_true_nodaps && !(iflag & SEFLG_NONUT)) {
|
|
swi_coortrf2(xp, xp, -swed.nut.snut, swed.nut.cnut);
|
|
if (iflag & SEFLG_SPEED)
|
|
swi_coortrf2(xp + 3, xp + 3, -swed.nut.snut, swed.nut.cnut);
|
|
}
|
|
swi_coortrf2(xp, xp, -oe->seps, oe->ceps);
|
|
swi_coortrf2(xp + 3, xp + 3, -oe->seps, oe->ceps);
|
|
if (is_true_nodaps) {
|
|
|
|
/****************************
|
|
* to mean ecliptic of date
|
|
****************************/
|
|
if (!(iflag & SEFLG_NONUT))
|
|
swi_nutate(xp, iflag, TRUE);
|
|
}
|
|
|
|
/*********************
|
|
* to J2000
|
|
*********************/
|
|
swi_precess(xp, tjd_et, J_TO_J2000);
|
|
if (iflag & SEFLG_SPEED)
|
|
swi_precess_speed(xp, tjd_et, J_TO_J2000);
|
|
|
|
/*********************
|
|
* to barycenter
|
|
*********************/
|
|
if (ipli == SE_MOON) {
|
|
for (i = 0; i <= 5; i++)
|
|
xp[i] += xear[i];
|
|
}
|
|
else {
|
|
if (!(iflag & SEFLG_MOSEPH) && !ellipse_is_bary)
|
|
for (j = 0; j <= 5; j++)
|
|
xp[j] += xsun[j];
|
|
}
|
|
|
|
/*********************
|
|
* to correct center
|
|
*********************/
|
|
for (j = 0; j <= 5; j++)
|
|
xp[j] -= xobs[j];
|
|
/* geocentric perigee/apogee of sun */
|
|
if (ipl == SE_SUN && !(iflag & (SEFLG_HELCTR | SEFLG_BARYCTR)))
|
|
for (j = 0; j <= 5; j++)
|
|
xp[j] = -xp[j];
|
|
|
|
/*********************
|
|
* light deflection
|
|
*********************/
|
|
dt = sqrt(square_sum(xp)) * AUNIT / CLIGHT / 86400.0;
|
|
if (do_defl)
|
|
swi_deflect_light(xp, dt, iflag);
|
|
|
|
/*********************
|
|
* aberration
|
|
*********************/
|
|
if (do_aberr) {
|
|
swi_aberr_light(xp, xobs, iflag);
|
|
/*
|
|
* Apparent speed is also influenced by
|
|
* the difference of speed of the earth between t and t-dt.
|
|
* Neglecting this would result in an error of several 0.1"
|
|
*/
|
|
if (iflag & SEFLG_SPEED) {
|
|
/* get barycentric sun and earth for t-dt into save area */
|
|
if (swe_calc
|
|
(tjd_et - dt, ipli, iflg0 | (iflag & SEFLG_TOPOCTR), x2,
|
|
serr) == ERR)
|
|
return ERR;
|
|
if (iflag & SEFLG_TOPOCTR) {
|
|
/* geocentric position of observer */
|
|
/* if (swi_get_observer(tjd_et - dt, iflag, FALSE, xobs, serr) != OK)
|
|
* return ERR; */
|
|
for (i = 0; i <= 5; i++)
|
|
xobs2[i] = swed.topd.xobs[i];
|
|
}
|
|
else {
|
|
for (i = 0; i <= 5; i++)
|
|
xobs2[i] = 0;
|
|
}
|
|
if (iflag & (SEFLG_HELCTR | SEFLG_BARYCTR)) {
|
|
if ((iflag & SEFLG_HELCTR) && !(iflag & SEFLG_MOSEPH))
|
|
for (i = 0; i <= 5; i++)
|
|
xobs2[i] = xsun[i];
|
|
}
|
|
else if (ipl == SE_SUN && !(iflag & SEFLG_MOSEPH)) {
|
|
for (i = 0; i <= 5; i++)
|
|
xobs2[i] = xsun[i];
|
|
}
|
|
else {
|
|
/* barycentric position of observer */
|
|
for (i = 0; i <= 5; i++)
|
|
xobs2[i] += xear[i];
|
|
}
|
|
for (i = 3; i <= 5; i++)
|
|
xp[i] += xobs[i] - xobs2[i];
|
|
/* The above call of swe_calc() has destroyed the
|
|
* parts of the save area
|
|
* (i.e. bary sun, earth nutation matrix!).
|
|
* to restore it:
|
|
*/
|
|
if (swe_calc
|
|
(tjd_et, SE_SUN, iflg0 | (iflag & SEFLG_TOPOCTR), x2,
|
|
serr) == ERR)
|
|
return ERR;
|
|
}
|
|
}
|
|
|
|
/*********************
|
|
* precession
|
|
*********************/
|
|
/* save J2000 coordinates; required for sidereal positions */
|
|
for (j = 0; j <= 5; j++)
|
|
x2000[j] = xp[j];
|
|
if (!(iflag & SEFLG_J2000)) {
|
|
swi_precess(xp, tjd_et, J2000_TO_J);
|
|
if (iflag & SEFLG_SPEED)
|
|
swi_precess_speed(xp, tjd_et, J2000_TO_J);
|
|
}
|
|
|
|
/*********************
|
|
* nutation
|
|
*********************/
|
|
if (!(iflag & SEFLG_NONUT))
|
|
swi_nutate(xp, iflag, FALSE);
|
|
/* now we have equatorial cartesian coordinates; keep them */
|
|
for (j = 0; j <= 5; j++)
|
|
pldat.xreturn[18 + j] = xp[j];
|
|
|
|
/************************************************
|
|
* transformation to ecliptic. *
|
|
* with sidereal calc. this will be overwritten *
|
|
* afterwards. *
|
|
************************************************/
|
|
swi_coortrf2(xp, xp, oe->seps, oe->ceps);
|
|
if (iflag & SEFLG_SPEED)
|
|
swi_coortrf2(xp + 3, xp + 3, oe->seps, oe->ceps);
|
|
if (!(iflag & SEFLG_NONUT)) {
|
|
swi_coortrf2(xp, xp, swed.nut.snut, swed.nut.cnut);
|
|
if (iflag & SEFLG_SPEED)
|
|
swi_coortrf2(xp + 3, xp + 3, swed.nut.snut, swed.nut.cnut);
|
|
}
|
|
/* now we have ecliptic cartesian coordinates */
|
|
for (j = 0; j <= 5; j++)
|
|
pldat.xreturn[6 + j] = xp[j];
|
|
|
|
/************************************
|
|
* sidereal positions *
|
|
************************************/
|
|
if (iflag & SEFLG_SIDEREAL) {
|
|
/* project onto ecliptic t0 */
|
|
if (swed.sidd.sid_mode & SE_SIDBIT_ECL_T0) {
|
|
if (swi_trop_ra2sid_lon
|
|
(x2000, pldat.xreturn + 6, pldat.xreturn + 18, iflag,
|
|
serr) != OK)
|
|
return ERR;
|
|
/* project onto solar system equator */
|
|
}
|
|
else if (swed.sidd.sid_mode & SE_SIDBIT_SSY_PLANE) {
|
|
if (swi_trop_ra2sid_lon_sosy
|
|
(x2000, pldat.xreturn + 6, pldat.xreturn + 18, iflag,
|
|
serr) != OK)
|
|
return ERR;
|
|
}
|
|
else {
|
|
/* traditional algorithm */
|
|
swi_cartpol_sp(pldat.xreturn + 6, pldat.xreturn);
|
|
pldat.xreturn[0] -= swe_get_ayanamsa(tjd_et) * DEGTORAD;
|
|
swi_polcart_sp(pldat.xreturn, pldat.xreturn + 6);
|
|
}
|
|
}
|
|
if ((iflag & SEFLG_XYZ) && (iflag & SEFLG_EQUATORIAL)) {
|
|
for (j = 0; j <= 5; j++)
|
|
xp[j] = pldat.xreturn[18 + j];
|
|
continue;
|
|
}
|
|
if (iflag & SEFLG_XYZ) {
|
|
for (j = 0; j <= 5; j++)
|
|
xp[j] = pldat.xreturn[6 + j];
|
|
continue;
|
|
}
|
|
|
|
/************************************************
|
|
* transformation to polar coordinates *
|
|
************************************************/
|
|
swi_cartpol_sp(pldat.xreturn + 18, pldat.xreturn + 12);
|
|
swi_cartpol_sp(pldat.xreturn + 6, pldat.xreturn);
|
|
|
|
/**********************
|
|
* radians to degrees *
|
|
**********************/
|
|
for (j = 0; j < 2; j++) {
|
|
pldat.xreturn[j] *= RADTODEG; /* ecliptic */
|
|
pldat.xreturn[j + 3] *= RADTODEG;
|
|
pldat.xreturn[j + 12] *= RADTODEG; /* equator */
|
|
pldat.xreturn[j + 15] *= RADTODEG;
|
|
}
|
|
if (iflag & SEFLG_EQUATORIAL) {
|
|
for (j = 0; j <= 5; j++)
|
|
xp[j] = pldat.xreturn[12 + j];
|
|
continue;
|
|
}
|
|
else {
|
|
for (j = 0; j <= 5; j++)
|
|
xp[j] = pldat.xreturn[j];
|
|
continue;
|
|
}
|
|
}
|
|
for (i = 0; i <= 5; i++) {
|
|
if (i > 2 && !(iflag & SEFLG_SPEED))
|
|
xna[i] = xnd[i] = xpe[i] = xap[i] = 0;
|
|
if (xnasc != NULL)
|
|
xnasc[i] = xna[i];
|
|
if (xndsc != NULL)
|
|
xndsc[i] = xnd[i];
|
|
if (xperi != NULL)
|
|
xperi[i] = xpe[i];
|
|
if (xaphe != NULL)
|
|
xaphe[i] = xap[i];
|
|
}
|
|
return OK;
|
|
}
|
|
|
|
int32 FAR PASCAL_CONV
|
|
swe_nod_aps_ut(double tjd_ut, int32 ipl, int32 iflag, int32 method,
|
|
double *xnasc, double *xndsc, double *xperi, double *xaphe,
|
|
char *serr)
|
|
{
|
|
return swe_nod_aps(tjd_ut + swe_deltat(tjd_ut), ipl, iflag, method, xnasc,
|
|
xndsc, xperi, xaphe, serr);
|
|
}
|
|
|
|
/* function finds the gauquelin sector position of a planet or fixed star
|
|
*
|
|
* if starname != NULL then a star is computed.
|
|
* iflag: use the flags SE_SWIEPH, SE_JPLEPH, SE_MOSEPH, SEFLG_TOPOCTR.
|
|
*
|
|
* imeth defines method:
|
|
* imeth = 0 use Placidus house position
|
|
* imeth = 1 use Placidus house posiition (with planetary lat = 0)
|
|
* imeth = 2 use rise and set of body's disc center
|
|
* imeth = 3 use rise and set of body's disc center with refraction
|
|
* rise and set are defined as appearance and disappearance of disc center
|
|
*
|
|
* geopos is an array of 3 doubles for geo. longitude, geo. latitude, elevation.
|
|
* atpress and attemp are only needed for imeth = 3. If imeth = 3,
|
|
* If imeth=3 and atpress not given (= 0), the programm assumes 1013.25 mbar;
|
|
* if a non-zero height above sea is given in geopos, atpress is estimated.
|
|
* dgsect is return area (pointer to a double)
|
|
* serr is pointer to error string, may be NULL
|
|
*/
|
|
int32 FAR PASCAL_CONV
|
|
swe_gauquelin_sector(double t_ut, int32 ipl, char *starname, int32 iflag,
|
|
int32 imeth, double *geopos, double atpress,
|
|
double attemp, double *dgsect, char *serr)
|
|
{
|
|
AS_BOOL rise_found = TRUE;
|
|
AS_BOOL set_found = TRUE;
|
|
int32 retval;
|
|
double tret[3];
|
|
double t_et, t;
|
|
double x0[6];
|
|
double eps, nutlo[2], armc;
|
|
int32 epheflag = iflag & SEFLG_EPHMASK;
|
|
AS_BOOL do_fixstar = (starname != NULL && *starname != '\0');
|
|
int32 risemeth = 0;
|
|
AS_BOOL above_horizon = FALSE;
|
|
if (imeth < 0 || imeth > 5) {
|
|
if (serr)
|
|
sprintf(serr, "invalid method: %d", imeth);
|
|
return ERR;
|
|
}
|
|
/* function calls for Pluto with asteroid number 134340
|
|
* are treated as calls for Pluto as main body SE_PLUTO */
|
|
if (ipl == SE_AST_OFFSET + 134340)
|
|
ipl = SE_PLUTO;
|
|
/*
|
|
* geometrically from ecl. longitude and latitude
|
|
*/
|
|
if (imeth == 0 || imeth == 1) {
|
|
t_et = t_ut + swe_deltat(t_ut);
|
|
eps = swi_epsiln(t_et) * RADTODEG;
|
|
swi_nutation(t_et, nutlo);
|
|
nutlo[0] *= RADTODEG;
|
|
nutlo[1] *= RADTODEG;
|
|
armc =
|
|
swe_degnorm(swe_sidtime0(t_ut, eps + nutlo[1], nutlo[0]) * 15 +
|
|
geopos[0]);
|
|
if (do_fixstar) {
|
|
if (swe_fixstar(starname, t_et, iflag, x0, serr) == ERR)
|
|
return ERR;
|
|
}
|
|
else {
|
|
if (swe_calc(t_et, ipl, iflag, x0, serr) == ERR)
|
|
return ERR;
|
|
}
|
|
if (imeth == 1)
|
|
x0[1] = 0;
|
|
*dgsect =
|
|
swe_house_pos(armc, geopos[1], eps + nutlo[1], 'G', x0, NULL);
|
|
return OK;
|
|
}
|
|
/*
|
|
* from rise and set times
|
|
*/
|
|
if (imeth == 2 || imeth == 4)
|
|
risemeth |= SE_BIT_NO_REFRACTION;
|
|
if (imeth == 2 || imeth == 3)
|
|
risemeth |= SE_BIT_DISC_CENTER;
|
|
/* find the next rising time of the planet or star */
|
|
retval =
|
|
swe_rise_trans(t_ut, ipl, starname, epheflag, SE_CALC_RISE | risemeth,
|
|
geopos, atpress, attemp, &(tret[0]), serr);
|
|
if (retval == ERR) {
|
|
return ERR;
|
|
}
|
|
else if (retval == -2) {
|
|
/* actually, we could return ERR here. However, we
|
|
* keep this variable, in case we implement an algorithm
|
|
* for Gauquelin sector positions of circumpolar bodies.
|
|
* As with the Ludwig Otto procedure with Placidus, one
|
|
* could replace missing rises or sets by meridian transits,
|
|
* although there are cases where even this is not possible.
|
|
* Sometimes a body both appears and disappears on the western
|
|
* part of the horizon. Using true culminations rather than meridan
|
|
* transits would not help in any case either, because there are
|
|
* cases where a body does not have a culmination within days,
|
|
* e.g. the sun near the poles.
|
|
*/
|
|
rise_found = FALSE;
|
|
}
|
|
/* find the next setting time of the planet or star */
|
|
retval =
|
|
swe_rise_trans(t_ut, ipl, starname, epheflag, SE_CALC_SET | risemeth,
|
|
geopos, atpress, attemp, &(tret[1]), serr);
|
|
if (retval == ERR) {
|
|
return ERR;
|
|
}
|
|
else if (retval == -2) {
|
|
set_found = FALSE;
|
|
}
|
|
if (tret[0] < tret[1] && rise_found == TRUE) {
|
|
above_horizon = FALSE;
|
|
/* find last set */
|
|
t = t_ut - 1.2;
|
|
if (set_found)
|
|
t = tret[1] - 1.2;
|
|
set_found = TRUE;
|
|
retval =
|
|
swe_rise_trans(t, ipl, starname, epheflag, SE_CALC_SET | risemeth,
|
|
geopos, atpress, attemp, &(tret[1]), serr);
|
|
if (retval == ERR) {
|
|
return ERR;
|
|
}
|
|
else if (retval == -2) {
|
|
set_found = FALSE;
|
|
}
|
|
}
|
|
else if (tret[0] >= tret[1] && set_found == TRUE) {
|
|
above_horizon = TRUE;
|
|
/* find last rise */
|
|
t = t_ut - 1.2;
|
|
if (rise_found)
|
|
t = tret[0] - 1.2;
|
|
rise_found = TRUE;
|
|
retval =
|
|
swe_rise_trans(t, ipl, starname, epheflag,
|
|
SE_CALC_RISE | risemeth, geopos, atpress, attemp,
|
|
&(tret[0]), serr);
|
|
if (retval == ERR) {
|
|
return ERR;
|
|
}
|
|
else if (retval == -2) {
|
|
rise_found = FALSE;
|
|
}
|
|
}
|
|
if (rise_found && set_found) {
|
|
if (above_horizon) {
|
|
*dgsect = (t_ut - tret[0]) / (tret[1] - tret[0]) * 18 + 1;
|
|
}
|
|
else {
|
|
*dgsect = (t_ut - tret[1]) / (tret[0] - tret[1]) * 18 + 19;
|
|
}
|
|
return OK;
|
|
}
|
|
else {
|
|
*dgsect = 0;
|
|
if (serr)
|
|
sprintf(serr, "rise or set not found for planet %d", ipl);
|
|
return ERR;
|
|
}
|
|
}
|