mirror of
https://github.com/kmein/niveum
synced 2026-03-16 10:11:08 +01:00
182 lines
5.6 KiB
Python
182 lines
5.6 KiB
Python
|
|
from flatlib import aspects, const
|
||
|
|
from flatlib.chart import Chart
|
||
|
|
from flatlib.datetime import Datetime
|
||
|
|
import pytz
|
||
|
|
from flatlib.geopos import GeoPos
|
||
|
|
import timezonefinder
|
||
|
|
import operator
|
||
|
|
import click
|
||
|
|
import itertools
|
||
|
|
from datetime import datetime, timedelta
|
||
|
|
|
||
|
|
tf = timezonefinder.TimezoneFinder()
|
||
|
|
|
||
|
|
planets = [
|
||
|
|
const.SUN,
|
||
|
|
const.MOON,
|
||
|
|
const.MERCURY,
|
||
|
|
const.VENUS,
|
||
|
|
const.MARS,
|
||
|
|
const.JUPITER,
|
||
|
|
const.SATURN,
|
||
|
|
const.URANUS,
|
||
|
|
const.NEPTUNE,
|
||
|
|
const.PLUTO,
|
||
|
|
]
|
||
|
|
|
||
|
|
planet_symbols = {
|
||
|
|
const.SUN: "☉",
|
||
|
|
const.MOON: "☽",
|
||
|
|
const.MERCURY: "☿",
|
||
|
|
const.VENUS: "♀",
|
||
|
|
const.MARS: "♂",
|
||
|
|
const.JUPITER: "♃",
|
||
|
|
const.SATURN: "♄",
|
||
|
|
const.URANUS: "♅",
|
||
|
|
const.NEPTUNE: "♆",
|
||
|
|
const.PLUTO: "⯓",
|
||
|
|
}
|
||
|
|
|
||
|
|
aspect_symbols = {
|
||
|
|
const.NO_ASPECT: " ",
|
||
|
|
const.CONJUNCTION: "☌",
|
||
|
|
const.SEXTILE: "⚹",
|
||
|
|
const.SQUARE: "□",
|
||
|
|
const.TRINE: "△",
|
||
|
|
const.OPPOSITION: "☍",
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
def convert_into_stupid_flatlib_format(dt):
|
||
|
|
return Datetime(
|
||
|
|
dt.strftime("%Y/%m/%d"),
|
||
|
|
dt.strftime("%H:%M"),
|
||
|
|
dt.utcoffset().total_seconds() / 3600,
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
here_latitude = 52.52
|
||
|
|
here_longitude = 13.4
|
||
|
|
|
||
|
|
|
||
|
|
def get_aspects(chart1, chart2, *, threshold):
|
||
|
|
for planet1 in chart1.objects:
|
||
|
|
for planet2 in chart2.objects:
|
||
|
|
aspect = aspects.getAspect(planet1, planet2, const.MAJOR_ASPECTS)
|
||
|
|
if aspect.exists() and aspect.orb <= threshold:
|
||
|
|
yield aspect
|
||
|
|
|
||
|
|
|
||
|
|
def get_chart(position, dt_naive):
|
||
|
|
timezone = pytz.timezone(tf.timezone_at(lat=position.lat, lng=position.lon))
|
||
|
|
dt_aware = timezone.localize(dt_naive)
|
||
|
|
return Chart(convert_into_stupid_flatlib_format(dt_aware), position, IDs=planets)
|
||
|
|
|
||
|
|
|
||
|
|
def show_aspect(aspect):
|
||
|
|
return " ".join(
|
||
|
|
[
|
||
|
|
planet_symbols[aspect.active.id],
|
||
|
|
aspect_symbols[aspect.type],
|
||
|
|
planet_symbols[aspect.passive.id],
|
||
|
|
]
|
||
|
|
)
|
||
|
|
|
||
|
|
|
||
|
|
@click.command()
|
||
|
|
@click.option("--natal-latitude", type=click.FLOAT, default=here_latitude)
|
||
|
|
@click.option("--natal-longitude", type=click.FLOAT, default=here_longitude)
|
||
|
|
@click.option("--natal-date", type=click.DateTime(), default=datetime.now())
|
||
|
|
@click.option("--transit-latitude", type=click.FLOAT, default=here_latitude)
|
||
|
|
@click.option("--transit-longitude", type=click.FLOAT, default=here_longitude)
|
||
|
|
@click.option("--transit-date", type=click.DateTime(), default=datetime.now())
|
||
|
|
@click.option("--threshold", type=click.FLOAT, default=5)
|
||
|
|
def forecast(
|
||
|
|
natal_latitude: float,
|
||
|
|
natal_longitude: float,
|
||
|
|
natal_date: datetime,
|
||
|
|
transit_latitude: float,
|
||
|
|
transit_longitude: float,
|
||
|
|
transit_date: datetime,
|
||
|
|
threshold: float,
|
||
|
|
):
|
||
|
|
transit_position = GeoPos(transit_latitude, transit_longitude)
|
||
|
|
natal_position = GeoPos(natal_latitude, natal_longitude)
|
||
|
|
natal_chart = get_chart(natal_position, natal_date)
|
||
|
|
transit_chart = get_chart(transit_position, transit_date)
|
||
|
|
|
||
|
|
offset = 0
|
||
|
|
previous_aspects = set(
|
||
|
|
show_aspect(a)
|
||
|
|
for a in get_aspects(natal_chart, transit_chart, threshold=threshold)
|
||
|
|
)
|
||
|
|
while True:
|
||
|
|
then = transit_date + timedelta(minutes=offset)
|
||
|
|
current_chart = get_chart(transit_position, then)
|
||
|
|
current_aspects = set(
|
||
|
|
show_aspect(a)
|
||
|
|
for a in get_aspects(natal_chart, current_chart, threshold=threshold)
|
||
|
|
)
|
||
|
|
entered = current_aspects - previous_aspects
|
||
|
|
exited = previous_aspects - current_aspects
|
||
|
|
if entered or exited:
|
||
|
|
print(
|
||
|
|
then.strftime("%Y-%m-%d %H:%M"),
|
||
|
|
"".join([" | +" + a for a in entered] + [" | -" + a for a in exited]),
|
||
|
|
sep="",
|
||
|
|
)
|
||
|
|
previous_aspects = current_aspects
|
||
|
|
offset += 1
|
||
|
|
|
||
|
|
|
||
|
|
@click.command()
|
||
|
|
@click.option("--natal-latitude", type=click.FLOAT, default=here_latitude)
|
||
|
|
@click.option("--natal-longitude", type=click.FLOAT, default=here_longitude)
|
||
|
|
@click.option("--natal-date", "-D", type=click.DateTime(), default=datetime.now())
|
||
|
|
@click.option("--transit-latitude", type=click.FLOAT, default=here_latitude)
|
||
|
|
@click.option("--transit-longitude", type=click.FLOAT, default=here_longitude)
|
||
|
|
@click.option("--transit-date", "-d", type=click.DateTime(), default=datetime.now())
|
||
|
|
@click.option("--threshold", "-t", type=click.FLOAT, default=5)
|
||
|
|
def current(
|
||
|
|
natal_latitude: float,
|
||
|
|
natal_longitude: float,
|
||
|
|
natal_date: datetime,
|
||
|
|
transit_latitude: float,
|
||
|
|
transit_longitude: float,
|
||
|
|
transit_date: datetime,
|
||
|
|
threshold: float,
|
||
|
|
):
|
||
|
|
transit_position = GeoPos(transit_latitude, transit_longitude)
|
||
|
|
natal_position = GeoPos(natal_latitude, natal_longitude)
|
||
|
|
natal_chart = get_chart(natal_position, natal_date)
|
||
|
|
transit_chart = get_chart(transit_position, transit_date)
|
||
|
|
|
||
|
|
relevant_aspects = list(
|
||
|
|
get_aspects(natal_chart, transit_chart, threshold=threshold)
|
||
|
|
)
|
||
|
|
|
||
|
|
def aspect_switch_date(aspect, *, direction=1, threshold):
|
||
|
|
offset = 0
|
||
|
|
while True:
|
||
|
|
then = transit_date + direction * timedelta(days=offset)
|
||
|
|
current_chart = get_chart(transit_position, then)
|
||
|
|
aspects = [
|
||
|
|
show_aspect(a)
|
||
|
|
for a in get_aspects(natal_chart, current_chart, threshold=threshold)
|
||
|
|
]
|
||
|
|
if aspect not in aspects:
|
||
|
|
return then.date()
|
||
|
|
offset += 1
|
||
|
|
|
||
|
|
for aspect in sorted(relevant_aspects, key=operator.attrgetter("orb")):
|
||
|
|
aspect_string = show_aspect(aspect)
|
||
|
|
print(
|
||
|
|
aspect_switch_date(
|
||
|
|
aspect_string, direction=-1, threshold=threshold
|
||
|
|
).isoformat(),
|
||
|
|
aspect_switch_date(
|
||
|
|
aspect_string, direction=1, threshold=threshold
|
||
|
|
).isoformat(),
|
||
|
|
aspect_string,
|
||
|
|
)
|