kerykeion 5.1.1__py3-none-any.whl → 5.1.3__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.

@@ -1023,65 +1023,34 @@ def draw_transit_aspect_list(
1023
1023
 
1024
1024
 
1025
1025
  def calculate_moon_phase_chart_params(
1026
- degrees_between_sun_and_moon: float,
1027
- latitude: float
1026
+ degrees_between_sun_and_moon: float
1028
1027
  ) -> dict:
1029
1028
  """
1030
- Calculate the parameters for the moon phase chart.
1029
+ Calculate normalized parameters used by the moon phase icon.
1031
1030
 
1032
1031
  Parameters:
1033
- - degrees_between_sun_and_moon (float): The degrees between the sun and the moon.
1034
- - latitude (float): The latitude for rotation calculation.
1032
+ - degrees_between_sun_and_moon (float): The elongation between the sun and moon.
1035
1033
 
1036
1034
  Returns:
1037
- - dict: The moon phase chart parameters.
1038
- """
1039
- deg = degrees_between_sun_and_moon
1040
-
1041
- # Initialize variables for lunar phase properties
1042
- circle_center_x = None
1043
- circle_radius = None
1044
-
1045
- # Determine lunar phase properties based on the degree
1046
- if deg < 90.0:
1047
- max_radius = deg
1048
- if deg > 80.0:
1049
- max_radius = max_radius * max_radius
1050
- circle_center_x = 20.0 + (deg / 90.0) * (max_radius + 10.0)
1051
- circle_radius = 10.0 + (deg / 90.0) * max_radius
1052
-
1053
- elif deg < 180.0:
1054
- max_radius = 180.0 - deg
1055
- if deg < 100.0:
1056
- max_radius = max_radius * max_radius
1057
- circle_center_x = 20.0 + ((deg - 90.0) / 90.0 * (max_radius + 10.0)) - (max_radius + 10.0)
1058
- circle_radius = 10.0 + max_radius - ((deg - 90.0) / 90.0 * max_radius)
1059
-
1060
- elif deg < 270.0:
1061
- max_radius = deg - 180.0
1062
- if deg > 260.0:
1063
- max_radius = max_radius * max_radius
1064
- circle_center_x = 20.0 + ((deg - 180.0) / 90.0 * (max_radius + 10.0))
1065
- circle_radius = 10.0 + ((deg - 180.0) / 90.0 * max_radius)
1066
-
1067
- elif deg < 361.0:
1068
- max_radius = 360.0 - deg
1069
- if deg < 280.0:
1070
- max_radius = max_radius * max_radius
1071
- circle_center_x = 20.0 + ((deg - 270.0) / 90.0 * (max_radius + 10.0)) - (max_radius + 10.0)
1072
- circle_radius = 10.0 + max_radius - ((deg - 270.0) / 90.0 * max_radius)
1073
-
1074
- else:
1075
- raise KerykeionException(f"Invalid degree value: {deg}")
1035
+ - dict: Normalized phase data (angle, illuminated fraction, shadow ellipse radius).
1036
+ """
1037
+ if not math.isfinite(degrees_between_sun_and_moon):
1038
+ raise KerykeionException(
1039
+ f"Invalid degree value: {degrees_between_sun_and_moon}"
1040
+ )
1076
1041
 
1042
+ phase_angle = degrees_between_sun_and_moon % 360.0
1043
+ radians = math.radians(phase_angle)
1044
+ cosine = math.cos(radians)
1045
+ illuminated_fraction = (1.0 - cosine) / 2.0
1077
1046
 
1078
- # Calculate rotation based on latitude
1079
- lunar_phase_rotate = -90.0 - latitude
1047
+ # Guard against floating point spillover outside [0, 1].
1048
+ illuminated_fraction = max(0.0, min(1.0, illuminated_fraction))
1080
1049
 
1081
1050
  return {
1082
- "circle_center_x": circle_center_x,
1083
- "circle_radius": circle_radius,
1084
- "lunar_phase_rotate": lunar_phase_rotate,
1051
+ "phase_angle": phase_angle,
1052
+ "illuminated_fraction": illuminated_fraction,
1053
+ "shadow_ellipse_rx": 10.0 * cosine,
1085
1054
  }
1086
1055
 
1087
1056
 
@@ -1697,34 +1666,92 @@ def makeLunarPhase(degrees_between_sun_and_moon: float, latitude: float) -> str:
1697
1666
 
1698
1667
  Parameters:
1699
1668
  - degrees_between_sun_and_moon (float): Angle between sun and moon in degrees
1700
- - latitude (float): Observer's latitude for correct orientation
1669
+ - latitude (float): Observer's latitude (no longer used, kept for backward compatibility)
1701
1670
 
1702
1671
  Returns:
1703
1672
  - str: SVG representation of lunar phase
1704
1673
  """
1705
- # Calculate parameters for the lunar phase visualization
1706
- params = calculate_moon_phase_chart_params(degrees_between_sun_and_moon, latitude)
1707
-
1708
- # Extract the calculated values
1709
- lunar_phase_circle_center_x = params["circle_center_x"]
1710
- lunar_phase_circle_radius = params["circle_radius"]
1711
- lunar_phase_rotate = params["lunar_phase_rotate"]
1712
-
1713
- # Generate the SVG for the lunar phase
1714
- svg = (
1715
- f'<g transform="rotate({lunar_phase_rotate} 20 10)">\n'
1716
- f' <defs>\n'
1717
- f' <clipPath id="moonPhaseCutOffCircle">\n'
1718
- f' <circle cx="20" cy="10" r="10" />\n'
1719
- f' </clipPath>\n'
1720
- f' </defs>\n'
1721
- f' <circle cx="20" cy="10" r="10" style="fill: var(--kerykeion-chart-color-lunar-phase-0)" />\n'
1722
- f' <circle cx="{lunar_phase_circle_center_x}" cy="10" r="{lunar_phase_circle_radius}" style="fill: var(--kerykeion-chart-color-lunar-phase-1)" clip-path="url(#moonPhaseCutOffCircle)" />\n'
1723
- f' <circle cx="20" cy="10" r="10" style="fill: none; stroke: var(--kerykeion-chart-color-lunar-phase-0); stroke-width: 0.5px; stroke-opacity: 0.5" />\n'
1724
- f'</g>'
1674
+ params = calculate_moon_phase_chart_params(degrees_between_sun_and_moon)
1675
+
1676
+ phase_angle = params["phase_angle"]
1677
+ illuminated_fraction = params["illuminated_fraction"]
1678
+ shadow_ellipse_rx = abs(params["shadow_ellipse_rx"])
1679
+
1680
+ radius = 10.0
1681
+ center_x = 20.0
1682
+ center_y = 10.0
1683
+
1684
+ bright_color = "var(--kerykeion-chart-color-lunar-phase-1)"
1685
+ shadow_color = "var(--kerykeion-chart-color-lunar-phase-0)"
1686
+
1687
+ is_waxing = phase_angle <= 180.0
1688
+
1689
+ if illuminated_fraction <= 1e-6:
1690
+ base_fill = shadow_color
1691
+ overlay_path = ""
1692
+ overlay_fill = ""
1693
+ elif 1.0 - illuminated_fraction <= 1e-6:
1694
+ base_fill = bright_color
1695
+ overlay_path = ""
1696
+ overlay_fill = ""
1697
+ else:
1698
+ is_lit_major = illuminated_fraction >= 0.5
1699
+ if is_lit_major:
1700
+ base_fill = bright_color
1701
+ overlay_fill = shadow_color
1702
+ overlay_side = "left" if is_waxing else "right"
1703
+ else:
1704
+ base_fill = shadow_color
1705
+ overlay_fill = bright_color
1706
+ overlay_side = "right" if is_waxing else "left"
1707
+
1708
+ # The illuminated limb is the orthographic projection of the lunar terminator;
1709
+ # it appears as an ellipse with vertical radius equal to the lunar radius and
1710
+ # horizontal radius scaled by |cos(phase)|.
1711
+ def build_lune_path(side: str, ellipse_rx: float) -> str:
1712
+ ellipse_rx = max(0.0, min(radius, ellipse_rx))
1713
+ top_y = center_y - radius
1714
+ bottom_y = center_y + radius
1715
+ circle_sweep = 1 if side == "right" else 0
1716
+
1717
+ if ellipse_rx <= 1e-6:
1718
+ return (
1719
+ f"M {center_x:.4f} {top_y:.4f}"
1720
+ f" A {radius:.4f} {radius:.4f} 0 0 {circle_sweep} {center_x:.4f} {bottom_y:.4f}"
1721
+ f" L {center_x:.4f} {top_y:.4f}"
1722
+ " Z"
1723
+ )
1724
+
1725
+ return (
1726
+ f"M {center_x:.4f} {top_y:.4f}"
1727
+ f" A {radius:.4f} {radius:.4f} 0 0 {circle_sweep} {center_x:.4f} {bottom_y:.4f}"
1728
+ f" A {ellipse_rx:.4f} {radius:.4f} 0 0 {circle_sweep} {center_x:.4f} {top_y:.4f}"
1729
+ " Z"
1730
+ )
1731
+
1732
+ overlay_path = build_lune_path(overlay_side, shadow_ellipse_rx)
1733
+
1734
+ svg_lines = [
1735
+ '<g transform="rotate(0 20 10)">',
1736
+ ' <defs>',
1737
+ ' <clipPath id="moonPhaseCutOffCircle">',
1738
+ ' <circle cx="20" cy="10" r="10" />',
1739
+ ' </clipPath>',
1740
+ ' </defs>',
1741
+ f' <circle cx="20" cy="10" r="10" style="fill: {base_fill}" />',
1742
+ ]
1743
+
1744
+ if overlay_path:
1745
+ svg_lines.append(
1746
+ f' <path d="{overlay_path}" style="fill: {overlay_fill}" clip-path="url(#moonPhaseCutOffCircle)" />'
1747
+ )
1748
+
1749
+ svg_lines.append(
1750
+ ' <circle cx="20" cy="10" r="10" style="fill: none; stroke: var(--kerykeion-chart-color-lunar-phase-0); stroke-width: 0.5px; stroke-opacity: 0.5" />'
1725
1751
  )
1752
+ svg_lines.append('</g>')
1726
1753
 
1727
- return svg
1754
+ return "\n".join(svg_lines)
1728
1755
 
1729
1756
 
1730
1757
  def calculate_quality_points(
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: kerykeion
3
- Version: 5.1.1
3
+ Version: 5.1.3
4
4
  Summary: A Python library for astrological calculations, including natal charts, houses, planetary aspects, and SVG chart generation.
5
5
  Project-URL: Homepage, https://www.kerykeion.net/
6
6
  Project-URL: Repository, https://github.com/g-battaglia/kerykeion
@@ -15,7 +15,7 @@ kerykeion/aspects/aspects_factory.py,sha256=XCuOOpo0ZW7sihYT2f50bLVpebEk19b9EtEj
15
15
  kerykeion/aspects/aspects_utils.py,sha256=00-MMLEGChpceab8sHKB1_qg6EG4ycTG2u2vYZcyLmQ,5784
16
16
  kerykeion/charts/__init__.py,sha256=i9NMZ7LdkllPlqQSi1or9gTobHbROGDKmJhBDO4R0mA,128
17
17
  kerykeion/charts/chart_drawer.py,sha256=VCk2s6kUT2AhNWhVdepuhp2_6qHk3Fiq0d4EMq0pvZQ,122240
18
- kerykeion/charts/charts_utils.py,sha256=JzPnbZJnH4lrIENb5saRtbHn_GbyaElXVBwKdyP90Dg,70110
18
+ kerykeion/charts/charts_utils.py,sha256=cZ_LNkaYXElTl-zhSaJGezWXoxPjZx_clknUFyL5wis,70906
19
19
  kerykeion/charts/draw_planets.py,sha256=tIj3FeLLomVSbCaZUxfw_qBEB3pxi4EIEhqaeTgTyTY,29061
20
20
  kerykeion/charts/templates/aspect_grid_only.xml,sha256=v3QtNMjk-kBdUTfB0r6thg--Ta_tNFdRQCzdk5PAycY,86429
21
21
  kerykeion/charts/templates/chart.xml,sha256=oUI9hV--4rdsVFqZJ8ChpgC2ZgfnqlL2Tl2vco1vlOc,92095
@@ -57,7 +57,7 @@ kerykeion/sweph/ast28/se28978s.se1,sha256=nU2Qp-ELc_tzFnRc1QT6uVueWXEipvhYDgfQRX
57
57
  kerykeion/sweph/ast50/se50000s.se1,sha256=9jTrPlIrZMOBWC9cNgwzcfz0KBHdXFZoY9-NZ_HtECo,15748
58
58
  kerykeion/sweph/ast90/se90377s.se1,sha256=bto2x4LtBv8b1ej1XhVFYq-kfHO9cczbKV9U1f9UVu4,10288
59
59
  kerykeion/sweph/ast90/se90482s.se1,sha256=uHxz6bP4K8zgtQFrlWFwxrYfmqm5kXxsg6OYhAIUbAA,16173
60
- kerykeion-5.1.1.dist-info/METADATA,sha256=Ec1Bzr2pPHj_k2Y_1QpZVIE0bHRRHFmJgQCvK3FgFpg,61445
61
- kerykeion-5.1.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
62
- kerykeion-5.1.1.dist-info/licenses/LICENSE,sha256=UTLH8EdbAsgQei4PA2PnBCPGLSZkq5J-dhkyJuXgWQU,34273
63
- kerykeion-5.1.1.dist-info/RECORD,,
60
+ kerykeion-5.1.3.dist-info/METADATA,sha256=ViUTy5oLSxPoCKl2q3ZOYTPF8gmmflVuJMQmw5_3ChE,61445
61
+ kerykeion-5.1.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
62
+ kerykeion-5.1.3.dist-info/licenses/LICENSE,sha256=UTLH8EdbAsgQei4PA2PnBCPGLSZkq5J-dhkyJuXgWQU,34273
63
+ kerykeion-5.1.3.dist-info/RECORD,,