From 2ee5f6f8f5ef511ca2239ce688a092602ab1de77 Mon Sep 17 00:00:00 2001 From: Don Cross Date: Fri, 1 Apr 2022 18:52:00 -0400 Subject: [PATCH] Kotlin: rotationEqdHor, rotationHorEqd. Added two more of the rotation functions. This is the pair for converting between of-date equatorial coordinates and an observer's horizontal system. --- generate/template/astronomy.kt | 68 +++++++++++++++++++ source/kotlin/doc/-astronomy/index.md | 2 + .../kotlin/doc/-astronomy/rotation-eqd-hor.md | 19 ++++++ .../kotlin/doc/-astronomy/rotation-hor-eqd.md | 19 ++++++ .../github/cosinekitty/astronomy/astronomy.kt | 68 +++++++++++++++++++ .../io/github/cosinekitty/astronomy/Tests.kt | 24 ++++++- 6 files changed, 199 insertions(+), 1 deletion(-) create mode 100644 source/kotlin/doc/-astronomy/rotation-eqd-hor.md create mode 100644 source/kotlin/doc/-astronomy/rotation-hor-eqd.md diff --git a/generate/template/astronomy.kt b/generate/template/astronomy.kt index 6063f554..ab5cb656 100644 --- a/generate/template/astronomy.kt +++ b/generate/template/astronomy.kt @@ -4159,6 +4159,74 @@ object Astronomy { fun rotationEqdEqj(time: AstroTime): RotationMatrix = nutationRot(time, PrecessDirection.Into2000) combine precessionRot(time, PrecessDirection.Into2000) + + /** + * Calculates a rotation matrix from equatorial of-date (EQD) to horizontal (HOR). + * + * This is one of the family of functions that returns a rotation matrix + * for converting from one orientation to another. + * Source: EQD = equatorial system, using equator of the specified date/time. + * Target: HOR = horizontal system. + * + * @param time + * The date and time at which the Earth's equator applies. + * + * @param observer + * A location near the Earth's mean sea level that defines the observer's horizon. + * + * @returns + * A rotation matrix that converts EQD to HOR at `time` and for `observer`. + * The components of the horizontal vector are: + * x = north, y = west, z = zenith (straight up from the observer). + * These components are chosen so that the "right-hand rule" works for the vector + * and so that north represents the direction where azimuth = 0. + */ + fun rotationEqdHor(time: AstroTime, observer: Observer): RotationMatrix { + // See the `horizon` function for more explanation of how this works. + + val sinlat = dsin(observer.latitude) + val coslat = dcos(observer.latitude) + val sinlon = dsin(observer.longitude) + val coslon = dcos(observer.longitude) + + val uze = AstroVector(coslat * coslon, coslat * sinlon, sinlat, time) + val une = AstroVector(-sinlat * coslon, -sinlat * sinlon, coslat, time) + val uwe = AstroVector(sinlon, -coslon, 0.0, time) + + // Multiply sidereal hours by -15 to convert to degrees and flip eastward + // rotation of the Earth to westward apparent movement of objects with time. + + val angle = -15.0 * siderealTime(time) + val uz = spin(angle, uze) + val un = spin(angle, une) + val uw = spin(angle, uwe) + + return RotationMatrix( + un.x, uw.x, uz.x, + un.y, uw.y, uz.y, + un.z, uw.z, uz.z + ) + } + + /** + * Calculates a rotation matrix from horizontal (HOR) to equatorial of-date (EQD). + * + * This is one of the family of functions that returns a rotation matrix + * for converting from one orientation to another. + * Source: HOR = horizontal system (x=North, y=West, z=Zenith). + * Target: EQD = equatorial system, using equator of the specified date/time. + * + * @param time + * The date and time at which the Earth's equator applies. + * + * @param observer + * A location near the Earth's mean sea level that defines the observer's horizon. + * + * @returns + * A rotation matrix that converts HOR to EQD at `time` and for `observer`. + */ + fun rotationHorEqd(time: AstroTime, observer: Observer): RotationMatrix = + rotationEqdHor(time, observer).inverse() } //======================================================================================= diff --git a/source/kotlin/doc/-astronomy/index.md b/source/kotlin/doc/-astronomy/index.md index 158aab6c..2f5c4411 100644 --- a/source/kotlin/doc/-astronomy/index.md +++ b/source/kotlin/doc/-astronomy/index.md @@ -28,6 +28,8 @@ The main container of astronomy calculation functions. | [rotationAxis](rotation-axis.md) | [jvm]
fun [rotationAxis](rotation-axis.md)(body: [Body](../-body/index.md), time: [AstroTime](../-astro-time/index.md)): [AxisInfo](../-axis-info/index.md)
Calculates information about a body's rotation axis at a given time. | | [rotationEclEqj](rotation-ecl-eqj.md) | [jvm]
fun [rotationEclEqj](rotation-ecl-eqj.md)(): [RotationMatrix](../-rotation-matrix/index.md)
Calculates a rotation matrix from ecliptic J2000 (ECL) to equatorial J2000 (EQJ). | | [rotationEqdEqj](rotation-eqd-eqj.md) | [jvm]
fun [rotationEqdEqj](rotation-eqd-eqj.md)(time: [AstroTime](../-astro-time/index.md)): [RotationMatrix](../-rotation-matrix/index.md)
Calculates a rotation matrix from equatorial of-date (EQD) to equatorial J2000 (EQJ). | +| [rotationEqdHor](rotation-eqd-hor.md) | [jvm]
fun [rotationEqdHor](rotation-eqd-hor.md)(time: [AstroTime](../-astro-time/index.md), observer: [Observer](../-observer/index.md)): [RotationMatrix](../-rotation-matrix/index.md)
Calculates a rotation matrix from equatorial of-date (EQD) to horizontal (HOR). | | [rotationEqjEcl](rotation-eqj-ecl.md) | [jvm]
fun [rotationEqjEcl](rotation-eqj-ecl.md)(): [RotationMatrix](../-rotation-matrix/index.md)
Calculates a rotation matrix from equatorial J2000 (EQJ) to ecliptic J2000 (ECL). | | [rotationEqjEqd](rotation-eqj-eqd.md) | [jvm]
fun [rotationEqjEqd](rotation-eqj-eqd.md)(time: [AstroTime](../-astro-time/index.md)): [RotationMatrix](../-rotation-matrix/index.md)
Calculates a rotation matrix from equatorial J2000 (EQJ) to equatorial of-date (EQD). | +| [rotationHorEqd](rotation-hor-eqd.md) | [jvm]
fun [rotationHorEqd](rotation-hor-eqd.md)(time: [AstroTime](../-astro-time/index.md), observer: [Observer](../-observer/index.md)): [RotationMatrix](../-rotation-matrix/index.md)
Calculates a rotation matrix from horizontal (HOR) to equatorial of-date (EQD). | | [siderealTime](sidereal-time.md) | [jvm]
fun [siderealTime](sidereal-time.md)(time: [AstroTime](../-astro-time/index.md)): [Double](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-double/index.html)
Calculates Greenwich Apparent Sidereal Time (GAST). | diff --git a/source/kotlin/doc/-astronomy/rotation-eqd-hor.md b/source/kotlin/doc/-astronomy/rotation-eqd-hor.md new file mode 100644 index 00000000..6fbfefb1 --- /dev/null +++ b/source/kotlin/doc/-astronomy/rotation-eqd-hor.md @@ -0,0 +1,19 @@ +//[astronomy](../../../index.md)/[io.github.cosinekitty.astronomy](../index.md)/[Astronomy](index.md)/[rotationEqdHor](rotation-eqd-hor.md) + +# rotationEqdHor + +[jvm]\ +fun [rotationEqdHor](rotation-eqd-hor.md)(time: [AstroTime](../-astro-time/index.md), observer: [Observer](../-observer/index.md)): [RotationMatrix](../-rotation-matrix/index.md) + +Calculates a rotation matrix from equatorial of-date (EQD) to horizontal (HOR). + +This is one of the family of functions that returns a rotation matrix for converting from one orientation to another. Source: EQD = equatorial system, using equator of the specified date/time. Target: HOR = horizontal system. + +## Parameters + +jvm + +| | | +|---|---| +| time | The date and time at which the Earth's equator applies. | +| observer | A location near the Earth's mean sea level that defines the observer's horizon. | diff --git a/source/kotlin/doc/-astronomy/rotation-hor-eqd.md b/source/kotlin/doc/-astronomy/rotation-hor-eqd.md new file mode 100644 index 00000000..565fb8c3 --- /dev/null +++ b/source/kotlin/doc/-astronomy/rotation-hor-eqd.md @@ -0,0 +1,19 @@ +//[astronomy](../../../index.md)/[io.github.cosinekitty.astronomy](../index.md)/[Astronomy](index.md)/[rotationHorEqd](rotation-hor-eqd.md) + +# rotationHorEqd + +[jvm]\ +fun [rotationHorEqd](rotation-hor-eqd.md)(time: [AstroTime](../-astro-time/index.md), observer: [Observer](../-observer/index.md)): [RotationMatrix](../-rotation-matrix/index.md) + +Calculates a rotation matrix from horizontal (HOR) to equatorial of-date (EQD). + +This is one of the family of functions that returns a rotation matrix for converting from one orientation to another. Source: HOR = horizontal system (x=North, y=West, z=Zenith). Target: EQD = equatorial system, using equator of the specified date/time. + +## Parameters + +jvm + +| | | +|---|---| +| time | The date and time at which the Earth's equator applies. | +| observer | A location near the Earth's mean sea level that defines the observer's horizon. | 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 ed79c499..edb014c5 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 @@ -4159,6 +4159,74 @@ object Astronomy { fun rotationEqdEqj(time: AstroTime): RotationMatrix = nutationRot(time, PrecessDirection.Into2000) combine precessionRot(time, PrecessDirection.Into2000) + + /** + * Calculates a rotation matrix from equatorial of-date (EQD) to horizontal (HOR). + * + * This is one of the family of functions that returns a rotation matrix + * for converting from one orientation to another. + * Source: EQD = equatorial system, using equator of the specified date/time. + * Target: HOR = horizontal system. + * + * @param time + * The date and time at which the Earth's equator applies. + * + * @param observer + * A location near the Earth's mean sea level that defines the observer's horizon. + * + * @returns + * A rotation matrix that converts EQD to HOR at `time` and for `observer`. + * The components of the horizontal vector are: + * x = north, y = west, z = zenith (straight up from the observer). + * These components are chosen so that the "right-hand rule" works for the vector + * and so that north represents the direction where azimuth = 0. + */ + fun rotationEqdHor(time: AstroTime, observer: Observer): RotationMatrix { + // See the `horizon` function for more explanation of how this works. + + val sinlat = dsin(observer.latitude) + val coslat = dcos(observer.latitude) + val sinlon = dsin(observer.longitude) + val coslon = dcos(observer.longitude) + + val uze = AstroVector(coslat * coslon, coslat * sinlon, sinlat, time) + val une = AstroVector(-sinlat * coslon, -sinlat * sinlon, coslat, time) + val uwe = AstroVector(sinlon, -coslon, 0.0, time) + + // Multiply sidereal hours by -15 to convert to degrees and flip eastward + // rotation of the Earth to westward apparent movement of objects with time. + + val angle = -15.0 * siderealTime(time) + val uz = spin(angle, uze) + val un = spin(angle, une) + val uw = spin(angle, uwe) + + return RotationMatrix( + un.x, uw.x, uz.x, + un.y, uw.y, uz.y, + un.z, uw.z, uz.z + ) + } + + /** + * Calculates a rotation matrix from horizontal (HOR) to equatorial of-date (EQD). + * + * This is one of the family of functions that returns a rotation matrix + * for converting from one orientation to another. + * Source: HOR = horizontal system (x=North, y=West, z=Zenith). + * Target: EQD = equatorial system, using equator of the specified date/time. + * + * @param time + * The date and time at which the Earth's equator applies. + * + * @param observer + * A location near the Earth's mean sea level that defines the observer's horizon. + * + * @returns + * A rotation matrix that converts HOR to EQD at `time` and for `observer`. + */ + fun rotationHorEqd(time: AstroTime, observer: Observer): RotationMatrix = + rotationEqdHor(time, observer).inverse() } //======================================================================================= 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 f13f9358..c8c82026 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 @@ -509,7 +509,7 @@ class Tests { //---------------------------------------------------------------------------------------- - private fun compareMatrices(a: RotationMatrix, b: RotationMatrix, comment: String, tolerance: Double = 1.0e-16) { + private fun compareMatrices(a: RotationMatrix, b: RotationMatrix, comment: String, tolerance: Double = 1.0e-99) { for (i in 0..2) { for (j in 0..2) { val diff = abs(a.rot[i][j] - b.rot[i][j]) @@ -523,6 +523,8 @@ class Tests { val time = AstroTime(8126.418466077072) assertTrue(time.toString() == "2022-04-01T22:02:35.469Z", "Unexpected time string.") + val observer = Observer(-30.0, +150.0, 200.0) + compareMatrices( Astronomy.rotationEqjEcl(), RotationMatrix( @@ -562,6 +564,26 @@ class Tests { ), "EQD EQJ" ) + + compareMatrices( + Astronomy.rotationEqdHor(time, observer), + RotationMatrix( + 0.3272894142412824, -0.7559937548038297, 0.5668818942453582, + -0.3779968774019148, -0.6545788284825649, -0.6547097967625005, + 0.8660254037844387, 0.0, -0.49999999999999994, + ), + "EQD HOR" + ) + + compareMatrices( + Astronomy.rotationHorEqd(time, observer), + RotationMatrix( + 0.3272894142412824, -0.3779968774019148, 0.8660254037844387, + -0.7559937548038297, -0.6545788284825649, 0.0, + 0.5668818942453582, -0.6547097967625005, -0.49999999999999994, + ), + "HOR EQD" + ) } //----------------------------------------------------------------------------------------