@@ -6,8 +6,9 @@ | |||||
\usepackage{graphicx} | \usepackage{graphicx} | ||||
\usepackage{hyperref} | \usepackage{hyperref} | ||||
% Fix non-break spaces issues | |||||
% Fix Unicode issues | |||||
\DeclareUnicodeCharacter{202F}{~} | \DeclareUnicodeCharacter{202F}{~} | ||||
\DeclareUnicodeCharacter{00B0}{$^\circ$} | |||||
\hypersetup{pdfinfo={ | \hypersetup{pdfinfo={ | ||||
Title={+++DOCUMENT-TITLE+++}, | Title={+++DOCUMENT-TITLE+++}, | ||||
@@ -18,30 +18,13 @@ | |||||
from shutil import rmtree | from shutil import rmtree | ||||
from pathlib import Path | from pathlib import Path | ||||
from typing import Union | |||||
from skyfield.api import Loader | from skyfield.api import Loader | ||||
from skyfield.timelib import Time | from skyfield.timelib import Time | ||||
from skyfield.nutationlib import iau2000b | from skyfield.nutationlib import iau2000b | ||||
from .data import Star, Planet, Satellite, MOON_PHASES, MoonPhase | |||||
from .i18n import _ | |||||
CACHE_FOLDER = str(Path.home()) + '/.kosmorro-cache' | CACHE_FOLDER = str(Path.home()) + '/.kosmorro-cache' | ||||
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')] | |||||
def get_loader(): | def get_loader(): | ||||
return Loader(CACHE_FOLDER) | return Loader(CACHE_FOLDER) | ||||
@@ -63,43 +46,6 @@ def clear_cache(): | |||||
rmtree(CACHE_FOLDER) | rmtree(CACHE_FOLDER) | ||||
def skyfield_to_moon_phase(times: [Time], vals: [int], now: Time) -> Union[MoonPhase, None]: | |||||
tomorrow = get_timescale().utc(now.utc_datetime().year, now.utc_datetime().month, now.utc_datetime().day + 1) | |||||
phases = list(MOON_PHASES.keys()) | |||||
current_phase = None | |||||
current_phase_time = None | |||||
next_phase_time = None | |||||
i = 0 | |||||
if len(times) == 0: | |||||
return None | |||||
for i, time in enumerate(times): | |||||
if now.utc_iso() <= time.utc_iso(): | |||||
if vals[i] in [0, 2, 4, 6]: | |||||
if time.utc_datetime() < tomorrow.utc_datetime(): | |||||
current_phase_time = time | |||||
current_phase = phases[vals[i]] | |||||
else: | |||||
i -= 1 | |||||
current_phase_time = None | |||||
current_phase = phases[vals[i]] | |||||
else: | |||||
current_phase = phases[vals[i]] | |||||
break | |||||
for j in range(i + 1, len(times)): | |||||
if vals[j] in [0, 2, 4, 6]: | |||||
next_phase_time = times[j] | |||||
break | |||||
return MoonPhase(current_phase, | |||||
current_phase_time.utc_datetime() if current_phase_time is not None else None, | |||||
next_phase_time.utc_datetime() if next_phase_time is not None else None) | |||||
def flatten_list(the_list: list): | def flatten_list(the_list: list): | ||||
new_list = [] | new_list = [] | ||||
for item in the_list: | for item in the_list: | ||||
@@ -20,8 +20,10 @@ from abc import ABC, abstractmethod | |||||
from typing import Union | from typing import Union | ||||
from datetime import datetime | from datetime import datetime | ||||
from skyfield.api import Topos | |||||
from skyfield.api import Topos, Time | |||||
from skyfield.vectorlib import VectorSum as SkfPlanet | |||||
from .core import get_skf_objects, get_timescale | |||||
from .i18n import _ | from .i18n import _ | ||||
MOON_PHASES = { | MOON_PHASES = { | ||||
@@ -37,7 +39,8 @@ 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')}, | |||||
'MAXIMAL_ELONGATION': {'message': _("%s's largest elongation")} | |||||
} | } | ||||
@@ -115,6 +118,9 @@ class Object(ABC): | |||||
self.skyfield_name = skyfield_name | self.skyfield_name = skyfield_name | ||||
self.ephemerides = ephemerides | self.ephemerides = ephemerides | ||||
def get_skyfield_object(self) -> SkfPlanet: | |||||
return get_skf_objects()[self.skyfield_name] | |||||
@abstractmethod | @abstractmethod | ||||
def get_type(self) -> str: | def get_type(self) -> str: | ||||
pass | pass | ||||
@@ -142,23 +148,77 @@ class Satellite(Object): | |||||
class Event: | class Event: | ||||
def __init__(self, event_type: str, objects: [Object], start_time: datetime, | def __init__(self, event_type: str, objects: [Object], start_time: datetime, | ||||
end_time: Union[datetime, None] = None): | |||||
end_time: Union[datetime, None] = None, details: str = None): | |||||
if event_type not in EVENTS.keys(): | if event_type not in EVENTS.keys(): | ||||
raise ValueError('event_type parameter must be one of the following: %s (got %s)' % ( | |||||
', '.join(EVENTS.keys()), | |||||
event_type) | |||||
) | |||||
accepted_types = ', '.join(EVENTS.keys()) | |||||
raise ValueError('event_type parameter must be one of the following: %s (got %s)' % (accepted_types, | |||||
event_type)) | |||||
self.event_type = event_type | self.event_type = event_type | ||||
self.objects = objects | self.objects = objects | ||||
self.start_time = start_time | self.start_time = start_time | ||||
self.end_time = end_time | self.end_time = end_time | ||||
self.details = details | |||||
def get_description(self) -> str: | |||||
return EVENTS[self.event_type]['message'] % self._get_objects_name() | |||||
def get_description(self, show_details: bool = True) -> str: | |||||
description = EVENTS[self.event_type]['message'] % self._get_objects_name() | |||||
if show_details and self.details is not None: | |||||
description += ' ({:s})'.format(self.details) | |||||
return description | |||||
def _get_objects_name(self): | def _get_objects_name(self): | ||||
if len(self.objects) == 1: | if len(self.objects) == 1: | ||||
return self.objects[0].name | return self.objects[0].name | ||||
return tuple(object.name for object in self.objects) | return tuple(object.name for object in self.objects) | ||||
def skyfield_to_moon_phase(times: [Time], vals: [int], now: Time) -> Union[MoonPhase, None]: | |||||
tomorrow = get_timescale().utc(now.utc_datetime().year, now.utc_datetime().month, now.utc_datetime().day + 1) | |||||
phases = list(MOON_PHASES.keys()) | |||||
current_phase = None | |||||
current_phase_time = None | |||||
next_phase_time = None | |||||
i = 0 | |||||
if len(times) == 0: | |||||
return None | |||||
for i, time in enumerate(times): | |||||
if now.utc_iso() <= time.utc_iso(): | |||||
if vals[i] in [0, 2, 4, 6]: | |||||
if time.utc_datetime() < tomorrow.utc_datetime(): | |||||
current_phase_time = time | |||||
current_phase = phases[vals[i]] | |||||
else: | |||||
i -= 1 | |||||
current_phase_time = None | |||||
current_phase = phases[vals[i]] | |||||
else: | |||||
current_phase = phases[vals[i]] | |||||
break | |||||
for j in range(i + 1, len(times)): | |||||
if vals[j] in [0, 2, 4, 6]: | |||||
next_phase_time = times[j] | |||||
break | |||||
return MoonPhase(current_phase, | |||||
current_phase_time.utc_datetime() if current_phase_time is not None else None, | |||||
next_phase_time.utc_datetime() if next_phase_time is not None else None) | |||||
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')] |
@@ -24,8 +24,8 @@ from skyfield.searchlib import find_discrete, find_maxima | |||||
from skyfield.timelib import Time | from skyfield.timelib import Time | ||||
from skyfield.constants import tau | from skyfield.constants import tau | ||||
from .data import Object, Position, AsterEphemerides, MoonPhase | |||||
from .core import get_skf_objects, get_timescale, get_iau2000b, ASTERS, MONTHS, skyfield_to_moon_phase | |||||
from .data import Object, Position, AsterEphemerides, MoonPhase, ASTERS, MONTHS, skyfield_to_moon_phase | |||||
from .core import get_skf_objects, get_timescale, get_iau2000b | |||||
RISEN_ANGLE = -0.8333 | RISEN_ANGLE = -0.8333 | ||||
@@ -88,6 +88,7 @@ class EphemeridesComputer: | |||||
rise_times, arr = find_discrete(start_time, end_time, is_risen) | rise_times, arr = find_discrete(start_time, end_time, is_risen) | ||||
try: | try: | ||||
culmination_time, _ = find_maxima(start_time, end_time, f=get_angle, epsilon=1./3600/24, num=12) | culmination_time, _ = find_maxima(start_time, end_time, f=get_angle, epsilon=1./3600/24, num=12) | ||||
culmination_time = culmination_time[0] if len(culmination_time) > 0 else None | |||||
except ValueError: | except ValueError: | ||||
culmination_time = None | culmination_time = None | ||||
@@ -98,12 +99,15 @@ class EphemeridesComputer: | |||||
rise_time = rise_times[0] if arr[0] else None | rise_time = rise_times[0] if arr[0] else None | ||||
set_time = rise_times[0] if not arr[0] else None | set_time = rise_times[0] if not arr[0] else None | ||||
culmination_time = culmination_time[0] if culmination_time is not None else None | |||||
# Convert the Time instances to Python datetime objects | # Convert the Time instances to Python datetime objects | ||||
rise_time = rise_time.utc_datetime().replace(microsecond=0) | |||||
culmination_time = culmination_time.utc_datetime().replace(microsecond=0) | |||||
set_time = set_time.utc_datetime().replace(microsecond=0) | |||||
if rise_time is not None: | |||||
rise_time = rise_time.utc_datetime().replace(microsecond=0) | |||||
if culmination_time is not None: | |||||
culmination_time = culmination_time.utc_datetime().replace(microsecond=0) | |||||
if set_time is not None: | |||||
set_time = set_time.utc_datetime().replace(microsecond=0) if set_time is not None else None | |||||
aster.ephemerides = AsterEphemerides(rise_time, culmination_time, set_time) | aster.ephemerides = AsterEphemerides(rise_time, culmination_time, set_time) | ||||
return aster | return aster | ||||
@@ -19,10 +19,10 @@ | |||||
from datetime import date as date_type | from datetime import date as date_type | ||||
from skyfield.timelib import Time | from skyfield.timelib import Time | ||||
from skyfield.almanac import find_discrete | |||||
from skyfield.searchlib import find_discrete, find_maxima | |||||
from .data import Event, Planet | |||||
from .core import get_timescale, get_skf_objects, ASTERS, flatten_list | |||||
from .data import Event, Planet, ASTERS | |||||
from .core import get_timescale, get_skf_objects, flatten_list | |||||
def _search_conjunction(start_time: Time, end_time: Time) -> [Event]: | def _search_conjunction(start_time: Time, end_time: Time) -> [Event]: | ||||
@@ -91,11 +91,41 @@ def _search_oppositions(start_time: Time, end_time: Time) -> [Event]: | |||||
return events | return events | ||||
def _search_maximal_elongations(start_time: Time, end_time: Time) -> [Event]: | |||||
earth = get_skf_objects()['earth'] | |||||
sun = get_skf_objects()['sun'] | |||||
aster = None | |||||
def get_elongation(time: Time): | |||||
sun_pos = (sun - earth).at(time) | |||||
aster_pos = (aster.get_skyfield_object() - earth).at(time) | |||||
separation = sun_pos.separation_from(aster_pos) | |||||
return separation.degrees | |||||
get_elongation.rough_period = 1.0 | |||||
events = [] | |||||
for aster in ASTERS: | |||||
if aster.skyfield_name not in ['MERCURY', 'VENUS']: | |||||
continue | |||||
times, elongations = find_maxima(start_time, end_time, f=get_elongation, epsilon=1./24/3600, num=12) | |||||
for i, time in enumerate(times): | |||||
elongation = elongations[i] | |||||
events.append(Event('MAXIMAL_ELONGATION', [aster], time.utc_datetime(), | |||||
details='{:.3n}°'.format(elongation))) | |||||
return events | |||||
def search_events(date: date_type) -> [Event]: | def search_events(date: date_type) -> [Event]: | ||||
start_time = get_timescale().utc(date.year, date.month, date.day) | start_time = get_timescale().utc(date.year, date.month, date.day) | ||||
end_time = get_timescale().utc(date.year, date.month, date.day + 1) | end_time = get_timescale().utc(date.year, date.month, date.day + 1) | ||||
return sorted(flatten_list([ | return sorted(flatten_list([ | ||||
_search_oppositions(start_time, end_time), | _search_oppositions(start_time, end_time), | ||||
_search_conjunction(start_time, end_time) | |||||
_search_conjunction(start_time, end_time), | |||||
_search_maximal_elongations(start_time, end_time) | |||||
]), key=lambda event: event.start_time) | ]), key=lambda event: event.start_time) |
@@ -8,7 +8,7 @@ msgid "" | |||||
msgstr "" | msgstr "" | ||||
"Project-Id-Version: kosmorro 0.5.2\n" | "Project-Id-Version: kosmorro 0.5.2\n" | ||||
"Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" | "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" | ||||
"POT-Creation-Date: 2020-02-17 20:58+0100\n" | |||||
"POT-Creation-Date: 2020-02-21 20:14+0100\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,86 +17,91 @@ 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/core.py:34 | |||||
msgid "Sun" | |||||
#: kosmorrolib/data.py:30 | |||||
msgid "New Moon" | |||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/core.py:35 | |||||
msgid "Moon" | |||||
#: kosmorrolib/data.py:31 | |||||
msgid "Waxing crescent" | |||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/core.py:36 | |||||
msgid "Mercury" | |||||
#: kosmorrolib/data.py:32 | |||||
msgid "First Quarter" | |||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/core.py:37 | |||||
msgid "Venus" | |||||
#: kosmorrolib/data.py:33 | |||||
msgid "Waxing gibbous" | |||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/core.py:38 | |||||
msgid "Mars" | |||||
#: kosmorrolib/data.py:34 | |||||
msgid "Full Moon" | |||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/core.py:39 | |||||
msgid "Jupiter" | |||||
#: kosmorrolib/data.py:35 | |||||
msgid "Waning gibbous" | |||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/core.py:40 | |||||
msgid "Saturn" | |||||
#: kosmorrolib/data.py:36 | |||||
msgid "Last Quarter" | |||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/core.py:41 | |||||
msgid "Uranus" | |||||
#: kosmorrolib/data.py:37 | |||||
msgid "Waning crescent" | |||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/core.py:42 | |||||
msgid "Neptune" | |||||
#: kosmorrolib/data.py:41 | |||||
#, python-format | |||||
msgid "%s is in opposition" | |||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/core.py:43 | |||||
msgid "Pluto" | |||||
#: kosmorrolib/data.py:42 | |||||
#, python-format | |||||
msgid "%s and %s are in conjunction" | |||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:28 | |||||
msgid "New Moon" | |||||
#: kosmorrolib/data.py:43 | |||||
#, python-format | |||||
msgid "%s's largest elongation" | |||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:29 | |||||
msgid "Waxing crescent" | |||||
#: kosmorrolib/data.py:215 | |||||
msgid "Sun" | |||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:30 | |||||
msgid "First Quarter" | |||||
#: kosmorrolib/data.py:216 | |||||
msgid "Moon" | |||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:31 | |||||
msgid "Waxing gibbous" | |||||
#: kosmorrolib/data.py:217 | |||||
msgid "Mercury" | |||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:32 | |||||
msgid "Full Moon" | |||||
#: kosmorrolib/data.py:218 | |||||
msgid "Venus" | |||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:33 | |||||
msgid "Waning gibbous" | |||||
#: kosmorrolib/data.py:219 | |||||
msgid "Mars" | |||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:34 | |||||
msgid "Last Quarter" | |||||
#: kosmorrolib/data.py:220 | |||||
msgid "Jupiter" | |||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:35 | |||||
msgid "Waning crescent" | |||||
#: kosmorrolib/data.py:221 | |||||
msgid "Saturn" | |||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:39 | |||||
#, python-format | |||||
msgid "%s is in opposition" | |||||
#: kosmorrolib/data.py:222 | |||||
msgid "Uranus" | |||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/data.py:40 | |||||
#, python-format | |||||
msgid "%s and %s are in conjunction" | |||||
#: kosmorrolib/data.py:223 | |||||
msgid "Neptune" | |||||
msgstr "" | |||||
#: kosmorrolib/data.py:224 | |||||
msgid "Pluto" | |||||
msgstr "" | msgstr "" | ||||
#: kosmorrolib/dumper.py:35 | #: kosmorrolib/dumper.py:35 | ||||
@@ -23,7 +23,17 @@ class DumperTestCase(unittest.TestCase): | |||||
' "Mars"\n' | ' "Mars"\n' | ||||
' ],\n' | ' ],\n' | ||||
' "start_time": "2019-10-14T23:00:00",\n' | ' "start_time": "2019-10-14T23:00:00",\n' | ||||
' "end_time": null\n' | |||||
' "end_time": null,\n' | |||||
' "details": null\n' | |||||
' },\n' | |||||
' {\n' | |||||
' "event_type": "MAXIMAL_ELONGATION",\n' | |||||
' "objects": [\n' | |||||
' "Venus"\n' | |||||
' ],\n' | |||||
' "start_time": "2019-10-14T12:00:00",\n' | |||||
' "end_time": null,\n' | |||||
' "details": "42.0\\u00b0"\n' | |||||
' }\n' | ' }\n' | ||||
' ],\n' | ' ],\n' | ||||
' "ephemerides": [\n' | ' "ephemerides": [\n' | ||||
@@ -52,7 +62,17 @@ class DumperTestCase(unittest.TestCase): | |||||
' "Mars"\n' | ' "Mars"\n' | ||||
' ],\n' | ' ],\n' | ||||
' "start_time": "2019-10-14T23:00:00",\n' | ' "start_time": "2019-10-14T23:00:00",\n' | ||||
' "end_time": null\n' | |||||
' "end_time": null,\n' | |||||
' "details": null\n' | |||||
' },\n' | |||||
' {\n' | |||||
' "event_type": "MAXIMAL_ELONGATION",\n' | |||||
' "objects": [\n' | |||||
' "Venus"\n' | |||||
' ],\n' | |||||
' "start_time": "2019-10-14T12:00:00",\n' | |||||
' "end_time": null,\n' | |||||
' "details": "42.0\\u00b0"\n' | |||||
' }\n' | ' }\n' | ||||
' ],\n' | ' ],\n' | ||||
' "ephemerides": [\n' | ' "ephemerides": [\n' | ||||
@@ -92,15 +112,16 @@ class DumperTestCase(unittest.TestCase): | |||||
def test_text_dumper_with_events(self): | def test_text_dumper_with_events(self): | ||||
ephemerides = self._get_data() | ephemerides = self._get_data() | ||||
self.assertEqual('Monday October 14, 2019\n\n' | |||||
'Object Rise time Culmination time Set time\n' | |||||
'-------- ----------- ------------------ ----------\n' | |||||
'Mars - - -\n\n' | |||||
'Moon phase: Full Moon\n' | |||||
'Last Quarter on Monday October 21, 2019 at 00:00\n\n' | |||||
'Expected events:\n' | |||||
'23:00 Mars is in opposition\n\n' | |||||
'Note: All the hours are given in UTC.', | |||||
self.assertEqual("Monday October 14, 2019\n\n" | |||||
"Object Rise time Culmination time Set time\n" | |||||
"-------- ----------- ------------------ ----------\n" | |||||
"Mars - - -\n\n" | |||||
"Moon phase: Full Moon\n" | |||||
"Last Quarter on Monday October 21, 2019 at 00:00\n\n" | |||||
"Expected events:\n" | |||||
"23:00 Mars is in opposition\n" | |||||
"12:00 Venus's largest elongation (42.0°)\n\n" | |||||
"Note: All the hours are given in UTC.", | |||||
TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False).to_string()) | TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False).to_string()) | ||||
def test_text_dumper_without_ephemerides_and_with_events(self): | def test_text_dumper_without_ephemerides_and_with_events(self): | ||||
@@ -109,7 +130,8 @@ class DumperTestCase(unittest.TestCase): | |||||
'Moon phase: Full Moon\n' | 'Moon phase: Full Moon\n' | ||||
'Last Quarter on Monday October 21, 2019 at 00:00\n\n' | 'Last Quarter on Monday October 21, 2019 at 00:00\n\n' | ||||
'Expected events:\n' | 'Expected events:\n' | ||||
'23:00 Mars is in opposition\n\n' | |||||
'23:00 Mars is in opposition\n' | |||||
"12:00 Venus's largest elongation (42.0°)\n\n" | |||||
'Note: All the hours are given in UTC.', | 'Note: All the hours are given in UTC.', | ||||
TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False).to_string()) | TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False).to_string()) | ||||
@@ -122,7 +144,8 @@ class DumperTestCase(unittest.TestCase): | |||||
'Moon phase: Full Moon\n' | 'Moon phase: Full Moon\n' | ||||
'Last Quarter on Monday October 21, 2019 at 01:00\n\n' | 'Last Quarter on Monday October 21, 2019 at 01:00\n\n' | ||||
'Expected events:\n' | 'Expected events:\n' | ||||
'Oct 15, 00:00 Mars is in opposition\n\n' | |||||
'Oct 15, 00:00 Mars is in opposition\n' | |||||
"13:00 Venus's largest elongation (42.0°)\n\n" | |||||
'Note: All the hours are given in the UTC+1 timezone.', | 'Note: All the hours are given in the UTC+1 timezone.', | ||||
TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False, timezone=1).to_string()) | TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False, timezone=1).to_string()) | ||||
@@ -134,7 +157,8 @@ class DumperTestCase(unittest.TestCase): | |||||
'Moon phase: Full Moon\n' | 'Moon phase: Full Moon\n' | ||||
'Last Quarter on Sunday October 20, 2019 at 23:00\n\n' | 'Last Quarter on Sunday October 20, 2019 at 23:00\n\n' | ||||
'Expected events:\n' | 'Expected events:\n' | ||||
'22:00 Mars is in opposition\n\n' | |||||
'22:00 Mars is in opposition\n' | |||||
"11:00 Venus's largest elongation (42.0°)\n\n" | |||||
'Note: All the hours are given in the UTC-1 timezone.', | 'Note: All the hours are given in the UTC-1 timezone.', | ||||
TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False, timezone=-1).to_string()) | TextDumper(ephemerides, self._get_events(), date=date(2019, 10, 14), with_colors=False, timezone=-1).to_string()) | ||||
@@ -146,6 +170,7 @@ class DumperTestCase(unittest.TestCase): | |||||
self.assertRegex(latex, r'\\section{\\sffamily Ephemerides of the day}') | self.assertRegex(latex, r'\\section{\\sffamily Ephemerides of the day}') | ||||
self.assertRegex(latex, r'\\object\{Mars\}\{-\}\{-\}\{-\}') | self.assertRegex(latex, r'\\object\{Mars\}\{-\}\{-\}\{-\}') | ||||
self.assertRegex(latex, r'\\event\{23:00\}\{Mars is in opposition\}') | self.assertRegex(latex, r'\\event\{23:00\}\{Mars is in opposition\}') | ||||
self.assertRegex(latex, r"\\event\{12:00\}\{Venus's largest elongation \(42.0°\)\}") | |||||
latex = _LatexDumper(self._get_data(aster_rise_set=True), | latex = _LatexDumper(self._get_data(aster_rise_set=True), | ||||
self._get_events(), date=date(2019, 10, 14)).to_string() | self._get_events(), date=date(2019, 10, 14)).to_string() | ||||
@@ -157,6 +182,7 @@ class DumperTestCase(unittest.TestCase): | |||||
self.assertRegex(latex, 'Full Moon') | self.assertRegex(latex, 'Full Moon') | ||||
self.assertRegex(latex, r'\\section{\\sffamily Expected events}') | self.assertRegex(latex, r'\\section{\\sffamily Expected events}') | ||||
self.assertRegex(latex, r'\\event\{23:00\}\{Mars is in opposition\}') | self.assertRegex(latex, r'\\event\{23:00\}\{Mars is in opposition\}') | ||||
self.assertRegex(latex, r"\\event\{12:00\}\{Venus's largest elongation \(42.0°\)\}") | |||||
self.assertNotRegex(latex, r'\\object\{Mars\}\{-\}\{-\}\{-\}') | self.assertNotRegex(latex, r'\\object\{Mars\}\{-\}\{-\}\{-\}') | ||||
self.assertNotRegex(latex, r'\\section{\\sffamily Ephemerides of the day}') | self.assertNotRegex(latex, r'\\section{\\sffamily Ephemerides of the day}') | ||||
@@ -186,7 +212,10 @@ class DumperTestCase(unittest.TestCase): | |||||
def _get_events(): | def _get_events(): | ||||
return [Event('OPPOSITION', | return [Event('OPPOSITION', | ||||
[Planet('Mars', 'MARS')], | [Planet('Mars', 'MARS')], | ||||
datetime(2019, 10, 14, 23, 00)) | |||||
datetime(2019, 10, 14, 23, 00)), | |||||
Event('MAXIMAL_ELONGATION', | |||||
[Planet('Venus', 'VENUS')], | |||||
datetime(2019, 10, 14, 12, 00), details='42.0°'), | |||||
] | ] | ||||
@@ -55,6 +55,33 @@ class MyTestCase(unittest.TestCase): | |||||
i += 1 | i += 1 | ||||
def test_find_maximal_elongation(self): | |||||
e = events.search_events(date(2020, 2, 10)) | |||||
self.assertEquals(1, len(e), 'Expected 1 events, got %d.' % len(e)) | |||||
e = e[0] | |||||
self.assertEquals('MAXIMAL_ELONGATION', e.event_type) | |||||
self.assertEquals(1, len(e.objects)) | |||||
self.assertEquals('MERCURY', e.objects[0].skyfield_name) | |||||
self.assertEqual('18.2°', e.details) | |||||
self.assertEquals((2020, 2, 10, 13, 46), (e.start_time.year, e.start_time.month, e.start_time.day, | |||||
e.start_time.hour, e.start_time.minute)) | |||||
e = events.search_events(date(2020, 3, 24)) | |||||
self.assertEquals(2, len(e), 'Expected 2 events, got %d.' % len(e)) | |||||
self.assertEquals('MAXIMAL_ELONGATION', e[0].event_type) | |||||
self.assertEquals(1, len(e[0].objects)) | |||||
self.assertEquals('MERCURY', e[0].objects[0].skyfield_name) | |||||
self.assertEqual('27.8°', e[0].details) | |||||
self.assertEquals((2020, 3, 24, 1, 56), (e[0].start_time.year, e[0].start_time.month, e[0].start_time.day, | |||||
e[0].start_time.hour, e[0].start_time.minute)) | |||||
self.assertEquals('MAXIMAL_ELONGATION', e[1].event_type) | |||||
self.assertEquals(1, len(e[1].objects)) | |||||
self.assertEquals('VENUS', e[1].objects[0].skyfield_name) | |||||
self.assertEqual('46.1°', e[1].details) | |||||
self.assertEquals((2020, 3, 24, 21, 58), (e[1].start_time.year, e[1].start_time.month, e[1].start_time.day, | |||||
e[1].start_time.hour, e[1].start_time.minute)) | |||||
if __name__ == '__main__': | if __name__ == '__main__': | ||||
unittest.main() | unittest.main() |