Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
 
 
 
 

164 rader
5.2 KiB

  1. #!/usr/bin/env python3
  2. # Kosmorro - Compute The Next Ephemerides
  3. # Copyright (C) 2019 Jérôme Deuchnord <jerome@deuchnord.fr>
  4. #
  5. # This program is free software: you can redistribute it and/or modify
  6. # it under the terms of the GNU Affero General Public License as
  7. # published by the Free Software Foundation, either version 3 of the
  8. # License, or (at your option) any later version.
  9. #
  10. # This program is distributed in the hope that it will be useful,
  11. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. # GNU Affero General Public License for more details.
  14. #
  15. # You should have received a copy of the GNU Affero General Public License
  16. # along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. from abc import ABC, abstractmethod
  18. from typing import Union
  19. from skyfield.api import Topos
  20. from skyfield.timelib import Time
  21. from .i18n import _
  22. MOON_PHASES = {
  23. 'NEW_MOON': _('New Moon'),
  24. 'WAXING_CRESCENT': _('Waxing crescent'),
  25. 'FIRST_QUARTER': _('First Quarter'),
  26. 'WAXING_GIBBOUS': _('Waxing gibbous'),
  27. 'FULL_MOON': _('Full Moon'),
  28. 'WANING_GIBBOUS': _('Waning gibbous'),
  29. 'LAST_QUARTER': _('Last Quarter'),
  30. 'WANING_CRESCENT': _('Waning crescent')
  31. }
  32. EVENTS = {
  33. 'OPPOSITION': {'message': _('%s is in opposition')},
  34. 'CONJUNCTION': {'message': _('%s and %s are in conjunction')}
  35. }
  36. class MoonPhase:
  37. def __init__(self, identifier: str, time: Union[Time, None], next_phase_date: Union[Time, None]):
  38. if identifier not in MOON_PHASES.keys():
  39. raise ValueError('identifier parameter must be one of %s (got %s)' % (', '.join(MOON_PHASES.keys()),
  40. identifier))
  41. self.identifier = identifier
  42. self.time = time
  43. self.next_phase_date = next_phase_date
  44. def get_phase(self):
  45. return MOON_PHASES[self.identifier]
  46. def get_next_phase(self):
  47. if self.identifier == 'NEW_MOON' or self.identifier == 'WAXING_CRESCENT':
  48. next_identifier = 'FIRST_QUARTER'
  49. elif self.identifier == 'FIRST_QUARTER' or self.identifier == 'WAXING_GIBBOUS':
  50. next_identifier = 'FULL_MOON'
  51. elif self.identifier == 'FULL_MOON' or self.identifier == 'WANING_GIBBOUS':
  52. next_identifier = 'LAST_QUARTER'
  53. else:
  54. next_identifier = 'NEW_MOON'
  55. return MOON_PHASES[next_identifier]
  56. class Position:
  57. def __init__(self, latitude: float, longitude: float):
  58. self.latitude = latitude
  59. self.longitude = longitude
  60. self.observation_planet = None
  61. self._topos = None
  62. def get_planet_topos(self) -> Topos:
  63. if self.observation_planet is None:
  64. raise TypeError('Observation planet must be set.')
  65. if self._topos is None:
  66. self._topos = self.observation_planet + Topos(latitude_degrees=self.latitude,
  67. longitude_degrees=self.longitude)
  68. return self._topos
  69. class AsterEphemerides:
  70. def __init__(self,
  71. rise_time: Union[Time, None],
  72. culmination_time: Union[Time, None],
  73. set_time: Union[Time, None]):
  74. self.rise_time = rise_time
  75. self.culmination_time = culmination_time
  76. self.set_time = set_time
  77. class Object(ABC):
  78. """
  79. An astronomical object.
  80. """
  81. def __init__(self,
  82. name: str,
  83. skyfield_name: str,
  84. ephemerides: AsterEphemerides or None = None):
  85. """
  86. Initialize an astronomical object
  87. :param str name: the official name of the object (may be internationalized)
  88. :param str skyfield_name: the internal name of the object in Skyfield library
  89. :param AsterEphemerides ephemerides: the ephemerides associated to the object
  90. """
  91. self.name = name
  92. self.skyfield_name = skyfield_name
  93. self.ephemerides = ephemerides
  94. @abstractmethod
  95. def get_type(self) -> str:
  96. pass
  97. class Star(Object):
  98. def get_type(self) -> str:
  99. return 'star'
  100. class Planet(Object):
  101. def get_type(self) -> str:
  102. return 'planet'
  103. class DwarfPlanet(Planet):
  104. def get_type(self) -> str:
  105. return 'dwarf_planet'
  106. class Satellite(Object):
  107. def get_type(self) -> str:
  108. return 'satellite'
  109. class Event:
  110. def __init__(self, event_type: str, objects: [Object], start_time: Time, end_time: Union[Time, None] = None):
  111. if event_type not in EVENTS.keys():
  112. raise ValueError('event_type parameter must be one of the following: %s (got %s)' % (
  113. ', '.join(EVENTS.keys()),
  114. event_type)
  115. )
  116. self.event_type = event_type
  117. self.objects = objects
  118. self.start_time = start_time
  119. self.end_time = end_time
  120. def get_description(self) -> str:
  121. return EVENTS[self.event_type]['message'] % self._get_objects_name()
  122. def _get_objects_name(self):
  123. if len(self.objects) == 1:
  124. return self.objects[0].name
  125. return tuple(object.name for object in self.objects)