kerykeion 5.0.0a12__py3-none-any.whl → 5.0.0b1__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.
Potentially problematic release.
This version of kerykeion might be problematic. Click here for more details.
- kerykeion/__init__.py +30 -6
- kerykeion/aspects/aspects_factory.py +40 -24
- kerykeion/aspects/aspects_utils.py +75 -6
- kerykeion/astrological_subject_factory.py +377 -226
- kerykeion/backword.py +680 -0
- kerykeion/chart_data_factory.py +484 -0
- kerykeion/charts/{kerykeion_chart_svg.py → chart_drawer.py} +612 -438
- kerykeion/charts/charts_utils.py +135 -94
- kerykeion/charts/draw_planets.py +38 -28
- kerykeion/charts/templates/aspect_grid_only.xml +188 -17
- kerykeion/charts/templates/chart.xml +104 -28
- kerykeion/charts/templates/wheel_only.xml +195 -24
- kerykeion/charts/themes/classic.css +11 -0
- kerykeion/charts/themes/dark-high-contrast.css +11 -0
- kerykeion/charts/themes/dark.css +11 -0
- kerykeion/charts/themes/light.css +11 -0
- kerykeion/charts/themes/strawberry.css +10 -0
- kerykeion/composite_subject_factory.py +4 -4
- kerykeion/ephemeris_data_factory.py +12 -9
- kerykeion/house_comparison/__init__.py +0 -3
- kerykeion/house_comparison/house_comparison_factory.py +3 -3
- kerykeion/house_comparison/house_comparison_utils.py +3 -4
- kerykeion/planetary_return_factory.py +8 -4
- kerykeion/relationship_score_factory.py +3 -3
- kerykeion/report.py +748 -67
- kerykeion/{kr_types → schemas}/__init__.py +44 -4
- kerykeion/schemas/chart_template_model.py +340 -0
- kerykeion/{kr_types → schemas}/kr_literals.py +7 -3
- kerykeion/{kr_types → schemas}/kr_models.py +220 -11
- kerykeion/{kr_types → schemas}/settings_models.py +7 -7
- kerykeion/settings/config_constants.py +75 -8
- kerykeion/settings/kerykeion_settings.py +1 -1
- kerykeion/settings/kr.config.json +130 -40
- kerykeion/settings/legacy/legacy_celestial_points_settings.py +8 -8
- kerykeion/sweph/ast136/s136108s.se1 +0 -0
- kerykeion/sweph/ast136/s136199s.se1 +0 -0
- kerykeion/sweph/ast136/s136472s.se1 +0 -0
- kerykeion/sweph/ast28/se28978s.se1 +0 -0
- kerykeion/sweph/ast50/se50000s.se1 +0 -0
- kerykeion/sweph/ast90/se90377s.se1 +0 -0
- kerykeion/sweph/ast90/se90482s.se1 +0 -0
- kerykeion/transits_time_range_factory.py +7 -7
- kerykeion/utilities.py +61 -38
- {kerykeion-5.0.0a12.dist-info → kerykeion-5.0.0b1.dist-info}/METADATA +507 -120
- kerykeion-5.0.0b1.dist-info/RECORD +58 -0
- kerykeion/house_comparison/house_comparison_models.py +0 -76
- kerykeion/kr_types/chart_types.py +0 -106
- kerykeion-5.0.0a12.dist-info/RECORD +0 -50
- /kerykeion/{kr_types → schemas}/kerykeion_exception.py +0 -0
- {kerykeion-5.0.0a12.dist-info → kerykeion-5.0.0b1.dist-info}/WHEEL +0 -0
- {kerykeion-5.0.0a12.dist-info → kerykeion-5.0.0b1.dist-info}/licenses/LICENSE +0 -0
|
@@ -38,10 +38,11 @@ from datetime import datetime
|
|
|
38
38
|
from pathlib import Path
|
|
39
39
|
from typing import Optional, List, Dict, Any, get_args, cast
|
|
40
40
|
from dataclasses import dataclass, field
|
|
41
|
+
from contextlib import contextmanager
|
|
41
42
|
|
|
42
43
|
|
|
43
44
|
from kerykeion.fetch_geonames import FetchGeonames
|
|
44
|
-
from kerykeion.
|
|
45
|
+
from kerykeion.schemas import (
|
|
45
46
|
KerykeionException,
|
|
46
47
|
ZodiacType,
|
|
47
48
|
AstrologicalSubjectModel,
|
|
@@ -81,8 +82,60 @@ GEONAMES_DEFAULT_USERNAME_WARNING = (
|
|
|
81
82
|
"********"
|
|
82
83
|
)
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
85
|
+
@contextmanager
|
|
86
|
+
def ephemeris_context(
|
|
87
|
+
ephe_path: str,
|
|
88
|
+
config: "ChartConfiguration",
|
|
89
|
+
lng: float,
|
|
90
|
+
lat: float,
|
|
91
|
+
alt: Optional[float] = None,
|
|
92
|
+
):
|
|
93
|
+
"""Context manager that isolates Swiss Ephemeris configuration.
|
|
94
|
+
|
|
95
|
+
Responsibilities:
|
|
96
|
+
- Set ephemeris path and calculation flags
|
|
97
|
+
- Configure perspective (true geo / helio / topo)
|
|
98
|
+
- Configure sidereal mode when needed
|
|
99
|
+
- Apply topocentric observer only inside the with-block
|
|
100
|
+
- Yield iflag for calculations
|
|
101
|
+
- Reset topocentric coordinates afterward (defensive)
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
ephe_path: Path containing Swiss Ephemeris data files.
|
|
105
|
+
config: Validated chart configuration.
|
|
106
|
+
lng: Observer longitude (used for topocentric charts).
|
|
107
|
+
lat: Observer latitude (used for topocentric charts).
|
|
108
|
+
alt: Observer altitude (meters) for topocentric charts.
|
|
109
|
+
|
|
110
|
+
Yields:
|
|
111
|
+
int: iflag to be passed to swe.calc_ut / swe.fixstar_ut.
|
|
112
|
+
"""
|
|
113
|
+
swe.set_ephe_path(ephe_path)
|
|
114
|
+
iflag = swe.FLG_SWIEPH | swe.FLG_SPEED
|
|
115
|
+
|
|
116
|
+
topo_used = False
|
|
117
|
+
|
|
118
|
+
# Perspective configuration
|
|
119
|
+
if config.perspective_type == "True Geocentric":
|
|
120
|
+
iflag |= swe.FLG_TRUEPOS
|
|
121
|
+
elif config.perspective_type == "Heliocentric":
|
|
122
|
+
iflag |= swe.FLG_HELCTR
|
|
123
|
+
elif config.perspective_type == "Topocentric":
|
|
124
|
+
iflag |= swe.FLG_TOPOCTR
|
|
125
|
+
swe.set_topo(lng, lat, alt or 0.0)
|
|
126
|
+
topo_used = True
|
|
127
|
+
|
|
128
|
+
# Sidereal configuration
|
|
129
|
+
if config.zodiac_type == "Sidereal":
|
|
130
|
+
iflag |= swe.FLG_SIDEREAL
|
|
131
|
+
swe.set_sid_mode(getattr(swe, f"SIDM_{config.sidereal_mode}"))
|
|
132
|
+
|
|
133
|
+
try:
|
|
134
|
+
yield iflag
|
|
135
|
+
finally:
|
|
136
|
+
# Defensive cleanup: reset topo if it was set
|
|
137
|
+
if topo_used:
|
|
138
|
+
swe.set_topo(0.0, 0.0, 0.0)
|
|
86
139
|
|
|
87
140
|
@dataclass
|
|
88
141
|
class ChartConfiguration:
|
|
@@ -118,13 +171,15 @@ class ChartConfiguration:
|
|
|
118
171
|
... houses_system_identifier="K",
|
|
119
172
|
... perspective_type="Topocentric"
|
|
120
173
|
... )
|
|
121
|
-
>>> config.validate()
|
|
122
174
|
"""
|
|
123
175
|
zodiac_type: ZodiacType = DEFAULT_ZODIAC_TYPE
|
|
124
176
|
sidereal_mode: Optional[SiderealMode] = None
|
|
125
177
|
houses_system_identifier: HousesSystemIdentifier = DEFAULT_HOUSES_SYSTEM_IDENTIFIER
|
|
126
178
|
perspective_type: PerspectiveType = DEFAULT_PERSPECTIVE_TYPE
|
|
127
179
|
|
|
180
|
+
def __post_init__(self) -> None:
|
|
181
|
+
self.validate()
|
|
182
|
+
|
|
128
183
|
def validate(self) -> None:
|
|
129
184
|
"""
|
|
130
185
|
Validate configuration settings for internal consistency.
|
|
@@ -364,11 +419,11 @@ class AstrologicalSubjectFactory:
|
|
|
364
419
|
def from_birth_data(
|
|
365
420
|
cls,
|
|
366
421
|
name: str = "Now",
|
|
367
|
-
year: int =
|
|
368
|
-
month: int =
|
|
369
|
-
day: int =
|
|
370
|
-
hour: int =
|
|
371
|
-
minute: int =
|
|
422
|
+
year: Optional[int] = None,
|
|
423
|
+
month: Optional[int] = None,
|
|
424
|
+
day: Optional[int] = None,
|
|
425
|
+
hour: Optional[int] = None,
|
|
426
|
+
minute: Optional[int] = None,
|
|
372
427
|
city: Optional[str] = None,
|
|
373
428
|
nation: Optional[str] = None,
|
|
374
429
|
lng: Optional[float] = None,
|
|
@@ -383,10 +438,11 @@ class AstrologicalSubjectFactory:
|
|
|
383
438
|
cache_expire_after_days: int = DEFAULT_GEONAMES_CACHE_EXPIRE_AFTER_DAYS,
|
|
384
439
|
is_dst: Optional[bool] = None,
|
|
385
440
|
altitude: Optional[float] = None,
|
|
386
|
-
active_points: List[AstrologicalPoint] =
|
|
441
|
+
active_points: Optional[List[AstrologicalPoint]] = None,
|
|
387
442
|
calculate_lunar_phase: bool = True,
|
|
388
443
|
*,
|
|
389
444
|
seconds: int = 0,
|
|
445
|
+
suppress_geonames_warning: bool = False,
|
|
390
446
|
|
|
391
447
|
) -> AstrologicalSubjectModel:
|
|
392
448
|
"""
|
|
@@ -440,11 +496,14 @@ class AstrologicalSubjectFactory:
|
|
|
440
496
|
altitude (float, optional): Altitude above sea level in meters. Used for
|
|
441
497
|
topocentric calculations and atmospheric corrections. Defaults to None
|
|
442
498
|
(sea level assumed).
|
|
443
|
-
active_points (List[AstrologicalPoint], optional): List of astrological
|
|
499
|
+
active_points (Optional[List[AstrologicalPoint]], optional): List of astrological
|
|
444
500
|
points to calculate. Omitting points can improve performance for
|
|
445
|
-
specialized applications.
|
|
501
|
+
specialized applications. If None, uses DEFAULT_ACTIVE_POINTS.
|
|
446
502
|
calculate_lunar_phase (bool, optional): Whether to calculate lunar phase.
|
|
447
503
|
Requires Sun and Moon in active_points. Defaults to True.
|
|
504
|
+
suppress_geonames_warning (bool, optional): If True, suppresses the warning
|
|
505
|
+
message when using the default GeoNames username. Useful for testing
|
|
506
|
+
or automated processes. Defaults to False.
|
|
448
507
|
|
|
449
508
|
Returns:
|
|
450
509
|
AstrologicalSubjectModel: Complete astrological subject with calculated
|
|
@@ -495,17 +554,30 @@ class AstrologicalSubjectFactory:
|
|
|
495
554
|
- The method handles polar regions by adjusting extreme latitudes
|
|
496
555
|
- Time zones are handled with full DST awareness via pytz
|
|
497
556
|
"""
|
|
557
|
+
# Resolve time defaults using current time
|
|
558
|
+
if year is None or month is None or day is None or hour is None or minute is None or seconds is None:
|
|
559
|
+
now = datetime.now()
|
|
560
|
+
year = year if year is not None else now.year
|
|
561
|
+
month = month if month is not None else now.month
|
|
562
|
+
day = day if day is not None else now.day
|
|
563
|
+
hour = hour if hour is not None else now.hour
|
|
564
|
+
minute = minute if minute is not None else now.minute
|
|
565
|
+
seconds = seconds if seconds is not None else now.second
|
|
566
|
+
|
|
498
567
|
# Create a calculation data container
|
|
499
|
-
calc_data = {}
|
|
568
|
+
calc_data: Dict[str, Any] = {}
|
|
500
569
|
|
|
501
570
|
# Basic identity
|
|
502
571
|
calc_data["name"] = name
|
|
503
572
|
calc_data["json_dir"] = str(Path.home())
|
|
504
573
|
|
|
505
574
|
# Create a deep copy of active points to avoid modifying the original list
|
|
506
|
-
active_points
|
|
575
|
+
if active_points is None:
|
|
576
|
+
active_points_list: List[AstrologicalPoint] = list(DEFAULT_ACTIVE_POINTS)
|
|
577
|
+
else:
|
|
578
|
+
active_points_list = list(active_points)
|
|
507
579
|
|
|
508
|
-
calc_data["active_points"] =
|
|
580
|
+
calc_data["active_points"] = active_points_list
|
|
509
581
|
|
|
510
582
|
# Initialize configuration
|
|
511
583
|
config = ChartConfiguration(
|
|
@@ -514,7 +586,6 @@ class AstrologicalSubjectFactory:
|
|
|
514
586
|
houses_system_identifier=houses_system_identifier,
|
|
515
587
|
perspective_type=perspective_type,
|
|
516
588
|
)
|
|
517
|
-
config.validate()
|
|
518
589
|
|
|
519
590
|
# Add configuration data to calculation data
|
|
520
591
|
calc_data["zodiac_type"] = config.zodiac_type
|
|
@@ -524,7 +595,8 @@ class AstrologicalSubjectFactory:
|
|
|
524
595
|
|
|
525
596
|
# Set up geonames username if needed
|
|
526
597
|
if geonames_username is None and online and (not lat or not lng or not tz_str):
|
|
527
|
-
|
|
598
|
+
if not suppress_geonames_warning:
|
|
599
|
+
logging.warning(GEONAMES_DEFAULT_USERNAME_WARNING)
|
|
528
600
|
geonames_username = DEFAULT_GEONAMES_USERNAME
|
|
529
601
|
|
|
530
602
|
# Initialize location data
|
|
@@ -571,20 +643,37 @@ class AstrologicalSubjectFactory:
|
|
|
571
643
|
calc_data["is_dst"] = is_dst
|
|
572
644
|
|
|
573
645
|
# Calculate time conversions
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
646
|
+
AstrologicalSubjectFactory._calculate_time_conversions(calc_data, location)
|
|
647
|
+
# Initialize Swiss Ephemeris and calculate houses and planets with context manager
|
|
648
|
+
ephe_path = str(Path(__file__).parent.absolute() / "sweph")
|
|
649
|
+
with ephemeris_context(
|
|
650
|
+
ephe_path=ephe_path,
|
|
651
|
+
config=config,
|
|
652
|
+
lng=calc_data["lng"],
|
|
653
|
+
lat=calc_data["lat"],
|
|
654
|
+
alt=calc_data["altitude"],
|
|
655
|
+
) as iflag:
|
|
656
|
+
calc_data["_iflag"] = iflag
|
|
657
|
+
# House system name (previously set in _setup_ephemeris)
|
|
658
|
+
calc_data["houses_system_name"] = swe.house_name(
|
|
659
|
+
config.houses_system_identifier.encode("ascii")
|
|
660
|
+
)
|
|
661
|
+
calculated_axial_cusps = AstrologicalSubjectFactory._calculate_houses(
|
|
662
|
+
calc_data, active_points_list
|
|
663
|
+
)
|
|
664
|
+
AstrologicalSubjectFactory._calculate_planets(
|
|
665
|
+
calc_data, active_points_list, calculated_axial_cusps
|
|
666
|
+
)
|
|
667
|
+
AstrologicalSubjectFactory._calculate_day_of_week(calc_data)
|
|
581
668
|
|
|
582
669
|
# Calculate lunar phase (optional - only if requested and Sun and Moon are available)
|
|
583
670
|
if calculate_lunar_phase and "moon" in calc_data and "sun" in calc_data:
|
|
584
671
|
calc_data["lunar_phase"] = calculate_moon_phase(
|
|
585
|
-
calc_data["moon"].abs_pos,
|
|
586
|
-
calc_data["sun"].abs_pos
|
|
672
|
+
calc_data["moon"].abs_pos, # type: ignore[attr-defined,union-attr]
|
|
673
|
+
calc_data["sun"].abs_pos # type: ignore[attr-defined,union-attr]
|
|
587
674
|
)
|
|
675
|
+
else:
|
|
676
|
+
calc_data["lunar_phase"] = None
|
|
588
677
|
|
|
589
678
|
# Create and return the AstrologicalSubjectModel
|
|
590
679
|
return AstrologicalSubjectModel(**calc_data)
|
|
@@ -606,8 +695,9 @@ class AstrologicalSubjectFactory:
|
|
|
606
695
|
houses_system_identifier: HousesSystemIdentifier = DEFAULT_HOUSES_SYSTEM_IDENTIFIER,
|
|
607
696
|
perspective_type: PerspectiveType = DEFAULT_PERSPECTIVE_TYPE,
|
|
608
697
|
altitude: Optional[float] = None,
|
|
609
|
-
active_points: List[AstrologicalPoint] =
|
|
610
|
-
calculate_lunar_phase: bool = True
|
|
698
|
+
active_points: Optional[List[AstrologicalPoint]] = None,
|
|
699
|
+
calculate_lunar_phase: bool = True,
|
|
700
|
+
suppress_geonames_warning: bool = False
|
|
611
701
|
) -> AstrologicalSubjectModel:
|
|
612
702
|
"""
|
|
613
703
|
Create an astrological subject from an ISO formatted UTC timestamp.
|
|
@@ -645,8 +735,8 @@ class AstrologicalSubjectFactory:
|
|
|
645
735
|
Defaults to 'Apparent Geocentric'.
|
|
646
736
|
altitude (float, optional): Altitude in meters for topocentric calculations.
|
|
647
737
|
Defaults to None (sea level).
|
|
648
|
-
active_points (List[AstrologicalPoint], optional): Points to calculate.
|
|
649
|
-
|
|
738
|
+
active_points (Optional[List[AstrologicalPoint]], optional): Points to calculate.
|
|
739
|
+
If None, uses DEFAULT_ACTIVE_POINTS.
|
|
650
740
|
calculate_lunar_phase (bool, optional): Whether to calculate lunar phase.
|
|
651
741
|
Defaults to True.
|
|
652
742
|
|
|
@@ -689,7 +779,8 @@ class AstrologicalSubjectFactory:
|
|
|
689
779
|
# Get location data if online mode is enabled
|
|
690
780
|
if online:
|
|
691
781
|
if geonames_username == DEFAULT_GEONAMES_USERNAME:
|
|
692
|
-
|
|
782
|
+
if not suppress_geonames_warning:
|
|
783
|
+
logging.warning(GEONAMES_DEFAULT_USERNAME_WARNING)
|
|
693
784
|
|
|
694
785
|
geonames = FetchGeonames(
|
|
695
786
|
city,
|
|
@@ -727,7 +818,8 @@ class AstrologicalSubjectFactory:
|
|
|
727
818
|
perspective_type=perspective_type,
|
|
728
819
|
altitude=altitude,
|
|
729
820
|
active_points=active_points,
|
|
730
|
-
calculate_lunar_phase=calculate_lunar_phase
|
|
821
|
+
calculate_lunar_phase=calculate_lunar_phase,
|
|
822
|
+
suppress_geonames_warning=suppress_geonames_warning
|
|
731
823
|
)
|
|
732
824
|
|
|
733
825
|
@classmethod
|
|
@@ -745,8 +837,9 @@ class AstrologicalSubjectFactory:
|
|
|
745
837
|
sidereal_mode: Optional[SiderealMode] = None,
|
|
746
838
|
houses_system_identifier: HousesSystemIdentifier = DEFAULT_HOUSES_SYSTEM_IDENTIFIER,
|
|
747
839
|
perspective_type: PerspectiveType = DEFAULT_PERSPECTIVE_TYPE,
|
|
748
|
-
active_points: List[AstrologicalPoint] =
|
|
749
|
-
calculate_lunar_phase: bool = True
|
|
840
|
+
active_points: Optional[List[AstrologicalPoint]] = None,
|
|
841
|
+
calculate_lunar_phase: bool = True,
|
|
842
|
+
suppress_geonames_warning: bool = False
|
|
750
843
|
) -> AstrologicalSubjectModel:
|
|
751
844
|
"""
|
|
752
845
|
Create an astrological subject for the current moment in time.
|
|
@@ -780,8 +873,8 @@ class AstrologicalSubjectFactory:
|
|
|
780
873
|
system for calculations. Defaults to 'P' (Placidus).
|
|
781
874
|
perspective_type (PerspectiveType, optional): Calculation perspective.
|
|
782
875
|
Defaults to 'Apparent Geocentric'.
|
|
783
|
-
active_points (List[AstrologicalPoint], optional): Astrological points
|
|
784
|
-
to calculate.
|
|
876
|
+
active_points (Optional[List[AstrologicalPoint]], optional): Astrological points
|
|
877
|
+
to calculate. If None, uses DEFAULT_ACTIVE_POINTS.
|
|
785
878
|
calculate_lunar_phase (bool, optional): Whether to calculate lunar phase.
|
|
786
879
|
Defaults to True.
|
|
787
880
|
|
|
@@ -845,11 +938,12 @@ class AstrologicalSubjectFactory:
|
|
|
845
938
|
houses_system_identifier=houses_system_identifier,
|
|
846
939
|
perspective_type=perspective_type,
|
|
847
940
|
active_points=active_points,
|
|
848
|
-
calculate_lunar_phase=calculate_lunar_phase
|
|
941
|
+
calculate_lunar_phase=calculate_lunar_phase,
|
|
942
|
+
suppress_geonames_warning=suppress_geonames_warning
|
|
849
943
|
)
|
|
850
944
|
|
|
851
|
-
@
|
|
852
|
-
def _calculate_time_conversions(
|
|
945
|
+
@staticmethod
|
|
946
|
+
def _calculate_time_conversions(data: Dict[str, Any], location: LocationData) -> None:
|
|
853
947
|
"""
|
|
854
948
|
Calculate time conversions between local time, UTC, and Julian Day Number.
|
|
855
949
|
|
|
@@ -890,6 +984,11 @@ class AstrologicalSubjectFactory:
|
|
|
890
984
|
"Ambiguous time error! The time falls during a DST transition. "
|
|
891
985
|
"Please specify is_dst=True or is_dst=False to clarify."
|
|
892
986
|
)
|
|
987
|
+
except pytz.exceptions.NonExistentTimeError:
|
|
988
|
+
raise KerykeionException(
|
|
989
|
+
"Non-existent time error! The time does not exist due to DST transition (spring forward). "
|
|
990
|
+
"Please specify a valid time."
|
|
991
|
+
)
|
|
893
992
|
|
|
894
993
|
# Store formatted times
|
|
895
994
|
utc_datetime = local_datetime.astimezone(pytz.utc)
|
|
@@ -899,71 +998,9 @@ class AstrologicalSubjectFactory:
|
|
|
899
998
|
# Calculate Julian day
|
|
900
999
|
data["julian_day"] = datetime_to_julian(utc_datetime)
|
|
901
1000
|
|
|
902
|
-
@classmethod
|
|
903
|
-
def _setup_ephemeris(cls, data: Dict[str, Any], config: ChartConfiguration) -> None:
|
|
904
|
-
"""
|
|
905
|
-
Configure Swiss Ephemeris with appropriate calculation flags and settings.
|
|
906
|
-
|
|
907
|
-
Sets up the Swiss Ephemeris library with the correct ephemeris data path,
|
|
908
|
-
calculation flags for the specified perspective type, and sidereal mode
|
|
909
|
-
configuration if applicable.
|
|
910
1001
|
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
config (ChartConfiguration): Validated chart configuration settings.
|
|
914
|
-
|
|
915
|
-
Side Effects:
|
|
916
|
-
- Sets Swiss Ephemeris data path to bundled ephemeris files
|
|
917
|
-
- Configures calculation flags (SWIEPH, SPEED, perspective flags)
|
|
918
|
-
- Sets sidereal mode for sidereal zodiac calculations
|
|
919
|
-
- Sets topocentric observer coordinates for topocentric perspective
|
|
920
|
-
- Updates data dictionary with houses_system_name and _iflag
|
|
921
|
-
|
|
922
|
-
Calculation Flags Set:
|
|
923
|
-
- FLG_SWIEPH: Use Swiss Ephemeris data files
|
|
924
|
-
- FLG_SPEED: Calculate planetary velocities
|
|
925
|
-
- FLG_TRUEPOS: True geometric positions (True Geocentric)
|
|
926
|
-
- FLG_HELCTR: Heliocentric coordinates (Heliocentric perspective)
|
|
927
|
-
- FLG_TOPOCTR: Topocentric coordinates (Topocentric perspective)
|
|
928
|
-
- FLG_SIDEREAL: Sidereal calculations (Sidereal zodiac)
|
|
929
|
-
|
|
930
|
-
Note:
|
|
931
|
-
The method assumes the Swiss Ephemeris data files are located in the
|
|
932
|
-
'sweph' subdirectory relative to this module. For topocentric calculations,
|
|
933
|
-
observer coordinates must be set via longitude, latitude, and altitude.
|
|
934
|
-
"""
|
|
935
|
-
# Set ephemeris path
|
|
936
|
-
swe.set_ephe_path(str(Path(__file__).parent.absolute() / "sweph"))
|
|
937
|
-
|
|
938
|
-
# Base flags
|
|
939
|
-
iflag = swe.FLG_SWIEPH + swe.FLG_SPEED
|
|
940
|
-
|
|
941
|
-
# Add perspective flags
|
|
942
|
-
if config.perspective_type == "True Geocentric":
|
|
943
|
-
iflag += swe.FLG_TRUEPOS
|
|
944
|
-
elif config.perspective_type == "Heliocentric":
|
|
945
|
-
iflag += swe.FLG_HELCTR
|
|
946
|
-
elif config.perspective_type == "Topocentric":
|
|
947
|
-
iflag += swe.FLG_TOPOCTR
|
|
948
|
-
# Set topocentric coordinates
|
|
949
|
-
swe.set_topo(data["lng"], data["lat"], data["altitude"] or 0)
|
|
950
|
-
|
|
951
|
-
# Add sidereal flag if needed
|
|
952
|
-
if config.zodiac_type == "Sidereal":
|
|
953
|
-
iflag += swe.FLG_SIDEREAL
|
|
954
|
-
# Set sidereal mode
|
|
955
|
-
mode = f"SIDM_{config.sidereal_mode}"
|
|
956
|
-
swe.set_sid_mode(getattr(swe, mode))
|
|
957
|
-
logging.debug(f"Using sidereal mode: {mode}")
|
|
958
|
-
|
|
959
|
-
# Save house system name and iflag for later use
|
|
960
|
-
data["houses_system_name"] = swe.house_name(
|
|
961
|
-
config.houses_system_identifier.encode('ascii')
|
|
962
|
-
)
|
|
963
|
-
data["_iflag"] = iflag
|
|
964
|
-
|
|
965
|
-
@classmethod
|
|
966
|
-
def _calculate_houses(cls, data: Dict[str, Any], active_points: Optional[List[AstrologicalPoint]]) -> None:
|
|
1002
|
+
@staticmethod
|
|
1003
|
+
def _calculate_houses(data: Dict[str, Any], active_points: Optional[List[AstrologicalPoint]]) -> List[AstrologicalPoint]:
|
|
967
1004
|
"""
|
|
968
1005
|
Calculate house cusps and angular points (Ascendant, MC, etc.).
|
|
969
1006
|
|
|
@@ -1004,7 +1041,7 @@ class AstrologicalSubjectFactory:
|
|
|
1004
1041
|
def should_calculate(point: AstrologicalPoint) -> bool:
|
|
1005
1042
|
return not active_points or point in active_points
|
|
1006
1043
|
# Track which axial cusps are actually calculated
|
|
1007
|
-
calculated_axial_cusps = []
|
|
1044
|
+
calculated_axial_cusps: List[AstrologicalPoint] = []
|
|
1008
1045
|
|
|
1009
1046
|
# Calculate houses based on zodiac type
|
|
1010
1047
|
if data["zodiac_type"] == "Sidereal":
|
|
@@ -1077,9 +1114,10 @@ class AstrologicalSubjectFactory:
|
|
|
1077
1114
|
data["imum_coeli"].retrograde = False
|
|
1078
1115
|
calculated_axial_cusps.append("Imum_Coeli")
|
|
1079
1116
|
|
|
1080
|
-
|
|
1117
|
+
return calculated_axial_cusps
|
|
1118
|
+
|
|
1119
|
+
@staticmethod
|
|
1081
1120
|
def _calculate_single_planet(
|
|
1082
|
-
cls,
|
|
1083
1121
|
data: Dict[str, Any],
|
|
1084
1122
|
planet_name: AstrologicalPoint,
|
|
1085
1123
|
planet_id: int,
|
|
@@ -1087,7 +1125,7 @@ class AstrologicalSubjectFactory:
|
|
|
1087
1125
|
iflag: int,
|
|
1088
1126
|
houses_degree_ut: List[float],
|
|
1089
1127
|
point_type: PointType,
|
|
1090
|
-
calculated_planets: List[
|
|
1128
|
+
calculated_planets: List[AstrologicalPoint],
|
|
1091
1129
|
active_points: List[AstrologicalPoint]
|
|
1092
1130
|
) -> None:
|
|
1093
1131
|
"""
|
|
@@ -1132,12 +1170,16 @@ class AstrologicalSubjectFactory:
|
|
|
1132
1170
|
component being negative (element index 3).
|
|
1133
1171
|
"""
|
|
1134
1172
|
try:
|
|
1135
|
-
# Calculate planet position using Swiss Ephemeris
|
|
1173
|
+
# Calculate planet position using Swiss Ephemeris (ecliptic coordinates)
|
|
1136
1174
|
planet_calc = swe.calc_ut(julian_day, planet_id, iflag)[0]
|
|
1137
1175
|
|
|
1176
|
+
# Get declination from equatorial coordinates
|
|
1177
|
+
planet_eq = swe.calc_ut(julian_day, planet_id, iflag | swe.FLG_EQUATORIAL)[0]
|
|
1178
|
+
declination = planet_eq[1] # Declination from equatorial coordinates
|
|
1179
|
+
|
|
1138
1180
|
# Create Kerykeion point from degree
|
|
1139
1181
|
data[planet_name.lower()] = get_kerykeion_point_from_degree(
|
|
1140
|
-
planet_calc[0], planet_name, point_type=point_type
|
|
1182
|
+
planet_calc[0], planet_name, point_type=point_type, speed=planet_calc[3], declination=declination
|
|
1141
1183
|
)
|
|
1142
1184
|
|
|
1143
1185
|
# Calculate house position
|
|
@@ -1154,8 +1196,8 @@ class AstrologicalSubjectFactory:
|
|
|
1154
1196
|
if planet_name in active_points:
|
|
1155
1197
|
active_points.remove(planet_name)
|
|
1156
1198
|
|
|
1157
|
-
@
|
|
1158
|
-
def _calculate_planets(
|
|
1199
|
+
@staticmethod
|
|
1200
|
+
def _calculate_planets(data: Dict[str, Any], active_points: List[AstrologicalPoint], calculated_axial_cusps: Optional[List[AstrologicalPoint]] = None) -> None:
|
|
1159
1201
|
"""
|
|
1160
1202
|
Calculate positions for all requested celestial bodies and special points.
|
|
1161
1203
|
|
|
@@ -1248,7 +1290,7 @@ class AstrologicalSubjectFactory:
|
|
|
1248
1290
|
houses_degree_ut = data["_houses_degree_ut"]
|
|
1249
1291
|
|
|
1250
1292
|
# Track which planets are actually calculated
|
|
1251
|
-
calculated_planets = []
|
|
1293
|
+
calculated_planets: List[AstrologicalPoint] = []
|
|
1252
1294
|
|
|
1253
1295
|
# ==================
|
|
1254
1296
|
# MAIN PLANETS
|
|
@@ -1256,75 +1298,87 @@ class AstrologicalSubjectFactory:
|
|
|
1256
1298
|
|
|
1257
1299
|
# Calculate Sun
|
|
1258
1300
|
if should_calculate("Sun"):
|
|
1259
|
-
|
|
1301
|
+
AstrologicalSubjectFactory._calculate_single_planet(data, "Sun", 0, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
1260
1302
|
|
|
1261
1303
|
# Calculate Moon
|
|
1262
1304
|
if should_calculate("Moon"):
|
|
1263
|
-
|
|
1305
|
+
AstrologicalSubjectFactory._calculate_single_planet(data, "Moon", 1, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
1264
1306
|
|
|
1265
1307
|
# Calculate Mercury
|
|
1266
1308
|
if should_calculate("Mercury"):
|
|
1267
|
-
|
|
1309
|
+
AstrologicalSubjectFactory._calculate_single_planet(data, "Mercury", 2, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
1268
1310
|
|
|
1269
1311
|
# Calculate Venus
|
|
1270
1312
|
if should_calculate("Venus"):
|
|
1271
|
-
|
|
1313
|
+
AstrologicalSubjectFactory._calculate_single_planet(data, "Venus", 3, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
1272
1314
|
|
|
1273
1315
|
# Calculate Mars
|
|
1274
1316
|
if should_calculate("Mars"):
|
|
1275
|
-
|
|
1317
|
+
AstrologicalSubjectFactory._calculate_single_planet(data, "Mars", 4, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
1276
1318
|
|
|
1277
1319
|
# Calculate Jupiter
|
|
1278
1320
|
if should_calculate("Jupiter"):
|
|
1279
|
-
|
|
1321
|
+
AstrologicalSubjectFactory._calculate_single_planet(data, "Jupiter", 5, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
1280
1322
|
|
|
1281
1323
|
# Calculate Saturn
|
|
1282
1324
|
if should_calculate("Saturn"):
|
|
1283
|
-
|
|
1325
|
+
AstrologicalSubjectFactory._calculate_single_planet(data, "Saturn", 6, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
1284
1326
|
|
|
1285
1327
|
# Calculate Uranus
|
|
1286
1328
|
if should_calculate("Uranus"):
|
|
1287
|
-
|
|
1329
|
+
AstrologicalSubjectFactory._calculate_single_planet(data, "Uranus", 7, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
1288
1330
|
|
|
1289
1331
|
# Calculate Neptune
|
|
1290
1332
|
if should_calculate("Neptune"):
|
|
1291
|
-
|
|
1333
|
+
AstrologicalSubjectFactory._calculate_single_planet(data, "Neptune", 8, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
1292
1334
|
|
|
1293
1335
|
# Calculate Pluto
|
|
1294
1336
|
if should_calculate("Pluto"):
|
|
1295
|
-
|
|
1337
|
+
AstrologicalSubjectFactory._calculate_single_planet(data, "Pluto", 9, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
1296
1338
|
|
|
1297
1339
|
# ==================
|
|
1298
1340
|
# LUNAR NODES
|
|
1299
1341
|
# ==================
|
|
1300
1342
|
|
|
1301
|
-
# Calculate Mean Lunar Node
|
|
1302
|
-
if should_calculate("
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
# Calculate
|
|
1310
|
-
if should_calculate("
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1343
|
+
# Calculate Mean North Lunar Node
|
|
1344
|
+
if should_calculate("Mean_North_Lunar_Node"):
|
|
1345
|
+
AstrologicalSubjectFactory._calculate_single_planet(data, "Mean_North_Lunar_Node", 10, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
1346
|
+
# Get correct declination using equatorial coordinates
|
|
1347
|
+
if "mean_north_lunar_node" in data:
|
|
1348
|
+
mean_north_lunar_node_eq = swe.calc_ut(julian_day, 10, iflag | swe.FLG_EQUATORIAL)[0]
|
|
1349
|
+
data["mean_north_lunar_node"].declination = mean_north_lunar_node_eq[1] # Declination from equatorial coordinates
|
|
1350
|
+
|
|
1351
|
+
# Calculate True North Lunar Node
|
|
1352
|
+
if should_calculate("True_North_Lunar_Node"):
|
|
1353
|
+
AstrologicalSubjectFactory._calculate_single_planet(data, "True_North_Lunar_Node", 11, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
1354
|
+
# Get correct declination using equatorial coordinates
|
|
1355
|
+
if "true_north_lunar_node" in data:
|
|
1356
|
+
true_north_lunar_node_eq = swe.calc_ut(julian_day, 11, iflag | swe.FLG_EQUATORIAL)[0]
|
|
1357
|
+
data["true_north_lunar_node"].declination = true_north_lunar_node_eq[1] # Declination from equatorial coordinates
|
|
1358
|
+
|
|
1359
|
+
# Calculate Mean South Lunar Node (opposite to Mean North Lunar Node)
|
|
1360
|
+
if should_calculate("Mean_South_Lunar_Node") and "mean_north_lunar_node" in data:
|
|
1361
|
+
mean_south_lunar_node_deg = math.fmod(data["mean_north_lunar_node"].abs_pos + 180, 360)
|
|
1362
|
+
data["mean_south_lunar_node"] = get_kerykeion_point_from_degree(
|
|
1363
|
+
mean_south_lunar_node_deg, "Mean_South_Lunar_Node", point_type=point_type,
|
|
1364
|
+
speed=-data["mean_north_lunar_node"].speed if data["mean_north_lunar_node"].speed is not None else None,
|
|
1365
|
+
declination=-data["mean_north_lunar_node"].declination if data["mean_north_lunar_node"].declination is not None else None
|
|
1314
1366
|
)
|
|
1315
|
-
data["
|
|
1316
|
-
data["
|
|
1317
|
-
calculated_planets.append("
|
|
1318
|
-
|
|
1319
|
-
# Calculate True South Node (opposite to True North Node)
|
|
1320
|
-
if should_calculate("
|
|
1321
|
-
|
|
1322
|
-
data["
|
|
1323
|
-
|
|
1367
|
+
data["mean_south_lunar_node"].house = get_planet_house(mean_south_lunar_node_deg, houses_degree_ut)
|
|
1368
|
+
data["mean_south_lunar_node"].retrograde = data["mean_north_lunar_node"].retrograde
|
|
1369
|
+
calculated_planets.append("Mean_South_Lunar_Node")
|
|
1370
|
+
|
|
1371
|
+
# Calculate True South Lunar Node (opposite to True North Lunar Node)
|
|
1372
|
+
if should_calculate("True_South_Lunar_Node") and "true_north_lunar_node" in data:
|
|
1373
|
+
true_south_lunar_node_deg = math.fmod(data["true_north_lunar_node"].abs_pos + 180, 360)
|
|
1374
|
+
data["true_south_lunar_node"] = get_kerykeion_point_from_degree(
|
|
1375
|
+
true_south_lunar_node_deg, "True_South_Lunar_Node", point_type=point_type,
|
|
1376
|
+
speed=-data["true_north_lunar_node"].speed if data["true_north_lunar_node"].speed is not None else None,
|
|
1377
|
+
declination=-data["true_north_lunar_node"].declination if data["true_north_lunar_node"].declination is not None else None
|
|
1324
1378
|
)
|
|
1325
|
-
data["
|
|
1326
|
-
data["
|
|
1327
|
-
calculated_planets.append("
|
|
1379
|
+
data["true_south_lunar_node"].house = get_planet_house(true_south_lunar_node_deg, houses_degree_ut)
|
|
1380
|
+
data["true_south_lunar_node"].retrograde = data["true_north_lunar_node"].retrograde
|
|
1381
|
+
calculated_planets.append("True_South_Lunar_Node")
|
|
1328
1382
|
|
|
1329
1383
|
# ==================
|
|
1330
1384
|
# LILITH POINTS
|
|
@@ -1332,14 +1386,14 @@ class AstrologicalSubjectFactory:
|
|
|
1332
1386
|
|
|
1333
1387
|
# Calculate Mean Lilith (Mean Black Moon)
|
|
1334
1388
|
if should_calculate("Mean_Lilith"):
|
|
1335
|
-
|
|
1389
|
+
AstrologicalSubjectFactory._calculate_single_planet(
|
|
1336
1390
|
data, "Mean_Lilith", 12, julian_day, iflag, houses_degree_ut,
|
|
1337
1391
|
point_type, calculated_planets, active_points
|
|
1338
1392
|
)
|
|
1339
1393
|
|
|
1340
1394
|
# Calculate True Lilith (Osculating Black Moon)
|
|
1341
1395
|
if should_calculate("True_Lilith"):
|
|
1342
|
-
|
|
1396
|
+
AstrologicalSubjectFactory._calculate_single_planet(
|
|
1343
1397
|
data, "True_Lilith", 13, julian_day, iflag, houses_degree_ut,
|
|
1344
1398
|
point_type, calculated_planets, active_points
|
|
1345
1399
|
)
|
|
@@ -1350,21 +1404,21 @@ class AstrologicalSubjectFactory:
|
|
|
1350
1404
|
|
|
1351
1405
|
# Calculate Earth - useful for heliocentric charts
|
|
1352
1406
|
if should_calculate("Earth"):
|
|
1353
|
-
|
|
1407
|
+
AstrologicalSubjectFactory._calculate_single_planet(
|
|
1354
1408
|
data, "Earth", 14, julian_day, iflag, houses_degree_ut,
|
|
1355
1409
|
point_type, calculated_planets, active_points
|
|
1356
1410
|
)
|
|
1357
1411
|
|
|
1358
1412
|
# Calculate Chiron
|
|
1359
1413
|
if should_calculate("Chiron"):
|
|
1360
|
-
|
|
1414
|
+
AstrologicalSubjectFactory._calculate_single_planet(
|
|
1361
1415
|
data, "Chiron", 15, julian_day, iflag, houses_degree_ut,
|
|
1362
1416
|
point_type, calculated_planets, active_points
|
|
1363
1417
|
)
|
|
1364
1418
|
|
|
1365
1419
|
# Calculate Pholus
|
|
1366
1420
|
if should_calculate("Pholus"):
|
|
1367
|
-
|
|
1421
|
+
AstrologicalSubjectFactory._calculate_single_planet(
|
|
1368
1422
|
data, "Pholus", 16, julian_day, iflag, houses_degree_ut,
|
|
1369
1423
|
point_type, calculated_planets, active_points
|
|
1370
1424
|
)
|
|
@@ -1375,28 +1429,28 @@ class AstrologicalSubjectFactory:
|
|
|
1375
1429
|
|
|
1376
1430
|
# Calculate Ceres
|
|
1377
1431
|
if should_calculate("Ceres"):
|
|
1378
|
-
|
|
1432
|
+
AstrologicalSubjectFactory._calculate_single_planet(
|
|
1379
1433
|
data, "Ceres", 17, julian_day, iflag, houses_degree_ut,
|
|
1380
1434
|
point_type, calculated_planets, active_points
|
|
1381
1435
|
)
|
|
1382
1436
|
|
|
1383
1437
|
# Calculate Pallas
|
|
1384
1438
|
if should_calculate("Pallas"):
|
|
1385
|
-
|
|
1439
|
+
AstrologicalSubjectFactory._calculate_single_planet(
|
|
1386
1440
|
data, "Pallas", 18, julian_day, iflag, houses_degree_ut,
|
|
1387
1441
|
point_type, calculated_planets, active_points
|
|
1388
1442
|
)
|
|
1389
1443
|
|
|
1390
1444
|
# Calculate Juno
|
|
1391
1445
|
if should_calculate("Juno"):
|
|
1392
|
-
|
|
1446
|
+
AstrologicalSubjectFactory._calculate_single_planet(
|
|
1393
1447
|
data, "Juno", 19, julian_day, iflag, houses_degree_ut,
|
|
1394
1448
|
point_type, calculated_planets, active_points
|
|
1395
1449
|
)
|
|
1396
1450
|
|
|
1397
1451
|
# Calculate Vesta
|
|
1398
1452
|
if should_calculate("Vesta"):
|
|
1399
|
-
|
|
1453
|
+
AstrologicalSubjectFactory._calculate_single_planet(
|
|
1400
1454
|
data, "Vesta", 20, julian_day, iflag, houses_degree_ut,
|
|
1401
1455
|
point_type, calculated_planets, active_points
|
|
1402
1456
|
)
|
|
@@ -1409,7 +1463,7 @@ class AstrologicalSubjectFactory:
|
|
|
1409
1463
|
if should_calculate("Eris"):
|
|
1410
1464
|
try:
|
|
1411
1465
|
eris_calc = swe.calc_ut(julian_day, swe.AST_OFFSET + 136199, iflag)[0]
|
|
1412
|
-
data["eris"] = get_kerykeion_point_from_degree(eris_calc[0], "Eris", point_type=point_type)
|
|
1466
|
+
data["eris"] = get_kerykeion_point_from_degree(eris_calc[0], "Eris", point_type=point_type, speed=eris_calc[3], declination=eris_calc[1])
|
|
1413
1467
|
data["eris"].house = get_planet_house(eris_calc[0], houses_degree_ut)
|
|
1414
1468
|
data["eris"].retrograde = eris_calc[3] < 0
|
|
1415
1469
|
calculated_planets.append("Eris")
|
|
@@ -1421,7 +1475,7 @@ class AstrologicalSubjectFactory:
|
|
|
1421
1475
|
if should_calculate("Sedna"):
|
|
1422
1476
|
try:
|
|
1423
1477
|
sedna_calc = swe.calc_ut(julian_day, swe.AST_OFFSET + 90377, iflag)[0]
|
|
1424
|
-
data["sedna"] = get_kerykeion_point_from_degree(sedna_calc[0], "Sedna", point_type=point_type)
|
|
1478
|
+
data["sedna"] = get_kerykeion_point_from_degree(sedna_calc[0], "Sedna", point_type=point_type, speed=sedna_calc[3], declination=sedna_calc[1])
|
|
1425
1479
|
data["sedna"].house = get_planet_house(sedna_calc[0], houses_degree_ut)
|
|
1426
1480
|
data["sedna"].retrograde = sedna_calc[3] < 0
|
|
1427
1481
|
calculated_planets.append("Sedna")
|
|
@@ -1433,7 +1487,7 @@ class AstrologicalSubjectFactory:
|
|
|
1433
1487
|
if should_calculate("Haumea"):
|
|
1434
1488
|
try:
|
|
1435
1489
|
haumea_calc = swe.calc_ut(julian_day, swe.AST_OFFSET + 136108, iflag)[0]
|
|
1436
|
-
data["haumea"] = get_kerykeion_point_from_degree(haumea_calc[0], "Haumea", point_type=point_type)
|
|
1490
|
+
data["haumea"] = get_kerykeion_point_from_degree(haumea_calc[0], "Haumea", point_type=point_type, speed=haumea_calc[3], declination=haumea_calc[1])
|
|
1437
1491
|
data["haumea"].house = get_planet_house(haumea_calc[0], houses_degree_ut)
|
|
1438
1492
|
data["haumea"].retrograde = haumea_calc[3] < 0
|
|
1439
1493
|
calculated_planets.append("Haumea")
|
|
@@ -1445,7 +1499,7 @@ class AstrologicalSubjectFactory:
|
|
|
1445
1499
|
if should_calculate("Makemake"):
|
|
1446
1500
|
try:
|
|
1447
1501
|
makemake_calc = swe.calc_ut(julian_day, swe.AST_OFFSET + 136472, iflag)[0]
|
|
1448
|
-
data["makemake"] = get_kerykeion_point_from_degree(makemake_calc[0], "Makemake", point_type=point_type)
|
|
1502
|
+
data["makemake"] = get_kerykeion_point_from_degree(makemake_calc[0], "Makemake", point_type=point_type, speed=makemake_calc[3], declination=makemake_calc[1])
|
|
1449
1503
|
data["makemake"].house = get_planet_house(makemake_calc[0], houses_degree_ut)
|
|
1450
1504
|
data["makemake"].retrograde = makemake_calc[3] < 0
|
|
1451
1505
|
calculated_planets.append("Makemake")
|
|
@@ -1457,7 +1511,7 @@ class AstrologicalSubjectFactory:
|
|
|
1457
1511
|
if should_calculate("Ixion"):
|
|
1458
1512
|
try:
|
|
1459
1513
|
ixion_calc = swe.calc_ut(julian_day, swe.AST_OFFSET + 28978, iflag)[0]
|
|
1460
|
-
data["ixion"] = get_kerykeion_point_from_degree(ixion_calc[0], "Ixion", point_type=point_type)
|
|
1514
|
+
data["ixion"] = get_kerykeion_point_from_degree(ixion_calc[0], "Ixion", point_type=point_type, speed=ixion_calc[3], declination=ixion_calc[1])
|
|
1461
1515
|
data["ixion"].house = get_planet_house(ixion_calc[0], houses_degree_ut)
|
|
1462
1516
|
data["ixion"].retrograde = ixion_calc[3] < 0
|
|
1463
1517
|
calculated_planets.append("Ixion")
|
|
@@ -1469,7 +1523,7 @@ class AstrologicalSubjectFactory:
|
|
|
1469
1523
|
if should_calculate("Orcus"):
|
|
1470
1524
|
try:
|
|
1471
1525
|
orcus_calc = swe.calc_ut(julian_day, swe.AST_OFFSET + 90482, iflag)[0]
|
|
1472
|
-
data["orcus"] = get_kerykeion_point_from_degree(orcus_calc[0], "Orcus", point_type=point_type)
|
|
1526
|
+
data["orcus"] = get_kerykeion_point_from_degree(orcus_calc[0], "Orcus", point_type=point_type, speed=orcus_calc[3], declination=orcus_calc[1])
|
|
1473
1527
|
data["orcus"].house = get_planet_house(orcus_calc[0], houses_degree_ut)
|
|
1474
1528
|
data["orcus"].retrograde = orcus_calc[3] < 0
|
|
1475
1529
|
calculated_planets.append("Orcus")
|
|
@@ -1481,7 +1535,7 @@ class AstrologicalSubjectFactory:
|
|
|
1481
1535
|
if should_calculate("Quaoar"):
|
|
1482
1536
|
try:
|
|
1483
1537
|
quaoar_calc = swe.calc_ut(julian_day, swe.AST_OFFSET + 50000, iflag)[0]
|
|
1484
|
-
data["quaoar"] = get_kerykeion_point_from_degree(quaoar_calc[0], "Quaoar", point_type=point_type)
|
|
1538
|
+
data["quaoar"] = get_kerykeion_point_from_degree(quaoar_calc[0], "Quaoar", point_type=point_type, speed=quaoar_calc[3], declination=quaoar_calc[1])
|
|
1485
1539
|
data["quaoar"].house = get_planet_house(quaoar_calc[0], houses_degree_ut)
|
|
1486
1540
|
data["quaoar"].retrograde = quaoar_calc[3] < 0
|
|
1487
1541
|
calculated_planets.append("Quaoar")
|
|
@@ -1497,9 +1551,11 @@ class AstrologicalSubjectFactory:
|
|
|
1497
1551
|
if should_calculate("Regulus"):
|
|
1498
1552
|
try:
|
|
1499
1553
|
star_name = "Regulus"
|
|
1500
|
-
swe.fixstar_ut(star_name, julian_day, iflag)
|
|
1501
|
-
regulus_deg =
|
|
1502
|
-
|
|
1554
|
+
pos = swe.fixstar_ut(star_name, julian_day, iflag)[0]
|
|
1555
|
+
regulus_deg = pos[0]
|
|
1556
|
+
regulus_speed = pos[3] if len(pos) > 3 else 0.0 # Fixed stars have very slow speed
|
|
1557
|
+
regulus_dec = pos[1] if len(pos) > 1 else None # Declination
|
|
1558
|
+
data["regulus"] = get_kerykeion_point_from_degree(regulus_deg, "Regulus", point_type=point_type, speed=regulus_speed, declination=regulus_dec)
|
|
1503
1559
|
data["regulus"].house = get_planet_house(regulus_deg, houses_degree_ut)
|
|
1504
1560
|
data["regulus"].retrograde = False # Fixed stars are never retrograde
|
|
1505
1561
|
calculated_planets.append("Regulus")
|
|
@@ -1511,9 +1567,11 @@ class AstrologicalSubjectFactory:
|
|
|
1511
1567
|
if should_calculate("Spica"):
|
|
1512
1568
|
try:
|
|
1513
1569
|
star_name = "Spica"
|
|
1514
|
-
swe.fixstar_ut(star_name, julian_day, iflag)
|
|
1515
|
-
spica_deg =
|
|
1516
|
-
|
|
1570
|
+
pos = swe.fixstar_ut(star_name, julian_day, iflag)[0]
|
|
1571
|
+
spica_deg = pos[0]
|
|
1572
|
+
spica_speed = pos[3] if len(pos) > 3 else 0.0 # Fixed stars have very slow speed
|
|
1573
|
+
spica_dec = pos[1] if len(pos) > 1 else None # Declination
|
|
1574
|
+
data["spica"] = get_kerykeion_point_from_degree(spica_deg, "Spica", point_type=point_type, speed=spica_speed, declination=spica_dec)
|
|
1517
1575
|
data["spica"].house = get_planet_house(spica_deg, houses_degree_ut)
|
|
1518
1576
|
data["spica"].retrograde = False # Fixed stars are never retrograde
|
|
1519
1577
|
calculated_planets.append("Spica")
|
|
@@ -1528,21 +1586,41 @@ class AstrologicalSubjectFactory:
|
|
|
1528
1586
|
# Calculate Pars Fortunae (Part of Fortune)
|
|
1529
1587
|
if should_calculate("Pars_Fortunae"):
|
|
1530
1588
|
# Auto-activate required points with notification
|
|
1531
|
-
|
|
1532
|
-
missing_points = [point for point in
|
|
1589
|
+
pars_fortunae_required_points: List[AstrologicalPoint] = ["Ascendant", "Sun", "Moon"]
|
|
1590
|
+
missing_points = [point for point in pars_fortunae_required_points if point not in active_points]
|
|
1533
1591
|
if missing_points:
|
|
1534
1592
|
logging.info(f"Automatically adding required points for Pars_Fortunae: {missing_points}")
|
|
1535
1593
|
active_points.extend(cast(List[AstrologicalPoint], missing_points))
|
|
1536
1594
|
# Recalculate the missing points
|
|
1537
1595
|
for point in missing_points:
|
|
1538
|
-
if point == "
|
|
1596
|
+
if point == "Ascendant" and "ascendant" not in data:
|
|
1597
|
+
# Calculate Ascendant from houses data if needed
|
|
1598
|
+
if data["zodiac_type"] == "Sidereal":
|
|
1599
|
+
cusps, ascmc = swe.houses_ex(
|
|
1600
|
+
tjdut=data["julian_day"],
|
|
1601
|
+
lat=data["lat"],
|
|
1602
|
+
lon=data["lng"],
|
|
1603
|
+
hsys=str.encode(data["houses_system_identifier"]),
|
|
1604
|
+
flags=swe.FLG_SIDEREAL
|
|
1605
|
+
)
|
|
1606
|
+
else:
|
|
1607
|
+
cusps, ascmc = swe.houses(
|
|
1608
|
+
tjdut=data["julian_day"],
|
|
1609
|
+
lat=data["lat"],
|
|
1610
|
+
lon=data["lng"],
|
|
1611
|
+
hsys=str.encode(data["houses_system_identifier"])
|
|
1612
|
+
)
|
|
1613
|
+
data["ascendant"] = get_kerykeion_point_from_degree(ascmc[0], "Ascendant", point_type=point_type)
|
|
1614
|
+
data["ascendant"].house = get_planet_house(ascmc[0], houses_degree_ut)
|
|
1615
|
+
data["ascendant"].retrograde = False
|
|
1616
|
+
elif point == "Sun" and "sun" not in data:
|
|
1539
1617
|
sun_calc = swe.calc_ut(julian_day, 0, iflag)[0]
|
|
1540
|
-
data["sun"] = get_kerykeion_point_from_degree(sun_calc[0], "Sun", point_type=point_type)
|
|
1618
|
+
data["sun"] = get_kerykeion_point_from_degree(sun_calc[0], "Sun", point_type=point_type, speed=sun_calc[3], declination=sun_calc[1])
|
|
1541
1619
|
data["sun"].house = get_planet_house(sun_calc[0], houses_degree_ut)
|
|
1542
1620
|
data["sun"].retrograde = sun_calc[3] < 0
|
|
1543
|
-
elif point == "Moon" and
|
|
1621
|
+
elif point == "Moon" and "moon" not in data:
|
|
1544
1622
|
moon_calc = swe.calc_ut(julian_day, 1, iflag)[0]
|
|
1545
|
-
data["moon"] = get_kerykeion_point_from_degree(moon_calc[0], "Moon", point_type=point_type)
|
|
1623
|
+
data["moon"] = get_kerykeion_point_from_degree(moon_calc[0], "Moon", point_type=point_type, speed=moon_calc[3], declination=moon_calc[1])
|
|
1546
1624
|
data["moon"].house = get_planet_house(moon_calc[0], houses_degree_ut)
|
|
1547
1625
|
data["moon"].retrograde = moon_calc[3] < 0
|
|
1548
1626
|
|
|
@@ -1569,21 +1647,41 @@ class AstrologicalSubjectFactory:
|
|
|
1569
1647
|
# Calculate Pars Spiritus (Part of Spirit)
|
|
1570
1648
|
if should_calculate("Pars_Spiritus"):
|
|
1571
1649
|
# Auto-activate required points with notification
|
|
1572
|
-
|
|
1573
|
-
missing_points = [point for point in
|
|
1650
|
+
pars_spiritus_required_points: List[AstrologicalPoint] = ["Ascendant", "Sun", "Moon"]
|
|
1651
|
+
missing_points = [point for point in pars_spiritus_required_points if point not in active_points]
|
|
1574
1652
|
if missing_points:
|
|
1575
1653
|
logging.info(f"Automatically adding required points for Pars_Spiritus: {missing_points}")
|
|
1576
1654
|
active_points.extend(cast(List[AstrologicalPoint], missing_points))
|
|
1577
1655
|
# Recalculate the missing points
|
|
1578
1656
|
for point in missing_points:
|
|
1579
|
-
if point == "
|
|
1657
|
+
if point == "Ascendant" and "ascendant" not in data:
|
|
1658
|
+
# Calculate Ascendant from houses data if needed
|
|
1659
|
+
if data["zodiac_type"] == "Sidereal":
|
|
1660
|
+
cusps, ascmc = swe.houses_ex(
|
|
1661
|
+
tjdut=data["julian_day"],
|
|
1662
|
+
lat=data["lat"],
|
|
1663
|
+
lon=data["lng"],
|
|
1664
|
+
hsys=str.encode(data["houses_system_identifier"]),
|
|
1665
|
+
flags=swe.FLG_SIDEREAL
|
|
1666
|
+
)
|
|
1667
|
+
else:
|
|
1668
|
+
cusps, ascmc = swe.houses(
|
|
1669
|
+
tjdut=data["julian_day"],
|
|
1670
|
+
lat=data["lat"],
|
|
1671
|
+
lon=data["lng"],
|
|
1672
|
+
hsys=str.encode(data["houses_system_identifier"])
|
|
1673
|
+
)
|
|
1674
|
+
data["ascendant"] = get_kerykeion_point_from_degree(ascmc[0], "Ascendant", point_type=point_type)
|
|
1675
|
+
data["ascendant"].house = get_planet_house(ascmc[0], houses_degree_ut)
|
|
1676
|
+
data["ascendant"].retrograde = False
|
|
1677
|
+
elif point == "Sun" and "sun" not in data:
|
|
1580
1678
|
sun_calc = swe.calc_ut(julian_day, 0, iflag)[0]
|
|
1581
|
-
data["sun"] = get_kerykeion_point_from_degree(sun_calc[0], "Sun", point_type=point_type)
|
|
1679
|
+
data["sun"] = get_kerykeion_point_from_degree(sun_calc[0], "Sun", point_type=point_type, speed=sun_calc[3], declination=sun_calc[1])
|
|
1582
1680
|
data["sun"].house = get_planet_house(sun_calc[0], houses_degree_ut)
|
|
1583
1681
|
data["sun"].retrograde = sun_calc[3] < 0
|
|
1584
|
-
elif point == "Moon" and
|
|
1682
|
+
elif point == "Moon" and "moon" not in data:
|
|
1585
1683
|
moon_calc = swe.calc_ut(julian_day, 1, iflag)[0]
|
|
1586
|
-
data["moon"] = get_kerykeion_point_from_degree(moon_calc[0], "Moon", point_type=point_type)
|
|
1684
|
+
data["moon"] = get_kerykeion_point_from_degree(moon_calc[0], "Moon", point_type=point_type, speed=moon_calc[3], declination=moon_calc[1])
|
|
1587
1685
|
data["moon"].house = get_planet_house(moon_calc[0], houses_degree_ut)
|
|
1588
1686
|
data["moon"].retrograde = moon_calc[3] < 0
|
|
1589
1687
|
|
|
@@ -1609,21 +1707,41 @@ class AstrologicalSubjectFactory:
|
|
|
1609
1707
|
# Calculate Pars Amoris (Part of Eros/Love)
|
|
1610
1708
|
if should_calculate("Pars_Amoris"):
|
|
1611
1709
|
# Auto-activate required points with notification
|
|
1612
|
-
|
|
1613
|
-
missing_points = [point for point in
|
|
1710
|
+
pars_amoris_required_points: List[AstrologicalPoint] = ["Ascendant", "Venus", "Sun"]
|
|
1711
|
+
missing_points = [point for point in pars_amoris_required_points if point not in active_points]
|
|
1614
1712
|
if missing_points:
|
|
1615
1713
|
logging.info(f"Automatically adding required points for Pars_Amoris: {missing_points}")
|
|
1616
1714
|
active_points.extend(cast(List[AstrologicalPoint], missing_points))
|
|
1617
1715
|
# Recalculate the missing points
|
|
1618
1716
|
for point in missing_points:
|
|
1619
|
-
if point == "
|
|
1717
|
+
if point == "Ascendant" and "ascendant" not in data:
|
|
1718
|
+
# Calculate Ascendant from houses data if needed
|
|
1719
|
+
if data["zodiac_type"] == "Sidereal":
|
|
1720
|
+
cusps, ascmc = swe.houses_ex(
|
|
1721
|
+
tjdut=data["julian_day"],
|
|
1722
|
+
lat=data["lat"],
|
|
1723
|
+
lon=data["lng"],
|
|
1724
|
+
hsys=str.encode(data["houses_system_identifier"]),
|
|
1725
|
+
flags=swe.FLG_SIDEREAL
|
|
1726
|
+
)
|
|
1727
|
+
else:
|
|
1728
|
+
cusps, ascmc = swe.houses(
|
|
1729
|
+
tjdut=data["julian_day"],
|
|
1730
|
+
lat=data["lat"],
|
|
1731
|
+
lon=data["lng"],
|
|
1732
|
+
hsys=str.encode(data["houses_system_identifier"])
|
|
1733
|
+
)
|
|
1734
|
+
data["ascendant"] = get_kerykeion_point_from_degree(ascmc[0], "Ascendant", point_type=point_type)
|
|
1735
|
+
data["ascendant"].house = get_planet_house(ascmc[0], houses_degree_ut)
|
|
1736
|
+
data["ascendant"].retrograde = False
|
|
1737
|
+
elif point == "Sun" and "sun" not in data:
|
|
1620
1738
|
sun_calc = swe.calc_ut(julian_day, 0, iflag)[0]
|
|
1621
|
-
data["sun"] = get_kerykeion_point_from_degree(sun_calc[0], "Sun", point_type=point_type)
|
|
1739
|
+
data["sun"] = get_kerykeion_point_from_degree(sun_calc[0], "Sun", point_type=point_type, speed=sun_calc[3], declination=sun_calc[1])
|
|
1622
1740
|
data["sun"].house = get_planet_house(sun_calc[0], houses_degree_ut)
|
|
1623
1741
|
data["sun"].retrograde = sun_calc[3] < 0
|
|
1624
|
-
elif point == "Venus" and
|
|
1742
|
+
elif point == "Venus" and "venus" not in data:
|
|
1625
1743
|
venus_calc = swe.calc_ut(julian_day, 3, iflag)[0]
|
|
1626
|
-
data["venus"] = get_kerykeion_point_from_degree(venus_calc[0], "Venus", point_type=point_type)
|
|
1744
|
+
data["venus"] = get_kerykeion_point_from_degree(venus_calc[0], "Venus", point_type=point_type, speed=venus_calc[3], declination=venus_calc[1])
|
|
1627
1745
|
data["venus"].house = get_planet_house(venus_calc[0], houses_degree_ut)
|
|
1628
1746
|
data["venus"].retrograde = venus_calc[3] < 0
|
|
1629
1747
|
|
|
@@ -1640,21 +1758,41 @@ class AstrologicalSubjectFactory:
|
|
|
1640
1758
|
# Calculate Pars Fidei (Part of Faith)
|
|
1641
1759
|
if should_calculate("Pars_Fidei"):
|
|
1642
1760
|
# Auto-activate required points with notification
|
|
1643
|
-
|
|
1644
|
-
missing_points = [point for point in
|
|
1761
|
+
pars_fidei_required_points: List[AstrologicalPoint] = ["Ascendant", "Jupiter", "Saturn"]
|
|
1762
|
+
missing_points = [point for point in pars_fidei_required_points if point not in active_points]
|
|
1645
1763
|
if missing_points:
|
|
1646
1764
|
logging.info(f"Automatically adding required points for Pars_Fidei: {missing_points}")
|
|
1647
1765
|
active_points.extend(cast(List[AstrologicalPoint], missing_points))
|
|
1648
1766
|
# Recalculate the missing points
|
|
1649
1767
|
for point in missing_points:
|
|
1650
|
-
if point == "
|
|
1768
|
+
if point == "Ascendant" and "ascendant" not in data:
|
|
1769
|
+
# Calculate Ascendant from houses data if needed
|
|
1770
|
+
if data["zodiac_type"] == "Sidereal":
|
|
1771
|
+
cusps, ascmc = swe.houses_ex(
|
|
1772
|
+
tjdut=data["julian_day"],
|
|
1773
|
+
lat=data["lat"],
|
|
1774
|
+
lon=data["lng"],
|
|
1775
|
+
hsys=str.encode(data["houses_system_identifier"]),
|
|
1776
|
+
flags=swe.FLG_SIDEREAL
|
|
1777
|
+
)
|
|
1778
|
+
else:
|
|
1779
|
+
cusps, ascmc = swe.houses(
|
|
1780
|
+
tjdut=data["julian_day"],
|
|
1781
|
+
lat=data["lat"],
|
|
1782
|
+
lon=data["lng"],
|
|
1783
|
+
hsys=str.encode(data["houses_system_identifier"])
|
|
1784
|
+
)
|
|
1785
|
+
data["ascendant"] = get_kerykeion_point_from_degree(ascmc[0], "Ascendant", point_type=point_type)
|
|
1786
|
+
data["ascendant"].house = get_planet_house(ascmc[0], houses_degree_ut)
|
|
1787
|
+
data["ascendant"].retrograde = False
|
|
1788
|
+
elif point == "Jupiter" and "jupiter" not in data:
|
|
1651
1789
|
jupiter_calc = swe.calc_ut(julian_day, 5, iflag)[0]
|
|
1652
|
-
data["jupiter"] = get_kerykeion_point_from_degree(jupiter_calc[0], "Jupiter", point_type=point_type)
|
|
1790
|
+
data["jupiter"] = get_kerykeion_point_from_degree(jupiter_calc[0], "Jupiter", point_type=point_type, speed=jupiter_calc[3], declination=jupiter_calc[1])
|
|
1653
1791
|
data["jupiter"].house = get_planet_house(jupiter_calc[0], houses_degree_ut)
|
|
1654
1792
|
data["jupiter"].retrograde = jupiter_calc[3] < 0
|
|
1655
|
-
elif point == "Saturn" and
|
|
1793
|
+
elif point == "Saturn" and "saturn" not in data:
|
|
1656
1794
|
saturn_calc = swe.calc_ut(julian_day, 6, iflag)[0]
|
|
1657
|
-
data["saturn"] = get_kerykeion_point_from_degree(saturn_calc[0], "Saturn", point_type=point_type)
|
|
1795
|
+
data["saturn"] = get_kerykeion_point_from_degree(saturn_calc[0], "Saturn", point_type=point_type, speed=saturn_calc[3], declination=saturn_calc[1])
|
|
1658
1796
|
data["saturn"].house = get_planet_house(saturn_calc[0], houses_degree_ut)
|
|
1659
1797
|
data["saturn"].retrograde = saturn_calc[3] < 0
|
|
1660
1798
|
|
|
@@ -1668,8 +1806,8 @@ class AstrologicalSubjectFactory:
|
|
|
1668
1806
|
data["pars_fidei"].retrograde = False
|
|
1669
1807
|
calculated_planets.append("Pars_Fidei")
|
|
1670
1808
|
|
|
1671
|
-
# Calculate Vertex
|
|
1672
|
-
if should_calculate("Vertex"):
|
|
1809
|
+
# Calculate Vertex and/or Anti-Vertex
|
|
1810
|
+
if should_calculate("Vertex") or should_calculate("Anti_Vertex"):
|
|
1673
1811
|
try:
|
|
1674
1812
|
# Vertex is at ascmc[3] in Swiss Ephemeris
|
|
1675
1813
|
if data["zodiac_type"] == "Sidereal":
|
|
@@ -1689,58 +1827,71 @@ class AstrologicalSubjectFactory:
|
|
|
1689
1827
|
)
|
|
1690
1828
|
|
|
1691
1829
|
vertex_deg = ascmc[3]
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1830
|
+
|
|
1831
|
+
# Calculate Vertex if requested
|
|
1832
|
+
if should_calculate("Vertex"):
|
|
1833
|
+
data["vertex"] = get_kerykeion_point_from_degree(vertex_deg, "Vertex", point_type=point_type)
|
|
1834
|
+
data["vertex"].house = get_planet_house(vertex_deg, houses_degree_ut)
|
|
1835
|
+
data["vertex"].retrograde = False
|
|
1836
|
+
calculated_planets.append("Vertex")
|
|
1837
|
+
|
|
1838
|
+
# Calculate Anti-Vertex if requested
|
|
1839
|
+
if should_calculate("Anti_Vertex"):
|
|
1840
|
+
anti_vertex_deg = math.fmod(vertex_deg + 180, 360)
|
|
1841
|
+
data["anti_vertex"] = get_kerykeion_point_from_degree(anti_vertex_deg, "Anti_Vertex", point_type=point_type)
|
|
1842
|
+
data["anti_vertex"].house = get_planet_house(anti_vertex_deg, houses_degree_ut)
|
|
1843
|
+
data["anti_vertex"].retrograde = False
|
|
1844
|
+
calculated_planets.append("Anti_Vertex")
|
|
1845
|
+
|
|
1703
1846
|
except Exception as e:
|
|
1704
|
-
logging.warning("Could not calculate Vertex position, error: %s", e)
|
|
1705
|
-
|
|
1847
|
+
logging.warning("Could not calculate Vertex/Anti-Vertex position, error: %s", e)
|
|
1848
|
+
if "Vertex" in active_points:
|
|
1849
|
+
active_points.remove("Vertex")
|
|
1850
|
+
if "Anti_Vertex" in active_points:
|
|
1851
|
+
active_points.remove("Anti_Vertex")
|
|
1706
1852
|
|
|
1707
1853
|
# Store only the planets that were actually calculated
|
|
1708
|
-
|
|
1854
|
+
all_calculated_points = calculated_planets.copy()
|
|
1855
|
+
if calculated_axial_cusps:
|
|
1856
|
+
all_calculated_points.extend(calculated_axial_cusps)
|
|
1857
|
+
data["active_points"] = all_calculated_points
|
|
1709
1858
|
|
|
1710
|
-
@
|
|
1711
|
-
def _calculate_day_of_week(
|
|
1859
|
+
@staticmethod
|
|
1860
|
+
def _calculate_day_of_week(data: Dict[str, Any]) -> None:
|
|
1712
1861
|
"""
|
|
1713
1862
|
Calculate the day of the week for the given astronomical event.
|
|
1714
1863
|
|
|
1715
|
-
Determines the day of the week corresponding to the
|
|
1716
|
-
|
|
1864
|
+
Determines the day of the week corresponding to the local datetime
|
|
1865
|
+
using the standard library for consistency.
|
|
1717
1866
|
|
|
1718
1867
|
Args:
|
|
1719
|
-
data (Dict[str, Any]): Calculation data dictionary containing
|
|
1720
|
-
Updated with the calculated day_of_week string.
|
|
1868
|
+
data (Dict[str, Any]): Calculation data dictionary containing
|
|
1869
|
+
iso_formatted_local_datetime. Updated with the calculated day_of_week string.
|
|
1721
1870
|
|
|
1722
1871
|
Side Effects:
|
|
1723
1872
|
Updates data dictionary with:
|
|
1724
1873
|
- day_of_week: Human-readable day name (e.g., "Monday", "Tuesday")
|
|
1725
|
-
|
|
1726
|
-
Note:
|
|
1727
|
-
The Swiss Ephemeris day_of_week function returns an integer where
|
|
1728
|
-
0=Monday, 1=Tuesday, ..., 6=Sunday. This is converted to readable
|
|
1729
|
-
day names for user convenience.
|
|
1730
1874
|
"""
|
|
1731
|
-
|
|
1732
|
-
day_of_week =
|
|
1733
|
-
# Map to human-readable names
|
|
1734
|
-
days_of_week = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]
|
|
1735
|
-
data["day_of_week"] = days_of_week[day_of_week]
|
|
1875
|
+
dt = datetime.fromisoformat(data["iso_formatted_local_datetime"])
|
|
1876
|
+
data["day_of_week"] = dt.strftime("%A")
|
|
1736
1877
|
|
|
1737
1878
|
if __name__ == "__main__":
|
|
1879
|
+
from kerykeion.schemas.kr_literals import AstrologicalPoint
|
|
1880
|
+
|
|
1738
1881
|
# Example usage
|
|
1739
|
-
|
|
1882
|
+
new_active_points: List[AstrologicalPoint] = ['Sun', 'Moon', 'Mercury', 'Venus', 'Mars', 'Jupiter', 'Saturn', 'Uranus', 'Neptune', 'Pluto', 'Mean_North_Lunar_Node', 'True_North_Lunar_Node', 'Mean_South_Lunar_Node', 'True_South_Lunar_Node', 'Chiron', 'Mean_Lilith', 'True_Lilith', 'Earth', 'Pholus', 'Ceres', 'Pallas', 'Juno', 'Vesta', 'Eris', 'Sedna', 'Haumea', 'Makemake', 'Ixion', 'Orcus', 'Quaoar', 'Regulus', 'Spica', 'Pars_Fortunae', 'Pars_Spiritus', 'Pars_Amoris', 'Pars_Fidei', 'Vertex', 'Anti_Vertex', 'Ascendant', 'Medium_Coeli', 'Descendant', 'Imum_Coeli']
|
|
1883
|
+
subject = AstrologicalSubjectFactory.from_current_time(name="Test Subject", active_points=new_active_points)
|
|
1740
1884
|
print(subject.sun)
|
|
1741
1885
|
print(subject.pars_amoris)
|
|
1742
1886
|
print(subject.eris)
|
|
1743
1887
|
print(subject.active_points)
|
|
1888
|
+
print(subject.pars_fidei)
|
|
1889
|
+
print("----")
|
|
1890
|
+
print(subject.anti_vertex)
|
|
1744
1891
|
|
|
1745
1892
|
# Create JSON output
|
|
1746
1893
|
json_string = subject.model_dump_json(exclude_none=True, indent=2)
|
|
1894
|
+
|
|
1895
|
+
# Write JSON to home
|
|
1896
|
+
with open(Path.home() / "kerykeion_subject_example.json", "w", encoding="utf-8") as f:
|
|
1897
|
+
f.write(json_string)
|