kerykeion 5.0.0a5__py3-none-any.whl → 5.0.0a7__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/astrological_subject_factory.py +237 -228
- kerykeion/charts/draw_planets_v2.py +13 -3
- kerykeion/charts/draw_planets_v3.py +679 -0
- kerykeion/charts/kerykeion_chart_svg.py +65 -22
- kerykeion/kr_types/kr_models.py +5 -5
- {kerykeion-5.0.0a5.dist-info → kerykeion-5.0.0a7.dist-info}/METADATA +1 -1
- {kerykeion-5.0.0a5.dist-info → kerykeion-5.0.0a7.dist-info}/RECORD +10 -9
- {kerykeion-5.0.0a5.dist-info → kerykeion-5.0.0a7.dist-info}/LICENSE +0 -0
- {kerykeion-5.0.0a5.dist-info → kerykeion-5.0.0a7.dist-info}/WHEEL +0 -0
- {kerykeion-5.0.0a5.dist-info → kerykeion-5.0.0a7.dist-info}/entry_points.txt +0 -0
|
@@ -186,6 +186,7 @@ class AstrologicalSubjectFactory:
|
|
|
186
186
|
is_dst: Optional[bool] = None,
|
|
187
187
|
altitude: Optional[float] = None,
|
|
188
188
|
active_points: List[AstrologicalPoint] = DEFAULT_ACTIVE_POINTS,
|
|
189
|
+
calculate_lunar_phase: bool = True,
|
|
189
190
|
*,
|
|
190
191
|
seconds: int = 0,
|
|
191
192
|
|
|
@@ -205,11 +206,12 @@ class AstrologicalSubjectFactory:
|
|
|
205
206
|
zodiac_type: Type of zodiac (Tropical or Sidereal)
|
|
206
207
|
sidereal_mode: Mode for sidereal calculations
|
|
207
208
|
houses_system_identifier: House system for calculations
|
|
208
|
-
perspective_type: Perspective
|
|
209
|
+
perspective_type: Perspective for calculations
|
|
209
210
|
cache_expire_after_days: Cache duration for geonames data
|
|
210
211
|
is_dst: Daylight saving time flag
|
|
211
212
|
altitude: Location altitude for topocentric calculations
|
|
212
213
|
active_points: Set of points to calculate (optimization)
|
|
214
|
+
calculate_lunar_phase: Whether to calculate lunar phase (requires Sun and Moon)
|
|
213
215
|
|
|
214
216
|
Returns:
|
|
215
217
|
An AstrologicalSubjectModel with calculated data
|
|
@@ -226,43 +228,6 @@ class AstrologicalSubjectFactory:
|
|
|
226
228
|
|
|
227
229
|
calc_data["active_points"] = active_points
|
|
228
230
|
|
|
229
|
-
|
|
230
|
-
if "Sun" not in calc_data["active_points"]:
|
|
231
|
-
logging.info("Automatically adding 'Sun' to active points")
|
|
232
|
-
calc_data["active_points"].append("Sun")
|
|
233
|
-
|
|
234
|
-
if "Moon" not in calc_data["active_points"]:
|
|
235
|
-
logging.info("Automatically adding 'Moon' to active points")
|
|
236
|
-
calc_data["active_points"].append("Moon")
|
|
237
|
-
|
|
238
|
-
if "Ascendant" not in calc_data["active_points"]:
|
|
239
|
-
logging.info("Automatically adding 'Ascendant' to active points")
|
|
240
|
-
calc_data["active_points"].append("Ascendant")
|
|
241
|
-
|
|
242
|
-
if "Medium_Coeli" not in calc_data["active_points"]:
|
|
243
|
-
logging.info("Automatically adding 'Medium_Coeli' to active points")
|
|
244
|
-
calc_data["active_points"].append("Medium_Coeli")
|
|
245
|
-
|
|
246
|
-
if "Mercury" not in calc_data["active_points"]:
|
|
247
|
-
logging.info("Automatically adding 'Mercury' to active points")
|
|
248
|
-
calc_data["active_points"].append("Mercury")
|
|
249
|
-
|
|
250
|
-
if "Venus" not in calc_data["active_points"]:
|
|
251
|
-
logging.info("Automatically adding 'Venus' to active points")
|
|
252
|
-
calc_data["active_points"].append("Venus")
|
|
253
|
-
|
|
254
|
-
if "Mars" not in calc_data["active_points"]:
|
|
255
|
-
logging.info("Automatically adding 'Mars' to active points")
|
|
256
|
-
calc_data["active_points"].append("Mars")
|
|
257
|
-
|
|
258
|
-
if "Jupiter" not in calc_data["active_points"]:
|
|
259
|
-
logging.info("Automatically adding 'Jupiter' to active points")
|
|
260
|
-
calc_data["active_points"].append("Jupiter")
|
|
261
|
-
|
|
262
|
-
if "Saturn" not in calc_data["active_points"]:
|
|
263
|
-
logging.info("Automatically adding 'Saturn' to active points")
|
|
264
|
-
calc_data["active_points"].append("Saturn")
|
|
265
|
-
|
|
266
231
|
# Initialize configuration
|
|
267
232
|
config = ChartConfiguration(
|
|
268
233
|
zodiac_type=zodiac_type,
|
|
@@ -294,13 +259,13 @@ class AstrologicalSubjectFactory:
|
|
|
294
259
|
)
|
|
295
260
|
|
|
296
261
|
# If offline mode is requested but required data is missing, raise error
|
|
297
|
-
if not online and (not tz_str or
|
|
262
|
+
if not online and (not tz_str or lat is None or lng is None):
|
|
298
263
|
raise KerykeionException(
|
|
299
264
|
"For offline mode, you must provide timezone (tz_str) and coordinates (lat, lng)"
|
|
300
265
|
)
|
|
301
266
|
|
|
302
267
|
# Fetch location data if needed
|
|
303
|
-
if online and (not tz_str or
|
|
268
|
+
if online and (not tz_str or lat is None or lng is None):
|
|
304
269
|
location.fetch_from_geonames(
|
|
305
270
|
username=geonames_username or DEFAULT_GEONAMES_USERNAME,
|
|
306
271
|
cache_expire_after_days=cache_expire_after_days
|
|
@@ -335,11 +300,12 @@ class AstrologicalSubjectFactory:
|
|
|
335
300
|
cls._calculate_planets(calc_data, calc_data["active_points"])
|
|
336
301
|
cls._calculate_day_of_week(calc_data)
|
|
337
302
|
|
|
338
|
-
# Calculate lunar phase
|
|
339
|
-
calc_data
|
|
340
|
-
calc_data["
|
|
341
|
-
|
|
342
|
-
|
|
303
|
+
# Calculate lunar phase (optional - only if requested and Sun and Moon are available)
|
|
304
|
+
if calculate_lunar_phase and "moon" in calc_data and "sun" in calc_data:
|
|
305
|
+
calc_data["lunar_phase"] = calculate_moon_phase(
|
|
306
|
+
calc_data["moon"].abs_pos,
|
|
307
|
+
calc_data["sun"].abs_pos
|
|
308
|
+
)
|
|
343
309
|
|
|
344
310
|
# Create and return the AstrologicalSubjectModel
|
|
345
311
|
return AstrologicalSubjectModel(**calc_data)
|
|
@@ -361,7 +327,8 @@ class AstrologicalSubjectFactory:
|
|
|
361
327
|
houses_system_identifier: HousesSystemIdentifier = DEFAULT_HOUSES_SYSTEM_IDENTIFIER,
|
|
362
328
|
perspective_type: PerspectiveType = DEFAULT_PERSPECTIVE_TYPE,
|
|
363
329
|
altitude: Optional[float] = None,
|
|
364
|
-
active_points: List[AstrologicalPoint] = DEFAULT_ACTIVE_POINTS
|
|
330
|
+
active_points: List[AstrologicalPoint] = DEFAULT_ACTIVE_POINTS,
|
|
331
|
+
calculate_lunar_phase: bool = True
|
|
365
332
|
) -> AstrologicalSubjectModel:
|
|
366
333
|
"""
|
|
367
334
|
Create an astrological subject from an ISO formatted UTC time.
|
|
@@ -381,6 +348,7 @@ class AstrologicalSubjectFactory:
|
|
|
381
348
|
perspective_type: Perspective for calculations
|
|
382
349
|
altitude: Location altitude
|
|
383
350
|
active_points: Set of points to calculate
|
|
351
|
+
calculate_lunar_phase: Whether to calculate lunar phase
|
|
384
352
|
|
|
385
353
|
Returns:
|
|
386
354
|
AstrologicalSubjectModel instance
|
|
@@ -428,7 +396,8 @@ class AstrologicalSubjectFactory:
|
|
|
428
396
|
houses_system_identifier=houses_system_identifier,
|
|
429
397
|
perspective_type=perspective_type,
|
|
430
398
|
altitude=altitude,
|
|
431
|
-
active_points=active_points
|
|
399
|
+
active_points=active_points,
|
|
400
|
+
calculate_lunar_phase=calculate_lunar_phase
|
|
432
401
|
)
|
|
433
402
|
|
|
434
403
|
@classmethod
|
|
@@ -446,7 +415,8 @@ class AstrologicalSubjectFactory:
|
|
|
446
415
|
sidereal_mode: Optional[SiderealMode] = None,
|
|
447
416
|
houses_system_identifier: HousesSystemIdentifier = DEFAULT_HOUSES_SYSTEM_IDENTIFIER,
|
|
448
417
|
perspective_type: PerspectiveType = DEFAULT_PERSPECTIVE_TYPE,
|
|
449
|
-
active_points: List[AstrologicalPoint] = DEFAULT_ACTIVE_POINTS
|
|
418
|
+
active_points: List[AstrologicalPoint] = DEFAULT_ACTIVE_POINTS,
|
|
419
|
+
calculate_lunar_phase: bool = True
|
|
450
420
|
) -> AstrologicalSubjectModel:
|
|
451
421
|
"""
|
|
452
422
|
Create an astrological subject for the current time.
|
|
@@ -464,6 +434,7 @@ class AstrologicalSubjectFactory:
|
|
|
464
434
|
houses_system_identifier: House system
|
|
465
435
|
perspective_type: Perspective for calculations
|
|
466
436
|
active_points: Set of points to calculate
|
|
437
|
+
calculate_lunar_phase: Whether to calculate lunar phase
|
|
467
438
|
|
|
468
439
|
Returns:
|
|
469
440
|
AstrologicalSubjectModel for current time
|
|
@@ -489,7 +460,8 @@ class AstrologicalSubjectFactory:
|
|
|
489
460
|
sidereal_mode=sidereal_mode,
|
|
490
461
|
houses_system_identifier=houses_system_identifier,
|
|
491
462
|
perspective_type=perspective_type,
|
|
492
|
-
active_points=active_points
|
|
463
|
+
active_points=active_points,
|
|
464
|
+
calculate_lunar_phase=calculate_lunar_phase
|
|
493
465
|
)
|
|
494
466
|
|
|
495
467
|
@classmethod
|
|
@@ -630,6 +602,56 @@ class AstrologicalSubjectFactory:
|
|
|
630
602
|
data["imum_coeli"].retrograde = False
|
|
631
603
|
calculated_axial_cusps.append("Imum_Coeli")
|
|
632
604
|
|
|
605
|
+
@classmethod
|
|
606
|
+
def _calculate_single_planet(
|
|
607
|
+
cls,
|
|
608
|
+
data: Dict[str, Any],
|
|
609
|
+
planet_name: AstrologicalPoint,
|
|
610
|
+
planet_id: int,
|
|
611
|
+
julian_day: float,
|
|
612
|
+
iflag: int,
|
|
613
|
+
houses_degree_ut: List[float],
|
|
614
|
+
point_type: PointType,
|
|
615
|
+
calculated_planets: List[str],
|
|
616
|
+
active_points: List[AstrologicalPoint]
|
|
617
|
+
) -> None:
|
|
618
|
+
"""
|
|
619
|
+
Calculate a single planet's position with error handling and store it in the data dictionary.
|
|
620
|
+
|
|
621
|
+
Args:
|
|
622
|
+
data: The data dictionary to store the planet information
|
|
623
|
+
planet_name: Name of the planet
|
|
624
|
+
planet_id: Swiss Ephemeris planet ID
|
|
625
|
+
julian_day: Julian day for the calculation
|
|
626
|
+
iflag: Swiss Ephemeris calculation flags
|
|
627
|
+
houses_degree_ut: House degrees for house calculation
|
|
628
|
+
point_type: Type of point being calculated
|
|
629
|
+
calculated_planets: List to track calculated planets
|
|
630
|
+
active_points: List of active points to modify if error occurs
|
|
631
|
+
"""
|
|
632
|
+
try:
|
|
633
|
+
# Calculate planet position using Swiss Ephemeris
|
|
634
|
+
planet_calc = swe.calc_ut(julian_day, planet_id, iflag)[0]
|
|
635
|
+
|
|
636
|
+
# Create Kerykeion point from degree
|
|
637
|
+
data[planet_name.lower()] = get_kerykeion_point_from_degree(
|
|
638
|
+
planet_calc[0], planet_name, point_type=point_type
|
|
639
|
+
)
|
|
640
|
+
|
|
641
|
+
# Calculate house position
|
|
642
|
+
data[planet_name.lower()].house = get_planet_house(planet_calc[0], houses_degree_ut)
|
|
643
|
+
|
|
644
|
+
# Determine if planet is retrograde
|
|
645
|
+
data[planet_name.lower()].retrograde = planet_calc[3] < 0
|
|
646
|
+
|
|
647
|
+
# Track calculated planet
|
|
648
|
+
calculated_planets.append(planet_name)
|
|
649
|
+
|
|
650
|
+
except Exception as e:
|
|
651
|
+
logging.error(f"Error calculating {planet_name}: {e}")
|
|
652
|
+
if planet_name in active_points:
|
|
653
|
+
active_points.remove(planet_name)
|
|
654
|
+
|
|
633
655
|
@classmethod
|
|
634
656
|
def _calculate_planets(cls, data: Dict[str, Any], active_points: List[AstrologicalPoint]) -> None:
|
|
635
657
|
"""Calculate planetary positions and related information"""
|
|
@@ -650,83 +672,43 @@ class AstrologicalSubjectFactory:
|
|
|
650
672
|
|
|
651
673
|
# Calculate Sun
|
|
652
674
|
if should_calculate("Sun"):
|
|
653
|
-
|
|
654
|
-
data["sun"] = get_kerykeion_point_from_degree(sun_deg, "Sun", point_type=point_type)
|
|
655
|
-
data["sun"].house = get_planet_house(sun_deg, houses_degree_ut)
|
|
656
|
-
data["sun"].retrograde = swe.calc_ut(julian_day, 0, iflag)[0][3] < 0
|
|
657
|
-
calculated_planets.append("Sun")
|
|
675
|
+
cls._calculate_single_planet(data, "Sun", 0, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
658
676
|
|
|
659
677
|
# Calculate Moon
|
|
660
678
|
if should_calculate("Moon"):
|
|
661
|
-
|
|
662
|
-
data["moon"] = get_kerykeion_point_from_degree(moon_deg, "Moon", point_type=point_type)
|
|
663
|
-
data["moon"].house = get_planet_house(moon_deg, houses_degree_ut)
|
|
664
|
-
data["moon"].retrograde = swe.calc_ut(julian_day, 1, iflag)[0][3] < 0
|
|
665
|
-
calculated_planets.append("Moon")
|
|
679
|
+
cls._calculate_single_planet(data, "Moon", 1, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
666
680
|
|
|
667
681
|
# Calculate Mercury
|
|
668
682
|
if should_calculate("Mercury"):
|
|
669
|
-
|
|
670
|
-
data["mercury"] = get_kerykeion_point_from_degree(mercury_deg, "Mercury", point_type=point_type)
|
|
671
|
-
data["mercury"].house = get_planet_house(mercury_deg, houses_degree_ut)
|
|
672
|
-
data["mercury"].retrograde = swe.calc_ut(julian_day, 2, iflag)[0][3] < 0
|
|
673
|
-
calculated_planets.append("Mercury")
|
|
683
|
+
cls._calculate_single_planet(data, "Mercury", 2, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
674
684
|
|
|
675
685
|
# Calculate Venus
|
|
676
686
|
if should_calculate("Venus"):
|
|
677
|
-
|
|
678
|
-
data["venus"] = get_kerykeion_point_from_degree(venus_deg, "Venus", point_type=point_type)
|
|
679
|
-
data["venus"].house = get_planet_house(venus_deg, houses_degree_ut)
|
|
680
|
-
data["venus"].retrograde = swe.calc_ut(julian_day, 3, iflag)[0][3] < 0
|
|
681
|
-
calculated_planets.append("Venus")
|
|
687
|
+
cls._calculate_single_planet(data, "Venus", 3, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
682
688
|
|
|
683
689
|
# Calculate Mars
|
|
684
690
|
if should_calculate("Mars"):
|
|
685
|
-
|
|
686
|
-
data["mars"] = get_kerykeion_point_from_degree(mars_deg, "Mars", point_type=point_type)
|
|
687
|
-
data["mars"].house = get_planet_house(mars_deg, houses_degree_ut)
|
|
688
|
-
data["mars"].retrograde = swe.calc_ut(julian_day, 4, iflag)[0][3] < 0
|
|
689
|
-
calculated_planets.append("Mars")
|
|
691
|
+
cls._calculate_single_planet(data, "Mars", 4, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
690
692
|
|
|
691
693
|
# Calculate Jupiter
|
|
692
694
|
if should_calculate("Jupiter"):
|
|
693
|
-
|
|
694
|
-
data["jupiter"] = get_kerykeion_point_from_degree(jupiter_deg, "Jupiter", point_type=point_type)
|
|
695
|
-
data["jupiter"].house = get_planet_house(jupiter_deg, houses_degree_ut)
|
|
696
|
-
data["jupiter"].retrograde = swe.calc_ut(julian_day, 5, iflag)[0][3] < 0
|
|
697
|
-
calculated_planets.append("Jupiter")
|
|
695
|
+
cls._calculate_single_planet(data, "Jupiter", 5, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
698
696
|
|
|
699
697
|
# Calculate Saturn
|
|
700
698
|
if should_calculate("Saturn"):
|
|
701
|
-
|
|
702
|
-
data["saturn"] = get_kerykeion_point_from_degree(saturn_deg, "Saturn", point_type=point_type)
|
|
703
|
-
data["saturn"].house = get_planet_house(saturn_deg, houses_degree_ut)
|
|
704
|
-
data["saturn"].retrograde = swe.calc_ut(julian_day, 6, iflag)[0][3] < 0
|
|
705
|
-
calculated_planets.append("Saturn")
|
|
699
|
+
cls._calculate_single_planet(data, "Saturn", 6, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
706
700
|
|
|
707
701
|
# Calculate Uranus
|
|
708
702
|
if should_calculate("Uranus"):
|
|
709
|
-
|
|
710
|
-
data["uranus"] = get_kerykeion_point_from_degree(uranus_deg, "Uranus", point_type=point_type)
|
|
711
|
-
data["uranus"].house = get_planet_house(uranus_deg, houses_degree_ut)
|
|
712
|
-
data["uranus"].retrograde = swe.calc_ut(julian_day, 7, iflag)[0][3] < 0
|
|
713
|
-
calculated_planets.append("Uranus")
|
|
703
|
+
cls._calculate_single_planet(data, "Uranus", 7, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
714
704
|
|
|
715
705
|
# Calculate Neptune
|
|
716
706
|
if should_calculate("Neptune"):
|
|
717
|
-
|
|
718
|
-
data["neptune"] = get_kerykeion_point_from_degree(neptune_deg, "Neptune", point_type=point_type)
|
|
719
|
-
data["neptune"].house = get_planet_house(neptune_deg, houses_degree_ut)
|
|
720
|
-
data["neptune"].retrograde = swe.calc_ut(julian_day, 8, iflag)[0][3] < 0
|
|
721
|
-
calculated_planets.append("Neptune")
|
|
707
|
+
cls._calculate_single_planet(data, "Neptune", 8, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
722
708
|
|
|
723
709
|
# Calculate Pluto
|
|
724
710
|
if should_calculate("Pluto"):
|
|
725
|
-
|
|
726
|
-
data["pluto"] = get_kerykeion_point_from_degree(pluto_deg, "Pluto", point_type=point_type)
|
|
727
|
-
data["pluto"].house = get_planet_house(pluto_deg, houses_degree_ut)
|
|
728
|
-
data["pluto"].retrograde = swe.calc_ut(julian_day, 9, iflag)[0][3] < 0
|
|
729
|
-
calculated_planets.append("Pluto")
|
|
711
|
+
cls._calculate_single_planet(data, "Pluto", 9, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
730
712
|
|
|
731
713
|
# ==================
|
|
732
714
|
# LUNAR NODES
|
|
@@ -734,19 +716,11 @@ class AstrologicalSubjectFactory:
|
|
|
734
716
|
|
|
735
717
|
# Calculate Mean Lunar Node
|
|
736
718
|
if should_calculate("Mean_Node"):
|
|
737
|
-
|
|
738
|
-
data["mean_node"] = get_kerykeion_point_from_degree(mean_node_deg, "Mean_Node", point_type=point_type)
|
|
739
|
-
data["mean_node"].house = get_planet_house(mean_node_deg, houses_degree_ut)
|
|
740
|
-
data["mean_node"].retrograde = swe.calc_ut(julian_day, 10, iflag)[0][3] < 0
|
|
741
|
-
calculated_planets.append("Mean_Node")
|
|
719
|
+
cls._calculate_single_planet(data, "Mean_Node", 10, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
742
720
|
|
|
743
721
|
# Calculate True Lunar Node
|
|
744
722
|
if should_calculate("True_Node"):
|
|
745
|
-
|
|
746
|
-
data["true_node"] = get_kerykeion_point_from_degree(true_node_deg, "True_Node", point_type=point_type)
|
|
747
|
-
data["true_node"].house = get_planet_house(true_node_deg, houses_degree_ut)
|
|
748
|
-
data["true_node"].retrograde = swe.calc_ut(julian_day, 11, iflag)[0][3] < 0
|
|
749
|
-
calculated_planets.append("True_Node")
|
|
723
|
+
cls._calculate_single_planet(data, "True_Node", 11, julian_day, iflag, houses_degree_ut, point_type, calculated_planets, active_points)
|
|
750
724
|
|
|
751
725
|
# Calculate Mean South Node (opposite to Mean North Node)
|
|
752
726
|
if should_calculate("Mean_South_Node") and "mean_node" in data:
|
|
@@ -774,28 +748,17 @@ class AstrologicalSubjectFactory:
|
|
|
774
748
|
|
|
775
749
|
# Calculate Mean Lilith (Mean Black Moon)
|
|
776
750
|
if should_calculate("Mean_Lilith"):
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
data["mean_lilith"].retrograde = swe.calc_ut(julian_day, 12, iflag)[0][3] < 0
|
|
782
|
-
calculated_planets.append("Mean_Lilith")
|
|
783
|
-
except Exception as e:
|
|
784
|
-
logging.error(f"Error calculating Mean Lilith: {e}")
|
|
785
|
-
active_points.remove("Mean_Lilith")
|
|
786
|
-
|
|
751
|
+
cls._calculate_single_planet(
|
|
752
|
+
data, "Mean_Lilith", 12, julian_day, iflag, houses_degree_ut,
|
|
753
|
+
point_type, calculated_planets, active_points
|
|
754
|
+
)
|
|
787
755
|
|
|
788
756
|
# Calculate True Lilith (Osculating Black Moon)
|
|
789
757
|
if should_calculate("True_Lilith"):
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
data["true_lilith"].retrograde = swe.calc_ut(julian_day, 13, iflag)[0][3] < 0
|
|
795
|
-
calculated_planets.append("True_Lilith")
|
|
796
|
-
except Exception as e:
|
|
797
|
-
logging.error(f"Error calculating True Lilith: {e}")
|
|
798
|
-
active_points.remove("True_Lilith")
|
|
758
|
+
cls._calculate_single_planet(
|
|
759
|
+
data, "True_Lilith", 13, julian_day, iflag, houses_degree_ut,
|
|
760
|
+
point_type, calculated_planets, active_points
|
|
761
|
+
)
|
|
799
762
|
|
|
800
763
|
# ==================
|
|
801
764
|
# SPECIAL POINTS
|
|
@@ -803,39 +766,24 @@ class AstrologicalSubjectFactory:
|
|
|
803
766
|
|
|
804
767
|
# Calculate Earth - useful for heliocentric charts
|
|
805
768
|
if should_calculate("Earth"):
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
data["earth"].retrograde = swe.calc_ut(julian_day, 14, iflag)[0][3] < 0
|
|
811
|
-
calculated_planets.append("Earth")
|
|
812
|
-
except Exception as e:
|
|
813
|
-
logging.error(f"Error calculating Earth position: {e}")
|
|
814
|
-
active_points.remove("Earth")
|
|
769
|
+
cls._calculate_single_planet(
|
|
770
|
+
data, "Earth", 14, julian_day, iflag, houses_degree_ut,
|
|
771
|
+
point_type, calculated_planets, active_points
|
|
772
|
+
)
|
|
815
773
|
|
|
816
774
|
# Calculate Chiron
|
|
817
775
|
if should_calculate("Chiron"):
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
data["chiron"].retrograde = swe.calc_ut(julian_day, 15, iflag)[0][3] < 0
|
|
823
|
-
calculated_planets.append("Chiron")
|
|
824
|
-
except Exception as e:
|
|
825
|
-
logging.error(f"Error calculating Chiron position: {e}")
|
|
826
|
-
active_points.remove("Chiron")
|
|
776
|
+
cls._calculate_single_planet(
|
|
777
|
+
data, "Chiron", 15, julian_day, iflag, houses_degree_ut,
|
|
778
|
+
point_type, calculated_planets, active_points
|
|
779
|
+
)
|
|
827
780
|
|
|
828
781
|
# Calculate Pholus
|
|
829
782
|
if should_calculate("Pholus"):
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
data["pholus"].retrograde = swe.calc_ut(julian_day, 16, iflag)[0][3] < 0
|
|
835
|
-
calculated_planets.append("Pholus")
|
|
836
|
-
except Exception as e:
|
|
837
|
-
logging.error(f"Error calculating Pholus position: {e}")
|
|
838
|
-
active_points.remove("Pholus")
|
|
783
|
+
cls._calculate_single_planet(
|
|
784
|
+
data, "Pholus", 16, julian_day, iflag, houses_degree_ut,
|
|
785
|
+
point_type, calculated_planets, active_points
|
|
786
|
+
)
|
|
839
787
|
|
|
840
788
|
# ==================
|
|
841
789
|
# ASTEROIDS
|
|
@@ -843,51 +791,31 @@ class AstrologicalSubjectFactory:
|
|
|
843
791
|
|
|
844
792
|
# Calculate Ceres
|
|
845
793
|
if should_calculate("Ceres"):
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
data["ceres"].retrograde = swe.calc_ut(julian_day, 17, iflag)[0][3] < 0
|
|
851
|
-
calculated_planets.append("Ceres")
|
|
852
|
-
except Exception as e:
|
|
853
|
-
logging.error(f"Error calculating Ceres position: {e}")
|
|
854
|
-
active_points.remove("Ceres")
|
|
794
|
+
cls._calculate_single_planet(
|
|
795
|
+
data, "Ceres", 17, julian_day, iflag, houses_degree_ut,
|
|
796
|
+
point_type, calculated_planets, active_points
|
|
797
|
+
)
|
|
855
798
|
|
|
856
799
|
# Calculate Pallas
|
|
857
800
|
if should_calculate("Pallas"):
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
data["pallas"].retrograde = swe.calc_ut(julian_day, 18, iflag)[0][3] < 0
|
|
863
|
-
calculated_planets.append("Pallas")
|
|
864
|
-
except Exception as e:
|
|
865
|
-
logging.error(f"Error calculating Pallas position: {e}")
|
|
866
|
-
active_points.remove("Pallas")
|
|
801
|
+
cls._calculate_single_planet(
|
|
802
|
+
data, "Pallas", 18, julian_day, iflag, houses_degree_ut,
|
|
803
|
+
point_type, calculated_planets, active_points
|
|
804
|
+
)
|
|
867
805
|
|
|
868
806
|
# Calculate Juno
|
|
869
807
|
if should_calculate("Juno"):
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
data["juno"].retrograde = swe.calc_ut(julian_day, 19, iflag)[0][3] < 0
|
|
875
|
-
calculated_planets.append("Juno")
|
|
876
|
-
except Exception as e:
|
|
877
|
-
logging.error(f"Error calculating Juno position: {e}")
|
|
878
|
-
active_points.remove("Juno")
|
|
808
|
+
cls._calculate_single_planet(
|
|
809
|
+
data, "Juno", 19, julian_day, iflag, houses_degree_ut,
|
|
810
|
+
point_type, calculated_planets, active_points
|
|
811
|
+
)
|
|
879
812
|
|
|
880
813
|
# Calculate Vesta
|
|
881
814
|
if should_calculate("Vesta"):
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
data["vesta"].retrograde = swe.calc_ut(julian_day, 20, iflag)[0][3] < 0
|
|
887
|
-
calculated_planets.append("Vesta")
|
|
888
|
-
except Exception as e:
|
|
889
|
-
logging.error(f"Error calculating Vesta position: {e}")
|
|
890
|
-
active_points.remove("Vesta")
|
|
815
|
+
cls._calculate_single_planet(
|
|
816
|
+
data, "Vesta", 20, julian_day, iflag, houses_degree_ut,
|
|
817
|
+
point_type, calculated_planets, active_points
|
|
818
|
+
)
|
|
891
819
|
|
|
892
820
|
# ==================
|
|
893
821
|
# TRANS-NEPTUNIAN OBJECTS
|
|
@@ -896,10 +824,10 @@ class AstrologicalSubjectFactory:
|
|
|
896
824
|
# Calculate Eris
|
|
897
825
|
if should_calculate("Eris"):
|
|
898
826
|
try:
|
|
899
|
-
|
|
900
|
-
data["eris"] = get_kerykeion_point_from_degree(
|
|
901
|
-
data["eris"].house = get_planet_house(
|
|
902
|
-
data["eris"].retrograde =
|
|
827
|
+
eris_calc = swe.calc_ut(julian_day, swe.AST_OFFSET + 136199, iflag)[0]
|
|
828
|
+
data["eris"] = get_kerykeion_point_from_degree(eris_calc[0], "Eris", point_type=point_type)
|
|
829
|
+
data["eris"].house = get_planet_house(eris_calc[0], houses_degree_ut)
|
|
830
|
+
data["eris"].retrograde = eris_calc[3] < 0
|
|
903
831
|
calculated_planets.append("Eris")
|
|
904
832
|
except Exception as e:
|
|
905
833
|
logging.warning(f"Could not calculate Eris position: {e}")
|
|
@@ -908,10 +836,10 @@ class AstrologicalSubjectFactory:
|
|
|
908
836
|
# Calculate Sedna
|
|
909
837
|
if should_calculate("Sedna"):
|
|
910
838
|
try:
|
|
911
|
-
|
|
912
|
-
data["sedna"] = get_kerykeion_point_from_degree(
|
|
913
|
-
data["sedna"].house = get_planet_house(
|
|
914
|
-
data["sedna"].retrograde =
|
|
839
|
+
sedna_calc = swe.calc_ut(julian_day, swe.AST_OFFSET + 90377, iflag)[0]
|
|
840
|
+
data["sedna"] = get_kerykeion_point_from_degree(sedna_calc[0], "Sedna", point_type=point_type)
|
|
841
|
+
data["sedna"].house = get_planet_house(sedna_calc[0], houses_degree_ut)
|
|
842
|
+
data["sedna"].retrograde = sedna_calc[3] < 0
|
|
915
843
|
calculated_planets.append("Sedna")
|
|
916
844
|
except Exception as e:
|
|
917
845
|
logging.warning(f"Could not calculate Sedna position: {e}")
|
|
@@ -920,10 +848,10 @@ class AstrologicalSubjectFactory:
|
|
|
920
848
|
# Calculate Haumea
|
|
921
849
|
if should_calculate("Haumea"):
|
|
922
850
|
try:
|
|
923
|
-
|
|
924
|
-
data["haumea"] = get_kerykeion_point_from_degree(
|
|
925
|
-
data["haumea"].house = get_planet_house(
|
|
926
|
-
data["haumea"].retrograde =
|
|
851
|
+
haumea_calc = swe.calc_ut(julian_day, swe.AST_OFFSET + 136108, iflag)[0]
|
|
852
|
+
data["haumea"] = get_kerykeion_point_from_degree(haumea_calc[0], "Haumea", point_type=point_type)
|
|
853
|
+
data["haumea"].house = get_planet_house(haumea_calc[0], houses_degree_ut)
|
|
854
|
+
data["haumea"].retrograde = haumea_calc[3] < 0
|
|
927
855
|
calculated_planets.append("Haumea")
|
|
928
856
|
except Exception as e:
|
|
929
857
|
logging.warning(f"Could not calculate Haumea position: {e}")
|
|
@@ -932,10 +860,10 @@ class AstrologicalSubjectFactory:
|
|
|
932
860
|
# Calculate Makemake
|
|
933
861
|
if should_calculate("Makemake"):
|
|
934
862
|
try:
|
|
935
|
-
|
|
936
|
-
data["makemake"] = get_kerykeion_point_from_degree(
|
|
937
|
-
data["makemake"].house = get_planet_house(
|
|
938
|
-
data["makemake"].retrograde =
|
|
863
|
+
makemake_calc = swe.calc_ut(julian_day, swe.AST_OFFSET + 136472, iflag)[0]
|
|
864
|
+
data["makemake"] = get_kerykeion_point_from_degree(makemake_calc[0], "Makemake", point_type=point_type)
|
|
865
|
+
data["makemake"].house = get_planet_house(makemake_calc[0], houses_degree_ut)
|
|
866
|
+
data["makemake"].retrograde = makemake_calc[3] < 0
|
|
939
867
|
calculated_planets.append("Makemake")
|
|
940
868
|
except Exception as e:
|
|
941
869
|
logging.warning(f"Could not calculate Makemake position: {e}")
|
|
@@ -944,10 +872,10 @@ class AstrologicalSubjectFactory:
|
|
|
944
872
|
# Calculate Ixion
|
|
945
873
|
if should_calculate("Ixion"):
|
|
946
874
|
try:
|
|
947
|
-
|
|
948
|
-
data["ixion"] = get_kerykeion_point_from_degree(
|
|
949
|
-
data["ixion"].house = get_planet_house(
|
|
950
|
-
data["ixion"].retrograde =
|
|
875
|
+
ixion_calc = swe.calc_ut(julian_day, swe.AST_OFFSET + 28978, iflag)[0]
|
|
876
|
+
data["ixion"] = get_kerykeion_point_from_degree(ixion_calc[0], "Ixion", point_type=point_type)
|
|
877
|
+
data["ixion"].house = get_planet_house(ixion_calc[0], houses_degree_ut)
|
|
878
|
+
data["ixion"].retrograde = ixion_calc[3] < 0
|
|
951
879
|
calculated_planets.append("Ixion")
|
|
952
880
|
except Exception as e:
|
|
953
881
|
logging.warning(f"Could not calculate Ixion position: {e}")
|
|
@@ -956,10 +884,10 @@ class AstrologicalSubjectFactory:
|
|
|
956
884
|
# Calculate Orcus
|
|
957
885
|
if should_calculate("Orcus"):
|
|
958
886
|
try:
|
|
959
|
-
|
|
960
|
-
data["orcus"] = get_kerykeion_point_from_degree(
|
|
961
|
-
data["orcus"].house = get_planet_house(
|
|
962
|
-
data["orcus"].retrograde =
|
|
887
|
+
orcus_calc = swe.calc_ut(julian_day, swe.AST_OFFSET + 90482, iflag)[0]
|
|
888
|
+
data["orcus"] = get_kerykeion_point_from_degree(orcus_calc[0], "Orcus", point_type=point_type)
|
|
889
|
+
data["orcus"].house = get_planet_house(orcus_calc[0], houses_degree_ut)
|
|
890
|
+
data["orcus"].retrograde = orcus_calc[3] < 0
|
|
963
891
|
calculated_planets.append("Orcus")
|
|
964
892
|
except Exception as e:
|
|
965
893
|
logging.warning(f"Could not calculate Orcus position: {e}")
|
|
@@ -968,10 +896,10 @@ class AstrologicalSubjectFactory:
|
|
|
968
896
|
# Calculate Quaoar
|
|
969
897
|
if should_calculate("Quaoar"):
|
|
970
898
|
try:
|
|
971
|
-
|
|
972
|
-
data["quaoar"] = get_kerykeion_point_from_degree(
|
|
973
|
-
data["quaoar"].house = get_planet_house(
|
|
974
|
-
data["quaoar"].retrograde =
|
|
899
|
+
quaoar_calc = swe.calc_ut(julian_day, swe.AST_OFFSET + 50000, iflag)[0]
|
|
900
|
+
data["quaoar"] = get_kerykeion_point_from_degree(quaoar_calc[0], "Quaoar", point_type=point_type)
|
|
901
|
+
data["quaoar"].house = get_planet_house(quaoar_calc[0], houses_degree_ut)
|
|
902
|
+
data["quaoar"].retrograde = quaoar_calc[3] < 0
|
|
975
903
|
calculated_planets.append("Quaoar")
|
|
976
904
|
except Exception as e:
|
|
977
905
|
logging.warning(f"Could not calculate Quaoar position: {e}")
|
|
@@ -1015,12 +943,34 @@ class AstrologicalSubjectFactory:
|
|
|
1015
943
|
|
|
1016
944
|
# Calculate Pars Fortunae (Part of Fortune)
|
|
1017
945
|
if should_calculate("Pars_Fortunae"):
|
|
946
|
+
# Auto-activate required points with notification
|
|
947
|
+
required_points: List[AstrologicalPoint] = ["Ascendant", "Sun", "Moon"]
|
|
948
|
+
missing_points = [point for point in required_points if point not in active_points]
|
|
949
|
+
if missing_points:
|
|
950
|
+
logging.info(f"Automatically adding required points for Pars_Fortunae: {missing_points}")
|
|
951
|
+
active_points.extend(cast(List[AstrologicalPoint], missing_points))
|
|
952
|
+
# Recalculate the missing points
|
|
953
|
+
for point in missing_points:
|
|
954
|
+
if point == "Sun" and point not in data:
|
|
955
|
+
sun_calc = swe.calc_ut(julian_day, 0, iflag)[0]
|
|
956
|
+
data["sun"] = get_kerykeion_point_from_degree(sun_calc[0], "Sun", point_type=point_type)
|
|
957
|
+
data["sun"].house = get_planet_house(sun_calc[0], houses_degree_ut)
|
|
958
|
+
data["sun"].retrograde = sun_calc[3] < 0
|
|
959
|
+
elif point == "Moon" and point not in data:
|
|
960
|
+
moon_calc = swe.calc_ut(julian_day, 1, iflag)[0]
|
|
961
|
+
data["moon"] = get_kerykeion_point_from_degree(moon_calc[0], "Moon", point_type=point_type)
|
|
962
|
+
data["moon"].house = get_planet_house(moon_calc[0], houses_degree_ut)
|
|
963
|
+
data["moon"].retrograde = moon_calc[3] < 0
|
|
964
|
+
|
|
1018
965
|
# Check if required points are available
|
|
1019
966
|
if all(k in data for k in ["ascendant", "sun", "moon"]):
|
|
1020
967
|
# Different calculation for day and night charts
|
|
1021
968
|
# Day birth (Sun above horizon): ASC + Moon - Sun
|
|
1022
969
|
# Night birth (Sun below horizon): ASC + Sun - Moon
|
|
1023
|
-
|
|
970
|
+
if data["sun"].house:
|
|
971
|
+
is_day_chart = get_house_number(data["sun"].house) < 7 # Houses 1-6 are above horizon
|
|
972
|
+
else:
|
|
973
|
+
is_day_chart = True # Default to day chart if house is None
|
|
1024
974
|
|
|
1025
975
|
if is_day_chart:
|
|
1026
976
|
fortune_deg = math.fmod(data["ascendant"].abs_pos + data["moon"].abs_pos - data["sun"].abs_pos, 360)
|
|
@@ -1034,11 +984,33 @@ class AstrologicalSubjectFactory:
|
|
|
1034
984
|
|
|
1035
985
|
# Calculate Pars Spiritus (Part of Spirit)
|
|
1036
986
|
if should_calculate("Pars_Spiritus"):
|
|
987
|
+
# Auto-activate required points with notification
|
|
988
|
+
required_points: List[AstrologicalPoint] = ["Ascendant", "Sun", "Moon"]
|
|
989
|
+
missing_points = [point for point in required_points if point not in active_points]
|
|
990
|
+
if missing_points:
|
|
991
|
+
logging.info(f"Automatically adding required points for Pars_Spiritus: {missing_points}")
|
|
992
|
+
active_points.extend(cast(List[AstrologicalPoint], missing_points))
|
|
993
|
+
# Recalculate the missing points
|
|
994
|
+
for point in missing_points:
|
|
995
|
+
if point == "Sun" and point not in data:
|
|
996
|
+
sun_calc = swe.calc_ut(julian_day, 0, iflag)[0]
|
|
997
|
+
data["sun"] = get_kerykeion_point_from_degree(sun_calc[0], "Sun", point_type=point_type)
|
|
998
|
+
data["sun"].house = get_planet_house(sun_calc[0], houses_degree_ut)
|
|
999
|
+
data["sun"].retrograde = sun_calc[3] < 0
|
|
1000
|
+
elif point == "Moon" and point not in data:
|
|
1001
|
+
moon_calc = swe.calc_ut(julian_day, 1, iflag)[0]
|
|
1002
|
+
data["moon"] = get_kerykeion_point_from_degree(moon_calc[0], "Moon", point_type=point_type)
|
|
1003
|
+
data["moon"].house = get_planet_house(moon_calc[0], houses_degree_ut)
|
|
1004
|
+
data["moon"].retrograde = moon_calc[3] < 0
|
|
1005
|
+
|
|
1037
1006
|
# Check if required points are available
|
|
1038
1007
|
if all(k in data for k in ["ascendant", "sun", "moon"]):
|
|
1039
1008
|
# Day birth: ASC + Sun - Moon
|
|
1040
1009
|
# Night birth: ASC + Moon - Sun
|
|
1041
|
-
|
|
1010
|
+
if data["sun"].house:
|
|
1011
|
+
is_day_chart = get_house_number(data["sun"].house) < 7
|
|
1012
|
+
else:
|
|
1013
|
+
is_day_chart = True # Default to day chart if house is None
|
|
1042
1014
|
|
|
1043
1015
|
if is_day_chart:
|
|
1044
1016
|
spirit_deg = math.fmod(data["ascendant"].abs_pos + data["sun"].abs_pos - data["moon"].abs_pos, 360)
|
|
@@ -1052,19 +1024,56 @@ class AstrologicalSubjectFactory:
|
|
|
1052
1024
|
|
|
1053
1025
|
# Calculate Pars Amoris (Part of Eros/Love)
|
|
1054
1026
|
if should_calculate("Pars_Amoris"):
|
|
1027
|
+
# Auto-activate required points with notification
|
|
1028
|
+
required_points: List[AstrologicalPoint] = ["Ascendant", "Venus", "Sun"]
|
|
1029
|
+
missing_points = [point for point in required_points if point not in active_points]
|
|
1030
|
+
if missing_points:
|
|
1031
|
+
logging.info(f"Automatically adding required points for Pars_Amoris: {missing_points}")
|
|
1032
|
+
active_points.extend(cast(List[AstrologicalPoint], missing_points))
|
|
1033
|
+
# Recalculate the missing points
|
|
1034
|
+
for point in missing_points:
|
|
1035
|
+
if point == "Sun" and point not in data:
|
|
1036
|
+
sun_calc = swe.calc_ut(julian_day, 0, iflag)[0]
|
|
1037
|
+
data["sun"] = get_kerykeion_point_from_degree(sun_calc[0], "Sun", point_type=point_type)
|
|
1038
|
+
data["sun"].house = get_planet_house(sun_calc[0], houses_degree_ut)
|
|
1039
|
+
data["sun"].retrograde = sun_calc[3] < 0
|
|
1040
|
+
elif point == "Venus" and point not in data:
|
|
1041
|
+
venus_calc = swe.calc_ut(julian_day, 3, iflag)[0]
|
|
1042
|
+
data["venus"] = get_kerykeion_point_from_degree(venus_calc[0], "Venus", point_type=point_type)
|
|
1043
|
+
data["venus"].house = get_planet_house(venus_calc[0], houses_degree_ut)
|
|
1044
|
+
data["venus"].retrograde = venus_calc[3] < 0
|
|
1045
|
+
|
|
1055
1046
|
# Check if required points are available
|
|
1056
|
-
if all(k in data for k in ["ascendant", "venus"]):
|
|
1047
|
+
if all(k in data for k in ["ascendant", "venus", "sun"]):
|
|
1057
1048
|
# ASC + Venus - Sun
|
|
1058
|
-
|
|
1059
|
-
amoris_deg = math.fmod(data["ascendant"].abs_pos + data["venus"].abs_pos - data["sun"].abs_pos, 360)
|
|
1049
|
+
amoris_deg = math.fmod(data["ascendant"].abs_pos + data["venus"].abs_pos - data["sun"].abs_pos, 360)
|
|
1060
1050
|
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1051
|
+
data["pars_amoris"] = get_kerykeion_point_from_degree(amoris_deg, "Pars_Amoris", point_type=point_type)
|
|
1052
|
+
data["pars_amoris"].house = get_planet_house(amoris_deg, houses_degree_ut)
|
|
1053
|
+
data["pars_amoris"].retrograde = False
|
|
1054
|
+
calculated_planets.append("Pars_Amoris")
|
|
1065
1055
|
|
|
1066
1056
|
# Calculate Pars Fidei (Part of Faith)
|
|
1067
1057
|
if should_calculate("Pars_Fidei"):
|
|
1058
|
+
# Auto-activate required points with notification
|
|
1059
|
+
required_points: List[AstrologicalPoint] = ["Ascendant", "Jupiter", "Saturn"]
|
|
1060
|
+
missing_points = [point for point in required_points if point not in active_points]
|
|
1061
|
+
if missing_points:
|
|
1062
|
+
logging.info(f"Automatically adding required points for Pars_Fidei: {missing_points}")
|
|
1063
|
+
active_points.extend(cast(List[AstrologicalPoint], missing_points))
|
|
1064
|
+
# Recalculate the missing points
|
|
1065
|
+
for point in missing_points:
|
|
1066
|
+
if point == "Jupiter" and point not in data:
|
|
1067
|
+
jupiter_calc = swe.calc_ut(julian_day, 5, iflag)[0]
|
|
1068
|
+
data["jupiter"] = get_kerykeion_point_from_degree(jupiter_calc[0], "Jupiter", point_type=point_type)
|
|
1069
|
+
data["jupiter"].house = get_planet_house(jupiter_calc[0], houses_degree_ut)
|
|
1070
|
+
data["jupiter"].retrograde = jupiter_calc[3] < 0
|
|
1071
|
+
elif point == "Saturn" and point not in data:
|
|
1072
|
+
saturn_calc = swe.calc_ut(julian_day, 6, iflag)[0]
|
|
1073
|
+
data["saturn"] = get_kerykeion_point_from_degree(saturn_calc[0], "Saturn", point_type=point_type)
|
|
1074
|
+
data["saturn"].house = get_planet_house(saturn_calc[0], houses_degree_ut)
|
|
1075
|
+
data["saturn"].retrograde = saturn_calc[3] < 0
|
|
1076
|
+
|
|
1068
1077
|
# Check if required points are available
|
|
1069
1078
|
if all(k in data for k in ["ascendant", "jupiter", "saturn"]):
|
|
1070
1079
|
# ASC + Jupiter - Saturn
|