libephemeris 0.1.6__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- libephemeris/__init__.py +151 -0
- libephemeris/angles.py +106 -0
- libephemeris/arabic_parts.py +232 -0
- libephemeris/constants.py +318 -0
- libephemeris/crossing.py +326 -0
- libephemeris/fixed_stars.py +228 -0
- libephemeris/houses.py +1625 -0
- libephemeris/lunar.py +269 -0
- libephemeris/minor_bodies.py +398 -0
- libephemeris/planets.py +1228 -0
- libephemeris/state.py +213 -0
- libephemeris/time_utils.py +136 -0
- libephemeris/utils.py +36 -0
- libephemeris-0.1.6.dist-info/METADATA +376 -0
- libephemeris-0.1.6.dist-info/RECORD +18 -0
- libephemeris-0.1.6.dist-info/WHEEL +5 -0
- libephemeris-0.1.6.dist-info/licenses/LICENSE +13 -0
- libephemeris-0.1.6.dist-info/top_level.txt +1 -0
libephemeris/__init__.py
ADDED
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
from .constants import *
|
|
2
|
+
from .time_utils import swe_julday, swe_revjul, swe_deltat
|
|
3
|
+
from .planets import (
|
|
4
|
+
swe_calc_ut,
|
|
5
|
+
swe_calc,
|
|
6
|
+
swe_get_ayanamsa_ut,
|
|
7
|
+
swe_get_ayanamsa,
|
|
8
|
+
swe_set_sid_mode,
|
|
9
|
+
)
|
|
10
|
+
from .houses import swe_houses, swe_houses_ex, swe_house_name
|
|
11
|
+
from .state import set_topo as swe_set_topo, set_ephe_path as swe_set_ephe_path
|
|
12
|
+
from .crossing import swe_solcross_ut, swe_mooncross_ut, swe_cross_ut
|
|
13
|
+
from .utils import difdeg2n
|
|
14
|
+
from .fixed_stars import swe_fixstar_ut
|
|
15
|
+
|
|
16
|
+
# =============================================================================
|
|
17
|
+
# PYSWISSEPH-COMPATIBLE FUNCTION ALIASES (without swe_ prefix)
|
|
18
|
+
# =============================================================================
|
|
19
|
+
# pyswisseph uses function names without the swe_ prefix
|
|
20
|
+
# These aliases provide 100% API compatibility with pyswisseph
|
|
21
|
+
|
|
22
|
+
# Time functions
|
|
23
|
+
julday = swe_julday
|
|
24
|
+
revjul = swe_revjul
|
|
25
|
+
deltat = swe_deltat
|
|
26
|
+
|
|
27
|
+
# Planet calculation
|
|
28
|
+
calc_ut = swe_calc_ut
|
|
29
|
+
calc = swe_calc
|
|
30
|
+
|
|
31
|
+
# Houses
|
|
32
|
+
houses = swe_houses
|
|
33
|
+
houses_ex = swe_houses_ex
|
|
34
|
+
house_name = swe_house_name
|
|
35
|
+
|
|
36
|
+
# Ayanamsa (sidereal)
|
|
37
|
+
get_ayanamsa_ut = swe_get_ayanamsa_ut
|
|
38
|
+
get_ayanamsa = swe_get_ayanamsa
|
|
39
|
+
set_sid_mode = swe_set_sid_mode
|
|
40
|
+
|
|
41
|
+
# Observer location
|
|
42
|
+
set_topo = swe_set_topo
|
|
43
|
+
set_ephe_path = swe_set_ephe_path
|
|
44
|
+
|
|
45
|
+
# Fixed Stars
|
|
46
|
+
fixstar_ut = swe_fixstar_ut
|
|
47
|
+
|
|
48
|
+
# Crossings
|
|
49
|
+
solcross_ut = swe_solcross_ut
|
|
50
|
+
mooncross_ut = swe_mooncross_ut
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
# Helper function to pre-calculate positions for Arabic parts
|
|
54
|
+
def swe_calc_angles(jd_ut: float, lat: float, lon: float):
|
|
55
|
+
"""
|
|
56
|
+
Pre-calculate and cache astrological angles and planet positions
|
|
57
|
+
for use with Arabic parts.
|
|
58
|
+
|
|
59
|
+
Args:
|
|
60
|
+
jd_ut: Julian Day (UT)
|
|
61
|
+
lat: Latitude (degrees)
|
|
62
|
+
lon: Longitude (degrees)
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
Dictionary with calculated positions
|
|
66
|
+
"""
|
|
67
|
+
from .state import set_angles_cache
|
|
68
|
+
from .angles import calc_angles
|
|
69
|
+
|
|
70
|
+
# Set observer location
|
|
71
|
+
swe_set_topo(lon, lat, 0)
|
|
72
|
+
|
|
73
|
+
# Calculate angles
|
|
74
|
+
angles_dict = calc_angles(jd_ut, lat, lon)
|
|
75
|
+
|
|
76
|
+
# Calculate and add planet positions for Arabic parts
|
|
77
|
+
from .constants import SE_SUN, SE_MOON, SE_MERCURY, SE_VENUS
|
|
78
|
+
|
|
79
|
+
sun_pos, _ = swe_calc_ut(jd_ut, SE_SUN, 0)
|
|
80
|
+
moon_pos, _ = swe_calc_ut(jd_ut, SE_MOON, 0)
|
|
81
|
+
mercury_pos, _ = swe_calc_ut(jd_ut, SE_MERCURY, 0)
|
|
82
|
+
venus_pos, _ = swe_calc_ut(jd_ut, SE_VENUS, 0)
|
|
83
|
+
|
|
84
|
+
angles_dict['Sun'] = sun_pos[0]
|
|
85
|
+
angles_dict['Moon'] = moon_pos[0]
|
|
86
|
+
angles_dict['Mercury'] = mercury_pos[0]
|
|
87
|
+
angles_dict['Venus'] = venus_pos[0]
|
|
88
|
+
|
|
89
|
+
# Cache for Arabic parts
|
|
90
|
+
set_angles_cache(angles_dict)
|
|
91
|
+
|
|
92
|
+
return angles_dict
|
|
93
|
+
|
|
94
|
+
# Helper for Arabic parts
|
|
95
|
+
from .arabic_parts import calc_all_arabic_parts
|
|
96
|
+
|
|
97
|
+
# Constants (planet IDs, flags, sidereal modes)
|
|
98
|
+
from .constants import *
|
|
99
|
+
|
|
100
|
+
__version__ = "0.1.0"
|
|
101
|
+
__author__ = "Giacomo Battaglia"
|
|
102
|
+
__license__ = "LGPL-3.0"
|
|
103
|
+
|
|
104
|
+
__all__ = [
|
|
105
|
+
# Time functions (both swe_ and non-prefixed aliases)
|
|
106
|
+
"swe_julday",
|
|
107
|
+
"julday",
|
|
108
|
+
"swe_revjul",
|
|
109
|
+
"revjul",
|
|
110
|
+
"swe_deltat",
|
|
111
|
+
"deltat",
|
|
112
|
+
# Planet calculation
|
|
113
|
+
"swe_calc_ut",
|
|
114
|
+
"calc_ut",
|
|
115
|
+
"swe_calc",
|
|
116
|
+
"calc",
|
|
117
|
+
"swe_get_planet_name",
|
|
118
|
+
# Houses
|
|
119
|
+
"swe_houses",
|
|
120
|
+
"houses",
|
|
121
|
+
"swe_houses_ex",
|
|
122
|
+
"houses_ex",
|
|
123
|
+
"swe_house_pos",
|
|
124
|
+
"swe_house_name",
|
|
125
|
+
# Ayanamsa (sidereal)
|
|
126
|
+
"swe_set_sid_mode",
|
|
127
|
+
"set_sid_mode",
|
|
128
|
+
"swe_get_ayanamsa_ut",
|
|
129
|
+
"get_ayanamsa_ut",
|
|
130
|
+
"swe_get_ayanamsa",
|
|
131
|
+
"get_ayanamsa",
|
|
132
|
+
"swe_get_ayanamsa_name",
|
|
133
|
+
# Observer location
|
|
134
|
+
"swe_set_topo",
|
|
135
|
+
"set_topo",
|
|
136
|
+
"swe_set_ephe_path",
|
|
137
|
+
"set_ephe_path",
|
|
138
|
+
# Crossings
|
|
139
|
+
"swe_solcross_ut",
|
|
140
|
+
"solcross_ut",
|
|
141
|
+
"swe_mooncross_ut",
|
|
142
|
+
"mooncross_ut",
|
|
143
|
+
"swe_cross_ut",
|
|
144
|
+
# Utilities
|
|
145
|
+
"difdeg2n",
|
|
146
|
+
# Helpers
|
|
147
|
+
"calc_all_arabic_parts",
|
|
148
|
+
# Fixed Stars
|
|
149
|
+
"swe_fixstar_ut",
|
|
150
|
+
"fixstar_ut",
|
|
151
|
+
]
|
libephemeris/angles.py
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Astrological angles and chart points for libephemeris.
|
|
3
|
+
|
|
4
|
+
This module calculates the primary astrological angles:
|
|
5
|
+
- Ascendant (ASC): Ecliptic degree rising on eastern horizon
|
|
6
|
+
- Midheaven (MC): Ecliptic degree culminating on meridian
|
|
7
|
+
- Descendant (DSC): Western horizon point (ASC + 180°)
|
|
8
|
+
- Imum Coeli (IC): Lower meridian (MC + 180°)
|
|
9
|
+
- Vertex: Intersection of prime vertical with western ecliptic
|
|
10
|
+
- Equatorial Ascendant: Equator crossing eastern horizon
|
|
11
|
+
|
|
12
|
+
All angles require observer geographic location (swe_set_topo).
|
|
13
|
+
Calculations are based on spherical astronomy and house system cusps.
|
|
14
|
+
|
|
15
|
+
Note:
|
|
16
|
+
Angles are independent of house system choice (though computed via houses).
|
|
17
|
+
They represent fundamental horizon/meridian intersections with the ecliptic.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
from typing import Dict
|
|
21
|
+
from .constants import (
|
|
22
|
+
SE_ASCENDANT,
|
|
23
|
+
SE_MC,
|
|
24
|
+
SE_DESCENDANT,
|
|
25
|
+
SE_IC,
|
|
26
|
+
SE_VERTEX,
|
|
27
|
+
SE_ANTIVERTEX,
|
|
28
|
+
)
|
|
29
|
+
from .houses import swe_houses
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def calc_angles(jd_ut: float, lat: float, lon: float) -> Dict[str, float]:
|
|
33
|
+
"""
|
|
34
|
+
Calculate all astrological angles for a given time and location.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
jd_ut: Julian Day in Universal Time (UT1)
|
|
38
|
+
lat: Geographic latitude in degrees (North positive)
|
|
39
|
+
lon: Geographic longitude in degrees (East positive)
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
Dict[str, float]: Dictionary mapping angle names to ecliptic longitudes:
|
|
43
|
+
- "Ascendant": Rising degree on eastern horizon
|
|
44
|
+
- "MC": Midheaven (culminating degree)
|
|
45
|
+
- "ARMC": Right Ascension of MC in degrees
|
|
46
|
+
- "Vertex": Prime vertical intersection (west)
|
|
47
|
+
- "Equatorial_Ascendant": Equator on eastern horizon
|
|
48
|
+
- "Descendant": Setting degree (Asc + 180°)
|
|
49
|
+
- "IC": Lower meridian (MC + 180°)
|
|
50
|
+
- "AntiVertex": Prime vertical intersection (east)
|
|
51
|
+
|
|
52
|
+
Note:
|
|
53
|
+
Uses Placidus house system internally, but angle values are
|
|
54
|
+
system-independent. They are purely geometric intersections.
|
|
55
|
+
|
|
56
|
+
Angles are sensitive to observer location. Polar regions may
|
|
57
|
+
have undefined values for some angles.
|
|
58
|
+
"""
|
|
59
|
+
_, ascmc = swe_houses(jd_ut, lat, lon, ord("P"))
|
|
60
|
+
|
|
61
|
+
return {
|
|
62
|
+
"Ascendant": ascmc[0],
|
|
63
|
+
"MC": ascmc[1],
|
|
64
|
+
"ARMC": ascmc[2],
|
|
65
|
+
"Vertex": ascmc[3],
|
|
66
|
+
"Equatorial_Ascendant": ascmc[4] if len(ascmc) > 4 else 0.0,
|
|
67
|
+
"Descendant": (ascmc[0] + 180.0) % 360.0,
|
|
68
|
+
"IC": (ascmc[1] + 180.0) % 360.0,
|
|
69
|
+
"AntiVertex": (ascmc[3] + 180.0) % 360.0,
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def get_angle_value(angle_id: int, jd_ut: float, lat: float, lon: float) -> float:
|
|
74
|
+
"""
|
|
75
|
+
Get ecliptic longitude for a specific angle.
|
|
76
|
+
|
|
77
|
+
Args:
|
|
78
|
+
angle_id: Angle identifier constant (SE_ASCENDANT, SE_MC, etc.)
|
|
79
|
+
jd_ut: Julian Day in Universal Time (UT1)
|
|
80
|
+
lat: Geographic latitude in degrees (North positive)
|
|
81
|
+
lon: Geographic longitude in degrees (East positive)
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
float: Ecliptic longitude of the angle in degrees (0-360)
|
|
85
|
+
Returns 0.0 if angle_id is not recognized
|
|
86
|
+
|
|
87
|
+
Example:
|
|
88
|
+
>>> asc = get_angle_value(SE_ASCENDANT, jd, 41.9, 12.5)
|
|
89
|
+
>>> mc = get_angle_value(SE_MC, jd, 41.9, 12.5)
|
|
90
|
+
"""
|
|
91
|
+
angles = calc_angles(jd_ut, lat, lon)
|
|
92
|
+
|
|
93
|
+
angle_map = {
|
|
94
|
+
SE_ASCENDANT: "Ascendant",
|
|
95
|
+
SE_MC: "MC",
|
|
96
|
+
SE_DESCENDANT: "Descendant",
|
|
97
|
+
SE_IC: "IC",
|
|
98
|
+
SE_VERTEX: "Vertex",
|
|
99
|
+
SE_ANTIVERTEX: "AntiVertex",
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if angle_id in angle_map:
|
|
103
|
+
return angles[angle_map[angle_id]]
|
|
104
|
+
|
|
105
|
+
return 0.0
|
|
106
|
+
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Arabic Parts (Lots) calculations for libephemeris.
|
|
3
|
+
|
|
4
|
+
Arabic Parts are classical astrological points calculated from combinations
|
|
5
|
+
of planetary positions and angles. They represent specific life areas and
|
|
6
|
+
are used in Hellenistic, Medieval, and modern astrology.
|
|
7
|
+
|
|
8
|
+
Formulas follow traditional methods from:
|
|
9
|
+
- Dorotheus of Sidon (1st century CE)
|
|
10
|
+
- Vettius Valens (2nd century CE)
|
|
11
|
+
- Al-Biruni "Book of Instruction" (11th century)
|
|
12
|
+
- Robert Schmidt translations (Project Hindsight)
|
|
13
|
+
|
|
14
|
+
Standard formula structure: ASC + [Point A] - [Point B]
|
|
15
|
+
Many parts have day/night variations for sect consideration.
|
|
16
|
+
|
|
17
|
+
Supported Parts:
|
|
18
|
+
- Part of Fortune (Pars Fortunae): Body, health, material success
|
|
19
|
+
- Part of Spirit (Pars Spiritus): Soul, intellect, spiritual matters
|
|
20
|
+
- Part of Love (Pars Amoris/Eros): Romance, desire, relationships
|
|
21
|
+
- Part of Faith (Pars Fidei): Belief, religion, trust
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from typing import Dict
|
|
25
|
+
from .constants import (
|
|
26
|
+
SE_PARS_FORTUNAE,
|
|
27
|
+
SE_PARS_SPIRITUS,
|
|
28
|
+
SE_PARS_AMORIS,
|
|
29
|
+
SE_PARS_FIDEI,
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def calc_arabic_part_of_fortune(
|
|
34
|
+
asc: float, sun: float, moon: float, is_diurnal: bool = True
|
|
35
|
+
) -> float:
|
|
36
|
+
"""
|
|
37
|
+
Calculate Part of Fortune (Pars Fortunae / Lot of Fortune).
|
|
38
|
+
|
|
39
|
+
The most important Arabic Part, representing body, health, and material fortune.
|
|
40
|
+
|
|
41
|
+
Formula (Vettius Valens, Al-Biruni):
|
|
42
|
+
- Day chart (Sun above horizon): ASC + Moon - Sun
|
|
43
|
+
- Night chart (Sun below horizon): ASC + Sun - Moon
|
|
44
|
+
|
|
45
|
+
Args:
|
|
46
|
+
asc: Ascendant (ecliptic) longitude in degrees
|
|
47
|
+
sun: Sun ecliptic longitude in degrees
|
|
48
|
+
moon: Moon ecliptic longitude in degrees
|
|
49
|
+
is_diurnal: True if day chart (Sun above horizon), False if night
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
float: Part of Fortune ecliptic longitude in degrees (0-360)
|
|
53
|
+
|
|
54
|
+
Note:
|
|
55
|
+
The formula reflects sect: in day charts, emphasize the Moon (nocturnal);
|
|
56
|
+
in night charts, emphasize the Sun (diurnal). This balances opposites.
|
|
57
|
+
|
|
58
|
+
Some modern astrologers use only the day formula regardless of sect.
|
|
59
|
+
This implementation follows classical tradition.
|
|
60
|
+
"""
|
|
61
|
+
if is_diurnal:
|
|
62
|
+
lot = (asc + moon - sun) % 360.0
|
|
63
|
+
else:
|
|
64
|
+
lot = (asc + sun - moon) % 360.0
|
|
65
|
+
|
|
66
|
+
return lot
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def calc_arabic_part_of_spirit(
|
|
70
|
+
asc: float, sun: float, moon: float, is_diurnal: bool = True
|
|
71
|
+
) -> float:
|
|
72
|
+
"""
|
|
73
|
+
Calculate Part of Spirit (Pars Spiritus / Lot of Spirit / Daimon).
|
|
74
|
+
|
|
75
|
+
Represents the soul, intellect, character, and spiritual development.
|
|
76
|
+
|
|
77
|
+
Formula (opposite of Part of Fortune by sect):
|
|
78
|
+
- Day chart: ASC + Sun - Moon
|
|
79
|
+
- Night chart: ASC + Moon - Sun
|
|
80
|
+
|
|
81
|
+
Args:
|
|
82
|
+
asc: Ascendant longitude in degrees
|
|
83
|
+
sun: Sun longitude in degrees
|
|
84
|
+
moon: Moon longitude in degrees
|
|
85
|
+
is_diurnal: True if day chart
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
float: Part of Spirit longitude in degrees (0-360)
|
|
89
|
+
|
|
90
|
+
Note:
|
|
91
|
+
In Hellenistic astrology (Valens), Part of Spirit was called "Daimon"
|
|
92
|
+
and considered complementary to Fortune. Together they represent
|
|
93
|
+
body (Fortune) and soul (Spirit).
|
|
94
|
+
"""
|
|
95
|
+
if is_diurnal:
|
|
96
|
+
lot = (asc + sun - moon) % 360.0
|
|
97
|
+
else:
|
|
98
|
+
lot = (asc + moon - sun) % 360.0
|
|
99
|
+
|
|
100
|
+
return lot
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def calc_arabic_part_of_love(asc: float, venus: float, sun: float) -> float:
|
|
104
|
+
"""
|
|
105
|
+
Calculate Part of Love (Pars Amoris / Lot of Eros).
|
|
106
|
+
|
|
107
|
+
Represents romantic love, desire, sexual attraction, and relationships.
|
|
108
|
+
|
|
109
|
+
Formula: ASC + Venus - Sun
|
|
110
|
+
|
|
111
|
+
Args:
|
|
112
|
+
asc: Ascendant longitude in degrees
|
|
113
|
+
venus: Venus longitude in degrees
|
|
114
|
+
sun: Sun longitude in degrees
|
|
115
|
+
|
|
116
|
+
Returns:
|
|
117
|
+
float: Part of Love longitude in degrees (0-360)
|
|
118
|
+
|
|
119
|
+
Note:
|
|
120
|
+
This formula is not sect-dependent. Venus naturally signifies
|
|
121
|
+
love and attraction in all charts. Some medieval sources use
|
|
122
|
+
alternate formulas with Moon or Mars for male/female charts.
|
|
123
|
+
"""
|
|
124
|
+
return (asc + venus - sun) % 360.0
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def calc_arabic_part_of_faith(asc: float, mercury: float, moon: float) -> float:
|
|
128
|
+
"""
|
|
129
|
+
Calculate Part of Faith (Pars Fidei / Lot of Faith).
|
|
130
|
+
|
|
131
|
+
Represents religious belief, trust, philosophical convictions.
|
|
132
|
+
|
|
133
|
+
Formula: ASC + Mercury - Moon
|
|
134
|
+
|
|
135
|
+
Args:
|
|
136
|
+
asc: Ascendant longitude in degrees
|
|
137
|
+
mercury: Mercury longitude in degrees
|
|
138
|
+
moon: Moon longitude in degrees
|
|
139
|
+
|
|
140
|
+
Returns:
|
|
141
|
+
float: Part of Faith longitude in degrees (0-360)
|
|
142
|
+
|
|
143
|
+
Note:
|
|
144
|
+
Mercury represents rational thought and communication of beliefs.
|
|
145
|
+
The Moon represents unconscious reception and emotional faith.
|
|
146
|
+
This part shows how one's beliefs are communicated/manifested.
|
|
147
|
+
"""
|
|
148
|
+
return (asc + mercury - moon) % 360.0
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def is_day_chart(sun_lon: float, asc: float) -> bool:
|
|
152
|
+
"""
|
|
153
|
+
Determine if chart is diurnal (day) or nocturnal (night) based on sect.
|
|
154
|
+
|
|
155
|
+
A chart is diurnal if the Sun is above the horizon (in houses 7-12).
|
|
156
|
+
|
|
157
|
+
Args:
|
|
158
|
+
sun_lon: Sun ecliptic longitude in degrees (0-360)
|
|
159
|
+
asc: Ascendant ecliptic longitude in degrees (0-360)
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
bool: True if day chart (Sun above horizon), False if night chart
|
|
163
|
+
|
|
164
|
+
Algorithm:
|
|
165
|
+
The horizon runs from Ascendant (east) to Descendant (west).
|
|
166
|
+
Points between ASC and DSC (going counter-clockwise through MC)
|
|
167
|
+
are above the horizon. This is the zodiacal arc from ASC to ASC+180°.
|
|
168
|
+
|
|
169
|
+
Note:
|
|
170
|
+
This is a simplified 2D calculation using ecliptic longitude only.
|
|
171
|
+
It assumes the horizon plane intersects the ecliptic at ASC/DSC.
|
|
172
|
+
|
|
173
|
+
For extreme latitudes or precise calculations, use 3D horizon
|
|
174
|
+
coordinates (altitude/azimuth). This method is traditional and
|
|
175
|
+
sufficient for most astrological purposes.
|
|
176
|
+
"""
|
|
177
|
+
desc = (asc + 180.0) % 360.0
|
|
178
|
+
|
|
179
|
+
# Check if Sun is in upper hemisphere (ASC to DSC counter-clockwise)
|
|
180
|
+
if asc < desc:
|
|
181
|
+
# Normal case: e.g., ASC=0°, DSC=180°
|
|
182
|
+
return asc <= sun_lon <= desc
|
|
183
|
+
else:
|
|
184
|
+
# Wrapped case: e.g., ASC=350°, DSC=170°
|
|
185
|
+
# Sun is above if >= ASC (e.g., 350-360°) OR <= DSC (e.g., 0-170°)
|
|
186
|
+
return sun_lon >= asc or sun_lon <= desc
|
|
187
|
+
|
|
188
|
+
|
|
189
|
+
def calc_all_arabic_parts(positions: Dict[str, float]) -> Dict[str, float]:
|
|
190
|
+
"""
|
|
191
|
+
Calculate all standard Arabic parts from a position dictionary.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
positions: Dictionary of celestial positions in ecliptic longitude degrees.
|
|
195
|
+
Required keys: 'Asc', 'Sun', 'Moon', 'Mercury', 'Venus'
|
|
196
|
+
All values should be in range 0-360 degrees.
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
Dict[str, float]: Dictionary mapping part names to longitudes:
|
|
200
|
+
- "Pars_Fortunae": Part of Fortune
|
|
201
|
+
- "Pars_Spiritus": Part of Spirit
|
|
202
|
+
- "Pars_Amoris": Part of Love
|
|
203
|
+
- "Pars_Fidei": Part of Faith
|
|
204
|
+
|
|
205
|
+
Example:
|
|
206
|
+
>>> positions = {
|
|
207
|
+
... 'Asc': 15.5, 'Sun': 120.0, 'Moon': 240.0,
|
|
208
|
+
... 'Mercury': 130.0, 'Venus': 110.0
|
|
209
|
+
... }
|
|
210
|
+
>>> parts = calc_all_arabic_parts(positions)
|
|
211
|
+
>>> print(parts['Pars_Fortunae'])
|
|
212
|
+
135.5
|
|
213
|
+
|
|
214
|
+
Note:
|
|
215
|
+
Missing keys will default to 0.0. Ensure all required positions
|
|
216
|
+
are present for accurate results.
|
|
217
|
+
"""
|
|
218
|
+
asc = positions.get("Asc", 0.0)
|
|
219
|
+
sun = positions.get("Sun", 0.0)
|
|
220
|
+
moon = positions.get("Moon", 0.0)
|
|
221
|
+
mercury = positions.get("Mercury", 0.0)
|
|
222
|
+
venus = positions.get("Venus", 0.0)
|
|
223
|
+
|
|
224
|
+
is_diurnal = is_day_chart(sun, asc)
|
|
225
|
+
|
|
226
|
+
return {
|
|
227
|
+
"Pars_Fortunae": calc_arabic_part_of_fortune(asc, sun, moon, is_diurnal),
|
|
228
|
+
"Pars_Spiritus": calc_arabic_part_of_spirit(asc, sun, moon, is_diurnal),
|
|
229
|
+
"Pars_Amoris": calc_arabic_part_of_love(asc, venus, sun),
|
|
230
|
+
"Pars_Fidei": calc_arabic_part_of_faith(asc, mercury, moon),
|
|
231
|
+
}
|
|
232
|
+
|