|
|
@@ -37,6 +37,20 @@ from .chart_styles import (
|
|
|
ANGULAR_HOUSES,
|
|
|
font_face_css,
|
|
|
r as _r,
|
|
|
+ _R_OUTER,
|
|
|
+ _R_TICK_OUTER,
|
|
|
+ _R_TICK_INNER_5,
|
|
|
+ _R_TICK_INNER_1,
|
|
|
+ _R_ZODIAC_OUTER,
|
|
|
+ _R_ZODIAC_GLYPH,
|
|
|
+ _R_ZODIAC_INNER,
|
|
|
+ _R_HOUSE_NUM,
|
|
|
+ _R_CUSP_INNER,
|
|
|
+ _R_PLANET,
|
|
|
+ _R_PLANET_DEG,
|
|
|
+ _R_CONNECTOR,
|
|
|
+ _R_CENTER,
|
|
|
+ _R_ASPECT,
|
|
|
)
|
|
|
from .chart_helpers import svg_to_image, render_envelope
|
|
|
|
|
|
@@ -117,23 +131,14 @@ def _format_degree(deg_float: float) -> str:
|
|
|
return f"{d}\u00b0{m:02d}\u2019"
|
|
|
|
|
|
|
|
|
-# ── Ring proportion constants (as fraction of outer_r) ────────────────
|
|
|
-# These mirror professional chart proportions.
|
|
|
-# outer_r = 1.0 (the canvas half-size)
|
|
|
-_R_OUTER = 1.000 # outermost edge, tick marks end here
|
|
|
-_R_TICK_OUTER = 0.980 # outer tick root (5° ticks)
|
|
|
-_R_TICK_INNER_5 = 0.955 # 5° tick inner end
|
|
|
-_R_TICK_INNER_1 = 0.967 # 1° tick inner end (not drawn at this res)
|
|
|
-_R_ZODIAC_OUTER = 0.940 # outer zodiac band edge (stroke circle)
|
|
|
-_R_ZODIAC_GLYPH = 0.855 # center of zodiac band ((0.940+0.770)/2)
|
|
|
-_R_ZODIAC_INNER = 0.770 # inner zodiac band edge (stroke circle)
|
|
|
-_R_HOUSE_NUM = 0.700 # house number label position
|
|
|
-_R_CUSP_INNER = 0.350 # house cusp lines extend inward to here
|
|
|
-_R_PLANET = 0.595 # planet glyph centre
|
|
|
-_R_PLANET_DEG = 0.490 # planet degree label (inside glyph)
|
|
|
-_R_CONNECTOR = 0.760 # connector tick inner end (near inner zodiac edge)
|
|
|
-_R_CENTER = 0.280 # inner center circle radius (was 0.18)
|
|
|
-_R_ASPECT = 0.345 # aspect lines drawn at this radius from center
|
|
|
+def _to_roman(num: int) -> str:
|
|
|
+ """Convert an integer (1-12) to a Roman numeral string."""
|
|
|
+ roman_map = {
|
|
|
+ 1: "I", 2: "II", 3: "III", 4: "IV", 5: "V",
|
|
|
+ 6: "VI", 7: "VII", 8: "VIII", 9: "IX", 10: "X",
|
|
|
+ 11: "XI", 12: "XII",
|
|
|
+ }
|
|
|
+ return roman_map.get(num, str(num))
|
|
|
|
|
|
|
|
|
# ── Main natal wheel renderer ─────────────────────────────────────────
|
|
|
@@ -305,15 +310,6 @@ def render_natal_wheel(
|
|
|
c1 = _svg_angle(cusp_lon, asc_lon)
|
|
|
c2 = _svg_angle(next_cusp, asc_lon)
|
|
|
|
|
|
- # Alternating sector fill inside the house ring
|
|
|
- if style != "minimal" and color_mode != "bw":
|
|
|
- fill_c = theme["house_fill_alt"] if i % 2 == 0 else "none"
|
|
|
- if fill_c != "none":
|
|
|
- sx, sy = _polar_to_cartesian(wheel_cx, wheel_cy, r_zod_in, c1)
|
|
|
- arc = _arc_path(wheel_cx, wheel_cy, r_zod_in, c1, c2, sweep=0)
|
|
|
- path_d = f"M {wheel_cx:.2f},{wheel_cy:.2f} L {sx:.2f},{sy:.2f} {arc} Z"
|
|
|
- dwg.add(dwg.path(d=path_d, fill=fill_c, stroke="none"))
|
|
|
-
|
|
|
# Cusp line from inner zodiac edge inward
|
|
|
is_angular = house.get("house", i + 1) in ANGULAR_HOUSES
|
|
|
sx, sy = _polar_to_cartesian(wheel_cx, wheel_cy, r_cusp_in, c1)
|
|
|
@@ -328,10 +324,12 @@ def render_natal_wheel(
|
|
|
diff = (c1 - c2) % 360.0 # CCW distance from c1 to c2
|
|
|
mid_c = (c1 - diff / 2.0) % 360.0
|
|
|
hx, hy = _polar_to_cartesian(wheel_cx, wheel_cy, r_hnum, mid_c)
|
|
|
+ house_num = house.get("house", i + 1)
|
|
|
dwg.add(dwg.text(
|
|
|
- str(house.get("house", i + 1)), insert=(hx, hy),
|
|
|
+ _to_roman(house_num), insert=(hx, hy),
|
|
|
text_anchor="middle", dominant_baseline="central",
|
|
|
- class_="lbl", font_size="11px", fill=theme["degree_text"],
|
|
|
+ class_="lbl", font_size="10px", font_style="italic",
|
|
|
+ fill=theme["degree_text"],
|
|
|
))
|
|
|
|
|
|
# ── Angle axis lines (ASC-DSC and MC-IC) ─────────────────────────
|