feat(tahuantinsuyu): capa "ascensional" topocéntrica completa
5 fases que cierran el sistema topocéntrico end-to-end, conviviendo
con el cómputo geocéntrico tradicional sin reemplazarlo:
T3 — Pipeline en tahuantinsuyu-engine:
- Nuevo `PipelineRequest::Topocentric`.
- `build_topocentric_overlay(natal, render)`: para cada placement
natal aplica `topocentric_ecliptic` (paralaje horizontal con
`distance_km/AU` + observer.lat_rad + LST + obliquidad), emite
Layer Bodies en ring=0.50 con `module_id="topocentric"`.
Recalcula cusps con `Houses::compute(PolichPage, ...)` y emite
Layer Houses asociado. Si la latitud cae en el círculo polar y
Polich-Page diverge, sigue con planetas topocéntricos solos.
T4 — Render overlay en canvas:
- Nuevo `Radii.topocentric = 0.555·r` (justo bajo el carril natal
bodies=0.60). `body_ring("topocentric")` lo mapea.
- Glyphs topocéntricos con disco más chico (22→22*s) y alpha 0.75
(vs 1.0 natal) — se distinguen como "el sutil debajo del
fuerte". En Luna el shift natal↔topo es visible; en Saturno los
dos glyphs casi se superponen.
- Cusps Polich-Page pintadas como línea punteada (dash 3/2.5px)
en un anillo interior al de casas geocéntricas, color
`house_cusp` α=0.55 — claramente sistema secundario sin
esconderse.
T5 — Módulo TopocentricModule:
- Nuevo módulo en tahuantinsuyu-modules con id="topocentric",
label "Topocéntrico (ascensional)". Toggle "Activar" default
OFF (es overlay opcional). Registrado en `Registry::with_builtins`.
- Shell traduce `module_configs["topocentric"]["enabled"] = true`
→ `PipelineRequest::Topocentric` en `build_requests`. Persiste
por carta vía el mismo mecanismo de `persist_module`.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1114,10 +1114,33 @@ fn render_wheel(
|
||||
for layer in &render.layers {
|
||||
if matches!(layer.kind, LayerKind::Bodies) {
|
||||
let is_natal = layer.module_id == "natal";
|
||||
let is_topo = layer.module_id == "topocentric";
|
||||
let ring = radii.body_ring(&layer.module_id);
|
||||
let alpha = if is_natal { 1.0 } else { 0.88 };
|
||||
let font_size = (if is_natal { 18.0 } else { 14.0 }) * s;
|
||||
let disk_size = (if is_natal { 26.0 } else { 22.0 }) * s;
|
||||
let alpha = if is_natal {
|
||||
1.0
|
||||
} else if is_topo {
|
||||
0.75
|
||||
} else {
|
||||
0.88
|
||||
};
|
||||
// Topocéntrico va con disco un poco más chico que el
|
||||
// natal, y con desaturación implícita en `alpha`. El
|
||||
// shift respecto al natal es lo que el ojo lee, no el
|
||||
// tamaño individual.
|
||||
let font_size = (if is_natal {
|
||||
18.0
|
||||
} else if is_topo {
|
||||
15.0
|
||||
} else {
|
||||
14.0
|
||||
}) * s;
|
||||
let disk_size = (if is_natal {
|
||||
26.0
|
||||
} else if is_topo {
|
||||
22.0
|
||||
} else {
|
||||
22.0
|
||||
}) * s;
|
||||
for g in &layer.glyphs {
|
||||
let (x, y) = polar_to_screen(g.deg, asc, rot_offset, ring);
|
||||
let color = with_alpha(planet_color(palette, &g.symbol), alpha);
|
||||
@@ -1596,6 +1619,12 @@ struct Radii {
|
||||
/// Borde interior del cinturón de planetas. Marca dónde "termina"
|
||||
/// la zona de cuerpos y empieza la zona de aspectos.
|
||||
bodies_inner: f32,
|
||||
/// Cuerpos topocéntricos (capa "ascensional") — un poco hacia
|
||||
/// adentro de `bodies` para que un mismo planeta se vea como
|
||||
/// "doble glyph": natal afuera, topocéntrico justo dentro. En
|
||||
/// Luna la separación angular es visible (~1°); en exteriores
|
||||
/// los dos glyphs se superponen casi exactamente.
|
||||
topocentric: f32,
|
||||
/// Anillo interno con cuerpos progresados (overlay opcional).
|
||||
progression: f32,
|
||||
/// Anillo más interno con cuerpos dirigidos por Solar Arc.
|
||||
@@ -1623,6 +1652,11 @@ impl Radii {
|
||||
// forman un "carril" estrecho que delimita la franja de
|
||||
// planetas, no dos líneas separadas que confunden.
|
||||
bodies_inner: r * 0.57,
|
||||
// Topocéntrico justo bajo el carril natal: los dos
|
||||
// glyphs comparten ancho visual, el shift relativo
|
||||
// (Luna en particular) se lee como "el natal apunta a
|
||||
// este grado, el topo a este otro".
|
||||
topocentric: r * 0.555,
|
||||
// aspects justo bajo el carril de cuerpos. Las líneas
|
||||
// de aspecto entran a este radio, pero el círculo en sí
|
||||
// no se pinta — son las líneas las que importan, no
|
||||
@@ -1641,6 +1675,7 @@ impl Radii {
|
||||
"solar_arc" => self.solar_arc,
|
||||
"composite" => self.composite,
|
||||
"midpoints" => self.midpoints,
|
||||
"topocentric" => self.topocentric,
|
||||
_ => self.bodies,
|
||||
}
|
||||
}
|
||||
@@ -1730,27 +1765,59 @@ fn paint_wheel(
|
||||
|
||||
for layer in layers {
|
||||
if matches!(layer.kind, LayerKind::Houses) {
|
||||
let is_topo = layer.module_id == "topocentric";
|
||||
if let Geometry::Ring { cusps_deg } = &layer.geometry {
|
||||
for (i, c) in cusps_deg.iter().enumerate() {
|
||||
let is_angle = i == 0 || i == 3 || i == 6 || i == 9;
|
||||
let color = if is_angle {
|
||||
let color = if is_topo {
|
||||
with_alpha(house_base, 0.55)
|
||||
} else if is_angle {
|
||||
palette.angle_highlight
|
||||
} else {
|
||||
with_alpha(house_base, 0.75)
|
||||
};
|
||||
let width = if is_angle { 2.0 } else { 0.8 };
|
||||
paint_radial_line(
|
||||
window,
|
||||
cx,
|
||||
cy,
|
||||
*c,
|
||||
ascendant_deg,
|
||||
rot_offset_deg,
|
||||
radii.houses_inner,
|
||||
radii.houses_outer,
|
||||
color,
|
||||
width,
|
||||
);
|
||||
let width = if is_angle && !is_topo { 2.0 } else { 0.8 };
|
||||
if is_topo {
|
||||
// Topocéntrico: cusp como línea punteada
|
||||
// en su propio anillo (un poco más
|
||||
// adentro que las casas geocéntricas) →
|
||||
// se distingue como sistema alternativo.
|
||||
let (xi, yi) = polar_to_screen(
|
||||
*c,
|
||||
ascendant_deg,
|
||||
rot_offset_deg,
|
||||
radii.houses_inner - 4.0,
|
||||
);
|
||||
let (xo, yo) = polar_to_screen(
|
||||
*c,
|
||||
ascendant_deg,
|
||||
rot_offset_deg,
|
||||
radii.houses_inner - 28.0,
|
||||
);
|
||||
paint_segment(
|
||||
window,
|
||||
cx + xi,
|
||||
cy + yi,
|
||||
cx + xo,
|
||||
cy + yo,
|
||||
color,
|
||||
Some((3.0, 2.5)),
|
||||
1.0,
|
||||
);
|
||||
} else {
|
||||
paint_radial_line(
|
||||
window,
|
||||
cx,
|
||||
cy,
|
||||
*c,
|
||||
ascendant_deg,
|
||||
rot_offset_deg,
|
||||
radii.houses_inner,
|
||||
radii.houses_outer,
|
||||
color,
|
||||
width,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user