flatangle / flatlib

Python library for Traditional Astrology
MIT License
296 stars 105 forks source link

Applying aspects #75

Closed velkyvont closed 2 years ago

velkyvont commented 2 years ago

Horary astrology, or at least John Frawley has a rule that for applying aspects one has to check if the aspect is going to occur - if before the aspect occurs, the planet turns retrograde and moves in the opposite direction, it will not occur and so it is not an applying aspect in the true sense of the word.

I haven't studied your code very thoroughly, but it seems to me that this feature is not built in. Is there any way to include it?

joaoventura commented 2 years ago

I do not know that rule, but I would say that an applying aspect does not necessarily mean that there will be perfection (i.e., the aspect will reach 0º of distance). The only way to check for perfection would be to generate successive charts (successive by date) and see if the angular distance would reach 0º.

velkyvont commented 2 years ago

"In horary we are concerned mainly with exact aspects. Exact means exact. If the aspect fails to perfect by even one minute of arc, it is not exact and the event that it would have foretold will not happen. For instance, if boy marrying girl would be shown by Venus reaching a conjunction with Mars at 22.17 Leo, but Venus turns retrograde at 22.16 Leo, thus failing to perfect the aspect, the marriage will not happen." (John Frawley: The Horary Textbook, 2005 edition, page 86)

I had another idea: Is there a way to figure out from Swiss ephemeris the next time a planet will turn retrograde?

dave-sdt commented 2 years ago

"In horary we are concerned mainly with exact aspects. Exact means exact. If the aspect fails to perfect by even one minute of arc, it is not exact and the event that it would have foretold will not happen. For instance, if boy marrying girl would be shown by Venus reaching a conjunction with Mars at 22.17 Leo, but Venus turns retrograde at 22.16 Leo, thus failing to perfect the aspect, the marriage will not happen." (John Frawley: The Horary Textbook, 2005 edition, page 86)

I had another idea: Is there a way to figure out from Swiss ephemeris the next time a planet will turn retrograde?

sun.movement() gives you Direct or Retrograde movement of Sun

dave-sdt commented 2 years ago

Horary astrology, or at least John Frawley has a rule that for applying aspects one has to check if the aspect is going to occur - if before the aspect occurs, the planet turns retrograde and moves in the opposite direction, it will not occur and so it is not an applying aspect in the true sense of the word.

I haven't studied your code very thoroughly, but it seems to me that this feature is not built in. Is there any way to include it?

I think we have same problems , did you used this app ? I am trying to calculate the exact degree of planets on the zodiac but i don't know about astrology systems , could you help me to understand which system is used in this app and which python library is suitable for it?

velkyvont commented 2 years ago

Horary astrology, or at least John Frawley has a rule that for applying aspects one has to check if the aspect is going to occur - if before the aspect occurs, the planet turns retrograde and moves in the opposite direction, it will not occur and so it is not an applying aspect in the true sense of the word. I haven't studied your code very thoroughly, but it seems to me that this feature is not built in. Is there any way to include it?

I think we have same problems , did you used this app ? I am trying to calculate the exact degree of planets on the zodiac but i don't know about astrology systems , could you help me to understand which system is used in this app and which python library is suitable for it?

I'm sorry, but I have no idea what you mean and I'm not gonna install that app.

PHCCorso commented 2 years ago

@velkyvont indeed, there is no such functionality. Additionally, John Frawley's rules for perfect aspects are:

  1. They happen within the same sign the planets were in — if any of the planets leaves its sign before the aspect perfects, it's not an aspect
  2. Trines are only aspects when the signs are of the same element

This is just a sketch and far from being polished, but it seems to work properly:

from flatlib.chart import Chart
from flatlib.datetime import Datetime
from flatlib.geopos import GeoPos
from flatlib import const
from flatlib import aspects
from flatlib import angle

from datetime import datetime
from datetime import timedelta

EXACT_OFFSET = 0.001

def getFlatlibDate(dt):
    dateString = dt.strftime('%Y/%m/%d')
    timeString = dt.strftime('%H:%M:%S')
    utcString = dt.tzname().replace('UTC', '')

    return Datetime(dateString, timeString, utcString)

def createChart(dt, lat, lon):
    datetime = getFlatlibDate(dt)
    geopos = GeoPos(lat, lon)
    chart = Chart(datetime, geopos, hsys=const.HOUSES_REGIOMONTANUS)
    return chart

def getApproxAspectDate(aspect, chartDateTime, chart):
    active = chart.get(aspect.active.id)
    passive = chart.get(aspect.passive.id)

    distance = angle.closestdistance(active.lon, passive.lon)

    daysToAspect = distance / active.lonspeed
    minutesToAspect = daysToAspect * 24 * 60

    return chartDateTime + timedelta(minutes=minutesToAspect)

def sameSign(aspect1, aspect2, chart1, chart2):
    active1 = chart1.get(aspect1.active.id)
    passive1 = chart1.get(aspect1.passive.id)
    active2 = chart2.get(aspect2.active.id)
    passive2 = chart2.get(aspect2.passive.id)

    return active1.sign == active2.sign and passive1.sign == passive2.sign

def getPerfectAspect(aspect, chartDateTime, chart):
    active = chart.get(aspect.active.id)
    passive = chart.get(aspect.passive.id)

    if (aspect.type == const.TRINE and active.element != passive.element):
        return None

    travelDistance = angle.closestdistance(active.lon, passive.lon)
    approxAspectDate = getApproxAspectDate(aspect, chartDateTime, chart)

    projectedChart = createChart(approxAspectDate, chart.pos.lat, chart.pos.lon)
    projectedActive = projectedChart.get(aspect.active.id)
    projectedPassive = projectedChart.get(aspect.passive.id)
    projectedAspect = aspects.getAspect(projectedActive, projectedPassive, [aspect.type])
    projectedDistance = angle.closestdistance(projectedActive.lon, projectedPassive.lon);

    if (not sameSign(aspect, projectedAspect, chart, projectedChart)):
        return None

    if projectedDistance > EXACT_OFFSET:

        perfectAspect = getPerfectAspect(projectedAspect, approxAspectDate, projectedChart)

        if perfectAspect is not None:
            perfectAspect[2] += travelDistance

        return perfectAspect

    travelDistance += projectedDistance

    return [projectedAspect, approxAspectDate, travelDistance]

Basically, I just generate a new chart until the aspect perfects within the given conditions.

velkyvont commented 2 years ago

hi @PHCCorso, I don't need this any more, but your code is awesome. Thank you for your time!