diff --git a/README.md b/README.md
index 9f7b89c8..4f59a252 100644
--- a/README.md
+++ b/README.md
@@ -10,7 +10,7 @@
Examples |
-
+
|
diff --git a/demo/java/correct/lunar_eclipse.txt b/demo/java/correct/lunar_eclipse.txt
index 77a70ca6..e0404be9 100644
--- a/demo/java/correct/lunar_eclipse.txt
+++ b/demo/java/correct/lunar_eclipse.txt
@@ -7,7 +7,7 @@
1988-08-27T12:01:33.171Z Partial eclipse ends.
1989-02-20T13:43:24.717Z Partial eclipse begins.
-1989-02-20T14:55:34.838Z Total eclipse begins.
+1989-02-20T14:55:34.839Z Total eclipse begins.
1989-02-20T15:35:19.955Z Peak of total eclipse.
1989-02-20T16:15:05.072Z Total eclipse ends.
1989-02-20T17:27:15.193Z Partial eclipse ends.
diff --git a/demo/java/correct/moonphase.txt b/demo/java/correct/moonphase.txt
index e7c1acc4..ce44af00 100644
--- a/demo/java/correct/moonphase.txt
+++ b/demo/java/correct/moonphase.txt
@@ -2,13 +2,13 @@
2019-06-15T09:15:32.987Z : Moon's illuminated fraction = 95.63%.
The next 10 lunar quarters are:
-2019-06-17T08:31:17.934Z : Full Moon
-2019-06-25T09:47:07.624Z : Third Quarter
-2019-07-02T19:16:46.550Z : New Moon
-2019-07-09T10:55:28.848Z : First Quarter
-2019-07-16T21:38:53.690Z : Full Moon
-2019-07-25T01:18:42.696Z : Third Quarter
-2019-08-01T03:12:26.151Z : New Moon
-2019-08-07T17:31:35.716Z : First Quarter
-2019-08-15T12:29:57.164Z : Full Moon
-2019-08-23T14:56:46.202Z : Third Quarter
+2019-06-17T08:31:17.942Z : Full Moon
+2019-06-25T09:47:05.866Z : Third Quarter
+2019-07-02T19:16:46.599Z : New Moon
+2019-07-09T10:55:27.398Z : First Quarter
+2019-07-16T21:38:53.592Z : Full Moon
+2019-07-25T01:18:41.310Z : Third Quarter
+2019-08-01T03:12:25.793Z : New Moon
+2019-08-07T17:31:34.799Z : First Quarter
+2019-08-15T12:29:56.276Z : Full Moon
+2019-08-23T14:56:45.684Z : Third Quarter
diff --git a/demo/kotlin/correct/lunar_eclipse.txt b/demo/kotlin/correct/lunar_eclipse.txt
index 77a70ca6..e0404be9 100644
--- a/demo/kotlin/correct/lunar_eclipse.txt
+++ b/demo/kotlin/correct/lunar_eclipse.txt
@@ -7,7 +7,7 @@
1988-08-27T12:01:33.171Z Partial eclipse ends.
1989-02-20T13:43:24.717Z Partial eclipse begins.
-1989-02-20T14:55:34.838Z Total eclipse begins.
+1989-02-20T14:55:34.839Z Total eclipse begins.
1989-02-20T15:35:19.955Z Peak of total eclipse.
1989-02-20T16:15:05.072Z Total eclipse ends.
1989-02-20T17:27:15.193Z Partial eclipse ends.
diff --git a/demo/kotlin/correct/moonphase.txt b/demo/kotlin/correct/moonphase.txt
index e7c1acc4..ce44af00 100644
--- a/demo/kotlin/correct/moonphase.txt
+++ b/demo/kotlin/correct/moonphase.txt
@@ -2,13 +2,13 @@
2019-06-15T09:15:32.987Z : Moon's illuminated fraction = 95.63%.
The next 10 lunar quarters are:
-2019-06-17T08:31:17.934Z : Full Moon
-2019-06-25T09:47:07.624Z : Third Quarter
-2019-07-02T19:16:46.550Z : New Moon
-2019-07-09T10:55:28.848Z : First Quarter
-2019-07-16T21:38:53.690Z : Full Moon
-2019-07-25T01:18:42.696Z : Third Quarter
-2019-08-01T03:12:26.151Z : New Moon
-2019-08-07T17:31:35.716Z : First Quarter
-2019-08-15T12:29:57.164Z : Full Moon
-2019-08-23T14:56:46.202Z : Third Quarter
+2019-06-17T08:31:17.942Z : Full Moon
+2019-06-25T09:47:05.866Z : Third Quarter
+2019-07-02T19:16:46.599Z : New Moon
+2019-07-09T10:55:27.398Z : First Quarter
+2019-07-16T21:38:53.592Z : Full Moon
+2019-07-25T01:18:41.310Z : Third Quarter
+2019-08-01T03:12:25.793Z : New Moon
+2019-08-07T17:31:34.799Z : First Quarter
+2019-08-15T12:29:56.276Z : Full Moon
+2019-08-23T14:56:45.684Z : Third Quarter
diff --git a/demo/python/astronomy.py b/demo/python/astronomy.py
index 6876364b..c4f96e2b 100644
--- a/demo/python/astronomy.py
+++ b/demo/python/astronomy.py
@@ -5084,34 +5084,44 @@ def SunPosition(time):
true_obliq = math.radians(adjusted_time._etilt().tobl)
return _RotateEquatorialToEcliptic(sun_ofdate, true_obliq, time)
-def Ecliptic(equ):
- """Converts J2000 equatorial Cartesian coordinates to J2000 ecliptic coordinates.
+def Ecliptic(eqj):
+ """Converts a J2000 mean equator (EQJ) vector to a true ecliptic of date (ETC) vector and angles.
Given coordinates relative to the Earth's equator at J2000 (the instant of noon UTC
- on 1 January 2000), this function converts those coordinates to J2000 ecliptic coordinates,
+ on 1 January 2000), this function converts those coordinates to true ecliptic coordinates of date,
which are relative to the plane of the Earth's orbit around the Sun.
Parameters
----------
- equ : Equatorial
+ eqj : Equatorial
Equatorial coordinates in the J2000 frame of reference.
+ You can call #GeoVector to obtain suitable equatorial coordinates.
Returns
-------
EclipticCoordinates
- Ecliptic coordinates in the J2000 frame of reference.
+ Spherical and vector coordinates expressed in true ecliptic coordinates of date (ECT).
"""
- # Based on NOVAS functions equ2ecl() and equ2ecl_vec().
- ob2000 = 0.40909260059599012 # mean obliquity of the J2000 ecliptic in radians
- return _RotateEquatorialToEcliptic([equ.x, equ.y, equ.z], ob2000, equ.t)
+ # Calculate nutation and obliquity for this time.
+ # As an optimization, the nutation angles are cached in `eqj.t`,
+ # and reused below when the `nutation` function is called.
+ et = _e_tilt(eqj.t)
+
+ # Convert J2000 mean equator (EQJ) to true equator of date (EQD).
+ mean_pos = _precession([eqj.x, eqj.y, eqj.z], eqj.t, _PrecessDir.From2000)
+ eqd_pos = _nutation(mean_pos, eqj.t, _PrecessDir.From2000)
+
+ # Rotate from EQD to true ecliptic of date (ECT).
+ return _RotateEquatorialToEcliptic(eqd_pos, math.radians(et.tobl), eqj.t)
+
def EclipticLongitude(body, time):
- """Calculates heliocentric ecliptic longitude of a body based on the J2000 equinox.
+ """Calculates heliocentric ecliptic longitude of a body.
This function calculates the angle around the plane of the Earth's orbit
of a celestial body, as seen from the center of the Sun.
The angle is measured prograde (in the direction of the Earth's orbit around the Sun)
- in degrees from the J2000 equinox. The ecliptic longitude is always in the range [0, 360).
+ in degrees from the true equinox of date. The ecliptic longitude is always in the range [0, 360).
Parameters
----------
diff --git a/demo/python/correct/lunar_angles.txt b/demo/python/correct/lunar_angles.txt
index 80b97880..667856c6 100644
--- a/demo/python/correct/lunar_angles.txt
+++ b/demo/python/correct/lunar_angles.txt
@@ -1,77 +1,77 @@
-2021-05-15T01:45:15.502Z Jupiter 120
-2021-05-15T17:53:54.557Z Venus 30
-2021-05-16T04:23:24.323Z Saturn 150
-2021-05-16T05:06:25.856Z Mars 0
-2021-05-16T12:51:08.386Z Mercury 30
-2021-05-17T06:05:46.557Z Sun 60
-2021-05-17T13:28:34.314Z Jupiter 150
-2021-05-18T10:43:24.043Z Venus 60
-2021-05-18T14:28:31.705Z Saturn 180
-2021-05-18T18:01:40.367Z Mars 30
-2021-05-19T02:55:48.293Z Mercury 60
-2021-05-19T19:13:17.318Z Sun 90
-2021-05-19T22:06:38.821Z Jupiter 180
-2021-05-20T21:07:44.292Z Saturn 210
-2021-05-20T23:01:26.198Z Venus 90
-2021-05-21T02:57:43.803Z Mars 60
-2021-05-21T11:47:54.388Z Mercury 90
-2021-05-22T02:58:57.125Z Jupiter 210
-2021-05-22T03:46:48.175Z Sun 120
-2021-05-23T00:10:42.249Z Saturn 240
-2021-05-23T06:36:37.117Z Venus 120
-2021-05-23T07:51:25.441Z Mars 90
-2021-05-23T15:59:55.611Z Mercury 120
-2021-05-24T04:37:03.217Z Jupiter 240
-2021-05-24T08:28:12.625Z Sun 150
-2021-05-25T00:34:55.763Z Saturn 270
-2021-05-25T10:01:10.928Z Mars 120
-2021-05-25T11:01:14.731Z Venus 150
-2021-05-25T17:13:39.257Z Mercury 150
-2021-05-26T04:29:33.492Z Jupiter 270
-2021-05-26T11:14:24.846Z Sun 180
-2021-05-27T00:00:58.503Z Saturn 300
-2021-05-27T11:31:13.830Z Mars 150
-2021-05-27T14:43:34.085Z Venus 180
-2021-05-27T17:36:05.800Z Mercury 180
-2021-05-28T04:30:48.514Z Jupiter 300
-2021-05-28T14:32:15.606Z Sun 210
-2021-05-29T00:23:12.944Z Saturn 330
-2021-05-29T14:36:19.185Z Mars 180
-2021-05-29T19:07:06.445Z Mercury 210
-2021-05-29T20:23:23.051Z Venus 210
-2021-05-30T06:34:02.076Z Jupiter 330
-2021-05-30T20:43:28.840Z Sun 240
-2021-05-31T03:24:49.116Z Saturn 0
-2021-05-31T21:11:00.051Z Mars 210
-2021-05-31T23:13:57.679Z Mercury 240
-2021-06-01T06:14:14.724Z Venus 240
-2021-06-01T12:03:46.946Z Jupiter 0
-2021-06-02T07:25:04.037Z Sun 270
-2021-06-02T10:08:01.205Z Saturn 30
-2021-06-03T06:24:41.602Z Mercury 270
-2021-06-03T08:08:58.541Z Mars 240
-2021-06-03T21:09:24.870Z Venus 270
-2021-06-03T21:22:13.482Z Jupiter 30
-2021-06-04T20:23:38.951Z Saturn 60
-2021-06-04T22:38:31.597Z Sun 300
-2021-06-05T15:57:17.165Z Mercury 300
-2021-06-05T22:47:34.963Z Mars 270
-2021-06-06T09:32:04.351Z Jupiter 60
-2021-06-06T15:57:32.038Z Venus 300
-2021-06-07T08:51:04.866Z Saturn 90
-2021-06-07T16:37:11.606Z Sun 330
-2021-06-08T02:27:50.910Z Mercury 330
-2021-06-08T15:07:18.196Z Mars 300
-2021-06-08T22:47:03.995Z Jupiter 90
-2021-06-09T12:02:10.026Z Venus 330
-2021-06-09T21:43:15.335Z Saturn 120
-2021-06-10T10:53:20.688Z Sun 0
-2021-06-10T12:38:05.006Z Mercury 0
-2021-06-11T07:02:57.519Z Mars 330
-2021-06-11T11:27:40.113Z Jupiter 120
-2021-06-12T06:59:51.615Z Venus 0
-2021-06-12T09:34:14.801Z Saturn 150
-2021-06-12T21:38:19.168Z Mercury 30
-2021-06-13T03:33:36.529Z Sun 30
-2021-06-13T21:08:06.755Z Mars 0
-2021-06-13T22:26:26.447Z Jupiter 150
+2021-05-15T01:45:15.706Z Jupiter 120
+2021-05-15T17:53:54.314Z Venus 30
+2021-05-16T04:23:24.170Z Saturn 150
+2021-05-16T05:06:25.682Z Mars 0
+2021-05-16T12:51:07.810Z Mercury 30
+2021-05-17T06:05:45.825Z Sun 60
+2021-05-17T13:28:33.770Z Jupiter 150
+2021-05-18T10:43:22.784Z Venus 60
+2021-05-18T14:28:30.696Z Saturn 180
+2021-05-18T18:01:39.264Z Mars 30
+2021-05-19T02:55:46.814Z Mercury 60
+2021-05-19T19:13:15.714Z Sun 90
+2021-05-19T22:06:37.540Z Jupiter 180
+2021-05-20T21:07:42.837Z Saturn 210
+2021-05-20T23:01:24.412Z Venus 90
+2021-05-21T02:57:42.297Z Mars 60
+2021-05-21T11:47:52.705Z Mercury 90
+2021-05-22T02:58:55.870Z Jupiter 210
+2021-05-22T03:46:46.605Z Sun 120
+2021-05-23T00:10:41.162Z Saturn 240
+2021-05-23T06:36:35.859Z Venus 120
+2021-05-23T07:51:24.443Z Mars 90
+2021-05-23T15:59:54.578Z Mercury 120
+2021-05-24T04:37:02.655Z Jupiter 240
+2021-05-24T08:28:11.867Z Sun 150
+2021-05-25T00:34:55.447Z Saturn 270
+2021-05-25T10:01:10.768Z Mars 120
+2021-05-25T11:01:14.390Z Venus 150
+2021-05-25T17:13:39.027Z Mercury 150
+2021-05-26T04:29:33.608Z Jupiter 270
+2021-05-26T11:14:24.797Z Sun 180
+2021-05-27T00:00:58.651Z Saturn 300
+2021-05-27T11:31:14.024Z Mars 150
+2021-05-27T14:43:34.090Z Venus 180
+2021-05-27T17:36:05.802Z Mercury 180
+2021-05-28T04:30:48.680Z Jupiter 300
+2021-05-28T14:32:15.449Z Sun 210
+2021-05-29T00:23:12.823Z Saturn 330
+2021-05-29T14:36:18.888Z Mars 180
+2021-05-29T19:07:05.905Z Mercury 210
+2021-05-29T20:23:22.440Z Venus 210
+2021-05-30T06:34:01.580Z Jupiter 330
+2021-05-30T20:43:27.790Z Sun 240
+2021-05-31T03:24:48.177Z Saturn 0
+2021-05-31T21:10:58.832Z Mars 210
+2021-05-31T23:13:56.300Z Mercury 240
+2021-06-01T06:14:13.103Z Venus 240
+2021-06-01T12:03:45.645Z Jupiter 0
+2021-06-02T07:25:02.187Z Sun 270
+2021-06-02T10:07:59.646Z Saturn 30
+2021-06-03T06:24:39.897Z Mercury 270
+2021-06-03T08:08:56.940Z Mars 240
+2021-06-03T21:09:23.029Z Venus 270
+2021-06-03T21:22:12.060Z Jupiter 30
+2021-06-04T20:23:37.640Z Saturn 60
+2021-06-04T22:38:30.011Z Sun 300
+2021-06-05T15:57:16.003Z Mercury 300
+2021-06-05T22:47:34.042Z Mars 270
+2021-06-06T09:32:03.690Z Jupiter 60
+2021-06-06T15:57:31.165Z Venus 300
+2021-06-07T08:51:04.462Z Saturn 90
+2021-06-07T16:37:11.096Z Sun 330
+2021-06-08T02:27:50.634Z Mercury 330
+2021-06-08T15:07:18.273Z Mars 300
+2021-06-08T22:47:04.179Z Jupiter 90
+2021-06-09T12:02:10.110Z Venus 330
+2021-06-09T21:43:15.531Z Saturn 120
+2021-06-10T10:53:20.717Z Sun 0
+2021-06-10T12:38:05.109Z Mercury 0
+2021-06-11T07:02:57.745Z Mars 330
+2021-06-11T11:27:40.329Z Jupiter 120
+2021-06-12T06:59:51.450Z Venus 0
+2021-06-12T09:34:14.672Z Saturn 150
+2021-06-12T21:38:18.839Z Mercury 30
+2021-06-13T03:33:35.931Z Sun 30
+2021-06-13T21:08:06.168Z Mars 0
+2021-06-13T22:26:25.894Z Jupiter 150
diff --git a/demo/python/correct/lunar_eclipse.txt b/demo/python/correct/lunar_eclipse.txt
index f50bf7eb..96df4170 100644
--- a/demo/python/correct/lunar_eclipse.txt
+++ b/demo/python/correct/lunar_eclipse.txt
@@ -9,7 +9,7 @@
1989-02-20T13:43:24.718Z Partial eclipse begins.
1989-02-20T14:55:34.839Z Total eclipse begins.
1989-02-20T15:35:19.956Z Peak of total eclipse.
-1989-02-20T16:15:05.072Z Total eclipse ends.
+1989-02-20T16:15:05.073Z Total eclipse ends.
1989-02-20T17:27:15.194Z Partial eclipse ends.
1989-08-17T01:20:43.868Z Partial eclipse begins.
diff --git a/demo/python/correct/moonphase.txt b/demo/python/correct/moonphase.txt
index 5edc97a7..38091930 100644
--- a/demo/python/correct/moonphase.txt
+++ b/demo/python/correct/moonphase.txt
@@ -2,13 +2,13 @@
2019-06-15T09:15:32.987Z : Moon's illuminated fraction = 95.63%.
The next 10 lunar quarters are:
-2019-06-17T08:31:17.934Z : Full Moon
-2019-06-25T09:47:07.624Z : Third Quarter
-2019-07-02T19:16:46.550Z : New Moon
-2019-07-09T10:55:28.849Z : First Quarter
-2019-07-16T21:38:53.691Z : Full Moon
-2019-07-25T01:18:42.697Z : Third Quarter
-2019-08-01T03:12:26.152Z : New Moon
-2019-08-07T17:31:35.717Z : First Quarter
-2019-08-15T12:29:57.164Z : Full Moon
-2019-08-23T14:56:46.202Z : Third Quarter
+2019-06-17T08:31:17.943Z : Full Moon
+2019-06-25T09:47:05.867Z : Third Quarter
+2019-07-02T19:16:46.600Z : New Moon
+2019-07-09T10:55:27.398Z : First Quarter
+2019-07-16T21:38:53.593Z : Full Moon
+2019-07-25T01:18:41.310Z : Third Quarter
+2019-08-01T03:12:25.793Z : New Moon
+2019-08-07T17:31:34.799Z : First Quarter
+2019-08-15T12:29:56.277Z : Full Moon
+2019-08-23T14:56:45.685Z : Third Quarter
diff --git a/generate/ctest.c b/generate/ctest.c
index deaffa01..5f2030e4 100644
--- a/generate/ctest.c
+++ b/generate/ctest.c
@@ -3576,7 +3576,7 @@ static int EclipticTest(void)
if (max_vec_diff > 3.388e-18)
FAIL("C EclipticTest: EXCESSIVE VECTOR DIFF = %0.6le AU.\n", max_vec_diff);
- DEBUG("C EclipticTest: PASS: count = %d, max_vec_diff = %0.6le AU, max_angle_diff = %0.6le AU.\n", count, max_vec_diff, max_angle_diff);
+ printf("C EclipticTest: PASS: count = %d, max_vec_diff = %0.6le AU, max_angle_diff = %0.6le AU.\n", count, max_vec_diff, max_angle_diff);
error = 0;
fail:
return error;
diff --git a/generate/dotnet/csharp_test/csharp_test.cs b/generate/dotnet/csharp_test/csharp_test.cs
index 352c8fc9..3a9e3830 100644
--- a/generate/dotnet/csharp_test/csharp_test.cs
+++ b/generate/dotnet/csharp_test/csharp_test.cs
@@ -2202,7 +2202,7 @@ static int EclipticTest()
if (max_vec_diff > 3.743e-18)
return Fail($"EclipticTest: EXCESSIVE VECTOR DIFF = {max_vec_diff:G6} AU.");
- Debug($"C# EclipticTest: PASS: count = {count}, max_diff = {max_vec_diff:G6} AU, max_angle_diff = {max_angle_diff:G6} AU.");
+ Console.WriteLine($"C# EclipticTest: PASS: count = {count}, max_diff = {max_vec_diff:G6} AU, max_angle_diff = {max_angle_diff:G6} AU.");
return 0;
}
diff --git a/generate/template/astronomy.cs b/generate/template/astronomy.cs
index dd3c5b0a..0c151986 100644
--- a/generate/template/astronomy.cs
+++ b/generate/template/astronomy.cs
@@ -5428,7 +5428,7 @@ private static Ecliptic RotateEquatorialToEcliptic(AstroVector pos, double obliq
public static Ecliptic EquatorialToEcliptic(AstroVector eqj)
{
// Calculate nutation and obliquity for this time.
- // As an optimization, the nutation angles are cached in `time`,
+ // As an optimization, the nutation angles are cached in `eqj.t`,
// and reused below when the `nutation` function is called.
earth_tilt_t et = e_tilt(eqj.t);
diff --git a/generate/template/astronomy.kt b/generate/template/astronomy.kt
index aed429b8..10a3fb01 100644
--- a/generate/template/astronomy.kt
+++ b/generate/template/astronomy.kt
@@ -5462,12 +5462,12 @@ fun horizon(
/**
- * Calculates heliocentric ecliptic longitude of a body based on the J2000 equinox.
+ * Calculates heliocentric ecliptic longitude of a body.
*
* This function calculates the angle around the plane of the Earth's orbit
* of a celestial body, as seen from the center of the Sun.
* The angle is measured prograde (in the direction of the Earth's orbit around the Sun)
- * in degrees from the J2000 equinox. The ecliptic longitude is always in the range [0, 360).
+ * in degrees from the true equinox of date. The ecliptic longitude is always in the range [0, 360).
*
* @param body
* A body other than the Sun.
@@ -5965,23 +5965,30 @@ private fun rotateEquatorialToEcliptic(pos: Vector, obliqRadians: Double): Eclip
}
/**
- * Converts J2000 equatorial Cartesian coordinates to J2000 ecliptic coordinates.
+ * Converts a J2000 mean equator (EQJ) vector to a true ecliptic of date (ETC) vector and angles.
*
* Given coordinates relative to the Earth's equator at J2000 (the instant of noon UTC
- * on 1 January 2000), this function converts those coordinates to J2000 ecliptic coordinates,
+ * on 1 January 2000), this function converts those coordinates to true ecliptic coordinates of date,
* which are relative to the plane of the Earth's orbit around the Sun.
*
- * @param equ
+ * @param eqj
* Equatorial coordinates in the J2000 frame of reference.
* You can call [geoVector] to obtain suitable equatorial coordinates.
*
- * @return Ecliptic coordinates in the J2000 frame of reference (ECL).
+ * @return Spherical and vector coordinates expressed in true ecliptic coordinates of date (ECT)..
*/
-fun equatorialToEcliptic(equ: Vector): Ecliptic =
- rotateEquatorialToEcliptic(
- equ,
- 0.40909260059599012 // mean obliquity of the J2000 ecliptic in radians
- )
+fun equatorialToEcliptic(eqj: Vector): Ecliptic {
+ // Calculate nutation and obliquity for this time.
+ // As an optimization, the nutation angles are cached in `eqj.t`,
+ // and reused below when the `nutation` function is called.
+ val et = earthTilt(eqj.t)
+
+ // Convert J2000 mean equator (EQJ) to true equator of date (EQD).
+ val eqd = gyration(eqj, PrecessDirection.From2000);
+
+ // Rotate from EQD to true ecliptic of date (ECT).
+ return rotateEquatorialToEcliptic(eqd, et.tobl.degreesToRadians())
+}
/**
* Searches for the time when the Sun reaches an apparent ecliptic longitude as seen from the Earth.
diff --git a/generate/template/astronomy.py b/generate/template/astronomy.py
index 183e352e..47df7ace 100644
--- a/generate/template/astronomy.py
+++ b/generate/template/astronomy.py
@@ -3578,34 +3578,44 @@ def SunPosition(time):
true_obliq = math.radians(adjusted_time._etilt().tobl)
return _RotateEquatorialToEcliptic(sun_ofdate, true_obliq, time)
-def Ecliptic(equ):
- """Converts J2000 equatorial Cartesian coordinates to J2000 ecliptic coordinates.
+def Ecliptic(eqj):
+ """Converts a J2000 mean equator (EQJ) vector to a true ecliptic of date (ETC) vector and angles.
Given coordinates relative to the Earth's equator at J2000 (the instant of noon UTC
- on 1 January 2000), this function converts those coordinates to J2000 ecliptic coordinates,
+ on 1 January 2000), this function converts those coordinates to true ecliptic coordinates of date,
which are relative to the plane of the Earth's orbit around the Sun.
Parameters
----------
- equ : Equatorial
+ eqj : Equatorial
Equatorial coordinates in the J2000 frame of reference.
+ You can call #GeoVector to obtain suitable equatorial coordinates.
Returns
-------
EclipticCoordinates
- Ecliptic coordinates in the J2000 frame of reference.
+ Spherical and vector coordinates expressed in true ecliptic coordinates of date (ECT).
"""
- # Based on NOVAS functions equ2ecl() and equ2ecl_vec().
- ob2000 = 0.40909260059599012 # mean obliquity of the J2000 ecliptic in radians
- return _RotateEquatorialToEcliptic([equ.x, equ.y, equ.z], ob2000, equ.t)
+ # Calculate nutation and obliquity for this time.
+ # As an optimization, the nutation angles are cached in `eqj.t`,
+ # and reused below when the `nutation` function is called.
+ et = _e_tilt(eqj.t)
+
+ # Convert J2000 mean equator (EQJ) to true equator of date (EQD).
+ mean_pos = _precession([eqj.x, eqj.y, eqj.z], eqj.t, _PrecessDir.From2000)
+ eqd_pos = _nutation(mean_pos, eqj.t, _PrecessDir.From2000)
+
+ # Rotate from EQD to true ecliptic of date (ECT).
+ return _RotateEquatorialToEcliptic(eqd_pos, math.radians(et.tobl), eqj.t)
+
def EclipticLongitude(body, time):
- """Calculates heliocentric ecliptic longitude of a body based on the J2000 equinox.
+ """Calculates heliocentric ecliptic longitude of a body.
This function calculates the angle around the plane of the Earth's orbit
of a celestial body, as seen from the center of the Sun.
The angle is measured prograde (in the direction of the Earth's orbit around the Sun)
- in degrees from the J2000 equinox. The ecliptic longitude is always in the range [0, 360).
+ in degrees from the true equinox of date. The ecliptic longitude is always in the range [0, 360).
Parameters
----------
diff --git a/generate/test.py b/generate/test.py
index 86747b14..92fd244d 100755
--- a/generate/test.py
+++ b/generate/test.py
@@ -587,13 +587,13 @@ def CheckSaturn():
# For now, I just test for consistency with Paul Schlyter's formulas at:
# http://www.stjarnhimlen.se/comp/ppcomp.html#15
data = [
- ( "1972-01-01T00:00Z", -0.31904865, +24.50061220 ),
- ( "1980-01-01T00:00Z", +0.85213663, -1.85761461 ),
- ( "2009-09-04T00:00Z", +1.01626809, +0.08380716 ),
- ( "2017-06-15T00:00Z", -0.12318790, -26.60871409 ),
- ( "2019-05-01T00:00Z", +0.32954097, -23.53880802 ),
- ( "2025-09-25T00:00Z", +0.51286575, +1.52327932 ),
- ( "2032-05-15T00:00Z", -0.04652109, +26.95717765 )
+ ( "1972-01-01T00:00Z", -0.31725492, +24.43386475 ),
+ ( "1980-01-01T00:00Z", +0.85796177, -1.72627324 ),
+ ( "2009-09-04T00:00Z", +1.01932560, +0.01834451 ),
+ ( "2017-06-15T00:00Z", -0.12303373, -26.60068380 ),
+ ( "2019-05-01T00:00Z", +0.33124502, -23.47173574 ),
+ ( "2025-09-25T00:00Z", +0.50543708, +1.69118986 ),
+ ( "2032-05-15T00:00Z", -0.04649573, +26.95238680 )
]
error = 0
for (dtext, mag, tilt) in data:
@@ -961,36 +961,6 @@ def VectorDiff(a, b):
return sqrt(dx*dx + dy*dy + dz*dz)
-def Test_EQJ_ECL():
- r = astronomy.Rotation_EQJ_ECL()
- # Calculate heliocentric Earth position at a test time.
- time = astronomy.Time.Make(2019, 12, 8, 19, 39, 15)
- ev = astronomy.HelioVector(astronomy.Body.Earth, time)
-
- # Use the existing astronomy.Ecliptic() to calculate ecliptic vector and angles.
- ecl = astronomy.Ecliptic(ev)
- Debug('PY Test_EQJ_ECL ecl = ({}, {}, {})'.format(ecl.vec.x, ecl.vec.y, ecl.vec.z))
-
- # Now compute the same vector via rotation matrix.
- ee = astronomy.RotateVector(r, ev)
- dx = ee.x - ecl.vec.x
- dy = ee.y - ecl.vec.y
- dz = ee.z - ecl.vec.z
- diff = sqrt(dx*dx + dy*dy + dz*dz)
- Debug('PY Test_EQJ_ECL ee = ({}, {}, {}); diff = {}'.format(ee.x, ee.y, ee.z, diff))
- if diff > 1.0e-16:
- print('PY Test_EQJ_ECL: EXCESSIVE VECTOR ERROR')
- sys.exit(1)
-
- # Reverse the test: go from ecliptic back to equatorial.
- ir = astronomy.Rotation_ECL_EQJ()
- et = astronomy.RotateVector(ir, ee)
- idiff = VectorDiff(et, ev)
- Debug('PY Test_EQJ_ECL ev diff = {}'.format(idiff))
- if idiff > 2.3e-16:
- print('PY Test_EQJ_ECL: EXCESSIVE REVERSE ROTATION ERROR')
- sys.exit(1)
-
def Test_GAL_EQJ_NOVAS(filename):
THRESHOLD_SECONDS = 8.8
rot = astronomy.Rotation_EQJ_GAL()
@@ -1265,11 +1235,51 @@ def Test_EQD_ECT():
sys.exit(1)
Debug('PY Test_EQD_ECT: PASS: count = {}, max_diff = {:0.6e} au.'.format(count, max_diff))
+
+def Ecliptic():
+ time = astronomy.Time.Make(1900, 1, 1, 0, 0, 0.0)
+ stopTime = astronomy.Time.Make(2100, 1, 1, 0, 0, 0.0)
+ count = 0
+ max_vec_diff = 0
+ max_angle_diff = 0.0
+ while time.ut <= stopTime.ut:
+ # Get Moon's geocentric position in EQJ.
+ eqj = astronomy.GeoMoon(time)
+
+ # Convert EQJ to ECT.
+ eclip = astronomy.Ecliptic(eqj)
+
+ # Confirm that the ecliptic angles and ecliptic vector are consistent.
+ check_sphere = astronomy.Spherical(eclip.elat, eclip.elon, eclip.vec.Length())
+ check_vec = astronomy.VectorFromSphere(check_sphere, time)
+ max_angle_diff = max(max_angle_diff, VectorDiff(eclip.vec, check_vec))
+
+ # Independently get the Moon's spherical coordinates in ECT.
+ sphere = astronomy.EclipticGeoMoon(time)
+
+ # Convert spherical coordinates to ECT vector.
+ check_ect = astronomy.VectorFromSphere(sphere, time)
+
+ # Verify the two ECT vectors are identical, within tolerance.
+ max_vec_diff = max(max_vec_diff, VectorDiff(eclip.vec, check_ect))
+
+ time = time.AddDays(10.0)
+ count += 1
+
+ if max_vec_diff > 3.388e-18:
+ return Fail('Ecliptic', 'EXCESSIVE VECTOR DIFF = {:0.6e} au.'.format(max_vec_diff))
+
+ if max_angle_diff > 2.910e-18:
+ return Fail('Ecliptic', 'EXCESSIVE ANGLE DIFF = {:0.6e} au.'.format(max_angle_diff))
+
+ print('PY Ecliptic: PASS: count = {:d}, max_vec_diff = {:0.6e} au, max_angle_diff = {:0.6e} au.'.format(count, max_vec_diff, max_angle_diff))
+ return 0
+
+
def Rotation():
Rotation_MatrixInverse()
Rotation_MatrixMultiply()
Rotation_Pivot()
- Test_EQJ_ECL()
Test_GAL_EQJ_NOVAS('temp/galeqj.txt')
Test_EQJ_EQD(astronomy.Body.Mercury)
Test_EQJ_EQD(astronomy.Body.Venus)
@@ -1669,7 +1679,7 @@ def LocalSolarEclipse1():
continue
diff_minutes = (24 * 60) * vabs(diff_days)
- if diff_minutes > 7.734:
+ if diff_minutes > 7.737:
return Fail(funcname, 'EXCESSIVE TIME ERROR = {} minutes'.format(diff_minutes))
if diff_minutes > max_minutes:
@@ -3127,6 +3137,7 @@ def StarRiseSetCulm():
'barystate': BaryState,
'constellation': Constellation,
'dates250': DatesIssue250,
+ 'ecliptic': Ecliptic,
'elongation': Elongation,
'geoid': Geoid,
'global_solar_eclipse': GlobalSolarEclipse,
diff --git a/generate/version.txt b/generate/version.txt
index 348fc11e..ea4bd0fb 100644
--- a/generate/version.txt
+++ b/generate/version.txt
@@ -1 +1 @@
-2.1.12
+2.1.13
diff --git a/source/csharp/astronomy.cs b/source/csharp/astronomy.cs
index da2e7e73..6cc4efdb 100644
--- a/source/csharp/astronomy.cs
+++ b/source/csharp/astronomy.cs
@@ -6562,7 +6562,7 @@ private static Ecliptic RotateEquatorialToEcliptic(AstroVector pos, double obliq
public static Ecliptic EquatorialToEcliptic(AstroVector eqj)
{
// Calculate nutation and obliquity for this time.
- // As an optimization, the nutation angles are cached in `time`,
+ // As an optimization, the nutation angles are cached in `eqj.t`,
// and reused below when the `nutation` function is called.
earth_tilt_t et = e_tilt(eqj.t);
diff --git a/source/csharp/astronomy.csproj b/source/csharp/astronomy.csproj
index 9bfe71fd..258f3320 100644
--- a/source/csharp/astronomy.csproj
+++ b/source/csharp/astronomy.csproj
@@ -4,7 +4,7 @@
true
true
CosineKitty.AstronomyEngine
- 2.1.12
+ 2.1.13
https://github.com/cosinekitty/astronomy
Don Cross
Astronomy Engine
diff --git a/source/js/package.json b/source/js/package.json
index cbc1273b..4f1eaf23 100644
--- a/source/js/package.json
+++ b/source/js/package.json
@@ -1,6 +1,6 @@
{
"name": "astronomy-engine",
- "version": "2.1.12",
+ "version": "2.1.13",
"description": "Astronomy calculation for Sun, Moon, and planets.",
"author": "Donald Cross",
"license": "MIT",
diff --git a/source/kotlin/README.md b/source/kotlin/README.md
index 31dc7960..8b15c102 100644
--- a/source/kotlin/README.md
+++ b/source/kotlin/README.md
@@ -25,7 +25,7 @@ allprojects {
Now add the dependency:
```kotlin
dependencies {
- implementation("io.github.cosinekitty:astronomy:2.1.12")
+ implementation("io.github.cosinekitty:astronomy:2.1.13")
}
```
@@ -129,10 +129,10 @@ movement through the Solar System.
| [defineStar](doc/define-star.md)
fun [defineStar](doc/define-star.md)(body: [Body](doc/-body/index.md), ra: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), dec: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), distanceLightYears: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html))
Assign equatorial coordinates to a user-defined star. |
| [degreesToRadians](doc/degrees-to-radians.md)
fun [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html).[degreesToRadians](doc/degrees-to-radians.md)(): [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html)
Convert an angle expressed in degrees to an angle expressed in radians. |
| [eclipticGeoMoon](doc/ecliptic-geo-moon.md)
fun [eclipticGeoMoon](doc/ecliptic-geo-moon.md)(time: [Time](doc/-time/index.md)): [Spherical](doc/-spherical/index.md)
Calculates spherical ecliptic geocentric position of the Moon. |
-| [eclipticLongitude](doc/ecliptic-longitude.md)
fun [eclipticLongitude](doc/ecliptic-longitude.md)(body: [Body](doc/-body/index.md), time: [Time](doc/-time/index.md)): [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html)
Calculates heliocentric ecliptic longitude of a body based on the J2000 equinox. |
+| [eclipticLongitude](doc/ecliptic-longitude.md)
fun [eclipticLongitude](doc/ecliptic-longitude.md)(body: [Body](doc/-body/index.md), time: [Time](doc/-time/index.md)): [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html)
Calculates heliocentric ecliptic longitude of a body. |
| [elongation](doc/elongation.md)
fun [elongation](doc/elongation.md)(body: [Body](doc/-body/index.md), time: [Time](doc/-time/index.md)): [ElongationInfo](doc/-elongation-info/index.md)
Determines visibility of a celestial body relative to the Sun, as seen from the Earth. |
| [equator](doc/equator.md)
fun [equator](doc/equator.md)(body: [Body](doc/-body/index.md), time: [Time](doc/-time/index.md), observer: [Observer](doc/-observer/index.md), equdate: [EquatorEpoch](doc/-equator-epoch/index.md), aberration: [Aberration](doc/-aberration/index.md)): [Equatorial](doc/-equatorial/index.md)
Calculates equatorial coordinates of a celestial body as seen by an observer on the Earth's surface. |
-| [equatorialToEcliptic](doc/equatorial-to-ecliptic.md)
fun [equatorialToEcliptic](doc/equatorial-to-ecliptic.md)(equ: [Vector](doc/-vector/index.md)): [Ecliptic](doc/-ecliptic/index.md)
Converts J2000 equatorial Cartesian coordinates to J2000 ecliptic coordinates. |
+| [equatorialToEcliptic](doc/equatorial-to-ecliptic.md)
fun [equatorialToEcliptic](doc/equatorial-to-ecliptic.md)(eqj: [Vector](doc/-vector/index.md)): [Ecliptic](doc/-ecliptic/index.md)
Converts a J2000 mean equator (EQJ) vector to a true ecliptic of date (ETC) vector and angles. |
| [geoEmbState](doc/geo-emb-state.md)
fun [geoEmbState](doc/geo-emb-state.md)(time: [Time](doc/-time/index.md)): [StateVector](doc/-state-vector/index.md)
Calculates the geocentric position and velocity of the Earth/Moon barycenter. |
| [geoMoon](doc/geo-moon.md)
fun [geoMoon](doc/geo-moon.md)(time: [Time](doc/-time/index.md)): [Vector](doc/-vector/index.md)
Calculates equatorial geocentric position of the Moon at a given time. |
| [geoMoonState](doc/geo-moon-state.md)
fun [geoMoonState](doc/geo-moon-state.md)(time: [Time](doc/-time/index.md)): [StateVector](doc/-state-vector/index.md)
Calculates equatorial geocentric position and velocity of the Moon at a given time. |
diff --git a/source/kotlin/build.gradle.kts b/source/kotlin/build.gradle.kts
index 79a831cc..cfc26320 100644
--- a/source/kotlin/build.gradle.kts
+++ b/source/kotlin/build.gradle.kts
@@ -6,7 +6,7 @@ plugins {
}
group = "io.github.cosinekitty"
-version = "2.1.12"
+version = "2.1.13"
repositories {
mavenCentral()
diff --git a/source/kotlin/doc/ecliptic-longitude.md b/source/kotlin/doc/ecliptic-longitude.md
index 487bd7ea..bccf5c04 100644
--- a/source/kotlin/doc/ecliptic-longitude.md
+++ b/source/kotlin/doc/ecliptic-longitude.md
@@ -4,9 +4,9 @@
fun [eclipticLongitude](ecliptic-longitude.md)(body: [Body](-body/index.md), time: [Time](-time/index.md)): [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html)
-Calculates heliocentric ecliptic longitude of a body based on the J2000 equinox.
+Calculates heliocentric ecliptic longitude of a body.
-This function calculates the angle around the plane of the Earth's orbit of a celestial body, as seen from the center of the Sun. The angle is measured prograde (in the direction of the Earth's orbit around the Sun) in degrees from the J2000 equinox. The ecliptic longitude is always in the range [0, 360).
+This function calculates the angle around the plane of the Earth's orbit of a celestial body, as seen from the center of the Sun. The angle is measured prograde (in the direction of the Earth's orbit around the Sun) in degrees from the true equinox of date. The ecliptic longitude is always in the range [0, 360).
#### Return
diff --git a/source/kotlin/doc/equatorial-to-ecliptic.md b/source/kotlin/doc/equatorial-to-ecliptic.md
index 09fc05e5..8a229d14 100644
--- a/source/kotlin/doc/equatorial-to-ecliptic.md
+++ b/source/kotlin/doc/equatorial-to-ecliptic.md
@@ -2,18 +2,18 @@
# equatorialToEcliptic
-fun [equatorialToEcliptic](equatorial-to-ecliptic.md)(equ: [Vector](-vector/index.md)): [Ecliptic](-ecliptic/index.md)
+fun [equatorialToEcliptic](equatorial-to-ecliptic.md)(eqj: [Vector](-vector/index.md)): [Ecliptic](-ecliptic/index.md)
-Converts J2000 equatorial Cartesian coordinates to J2000 ecliptic coordinates.
+Converts a J2000 mean equator (EQJ) vector to a true ecliptic of date (ETC) vector and angles.
-Given coordinates relative to the Earth's equator at J2000 (the instant of noon UTC on 1 January 2000), this function converts those coordinates to J2000 ecliptic coordinates, which are relative to the plane of the Earth's orbit around the Sun.
+Given coordinates relative to the Earth's equator at J2000 (the instant of noon UTC on 1 January 2000), this function converts those coordinates to true ecliptic coordinates of date, which are relative to the plane of the Earth's orbit around the Sun.
#### Return
-Ecliptic coordinates in the J2000 frame of reference (ECL).
+Spherical and vector coordinates expressed in true ecliptic coordinates of date (ECT)..
## Parameters
| | |
|---|---|
-| equ | Equatorial coordinates in the J2000 frame of reference. You can call [geoVector](geo-vector.md) to obtain suitable equatorial coordinates. |
+| eqj | Equatorial coordinates in the J2000 frame of reference. You can call [geoVector](geo-vector.md) to obtain suitable equatorial coordinates. |
diff --git a/source/kotlin/doc/index.md b/source/kotlin/doc/index.md
index edc95c32..7bba70e3 100644
--- a/source/kotlin/doc/index.md
+++ b/source/kotlin/doc/index.md
@@ -60,10 +60,10 @@
| [defineStar](define-star.md)
fun [defineStar](define-star.md)(body: [Body](-body/index.md), ra: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), dec: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html), distanceLightYears: [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html))
Assign equatorial coordinates to a user-defined star. |
| [degreesToRadians](degrees-to-radians.md)
fun [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html).[degreesToRadians](degrees-to-radians.md)(): [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html)
Convert an angle expressed in degrees to an angle expressed in radians. |
| [eclipticGeoMoon](ecliptic-geo-moon.md)
fun [eclipticGeoMoon](ecliptic-geo-moon.md)(time: [Time](-time/index.md)): [Spherical](-spherical/index.md)
Calculates spherical ecliptic geocentric position of the Moon. |
-| [eclipticLongitude](ecliptic-longitude.md)
fun [eclipticLongitude](ecliptic-longitude.md)(body: [Body](-body/index.md), time: [Time](-time/index.md)): [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html)
Calculates heliocentric ecliptic longitude of a body based on the J2000 equinox. |
+| [eclipticLongitude](ecliptic-longitude.md)
fun [eclipticLongitude](ecliptic-longitude.md)(body: [Body](-body/index.md), time: [Time](-time/index.md)): [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html)
Calculates heliocentric ecliptic longitude of a body. |
| [elongation](elongation.md)
fun [elongation](elongation.md)(body: [Body](-body/index.md), time: [Time](-time/index.md)): [ElongationInfo](-elongation-info/index.md)
Determines visibility of a celestial body relative to the Sun, as seen from the Earth. |
| [equator](equator.md)
fun [equator](equator.md)(body: [Body](-body/index.md), time: [Time](-time/index.md), observer: [Observer](-observer/index.md), equdate: [EquatorEpoch](-equator-epoch/index.md), aberration: [Aberration](-aberration/index.md)): [Equatorial](-equatorial/index.md)
Calculates equatorial coordinates of a celestial body as seen by an observer on the Earth's surface. |
-| [equatorialToEcliptic](equatorial-to-ecliptic.md)
fun [equatorialToEcliptic](equatorial-to-ecliptic.md)(equ: [Vector](-vector/index.md)): [Ecliptic](-ecliptic/index.md)
Converts J2000 equatorial Cartesian coordinates to J2000 ecliptic coordinates. |
+| [equatorialToEcliptic](equatorial-to-ecliptic.md)
fun [equatorialToEcliptic](equatorial-to-ecliptic.md)(eqj: [Vector](-vector/index.md)): [Ecliptic](-ecliptic/index.md)
Converts a J2000 mean equator (EQJ) vector to a true ecliptic of date (ETC) vector and angles. |
| [geoEmbState](geo-emb-state.md)
fun [geoEmbState](geo-emb-state.md)(time: [Time](-time/index.md)): [StateVector](-state-vector/index.md)
Calculates the geocentric position and velocity of the Earth/Moon barycenter. |
| [geoMoon](geo-moon.md)
fun [geoMoon](geo-moon.md)(time: [Time](-time/index.md)): [Vector](-vector/index.md)
Calculates equatorial geocentric position of the Moon at a given time. |
| [geoMoonState](geo-moon-state.md)
fun [geoMoonState](geo-moon-state.md)(time: [Time](-time/index.md)): [StateVector](-state-vector/index.md)
Calculates equatorial geocentric position and velocity of the Moon at a given time. |
diff --git a/source/kotlin/src/main/kotlin/io/github/cosinekitty/astronomy/astronomy.kt b/source/kotlin/src/main/kotlin/io/github/cosinekitty/astronomy/astronomy.kt
index edf71aed..740fcf5a 100644
--- a/source/kotlin/src/main/kotlin/io/github/cosinekitty/astronomy/astronomy.kt
+++ b/source/kotlin/src/main/kotlin/io/github/cosinekitty/astronomy/astronomy.kt
@@ -5462,12 +5462,12 @@ fun horizon(
/**
- * Calculates heliocentric ecliptic longitude of a body based on the J2000 equinox.
+ * Calculates heliocentric ecliptic longitude of a body.
*
* This function calculates the angle around the plane of the Earth's orbit
* of a celestial body, as seen from the center of the Sun.
* The angle is measured prograde (in the direction of the Earth's orbit around the Sun)
- * in degrees from the J2000 equinox. The ecliptic longitude is always in the range [0, 360).
+ * in degrees from the true equinox of date. The ecliptic longitude is always in the range [0, 360).
*
* @param body
* A body other than the Sun.
@@ -5965,23 +5965,30 @@ private fun rotateEquatorialToEcliptic(pos: Vector, obliqRadians: Double): Eclip
}
/**
- * Converts J2000 equatorial Cartesian coordinates to J2000 ecliptic coordinates.
+ * Converts a J2000 mean equator (EQJ) vector to a true ecliptic of date (ETC) vector and angles.
*
* Given coordinates relative to the Earth's equator at J2000 (the instant of noon UTC
- * on 1 January 2000), this function converts those coordinates to J2000 ecliptic coordinates,
+ * on 1 January 2000), this function converts those coordinates to true ecliptic coordinates of date,
* which are relative to the plane of the Earth's orbit around the Sun.
*
- * @param equ
+ * @param eqj
* Equatorial coordinates in the J2000 frame of reference.
* You can call [geoVector] to obtain suitable equatorial coordinates.
*
- * @return Ecliptic coordinates in the J2000 frame of reference (ECL).
+ * @return Spherical and vector coordinates expressed in true ecliptic coordinates of date (ECT)..
*/
-fun equatorialToEcliptic(equ: Vector): Ecliptic =
- rotateEquatorialToEcliptic(
- equ,
- 0.40909260059599012 // mean obliquity of the J2000 ecliptic in radians
- )
+fun equatorialToEcliptic(eqj: Vector): Ecliptic {
+ // Calculate nutation and obliquity for this time.
+ // As an optimization, the nutation angles are cached in `eqj.t`,
+ // and reused below when the `nutation` function is called.
+ val et = earthTilt(eqj.t)
+
+ // Convert J2000 mean equator (EQJ) to true equator of date (EQD).
+ val eqd = gyration(eqj, PrecessDirection.From2000);
+
+ // Rotate from EQD to true ecliptic of date (ECT).
+ return rotateEquatorialToEcliptic(eqd, et.tobl.degreesToRadians())
+}
/**
* Searches for the time when the Sun reaches an apparent ecliptic longitude as seen from the Earth.
diff --git a/source/kotlin/src/test/kotlin/io/github/cosinekitty/astronomy/Tests.kt b/source/kotlin/src/test/kotlin/io/github/cosinekitty/astronomy/Tests.kt
index 89fd4ed8..b678b901 100644
--- a/source/kotlin/src/test/kotlin/io/github/cosinekitty/astronomy/Tests.kt
+++ b/source/kotlin/src/test/kotlin/io/github/cosinekitty/astronomy/Tests.kt
@@ -287,16 +287,24 @@ class Tests {
}
@Test
- fun `Rotation matrices EQJ ECT`() {
+ fun `Convert EQJ to ECT`() {
var time = Time(1900, 1, 1, 0, 0, 0.0)
val stopTime = Time(2100, 1, 1, 0, 0, 0.0)
+ var max_eclip_diff = 0.0
+ var max_sphere_diff = 0.0
while (time.ut <= stopTime.ut) {
// Get Moon's geocentric position in EQJ.
val eqj = geoMoon(time)
- // Convert EQJ to ECT.
+ // Convert EQJ to ECT using rotation matrices.
val eqjEct = rotationEqjEct(time)
- val ect = eqjEct.rotate(eqj)
+ val ect_r = eqjEct.rotate(eqj)
+
+ // Convert EQJ to ECT using the special-purpose function.
+ val eclip = equatorialToEcliptic(eqj)
+
+ // Verify both answers are consistent
+ max_eclip_diff = max(max_eclip_diff, (eclip.vec - ect_r).length())
// Independently get the Moon's spherical coordinates in ECT.
val sphere = eclipticGeoMoon(time)
@@ -305,8 +313,7 @@ class Tests {
val check_ect = sphere.toVector(time)
// Verify the two ECT vectors are identical, within tolerance.
- val diff = (ect - check_ect).length()
- assertTrue(diff < 3.743e-18, "excessive vector diff = $diff")
+ max_sphere_diff = max(max_sphere_diff, (eclip.vec - check_ect).length())
// Make sure counterpart is the inverse rotation matrix.
val ectEqj = rotationEctEqj(time)
@@ -314,6 +321,9 @@ class Tests {
time = time.addDays(10.0)
}
+
+ assertTrue(max_eclip_diff < 1.511e-18, "excessive eclip_diff = $max_eclip_diff AU.")
+ assertTrue(max_sphere_diff < 3.406e-18, "excessive sphere_diff = $max_sphere_diff AU.")
}
//----------------------------------------------------------------------------------------
@@ -1550,7 +1560,7 @@ class Tests {
}
val diffMinutes = MINUTES_PER_DAY * abs(diffDays)
- assertTrue(diffMinutes < 7.734, "$filename line $lnum: excessive time error = $diffMinutes minutes")
+ assertTrue(diffMinutes < 7.737, "$filename line $lnum: excessive time error = $diffMinutes minutes")
}
assertTrue(skipCount <= 6, "$filename: excessive skip count = $skipCount")
@@ -1736,18 +1746,17 @@ class Tests {
fun `Heliocentric ecliptic longitude`() {
// These test data were generated using the Python version of Astronomy Engine.
val time = Time(8141.199164526366) // 2022-04-16T16:46:47.815Z
- verifyEclipticLongitude(time, Body.Mercury, 94.721630860364 )
- verifyEclipticLongitude(time, Body.Venus, 265.7830489493118 )
- verifyEclipticLongitude(time, Body.Earth, 206.37462137776242)
- verifyEclipticLongitude(time, Body.EMB, 206.37458597072734)
- verifyEclipticLongitude(time, Body.Moon, 206.37171443948878)
- verifyEclipticLongitude(time, Body.Mars, 294.9980436292426 )
- verifyEclipticLongitude(time, Body.Jupiter, 348.4960299261051 )
- verifyEclipticLongitude(time, Body.Saturn, 317.84336759149676)
- verifyEclipticLongitude(time, Body.Uranus, 44.28789479945196)
- verifyEclipticLongitude(time, Body.Neptune, 352.78484144085974)
- verifyEclipticLongitude(time, Body.Pluto, 296.58427291483525)
- verifyEclipticLongitude(time, Body.SSB, 344.6690770393668 )
+ verifyEclipticLongitude(time, Body.Mercury, 95.02894558749874)
+ verifyEclipticLongitude(time, Body.Venus, 266.0903196139245 )
+ verifyEclipticLongitude(time, Body.Earth, 206.6818916092405)
+ verifyEclipticLongitude(time, Body.EMB, 206.68185620530505)
+ verifyEclipticLongitude(time, Body.Moon, 206.67898492545427)
+ verifyEclipticLongitude(time, Body.Mars, 295.3053568069638)
+ verifyEclipticLongitude(time, Body.Jupiter, 348.8033611282255)
+ verifyEclipticLongitude(time, Body.Saturn, 318.1506794001811)
+ verifyEclipticLongitude(time, Body.Uranus, 44.59517759166631)
+ verifyEclipticLongitude(time, Body.Neptune, 353.0921704660749)
+ verifyEclipticLongitude(time, Body.Pluto, 296.89159475346855)
}
private fun verifyEclipticLongitude(time: Time, body: Body, expectedLongitude: Double) {
@@ -2077,11 +2086,11 @@ class Tests {
fun `Elongation sanity check`() {
// Comparison with Python calculations.
val time = Time(8143.135471001447) // 2022-04-18T15:15:04.695Z
- verifyElongation(Body.Mercury, time, Visibility.Evening, 16.100478087685758, 16.01391544801653 )
- verifyElongation(Body.Venus, time, Visibility.Morning, 44.380271294737405, 44.37884461595604 )
- verifyElongation(Body.Mars, time, Visibility.Morning, 55.92935847869356, 55.920119745861314)
- verifyElongation(Body.Jupiter, time, Visibility.Morning, 33.25618304272404, 33.2426920240577 )
- verifyElongation(Body.Uranus, time, Visibility.Evening, 15.276009178442616, 15.271572246395817)
+ verifyElongation(Body.Mercury, time, Visibility.Evening, 16.100478087685758, 16.013859719196727)
+ verifyElongation(Body.Venus, time, Visibility.Morning, 44.380271294737405, 44.37881570570113 )
+ verifyElongation(Body.Mars, time, Visibility.Morning, 55.92935847869356, 55.9200536671587 )
+ verifyElongation(Body.Jupiter, time, Visibility.Morning, 33.25618304272404, 33.24263918900169 )
+ verifyElongation(Body.Uranus, time, Visibility.Evening, 15.276009178442616, 15.27158439607594 )
}
private fun verifyElongation(body: Body, time: Time, visibility: Visibility, elong: Double, sep: Double) {
@@ -2288,13 +2297,13 @@ class Tests {
val tilt: Double
)
val saturnTestList = arrayOf(
- SaturnTestCase("1972-01-01T00:00Z", -0.31904865, +24.50061220),
- SaturnTestCase("1980-01-01T00:00Z", +0.85213663, -1.85761461),
- SaturnTestCase("2009-09-04T00:00Z", +1.01626809, +0.08380716),
- SaturnTestCase("2017-06-15T00:00Z", -0.12318790, -26.60871409),
- SaturnTestCase("2019-05-01T00:00Z", +0.32954097, -23.53880802),
- SaturnTestCase("2025-09-25T00:00Z", +0.51286575, +1.52327932),
- SaturnTestCase("2032-05-15T00:00Z", -0.04652109, +26.95717765)
+ SaturnTestCase("1972-01-01T00:00Z", -0.31725492, +24.43386475),
+ SaturnTestCase("1980-01-01T00:00Z", +0.85796177, -1.72627324),
+ SaturnTestCase("2009-09-04T00:00Z", +1.01932560, +0.01834451),
+ SaturnTestCase("2017-06-15T00:00Z", -0.12303373, -26.60068380),
+ SaturnTestCase("2019-05-01T00:00Z", +0.33124502, -23.47173574),
+ SaturnTestCase("2025-09-25T00:00Z", +0.50543708, +1.69118986),
+ SaturnTestCase("2032-05-15T00:00Z", -0.04649573, +26.95238680)
)
for (c in saturnTestList) {
val time = parseDate(c.date)
diff --git a/source/python/README.md b/source/python/README.md
index a5da9e0a..a221c402 100644
--- a/source/python/README.md
+++ b/source/python/README.md
@@ -1494,20 +1494,20 @@ The estimated difference TT-UT on the given date, expressed in seconds.
---
-### Ecliptic(equ)
+### Ecliptic(eqj)
-**Converts J2000 equatorial Cartesian coordinates to J2000 ecliptic coordinates.**
+**Converts a J2000 mean equator (EQJ) vector to a true ecliptic of date (ETC) vector and angles.**
Given coordinates relative to the Earth's equator at J2000 (the instant of noon UTC
-on 1 January 2000), this function converts those coordinates to J2000 ecliptic coordinates,
+on 1 January 2000), this function converts those coordinates to true ecliptic coordinates of date,
which are relative to the plane of the Earth's orbit around the Sun.
| Type | Parameter | Description |
| --- | --- | --- |
-| [`Equatorial`](#Equatorial) | `equ` | Equatorial coordinates in the J2000 frame of reference. |
+| [`Equatorial`](#Equatorial) | `eqj` | Equatorial coordinates in the J2000 frame of reference. You can call [`GeoVector`](#GeoVector) to obtain suitable equatorial coordinates. |
**Returns**: [`EclipticCoordinates`](#EclipticCoordinates)
-Ecliptic coordinates in the J2000 frame of reference.
+Spherical and vector coordinates expressed in true ecliptic coordinates of date (ECT).
---
@@ -1542,12 +1542,12 @@ The Moon's position as a distance, ecliptic latitude, and ecliptic longitude.
### EclipticLongitude(body, time)
-**Calculates heliocentric ecliptic longitude of a body based on the J2000 equinox.**
+**Calculates heliocentric ecliptic longitude of a body.**
This function calculates the angle around the plane of the Earth's orbit
of a celestial body, as seen from the center of the Sun.
The angle is measured prograde (in the direction of the Earth's orbit around the Sun)
-in degrees from the J2000 equinox. The ecliptic longitude is always in the range [0, 360).
+in degrees from the true equinox of date. The ecliptic longitude is always in the range [0, 360).
| Type | Parameter | Description |
| --- | --- | --- |
diff --git a/source/python/astronomy/astronomy.py b/source/python/astronomy/astronomy.py
index 6876364b..c4f96e2b 100644
--- a/source/python/astronomy/astronomy.py
+++ b/source/python/astronomy/astronomy.py
@@ -5084,34 +5084,44 @@ def SunPosition(time):
true_obliq = math.radians(adjusted_time._etilt().tobl)
return _RotateEquatorialToEcliptic(sun_ofdate, true_obliq, time)
-def Ecliptic(equ):
- """Converts J2000 equatorial Cartesian coordinates to J2000 ecliptic coordinates.
+def Ecliptic(eqj):
+ """Converts a J2000 mean equator (EQJ) vector to a true ecliptic of date (ETC) vector and angles.
Given coordinates relative to the Earth's equator at J2000 (the instant of noon UTC
- on 1 January 2000), this function converts those coordinates to J2000 ecliptic coordinates,
+ on 1 January 2000), this function converts those coordinates to true ecliptic coordinates of date,
which are relative to the plane of the Earth's orbit around the Sun.
Parameters
----------
- equ : Equatorial
+ eqj : Equatorial
Equatorial coordinates in the J2000 frame of reference.
+ You can call #GeoVector to obtain suitable equatorial coordinates.
Returns
-------
EclipticCoordinates
- Ecliptic coordinates in the J2000 frame of reference.
+ Spherical and vector coordinates expressed in true ecliptic coordinates of date (ECT).
"""
- # Based on NOVAS functions equ2ecl() and equ2ecl_vec().
- ob2000 = 0.40909260059599012 # mean obliquity of the J2000 ecliptic in radians
- return _RotateEquatorialToEcliptic([equ.x, equ.y, equ.z], ob2000, equ.t)
+ # Calculate nutation and obliquity for this time.
+ # As an optimization, the nutation angles are cached in `eqj.t`,
+ # and reused below when the `nutation` function is called.
+ et = _e_tilt(eqj.t)
+
+ # Convert J2000 mean equator (EQJ) to true equator of date (EQD).
+ mean_pos = _precession([eqj.x, eqj.y, eqj.z], eqj.t, _PrecessDir.From2000)
+ eqd_pos = _nutation(mean_pos, eqj.t, _PrecessDir.From2000)
+
+ # Rotate from EQD to true ecliptic of date (ECT).
+ return _RotateEquatorialToEcliptic(eqd_pos, math.radians(et.tobl), eqj.t)
+
def EclipticLongitude(body, time):
- """Calculates heliocentric ecliptic longitude of a body based on the J2000 equinox.
+ """Calculates heliocentric ecliptic longitude of a body.
This function calculates the angle around the plane of the Earth's orbit
of a celestial body, as seen from the center of the Sun.
The angle is measured prograde (in the direction of the Earth's orbit around the Sun)
- in degrees from the J2000 equinox. The ecliptic longitude is always in the range [0, 360).
+ in degrees from the true equinox of date. The ecliptic longitude is always in the range [0, 360).
Parameters
----------
diff --git a/source/python/setup.py b/source/python/setup.py
index 083c5fb2..2e915ebd 100644
--- a/source/python/setup.py
+++ b/source/python/setup.py
@@ -6,7 +6,7 @@ def _LoadFile(filename):
setup(
name='astronomy-engine',
- version='2.1.12',
+ version='2.1.13',
description='Astronomy calculation for Sun, Moon, and planets.',
long_description=_LoadFile('README.md'),
long_description_content_type='text/markdown',