debian-skyfield/skyfield/toposlib.py

97 lines
3.6 KiB
Python

from .constants import ASEC2RAD, tau
from .earthlib import terra
from .functions import mxmxm, mxv, rot_x, rot_y, rot_z
from .units import Distance, Angle, _interpret_ltude
from .vectorlib import VectorFunction
class Topos(VectorFunction):
"""A vector function that knows the position of a place on Earth.
You can specify latitude and longitude by either either building
Skyfield :class:`~skyfield.units.Angle` objects yourself and
supplying them to the constructor as its first two arguments, or by
providing floating point numbers to the alternate keyword arguments
``latitude_degrees`` and ``longitude_degrees``.
The ``center`` of a topos object is always ``399``, the center of
gravity of the Earth, so every call to the ``at(t)`` method of a
topos object returns a :class:`~skyfield.positionlib.Geocentric`
position.
"""
center = 399
def __init__(self, latitude=None, longitude=None, latitude_degrees=None,
longitude_degrees=None, elevation_m=0.0, x=0.0, y=0.0):
if latitude_degrees is not None:
latitude = Angle(degrees=latitude_degrees)
elif isinstance(latitude, (str, float, tuple)):
latitude = _interpret_ltude(latitude, 'latitude', 'N', 'S')
elif not isinstance(latitude, Angle):
raise TypeError('please provide either latitude_degrees=<float>'
' or latitude=<skyfield.units.Angle object>'
' with north being positive')
if longitude_degrees is not None:
longitude = Angle(degrees=longitude_degrees)
elif isinstance(longitude, (str, float, tuple)):
longitude = _interpret_ltude(longitude, 'longitude', 'E', 'W')
elif not isinstance(longitude, Angle):
raise TypeError('please provide either longitude_degrees=<float>'
' or longitude=<skyfield.units.Angle object>'
' with east being positive')
self.latitude = latitude
self.longitude = longitude
self.elevation = Distance(m=elevation_m)
self.x = x
self.y = y
self.R_lat = rot_y(latitude.radians)[::-1]
self.target = str(self)
def __str__(self):
return 'Topos {0} N {1} E'.format(self.latitude, self.longitude)
def __repr__(self):
return '<{0}>'.format(self)
def _snag_observer_data(self, observer_data, t):
observer_data.altaz_rotation = self._altaz_rotation(t)
observer_data.elevation_m = self.elevation.m
def _altaz_rotation(self, t):
"""Compute the rotation from the ICRF into the alt-az system."""
R_lon = rot_z(- self.longitude.radians - t.gast * tau / 24.0)
return mxmxm(self.R_lat, R_lon, t.M)
def _at(self, t):
"""Compute the GCRS position and velocity of this Topos at time `t`."""
pos, vel = terra(self.latitude.radians, self.longitude.radians,
self.elevation.au, t.gast)
pos = mxv(t.MT, pos)
vel = mxv(t.MT, vel)
if self.x:
R = rot_y(self.x * ASEC2RAD)
pos = mxv(R, pos)
if self.y:
R = rot_x(self.y * ASEC2RAD)
pos = mxv(R, pos)
# TODO: also rotate velocity
return pos, vel, pos, None
def itrf_xyz(self):
"""Return this location as an (x,y,z) vector in the ITRF frame.
Returns a 3-element :class:`~skyfield.units.Distance` object.
"""
gast = 0.0
pos, vel = terra(self.latitude.radians, self.longitude.radians,
self.elevation.au, gast)
return Distance(pos)