Add support for occultationstags/v0.7.0
@@ -20,6 +20,8 @@ from abc import ABC, abstractmethod | |||||
from typing import Union | from typing import Union | ||||
from datetime import datetime | from datetime import datetime | ||||
from numpy import pi, arcsin | |||||
from skyfield.api import Topos, Time | from skyfield.api import Topos, Time | ||||
from skyfield.vectorlib import VectorSum as SkfPlanet | from skyfield.vectorlib import VectorSum as SkfPlanet | ||||
@@ -40,6 +42,7 @@ MOON_PHASES = { | |||||
EVENTS = { | EVENTS = { | ||||
'OPPOSITION': {'message': _('%s is in opposition')}, | 'OPPOSITION': {'message': _('%s is in opposition')}, | ||||
'CONJUNCTION': {'message': _('%s and %s are in conjunction')}, | 'CONJUNCTION': {'message': _('%s and %s are in conjunction')}, | ||||
'OCCULTATION': {'message': _('%s occults %s')}, | |||||
'MAXIMAL_ELONGATION': {'message': _("%s's largest elongation")} | 'MAXIMAL_ELONGATION': {'message': _("%s's largest elongation")} | ||||
} | } | ||||
@@ -106,16 +109,19 @@ class Object(ABC): | |||||
def __init__(self, | def __init__(self, | ||||
name: str, | name: str, | ||||
skyfield_name: str, | skyfield_name: str, | ||||
ephemerides: AsterEphemerides or None = None): | |||||
ephemerides: AsterEphemerides or None = None, | |||||
radius: float = None): | |||||
""" | """ | ||||
Initialize an astronomical object | Initialize an astronomical object | ||||
:param str name: the official name of the object (may be internationalized) | :param str name: the official name of the object (may be internationalized) | ||||
:param str skyfield_name: the internal name of the object in Skyfield library | :param str skyfield_name: the internal name of the object in Skyfield library | ||||
:param float radius: the radius (in km) of the object | |||||
:param AsterEphemerides ephemerides: the ephemerides associated to the object | :param AsterEphemerides ephemerides: the ephemerides associated to the object | ||||
""" | """ | ||||
self.name = name | self.name = name | ||||
self.skyfield_name = skyfield_name | self.skyfield_name = skyfield_name | ||||
self.radius = radius | |||||
self.ephemerides = ephemerides | self.ephemerides = ephemerides | ||||
def get_skyfield_object(self) -> SkfPlanet: | def get_skyfield_object(self) -> SkfPlanet: | ||||
@@ -125,6 +131,18 @@ class Object(ABC): | |||||
def get_type(self) -> str: | def get_type(self) -> str: | ||||
pass | pass | ||||
def get_apparent_radius(self, time: Time, from_place) -> float: | |||||
""" | |||||
Calculate the apparent radius, in degrees, of the object from the given place at a given time. | |||||
:param time: | |||||
:param from_place: | |||||
:return: | |||||
""" | |||||
if self.radius is None: | |||||
raise ValueError('Missing radius for %s object' % self.name) | |||||
return 360 / pi * arcsin(self.radius / from_place.at(time).observe(self.get_skyfield_object()).distance().km) | |||||
class Star(Object): | class Star(Object): | ||||
def get_type(self) -> str: | def get_type(self) -> str: | ||||
@@ -212,13 +230,13 @@ def skyfield_to_moon_phase(times: [Time], vals: [int], now: Time) -> Union[MoonP | |||||
MONTHS = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'] | MONTHS = ['JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC'] | ||||
ASTERS = [Star(_('Sun'), 'SUN'), | |||||
Satellite(_('Moon'), 'MOON'), | |||||
Planet(_('Mercury'), 'MERCURY'), | |||||
Planet(_('Venus'), 'VENUS'), | |||||
Planet(_('Mars'), 'MARS'), | |||||
Planet(_('Jupiter'), 'JUPITER BARYCENTER'), | |||||
Planet(_('Saturn'), 'SATURN BARYCENTER'), | |||||
Planet(_('Uranus'), 'URANUS BARYCENTER'), | |||||
Planet(_('Neptune'), 'NEPTUNE BARYCENTER'), | |||||
Planet(_('Pluto'), 'PLUTO BARYCENTER')] | |||||
ASTERS = [Star(_('Sun'), 'SUN', radius=696342), | |||||
Satellite(_('Moon'), 'MOON', radius=1737.4), | |||||
Planet(_('Mercury'), 'MERCURY', radius=2439.7), | |||||
Planet(_('Venus'), 'VENUS', radius=6051.8), | |||||
Planet(_('Mars'), 'MARS', radius=3396.2), | |||||
Planet(_('Jupiter'), 'JUPITER BARYCENTER', radius=71492), | |||||
Planet(_('Saturn'), 'SATURN BARYCENTER', radius=60268), | |||||
Planet(_('Uranus'), 'URANUS BARYCENTER', radius=25559), | |||||
Planet(_('Neptune'), 'NEPTUNE BARYCENTER', radius=24764), | |||||
Planet(_('Pluto'), 'PLUTO BARYCENTER', radius=1185)] |
@@ -116,6 +116,7 @@ class JsonDumper(Dumper): | |||||
if isinstance(obj, Object): | if isinstance(obj, Object): | ||||
obj = obj.__dict__ | obj = obj.__dict__ | ||||
obj.pop('skyfield_name') | obj.pop('skyfield_name') | ||||
obj.pop('radius') | |||||
obj['object'] = obj.pop('name') | obj['object'] = obj.pop('name') | ||||
obj['details'] = obj.pop('ephemerides') | obj['details'] = obj.pop('ephemerides') | ||||
return obj | return obj | ||||
@@ -56,7 +56,18 @@ def _search_conjunction(start_time: Time, end_time: Time) -> [Event]: | |||||
for i, time in enumerate(times): | for i, time in enumerate(times): | ||||
if is_conjs[i]: | if is_conjs[i]: | ||||
conjunctions.append(Event('CONJUNCTION', [aster1, aster2], time.utc_datetime())) | |||||
aster1_pos = (aster1.get_skyfield_object() - earth).at(time) | |||||
aster2_pos = (aster2.get_skyfield_object() - earth).at(time) | |||||
distance = aster1_pos.separation_from(aster2_pos).degrees | |||||
if distance - aster2.get_apparent_radius(time, earth) < aster1.get_apparent_radius(time, earth): | |||||
occulting_aster = [aster1, | |||||
aster2] if aster1_pos.distance().km < aster2_pos.distance().km else [aster2, | |||||
aster1] | |||||
conjunctions.append(Event('OCCULTATION', occulting_aster, time.utc_datetime())) | |||||
else: | |||||
conjunctions.append(Event('CONJUNCTION', [aster1, aster2], time.utc_datetime())) | |||||
computed.append(aster1) | computed.append(aster1) | ||||
@@ -8,7 +8,7 @@ msgid "" | |||||
msgstr "" | msgstr "" | ||||
"Project-Id-Version: kosmorro 0.6.2\n" | "Project-Id-Version: kosmorro 0.6.2\n" | ||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" | ||||
"POT-Creation-Date: 2020-03-24 13:44+0100\n" | |||||
"POT-Creation-Date: 2020-03-29 14:06+0200\n" | |||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" | ||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" | ||||
"Language-Team: LANGUAGE <LL@li.org>\n" | "Language-Team: LANGUAGE <LL@li.org>\n" | ||||
@@ -17,90 +17,95 @@ msgstr "" | |||||
"Content-Transfer-Encoding: 8bit\n" | "Content-Transfer-Encoding: 8bit\n" | ||||
"Generated-By: Babel 2.8.0\n" | "Generated-By: Babel 2.8.0\n" | ||||
#: kosmorrolib/data.py:30 | |||||
#: kosmorrolib/data.py:32 | |||||
msgid "New Moon" | msgid "New Moon" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:31 | |||||
#: kosmorrolib/data.py:33 | |||||
msgid "Waxing crescent" | msgid "Waxing crescent" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:32 | |||||
#: kosmorrolib/data.py:34 | |||||
msgid "First Quarter" | msgid "First Quarter" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:33 | |||||
#: kosmorrolib/data.py:35 | |||||
msgid "Waxing gibbous" | msgid "Waxing gibbous" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:34 | |||||
#: kosmorrolib/data.py:36 | |||||
msgid "Full Moon" | msgid "Full Moon" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:35 | |||||
#: kosmorrolib/data.py:37 | |||||
msgid "Waning gibbous" | msgid "Waning gibbous" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:36 | |||||
#: kosmorrolib/data.py:38 | |||||
msgid "Last Quarter" | msgid "Last Quarter" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:37 | |||||
#: kosmorrolib/data.py:39 | |||||
msgid "Waning crescent" | msgid "Waning crescent" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:41 | |||||
#: kosmorrolib/data.py:43 | |||||
#, python-format | #, python-format | ||||
msgid "%s is in opposition" | msgid "%s is in opposition" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:42 | |||||
#: kosmorrolib/data.py:44 | |||||
#, python-format | #, python-format | ||||
msgid "%s and %s are in conjunction" | msgid "%s and %s are in conjunction" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:43 | |||||
#: kosmorrolib/data.py:45 | |||||
#, python-format | |||||
msgid "%s occults %s" | |||||
msgstr "" | |||||
#: kosmorrolib/data.py:46 | |||||
#, python-format | #, python-format | ||||
msgid "%s's largest elongation" | msgid "%s's largest elongation" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:215 | |||||
#: kosmorrolib/data.py:233 | |||||
msgid "Sun" | msgid "Sun" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:216 | |||||
#: kosmorrolib/data.py:234 | |||||
msgid "Moon" | msgid "Moon" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:217 | |||||
#: kosmorrolib/data.py:235 | |||||
msgid "Mercury" | msgid "Mercury" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:218 | |||||
#: kosmorrolib/data.py:236 | |||||
msgid "Venus" | msgid "Venus" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:219 | |||||
#: kosmorrolib/data.py:237 | |||||
msgid "Mars" | msgid "Mars" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:220 | |||||
#: kosmorrolib/data.py:238 | |||||
msgid "Jupiter" | msgid "Jupiter" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:221 | |||||
#: kosmorrolib/data.py:239 | |||||
msgid "Saturn" | msgid "Saturn" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:222 | |||||
#: kosmorrolib/data.py:240 | |||||
msgid "Uranus" | msgid "Uranus" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:223 | |||||
#: kosmorrolib/data.py:241 | |||||
msgid "Neptune" | msgid "Neptune" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:224 | |||||
#: kosmorrolib/data.py:242 | |||||
msgid "Pluto" | msgid "Pluto" | ||||
msgstr "" | msgstr "" | ||||
@@ -116,68 +121,68 @@ msgstr "" | |||||
msgid "{hours}:{minutes}" | msgid "{hours}:{minutes}" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:147 | |||||
#: kosmorrolib/dumper.py:148 | |||||
msgid "Expected events:" | msgid "Expected events:" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:151 | |||||
#: kosmorrolib/dumper.py:152 | |||||
msgid "Note: All the hours are given in UTC." | msgid "Note: All the hours are given in UTC." | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:156 | |||||
#: kosmorrolib/dumper.py:157 | |||||
msgid "Note: All the hours are given in the UTC{offset} timezone." | msgid "Note: All the hours are given in the UTC{offset} timezone." | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:202 kosmorrolib/dumper.py:271 | |||||
#: kosmorrolib/dumper.py:203 kosmorrolib/dumper.py:272 | |||||
msgid "Object" | msgid "Object" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:203 kosmorrolib/dumper.py:272 | |||||
#: kosmorrolib/dumper.py:204 kosmorrolib/dumper.py:273 | |||||
msgid "Rise time" | msgid "Rise time" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:204 kosmorrolib/dumper.py:273 | |||||
#: kosmorrolib/dumper.py:205 kosmorrolib/dumper.py:274 | |||||
msgid "Culmination time" | msgid "Culmination time" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:205 kosmorrolib/dumper.py:274 | |||||
#: kosmorrolib/dumper.py:206 kosmorrolib/dumper.py:275 | |||||
msgid "Set time" | msgid "Set time" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:219 kosmorrolib/dumper.py:277 | |||||
#: kosmorrolib/dumper.py:220 kosmorrolib/dumper.py:278 | |||||
msgid "Moon phase:" | msgid "Moon phase:" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:220 | |||||
#: kosmorrolib/dumper.py:221 | |||||
msgid "{next_moon_phase} on {next_moon_phase_date} at {next_moon_phase_time}" | msgid "{next_moon_phase} on {next_moon_phase_date} at {next_moon_phase_time}" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:258 | |||||
#: kosmorrolib/dumper.py:259 | |||||
msgid "A Summary of your Sky" | msgid "A Summary of your Sky" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:262 | |||||
#: kosmorrolib/dumper.py:263 | |||||
msgid "" | msgid "" | ||||
"This document summarizes the ephemerides and the events of {date}. It " | "This document summarizes the ephemerides and the events of {date}. It " | ||||
"aims to help you to prepare your observation session. All the hours are " | "aims to help you to prepare your observation session. All the hours are " | ||||
"given in {timezone}." | "given in {timezone}." | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:268 | |||||
#: kosmorrolib/dumper.py:269 | |||||
msgid "" | msgid "" | ||||
"Don't forget to check the weather forecast before you go out with your " | "Don't forget to check the weather forecast before you go out with your " | ||||
"material." | "material." | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:270 | |||||
#: kosmorrolib/dumper.py:271 | |||||
msgid "Ephemerides of the day" | msgid "Ephemerides of the day" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:279 | |||||
#: kosmorrolib/dumper.py:280 | |||||
msgid "Expected events" | msgid "Expected events" | ||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:354 | |||||
#: kosmorrolib/dumper.py:355 | |||||
msgid "" | msgid "" | ||||
"Building PDFs was not possible, because some dependencies are not " | "Building PDFs was not possible, because some dependencies are not " | ||||
"installed.\n" | "installed.\n" | ||||
@@ -1,5 +1,5 @@ | |||||
from .core import * | |||||
from .data import * | |||||
from .dumper import * | from .dumper import * | ||||
from .ephemerides import * | from .ephemerides import * | ||||
from .events import * | from .events import * | ||||
from .core import * | |||||
@@ -0,0 +1,17 @@ | |||||
import unittest | |||||
from kosmorrolib import data, core | |||||
class DataTestCase(unittest.TestCase): | |||||
def test_object_radius_must_be_set_to_get_apparent_radius(self): | |||||
o = data.Planet('Saturn', 'SATURN') | |||||
with self.assertRaises(ValueError) as context: | |||||
o.get_apparent_radius(core.get_timescale().now(), core.get_skf_objects()['earth']) | |||||
self.assertEqual(('Missing radius for Saturn object',), context.exception.args) | |||||
if __name__ == '__main__': | |||||
unittest.main() |
@@ -38,6 +38,8 @@ class EventTestCase(unittest.TestCase): | |||||
(date(2020, 3, 24), [Event('MAXIMAL_ELONGATION', [ASTERS[2]], datetime(2020, 3, 24, 1, 56), details='27.8°'), | (date(2020, 3, 24), [Event('MAXIMAL_ELONGATION', [ASTERS[2]], datetime(2020, 3, 24, 1, 56), details='27.8°'), | ||||
Event('MAXIMAL_ELONGATION', [ASTERS[3]], datetime(2020, 3, 24, 21, 58), details='46.1°')]), | Event('MAXIMAL_ELONGATION', [ASTERS[3]], datetime(2020, 3, 24, 21, 58), details='46.1°')]), | ||||
(date(2005, 6, 16), [Event('OCCULTATION', [ASTERS[1], ASTERS[5]], datetime(2005, 6, 16, 6, 31))]) | |||||
) | ) | ||||
@data_provider(expected_events_provider) | @data_provider(expected_events_provider) | ||||