From 98deea4523ee0f9ece4113655db5a12b45e9466b Mon Sep 17 00:00:00 2001 From: Don Cross Date: Tue, 17 Dec 2019 20:32:37 -0500 Subject: [PATCH] Python: Finished coding rotation functions. Need to finish test cases. --- generate/template/astronomy.py | 217 +++++++++++++++++++++++++++++++++ generate/test.py | 72 +++++++++++ pydown/pydown.py | 2 + source/python/README.md | 153 +++++++++++++++++++++++ source/python/astronomy.py | 217 +++++++++++++++++++++++++++++++++ 5 files changed, 661 insertions(+) diff --git a/generate/template/astronomy.py b/generate/template/astronomy.py index 473c1c05..e82f2892 100644 --- a/generate/template/astronomy.py +++ b/generate/template/astronomy.py @@ -3122,6 +3122,75 @@ def SphereFromVector(vector): return Spherical(lat, lon, dist) +def _ToggleAzimuthDirection(az): + az = 360.0 - az + if az >= 360.0: + az -= 360.0 + elif az < 0.0: + az += 360.0 + return az + + +def VectorFromHorizon(sphere, time, refraction): + """Given apparent angular horizontal coordinates in `sphere`, calculate horizontal vector. + + Parameters + ---------- + sphere : Spherical + A structure that contains apparent horizontal coordinates: + `lat` holds the refracted azimuth angle, + `lon` holds the azimuth in degrees clockwise from north, + and `dist` holds the distance from the observer to the object in AU. + time : Time + The date and time of the observation. This is needed because the returned + vector object requires a valid time value when passed to certain other functions. + refraction : Refraction + See remarks in function #RefractionAngle. + + Returns + ------- + Vector + A vector in the horizontal system: `x` = north, `y` = west, and `z` = zenith (up). + """ + lon = _ToggleAzimuthDirection(sphere.lon) + lat = sphere.lat + InverseRefractionAngle(refraction, sphere.lat) + xsphere = Spherical(lat, lon, sphere.dist) + return VectorFromSphere(xsphere, time) + + +def HorizonFromVector(vector, refraction): + """Converts Cartesian coordinates to horizontal coordinates. + + Given a horizontal Cartesian vector, returns horizontal azimuth and altitude. + + *IMPORTANT:* This function differs from `SphereFromVector` in two ways: + - `SphereFromVector` returns a `lon` value that represents azimuth defined counterclockwise + from north (e.g., west = +90), but this function represents a clockwise rotation + (e.g., east = +90). The difference is because `SphereFromVector` is intended + to preserve the vector "right-hand rule", while this function defines azimuth in a more + traditional way as used in navigation and cartography. + - This function optionally corrects for atmospheric refraction, while `SphereFromVector` does not. + + The returned object contains the azimuth in `lon`. + It is measured in degrees clockwise from north: east = +90 degrees, west = +270 degrees. + + The altitude is stored in `lat`. + + The distance to the observed object is stored in `dist`, + and is expressed in astronomical units (AU). + + Parameters + ---------- + vector : Vector + Cartesian vector to be converted to horizontal angular coordinates. + refraction : Refraction + See comments in the #RefractionAngle function. + """ + sphere = SphereFromVector(vector) + sphere.lon = _ToggleAzimuthDirection(sphere.lon) + sphere.lat += RefractionAngle(refraction, sphere.lat) + return sphere + def InverseRotation(rotation): """Calculates the inverse of a rotation matrix. @@ -3305,3 +3374,151 @@ def Rotation_EQD_EQJ(time): nut = _nutation_rot(time, 1) prec = _precession_rot(time.tt, 0.0) return CombineRotation(nut, prec) + + +def Rotation_EQD_HOR(time, observer): + """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. + + Use #HorizonFromVector to convert the return value + to a traditional altitude/azimuth pair. + + Parameters + ---------- + time : Time + The date and time at which the Earth's equator applies. + observer: Observer + A location near the Earth's mean sea level that defines the observer's location. + + Returns + ------- + RotationMatrix + 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. + """ + sinlat = math.sin(math.radians(observer.latitude)) + coslat = math.cos(math.radians(observer.latitude)) + sinlon = math.sin(math.radians(observer.longitude)) + coslon = math.cos(math.radians(observer.longitude)) + uze = [coslat * coslon, coslat * sinlon, sinlat] + une = [-sinlat * coslon, -sinlat * sinlon, coslat] + uwe = [sinlon, -coslon, 0.0] + spin_angle = -15.0 * _sidereal_time(time) + uz = _spin(spin_angle, uze) + un = _spin(spin_angle, une) + uw = _spin(spin_angle, uwe) + return RotationMatrix([ + [un[0], uw[0], uz[0]], + [un[1], uw[1], uz[1]], + [un[2], uw[2], uz[2]], + ]) + + +def Rotation_HOR_EQD(time, observer): + """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 + ---------- + time : Time + The date and time at which the Earth's equator applies. + observer : Observer + A location near the Earth's mean sea level that defines the observer's horizon. + + Returns + ------- + RotationMatrix + A rotation matrix that converts HOR to EQD at `time` and for `observer`. + """ + rot = Rotation_EQD_HOR(time, observer) + return InverseRotation(rot) + + +def Rotation_HOR_EQJ(time, observer): + """Calculates a rotation matrix from horizontal (HOR) to J2000 equatorial (EQJ). + + 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: EQJ = equatorial system, using equator at the J2000 epoch. + + Parameters + ---------- + time : Time + The date and time of the observation. + observer : Observer + A location near the Earth's mean sea level that define's the observer's horizon. + + Returns + ------- + RotationMatrix + A rotation matrix that converts HOR to EQD at `time` and for `observer`. + """ + hor_eqd = Rotation_HOR_EQD(time, observer) + eqd_eqj = Rotation_EQD_EQJ(time) + return CombineRotation(hor_eqd, eqd_eqj) + + +def Rotation_EQJ_HOR(time, observer): + """Calculates a rotation matrix from equatorial J2000 (EQJ) to horizontal (HOR). + + This is one of the family of functions that returns a rotation matrix + for converting from one orientation to another. + Source: EQJ = equatorial system, using the equator at the J2000 epoch. + Target: HOR = horizontal system. + + Use #HorizonFromVector to convert the return value to + a traditional altitude/azimuth pair. + + Parameters + ---------- + time : Time + The date and time of the desired horizontal orientation. + observer : Observer + A location near the Earth's mean sea level that defines the observer's horizon. + + Returns + ------- + RotationMatrix + A rotation matrix that converts EQJ 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. + """ + rot = Rotation_HOR_EQJ(time, observer) + return InverseRotation(rot) + + +def Rotation_EQD_ECL(time): + """Calculates a rotation matrix from equatorial of-date (EQD) to ecliptic J2000 (ECL). + + 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 date. + Target: ECL = ecliptic system, using equator at J2000 epoch. + + Parameters + ---------- + time : Time + The date and time of the source equator. + + Returns + ------- + A rotation matrix that converts EQD to ECL. + """ + eqd_eqj = Rotation_EQD_EQJ(time) + eqj_ecl = Rotation_EQJ_ECL() + return CombineRotation(eqd_eqj, eqj_ecl) + diff --git a/generate/test.py b/generate/test.py index 667a6a7c..2d7f1a3f 100755 --- a/generate/test.py +++ b/generate/test.py @@ -854,6 +854,73 @@ def Test_EQJ_EQD(body): sys.exit(1) +def Test_EQD_HOR(body): + # Use existing functions to calculate horizontal coordinates of the body for the time+observer. + time = astronomy.Time.Make(1970, 12, 13, 5, 15, 0) + observer = astronomy.Observer(-37, +45, 0) + eqd = astronomy.Equator(body, time, observer, True, True) + print('Test_EQD_HOR {}: OFDATE ra={}, dec={}'.format(body.name, eqd.ra, eqd.dec)) + hor = astronomy.Horizon(time, observer, eqd.ra, eqd.dec, astronomy.Refraction.Normal) + + # Calculate the position of the body as an equatorial vector of date. + vec_eqd = astronomy.VectorFromEquator(eqd, time) + + # Calculate rotation matrix to convert equatorial J2000 vector to horizontal vector. + rot = astronomy.Rotation_EQD_HOR(time, observer) + + # Rotate the equator of date vector to a horizontal vector. + vec_hor = astronomy.RotateVector(rot, vec_eqd) + + # Convert the horizontal vector to horizontal angular coordinates. + xsphere = astronomy.HorizonFromVector(vec_hor, astronomy.Refraction.Normal) + diff_alt = abs(xsphere.lat - hor.altitude) + diff_az = abs(xsphere.lon - hor.azimuth) + + print('Test_EQD_HOR {}: trusted alt={}, az={}; test alt={}, az={}; diff_alt={}, diff_az={}'.format( + body.name, hor.altitude, hor.azimuth, xsphere.lat, xsphere.lon, diff_alt, diff_az)) + + if diff_alt > 4.0e-14 or diff_az > 1.0e-13: + print('Test_EQD_HOR: EXCESSIVE HORIZONTAL ERROR.') + sys.exit(1) + + # Confirm that we can convert back to horizontal vector. + check_hor = astronomy.VectorFromHorizon(xsphere, time, astronomy.Refraction.Normal) + diff = VectorDiff(check_hor, vec_hor) + print('Test_EQD_HOR {}: horizontal recovery: diff = {}'.format(body.name, diff)) + if diff > 2.0e-15: + print('Test_EQD_HOR: EXCESSIVE ERROR IN HORIZONTAL RECOVERY.') + sys.exit(1) + + # Verify the inverse translation from horizontal vector to equatorial of-date vector. + irot = astronomy.Rotation_HOR_EQD(time, observer) + check_eqd = astronomy.RotateVector(irot, vec_hor) + diff = VectorDiff(check_eqd, vec_eqd) + print('Test_EQD_HOR {}: OFDATE inverse rotation diff = {}'.format(body.name, diff)) + if diff > 1.0e-15: + print('Test_EQD_HOR: EXCESSIVE OFDATE INVERSE HORIZONTAL ERROR.') + sys.exit(1) + + # Exercise HOR to EQJ translation. + eqj = astronomy.Equator(body, time, observer, False, True) + vec_eqj = astronomy.VectorFromEquator(eqj, time) + yrot = astronomy.Rotation_HOR_EQJ(time, observer) + check_eqj = astronomy.RotateVector(yrot, vec_hor) + diff = VectorDiff(check_eqj, vec_eqj) + print('Test_EQD_HOR {}: J2000 inverse rotation diff = {}'.format(body.name, diff)) + if diff > 3.0e-15: + print('Test_EQD_HOR: EXCESSIVE J2000 INVERSE HORIZONTAL ERROR.') + sys.exit(1) + + # Verify the inverse translation: EQJ to HOR. + zrot = astronomy.Rotation_EQJ_HOR(time, observer) + another_hor = astronomy.RotateVector(zrot, vec_eqj) + diff = VectorDiff(another_hor, vec_hor) + print('Test_EQD_HOR {}: EQJ inverse rotation diff = {}'.format(body.name, diff)) + if diff > 3.0e-15: + print('Test_EQD_HOR: EXCESSIVE EQJ INVERSE HORIZONTAL ERROR.') + sys.exit(1) + + def Test_Rotation(): Rotation_MatrixInverse() Rotation_MatrixMultiply() @@ -863,6 +930,11 @@ def Test_Rotation(): Test_EQJ_EQD(astronomy.Body.Mars) Test_EQJ_EQD(astronomy.Body.Jupiter) Test_EQJ_EQD(astronomy.Body.Saturn) + Test_EQD_HOR(astronomy.Body.Mercury) + Test_EQD_HOR(astronomy.Body.Venus) + Test_EQD_HOR(astronomy.Body.Mars) + Test_EQD_HOR(astronomy.Body.Jupiter) + Test_EQD_HOR(astronomy.Body.Saturn) print('Python Test_Rotation: PASS') return 0 diff --git a/pydown/pydown.py b/pydown/pydown.py index e03116ae..aeda883d 100755 --- a/pydown/pydown.py +++ b/pydown/pydown.py @@ -132,6 +132,8 @@ class DocInfo: md += '| Type | {} | Description |\n'.format(tag) md += '| --- | --- | --- |\n' for p in itemlist: + if not p.type: + raise Exception('Symbol "{}" has missing type declaration.'.format(p.name)) md += '| {} | {} | {} |\n'.format(SymbolLink(p.type), '`' + p.name + '`', p.description.strip()) md += '\n' return md diff --git a/source/python/README.md b/source/python/README.md index c00783dc..fcb1add0 100644 --- a/source/python/README.md +++ b/source/python/README.md @@ -760,6 +760,32 @@ for more details. --- + +### HorizonFromVector(vector, refraction) + +**Converts Cartesian coordinates to horizontal coordinates.** + +Given a horizontal Cartesian vector, returns horizontal azimuth and altitude. +*IMPORTANT:* This function differs from `SphereFromVector` in two ways: +- `SphereFromVector` returns a `lon` value that represents azimuth defined counterclockwise + from north (e.g., west = +90), but this function represents a clockwise rotation + (e.g., east = +90). The difference is because `SphereFromVector` is intended + to preserve the vector "right-hand rule", while this function defines azimuth in a more + traditional way as used in navigation and cartography. +- This function optionally corrects for atmospheric refraction, while `SphereFromVector` does not. +The returned object contains the azimuth in `lon`. +It is measured in degrees clockwise from north: east = +90 degrees, west = +270 degrees. +The altitude is stored in `lat`. +The distance to the observed object is stored in `dist`, +and is expressed in astronomical units (AU). + +| Type | Parameter | Description | +| --- | --- | --- | +| [`Vector`](#Vector) | `vector` | Cartesian vector to be converted to horizontal angular coordinates. | +| [`Refraction`](#Refraction) | `refraction` | See comments in the #RefractionAngle function. | + +--- + ### Illumination(body, time) @@ -976,6 +1002,25 @@ A rotation matrix that converts ECL to EQJ. --- + +### Rotation_EQD_ECL(time) + +**Calculates a rotation matrix from equatorial of-date (EQD) to ecliptic J2000 (ECL).** + +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 date. +Target: ECL = ecliptic system, using equator at J2000 epoch. + +| Type | Parameter | Description | +| --- | --- | --- | +| [`Time`](#Time) | `time` | The date and time of the source equator. | + +### Returns +A rotation matrix that converts EQD to ECL. + +--- + ### Rotation_EQD_EQJ(time) @@ -995,6 +1040,32 @@ A rotation matrix that converts EQD at `time` to EQJ. --- + +### Rotation_EQD_HOR(time, observer) + +**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. +Use #HorizonFromVector to convert the return value +to a traditional altitude/azimuth pair. + +| Type | Parameter | Description | +| --- | --- | --- | +| [`Time`](#Time) | `time` | The date and time at which the Earth's equator applies. | +| [`Observer`](#Observer) | `observer` | A location near the Earth's mean sea level that defines the observer's location. | + +### Returns: RotationMatrix +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. + +--- + ### Rotation_EQJ_ECL() @@ -1029,6 +1100,72 @@ A rotation matrix that converts EQJ to EQD at `time`. --- + +### Rotation_EQJ_HOR(time, observer) + +**Calculates a rotation matrix from equatorial J2000 (EQJ) to horizontal (HOR).** + +This is one of the family of functions that returns a rotation matrix +for converting from one orientation to another. +Source: EQJ = equatorial system, using the equator at the J2000 epoch. +Target: HOR = horizontal system. +Use #HorizonFromVector to convert the return value to +a traditional altitude/azimuth pair. + +| Type | Parameter | Description | +| --- | --- | --- | +| [`Time`](#Time) | `time` | The date and time of the desired horizontal orientation. | +| [`Observer`](#Observer) | `observer` | A location near the Earth's mean sea level that defines the observer's horizon. | + +### Returns: RotationMatrix +A rotation matrix that converts EQJ 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. + +--- + + +### Rotation_HOR_EQD(time, observer) + +**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. + +| Type | Parameter | Description | +| --- | --- | --- | +| [`Time`](#Time) | `time` | The date and time at which the Earth's equator applies. | +| [`Observer`](#Observer) | `observer` | A location near the Earth's mean sea level that defines the observer's horizon. | + +### Returns: RotationMatrix +A rotation matrix that converts HOR to EQD at `time` and for `observer`. + +--- + + +### Rotation_HOR_EQJ(time, observer) + +**Calculates a rotation matrix from horizontal (HOR) to J2000 equatorial (EQJ).** + +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: EQJ = equatorial system, using equator at the J2000 epoch. + +| Type | Parameter | Description | +| --- | --- | --- | +| [`Time`](#Time) | `time` | The date and time of the observation. | +| [`Observer`](#Observer) | `observer` | A location near the Earth's mean sea level that define's the observer's horizon. | + +### Returns: RotationMatrix +A rotation matrix that converts HOR to EQD at `time` and for `observer`. + +--- + ### Search(func, context, t1, t2, dt_tolerance_seconds) @@ -1444,6 +1581,22 @@ A vector in the equatorial system. --- + +### VectorFromHorizon(sphere, time, refraction) + +**Given apparent angular horizontal coordinates in `sphere`, calculate horizontal vector.** + +| Type | Parameter | Description | +| --- | --- | --- | +| [`Spherical`](#Spherical) | `sphere` | A structure that contains apparent horizontal coordinates: `lat` holds the refracted azimuth angle, `lon` holds the azimuth in degrees clockwise from north, and `dist` holds the distance from the observer to the object in AU. | +| [`Time`](#Time) | `time` | The date and time of the observation. This is needed because the returned vector object requires a valid time value when passed to certain other functions. | +| [`Refraction`](#Refraction) | `refraction` | See remarks in function #RefractionAngle. | + +### Returns: Vector +A vector in the horizontal system: `x` = north, `y` = west, and `z` = zenith (up). + +--- + ### VectorFromSphere(sphere, time) diff --git a/source/python/astronomy.py b/source/python/astronomy.py index 3827237f..129585a9 100644 --- a/source/python/astronomy.py +++ b/source/python/astronomy.py @@ -5183,6 +5183,75 @@ def SphereFromVector(vector): return Spherical(lat, lon, dist) +def _ToggleAzimuthDirection(az): + az = 360.0 - az + if az >= 360.0: + az -= 360.0 + elif az < 0.0: + az += 360.0 + return az + + +def VectorFromHorizon(sphere, time, refraction): + """Given apparent angular horizontal coordinates in `sphere`, calculate horizontal vector. + + Parameters + ---------- + sphere : Spherical + A structure that contains apparent horizontal coordinates: + `lat` holds the refracted azimuth angle, + `lon` holds the azimuth in degrees clockwise from north, + and `dist` holds the distance from the observer to the object in AU. + time : Time + The date and time of the observation. This is needed because the returned + vector object requires a valid time value when passed to certain other functions. + refraction : Refraction + See remarks in function #RefractionAngle. + + Returns + ------- + Vector + A vector in the horizontal system: `x` = north, `y` = west, and `z` = zenith (up). + """ + lon = _ToggleAzimuthDirection(sphere.lon) + lat = sphere.lat + InverseRefractionAngle(refraction, sphere.lat) + xsphere = Spherical(lat, lon, sphere.dist) + return VectorFromSphere(xsphere, time) + + +def HorizonFromVector(vector, refraction): + """Converts Cartesian coordinates to horizontal coordinates. + + Given a horizontal Cartesian vector, returns horizontal azimuth and altitude. + + *IMPORTANT:* This function differs from `SphereFromVector` in two ways: + - `SphereFromVector` returns a `lon` value that represents azimuth defined counterclockwise + from north (e.g., west = +90), but this function represents a clockwise rotation + (e.g., east = +90). The difference is because `SphereFromVector` is intended + to preserve the vector "right-hand rule", while this function defines azimuth in a more + traditional way as used in navigation and cartography. + - This function optionally corrects for atmospheric refraction, while `SphereFromVector` does not. + + The returned object contains the azimuth in `lon`. + It is measured in degrees clockwise from north: east = +90 degrees, west = +270 degrees. + + The altitude is stored in `lat`. + + The distance to the observed object is stored in `dist`, + and is expressed in astronomical units (AU). + + Parameters + ---------- + vector : Vector + Cartesian vector to be converted to horizontal angular coordinates. + refraction : Refraction + See comments in the #RefractionAngle function. + """ + sphere = SphereFromVector(vector) + sphere.lon = _ToggleAzimuthDirection(sphere.lon) + sphere.lat += RefractionAngle(refraction, sphere.lat) + return sphere + def InverseRotation(rotation): """Calculates the inverse of a rotation matrix. @@ -5366,3 +5435,151 @@ def Rotation_EQD_EQJ(time): nut = _nutation_rot(time, 1) prec = _precession_rot(time.tt, 0.0) return CombineRotation(nut, prec) + + +def Rotation_EQD_HOR(time, observer): + """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. + + Use #HorizonFromVector to convert the return value + to a traditional altitude/azimuth pair. + + Parameters + ---------- + time : Time + The date and time at which the Earth's equator applies. + observer: Observer + A location near the Earth's mean sea level that defines the observer's location. + + Returns + ------- + RotationMatrix + 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. + """ + sinlat = math.sin(math.radians(observer.latitude)) + coslat = math.cos(math.radians(observer.latitude)) + sinlon = math.sin(math.radians(observer.longitude)) + coslon = math.cos(math.radians(observer.longitude)) + uze = [coslat * coslon, coslat * sinlon, sinlat] + une = [-sinlat * coslon, -sinlat * sinlon, coslat] + uwe = [sinlon, -coslon, 0.0] + spin_angle = -15.0 * _sidereal_time(time) + uz = _spin(spin_angle, uze) + un = _spin(spin_angle, une) + uw = _spin(spin_angle, uwe) + return RotationMatrix([ + [un[0], uw[0], uz[0]], + [un[1], uw[1], uz[1]], + [un[2], uw[2], uz[2]], + ]) + + +def Rotation_HOR_EQD(time, observer): + """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 + ---------- + time : Time + The date and time at which the Earth's equator applies. + observer : Observer + A location near the Earth's mean sea level that defines the observer's horizon. + + Returns + ------- + RotationMatrix + A rotation matrix that converts HOR to EQD at `time` and for `observer`. + """ + rot = Rotation_EQD_HOR(time, observer) + return InverseRotation(rot) + + +def Rotation_HOR_EQJ(time, observer): + """Calculates a rotation matrix from horizontal (HOR) to J2000 equatorial (EQJ). + + 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: EQJ = equatorial system, using equator at the J2000 epoch. + + Parameters + ---------- + time : Time + The date and time of the observation. + observer : Observer + A location near the Earth's mean sea level that define's the observer's horizon. + + Returns + ------- + RotationMatrix + A rotation matrix that converts HOR to EQD at `time` and for `observer`. + """ + hor_eqd = Rotation_HOR_EQD(time, observer) + eqd_eqj = Rotation_EQD_EQJ(time) + return CombineRotation(hor_eqd, eqd_eqj) + + +def Rotation_EQJ_HOR(time, observer): + """Calculates a rotation matrix from equatorial J2000 (EQJ) to horizontal (HOR). + + This is one of the family of functions that returns a rotation matrix + for converting from one orientation to another. + Source: EQJ = equatorial system, using the equator at the J2000 epoch. + Target: HOR = horizontal system. + + Use #HorizonFromVector to convert the return value to + a traditional altitude/azimuth pair. + + Parameters + ---------- + time : Time + The date and time of the desired horizontal orientation. + observer : Observer + A location near the Earth's mean sea level that defines the observer's horizon. + + Returns + ------- + RotationMatrix + A rotation matrix that converts EQJ 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. + """ + rot = Rotation_HOR_EQJ(time, observer) + return InverseRotation(rot) + + +def Rotation_EQD_ECL(time): + """Calculates a rotation matrix from equatorial of-date (EQD) to ecliptic J2000 (ECL). + + 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 date. + Target: ECL = ecliptic system, using equator at J2000 epoch. + + Parameters + ---------- + time : Time + The date and time of the source equator. + + Returns + ------- + A rotation matrix that converts EQD to ECL. + """ + eqd_eqj = Rotation_EQD_EQJ(time) + eqj_ecl = Rotation_EQJ_ECL() + return CombineRotation(eqd_eqj, eqj_ecl) +