feat(tahuantinsuyu): anti-solapamiento de glyphs + selector Naibod/Ptolomeo
Tres mejoras de UX para manejar conjunciones (stelium) y dar más control sobre el sistema GR: 1. `spread_angles(angles, min_sep_deg)`: reposiciona angularmente los glyphs adyacentes para que ningún par caiga más cerca que el threshold visual (derivado del ancho del label pill al radio del ring). Iterativo (≤60 pasos), re-ordena cada iteración para preservar el orden circular, devuelve también `residual` ∈ [0,1] = fracción de presión no resuelta. Las posiciones REALES no se tocan — solo afecta la geometría visual del glyph. 5 tests cubren: empty, separados intactos, cluster cerrado, orden preservado, cluster infactible. 2. Aplicación al render de Bodies (natal/topo/pd/outer): cada layer pasa por spread_angles antes de iterar glyphs. Si residual queda alta, los discos y fonts se encogen proporcionalmente (0.55..1.0×) y los coord labels se omiten — evita pillas montadas sobre el bloque. 3. `find_clusters(angles, threshold_deg)`: detecta grupos angularmente cercanos (incluye wrap-around 359°→1°). Glyphs en cluster de ≥3 miembros NO llevan coord label individual; en su lugar, al final del loop se pinta UN solo label compartido con los símbolos concatenados (ej. "☉ ☿ ♀ 14°56'♈") posicionado en el centroide angular del cluster. El usuario sigue viendo cada planeta con su disco, pero no se ahoga en pills superpuestas. 4. Selector Naibod/Ptolomeo en PrimaryDirectionsModule via `Control::Select`. Default Naibod (0°59'08.33″/año, moderno). El shell extrae `module_configs["primary_directions"]["key"]` y lo pasa en `PipelineRequest::PrimaryDirections { key }`; el bridge mapea string → `DirectionKey` y pasa al cómputo. El overlay meta muestra qué clave se usó: "GR Direcciones · 30.5a · Naibod". Tests: 16 verdes (6 shell + 5 spread + 5 coord). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -390,12 +390,31 @@ pub fn compose(
|
||||
"Topocéntrico (Polich-Page)".into(),
|
||||
);
|
||||
}
|
||||
crate::PipelineRequest::PrimaryDirections { target_age_years } => {
|
||||
build_primary_directions_overlay(&natal, *target_age_years, &mut render);
|
||||
crate::PipelineRequest::PrimaryDirections {
|
||||
target_age_years,
|
||||
key,
|
||||
} => {
|
||||
let dkey = match key.as_str() {
|
||||
"ptolemy" => EDirectionKey::Ptolemy,
|
||||
_ => EDirectionKey::Naibod,
|
||||
};
|
||||
build_primary_directions_overlay(
|
||||
&natal,
|
||||
*target_age_years,
|
||||
dkey,
|
||||
&mut render,
|
||||
);
|
||||
push_overlay_meta(
|
||||
&mut render,
|
||||
"primary_directions",
|
||||
format!("GR Direcciones · {:.1}a", target_age_years),
|
||||
format!(
|
||||
"GR Direcciones · {:.1}a · {}",
|
||||
target_age_years,
|
||||
match dkey {
|
||||
EDirectionKey::Naibod => "Naibod",
|
||||
EDirectionKey::Ptolemy => "Ptolomeo",
|
||||
}
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -578,9 +597,9 @@ fn build_topocentric_overlay(
|
||||
fn build_primary_directions_overlay(
|
||||
natal: &NatalChart,
|
||||
target_age_years: f64,
|
||||
key: EDirectionKey,
|
||||
render: &mut RenderModel,
|
||||
) {
|
||||
let key = EDirectionKey::Naibod;
|
||||
let eps = natal.obliquity_rad;
|
||||
|
||||
let project = |dir: PrimaryDirection| -> Vec<Glyph> {
|
||||
|
||||
@@ -338,8 +338,12 @@ pub enum PipelineRequest {
|
||||
/// proyecta dos veces: hacia adelante en el tiempo diurno
|
||||
/// (direct) y hacia atrás (converse). Los dos resultados a la
|
||||
/// edad pedida pintan un dual-ring para rectificación en vivo.
|
||||
///
|
||||
/// `key` controla la conversión arco↔año: "naibod" (default
|
||||
/// moderno, 0°59'08.33″/año) o "ptolemy" (clásica, 1°/año).
|
||||
PrimaryDirections {
|
||||
target_age_years: f64,
|
||||
key: String,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user