diff --git a/crates/modules/tahuantinsuyu/tahuantinsuyu-canvas/src/lib.rs b/crates/modules/tahuantinsuyu/tahuantinsuyu-canvas/src/lib.rs index e61d532..5bf314f 100644 --- a/crates/modules/tahuantinsuyu/tahuantinsuyu-canvas/src/lib.rs +++ b/crates/modules/tahuantinsuyu/tahuantinsuyu-canvas/src/lib.rs @@ -1067,13 +1067,25 @@ fn render_wheel( } // House numbers + (opcional) coord del cusp. + // + // El layer `natal` usa Zona CD (entre aros C y D); `topocentric` + // usa Zona BC (entre aros B y C). Los house numbers se posan al + // centro de la zona; las coord pills se posan adyacentes al aro + // interior de la propia zona, así no se sale del bloque. if visible.get(&LayerKind::Houses).copied().unwrap_or(true) { - let house_label_r = (radii.houses_outer + radii.houses_inner) / 2.0; let house_label_color = house_ring_color(palette); for layer in &render.layers { if matches!(layer.kind, LayerKind::Houses) { + let is_topo = layer.module_id == "topocentric"; + let (r_out, r_in) = if is_topo { + (radii.topo_houses_outer, radii.topo_houses_inner) + } else { + (radii.houses_outer, radii.houses_inner) + }; + let label_r = (r_out + r_in) / 2.0; + let coord_r = r_in + (r_out - r_in) * 0.18; for g in &layer.glyphs { - let (x, y) = polar_to_screen(g.deg, asc, rot_offset, house_label_r); + let (x, y) = polar_to_screen(g.deg, asc, rot_offset, label_r); if let Some(h) = g.house { wheel = wheel.child(centered_glyph( cx_center + x, @@ -1083,14 +1095,10 @@ fn render_wheel( format!("{}", h).into(), house_label_color, )); - // Coord del cusp justo dentro del anillo de - // casas — los grados se imprimen en una pill - // pequeña pegada al radio del cusp. if show_coords { let coord = format_coord_compact(g.deg); - let label_r = radii.houses_inner - 8.0 * s; let (lx, ly) = - polar_to_screen(g.deg, asc, rot_offset, label_r); + polar_to_screen(g.deg, asc, rot_offset, coord_r); wheel = wheel.child(coord_label( cx_center + lx, cy_center + ly, @@ -1167,23 +1175,14 @@ fn render_wheel( with_alpha(color, 0.85), )); - // Coord label: grado dentro del signo + glyph del - // signo, pintado afuera del disco del planeta - // (radialmente). Se pinta para el natal (afuera) - // y para el topocéntrico (más afuera aún, hacia - // el sign dial) — los dos sistemas conviven con - // sus coords. Otros overlays (progression, solar - // arc) usan badges en el footer. + // Coord label en pill — junto al planeta, dentro + // de su propia zona radial. Topo en zona BC + // (label hacia C, lado interior); natal en + // zona cerca de D (label hacia E, lado interior + // del cinturón natal — del lado de los aspectos). if show_coords && (is_natal || is_topo) { let coord = format_coord_compact(g.deg); - // Topo: label hacia ADENTRO (entre planeta y - // casas P-P arriba); natal: label hacia - // AFUERA (entre planeta y casas Placidus). - let label_r = if is_topo { - ring - disk_size * 0.7 - } else { - ring + disk_size * 0.7 - }; + let label_r = ring - disk_size * 0.7; let (lx, ly) = polar_to_screen(g.deg, asc, rot_offset, label_r); wheel = wheel.child(coord_label( cx_center + lx, @@ -1615,88 +1614,82 @@ fn format_offset(minutes: i64) -> String { // Painting // ===================================================================== +/// Geometría radial canónica de la rueda. Aros nombrados según +/// convención del usuario, de afuera hacia adentro: +/// +/// * **Aro A** (`sign_outer`) — externo del zodiaco. +/// * **Zona AB** — sign dial: glyphs de signos zodiacales. +/// * **Aro B** (`sign_inner` = `topo_houses_outer`) — interno del +/// zodiaco / externo del bloque ascensional. +/// * **Zona BC** — casas topocéntricas (cusps b→c) + planetas +/// topocéntricos, ambos con sus coordenadas. +/// * **Aro C** (`topo_houses_inner` = `houses_outer`) — separador +/// ascensional / casas geo. +/// * **Zona CD** — casas geocéntricas (cusps c→d) + sus coordenadas. +/// * **Aro D** (`houses_inner`) — externo de los planetas natales. +/// Junto a D, hacia adentro, se posan los planetas natales y sus +/// coordenadas. +/// * **Aro E** (`aspects`) — el más interno. Desde aquí nacen las +/// líneas de aspecto / relaciones / overlays opcionales. +/// +/// Los overlays adicionales (transits, midpoints, progression, solar +/// arc, composite) viven INTERIORES al aro E — solo se pintan +/// cuando el módulo correspondiente está activo, así no compiten +/// con el layout base. #[derive(Clone, Copy)] struct Radii { - // Layout outer→inner. La capa **ascensional** (sistema topocéntrico - // Polich-Page) va pegada al sign dial — su lógica nace del eje - // ASC/MC y de la ascensión recta del observador, conceptualmente - // hermana del zodiaco. La capa **geocéntrica** clásica - // (casas Placidus + planetas tropicales sin paralaje) vive más - // adentro, alrededor del cinturón de planetas natales. - sign_outer: f32, - sign_inner: f32, - /// Anillo exterior de las casas Polich-Page (topocéntricas), pegado - /// al sign dial. Los cusps llegan hasta el `sign_inner`. - topo_houses_outer: f32, - topo_houses_inner: f32, - /// Carril de planetas topocéntricos — apenas dentro del anillo - /// de casas P-P. Lleva sus propios coord labels. - topocentric: f32, - /// Anillo de glifos de tránsito (cuando el overlay está activo). + sign_outer: f32, // Aro A + sign_inner: f32, // Aro B + topo_houses_outer: f32, // = Aro B + topocentric: f32, // Zona BC: planetas topo + topo_houses_inner: f32, // Aro C + houses_outer: f32, // = Aro C + houses_inner: f32, // Aro D + bodies: f32, // Zona D-E: planetas natales (junto a D) + pd_direct: f32, // GR (cuando activo): exterior al cinturón natal + pd_converse: f32, // GR (cuando activo): interior al cinturón natal + aspects: f32, // Aro E (invisible, ancla de líneas) + // Overlays adicionales — todos interiores a E. transits: f32, - /// Casas geocéntricas (Placidus default) — más adentro que las - /// topocéntricas, claramente diferenciables. - houses_outer: f32, - houses_inner: f32, - /// Anillo de midpoints — entre cuerpos geocéntricos y `houses_inner`. midpoints: f32, - /// Anillo principal de cuerpos natales geocéntricos. - bodies: f32, - /// Borde interior del cinturón de planetas geocéntricos. - bodies_inner: f32, - /// Direcciones Primarias DIRECTAS (Sistema GR): ring exterior del - /// "abrazo" GR — justo afuera del cinturón natal. - pd_direct: f32, - /// Direcciones Primarias CONVERSAS (Sistema GR): ring interior — - /// el cinturón natal queda entre `pd_direct` (afuera) y - /// `pd_converse` (dentro), formando el dual-ring de rectificación. - pd_converse: f32, - /// Anillo interno con cuerpos progresados (overlay opcional). progression: f32, - /// Anillo más interno con cuerpos dirigidos por Solar Arc. solar_arc: f32, - /// Anillo de carta compuesta (midpoint Davison) con un partner. composite: f32, - /// Círculo donde anclan las líneas de aspecto entre cuerpos - /// natales. Justo dentro del cinturón de planetas. - aspects: f32, } impl Radii { fn from_outer(r: f32) -> Self { Self { + // Aro A — externo zodiaco. sign_outer: r, - sign_inner: r * 0.88, - // Ascensional (Polich-Page): pegado al sign dial. - topo_houses_outer: r * 0.875, - topo_houses_inner: r * 0.79, - // Carril topocéntrico de planetas: justo dentro de las - // casas P-P. Lleva sus coord labels al borde interior. - topocentric: r * 0.755, - // Tránsitos: ring intermedio entre las dos coronas (topo y - // geo), apenas debajo del topocéntrico. - transits: r * 0.71, - // Capa geocéntrica clásica más adentro — claramente - // separada del bloque ascensional. - houses_outer: r * 0.66, - houses_inner: r * 0.54, - midpoints: r * 0.50, - bodies: r * 0.47, - bodies_inner: r * 0.44, - // Dual-ring GR — abraza el cinturón natal por afuera y por - // adentro. Para Saturno los dos rings caen casi en la misma - // posición angular (poca rotación diurna afecta su lon en - // años humanos); para luminarias los rings divergen - // visiblemente y leen "directa rumbo a este grado, conversa - // hacia este otro". - pd_direct: r * 0.495, - pd_converse: r * 0.425, - // aspects justo bajo el carril natal — las líneas entran - // a este radio sin pintar el círculo (sería ruido extra). - aspects: r * 0.41, - progression: r * 0.36, - solar_arc: r * 0.30, - composite: r * 0.24, + // Aro B — interno zodiaco / externo bloque ascensional. + sign_inner: r * 0.92, + topo_houses_outer: r * 0.92, + // Zona BC: planetas topocéntricos centrados. + topocentric: r * 0.85, + // Aro C — separador ascensional / casas geo. + topo_houses_inner: r * 0.78, + houses_outer: r * 0.78, + // Aro D — externo planetas natales. + houses_inner: r * 0.62, + // Planetas natales justo dentro de D. + bodies: r * 0.57, + // GR dual-ring (cuando se activa): abraza el cinturón + // natal por afuera (`pd_direct`) y por adentro + // (`pd_converse`). Si GR está OFF, ninguno de los dos se + // pinta — no compite con el layout base. + pd_direct: r * 0.545, + pd_converse: r * 0.515, + // Aro E — anclaje invisible de las líneas de aspecto. + aspects: r * 0.49, + // Overlays adicionales — todos INTERIORES al aro E. Se + // pintan solo cuando el módulo correspondiente está + // activo, así no compiten con el layout base. + transits: r * 0.43, + midpoints: r * 0.39, + progression: r * 0.33, + solar_arc: r * 0.27, + composite: r * 0.21, } } @@ -1917,22 +1910,13 @@ fn paint_wheel( } } - // 2.5. Carril de planetas. `bodies` + `bodies_inner` muy juntos - // delimitan la franja estrecha donde viven los glyphs natales. - // El círculo de aspectos NO se pinta — `radii.aspects` solo - // existe como punto donde se anclan las líneas; un stroke ahí - // sería un anillo extra que confunde sin aportar. + // Aro D — único anillo visible del bloque de planetas natales + // (la idea del "carril doble" se descartó: confundía con el + // sistema de casas). El aro E (`radii.aspects`) no se pinta por + // diseño; solo es ancla invisible de las líneas. if show(LayerKind::Bodies) { let belt_color = with_alpha(palette.dial_ring, 0.55); - stroke_circle_3d(window, cx, cy, radii.bodies, 0.9, belt_color, theme); - stroke_circle( - window, - cx, - cy, - radii.bodies_inner, - 0.6, - with_alpha(palette.dial_ring, 0.35), - ); + stroke_circle_3d(window, cx, cy, radii.houses_inner, 0.9, belt_color, theme); // GR dual-ring: si las capas de direcciones primarias están // presentes, marcar sus anillos para que el visual lea como // "abrazo" del cinturón natal. La directa va punteada,