tawasuyu

tawasuyu/brahman

Rust 321TOML 122JSON 14Markdown 114332 Definiciones

fix(tahuantinsuyu): hit-test del hover usa display_deg post-spread

El hover hacía hit-test contra la posición REAL del planeta
(`g.deg`) en vez de la posición de pintura (post-spread). Con
clusters esto generaba que el cursor sobre el disco visible NO
disparara el hover — había que apuntar al grado real (zona
vacía) para activarlo.

Fix: `on_hover_check` ahora corre el mismo `spread_angles` que
`render_wheel` con los inputs equivalentes, y compara la
posición del mouse contra `display_degs[i]` en lugar de
`g.deg`. Nuevo helper `body_disk_base(module_id, kind,
view_scale)` centraliza el cálculo del disco base — render y
hit-test ambos lo usan, así no divergen si más adelante se
ajusta el tamaño por tipo de capa.

11 tests verdes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>

0e66cda079bcb2c3f7b282c73a799f270cee3537 · por sergio · (hace 5 meses) · padre e4882033c · ver el árbol en este commit

Delta semántico · 2

crates/modules/tahuantinsuyu/tahuantinsuyu-canvas/src/lib.rs

1 archivos · +32 −2

diff --git a/crates/modules/tahuantinsuyu/tahuantinsuyu-canvas/src/lib.rs b/crates/modules/tahuantinsuyu/tahuantinsuyu-canvas/src/lib.rs
index 54ab5be..b2814c0 100644
--- a/crates/modules/tahuantinsuyu/tahuantinsuyu-canvas/src/lib.rs
+++ b/crates/modules/tahuantinsuyu/tahuantinsuyu-canvas/src/lib.rs
@@ -459,6 +459,13 @@ impl AstrologyCanvas {
         let mut best: Option<(f32, HoverInfo)> = None;
 
         // 1) Body glyphs (incluye natal, overlays, midpoints).
+        //
+        // Importante: el hit-test debe usar `display_deg` (post-spread)
+        // y no `g.deg` (raw) — el spread mueve los discos para evitar
+        // solapes y si el hover sigue al raw, el usuario tendría que
+        // apuntar a una zona vacía para activarlo. Calculamos los
+        // displays con la misma función que render_wheel.
+        let view_scale = self.state.view_scale;
         for layer in &render.layers {
             let ring = match layer.kind {
                 LayerKind::Bodies => radii.body_ring(&layer.module_id),
@@ -468,8 +475,13 @@ impl AstrologyCanvas {
                 }
                 _ => continue,
             };
-            for g in &layer.glyphs {
-                let (gx, gy) = polar_to_screen(g.deg, asc, rot, ring);
+            let disk_base = body_disk_base(&layer.module_id, layer.kind, view_scale);
+            let raw_degs: Vec<f32> = layer.glyphs.iter().map(|g| g.deg).collect();
+            let disk_angular = (disk_base / (std::f32::consts::TAU * ring)) * 360.0;
+            let (display_degs, _) =
+                spread_angles(&raw_degs, disk_angular, disk_angular);
+            for (i, g) in layer.glyphs.iter().enumerate() {
+                let (gx, gy) = polar_to_screen(display_degs[i], asc, rot, ring);
                 let dx = mx - (cx_px + gx);
                 let dy = my - (cy_px + gy);
                 let dist = (dx * dx + dy * dy).sqrt();
@@ -2641,6 +2653,24 @@ fn planet_glyph(
         .child(text)
 }
 
+/// Disco base (px) de un body glyph según `module_id` y kind. Lo
+/// usan render_wheel (para pintar) y on_hover_check (para
+/// hit-testear) — ambos deben coincidir o el hover apunta a una
+/// posición distinta a donde se pinta el disco.
+fn body_disk_base(module_id: &str, kind: LayerKind, view_scale: f32) -> f32 {
+    let base = match kind {
+        LayerKind::Outer => 20.0,
+        LayerKind::Midpoints => 16.0,
+        _ => match module_id {
+            "natal" => 26.0,
+            "topocentric" => 22.0,
+            "pd_direct" | "pd_converse" => 20.0,
+            _ => 22.0,
+        },
+    };
+    base * view_scale
+}
+
 /// Reposiciona angularmente un conjunto de longitudes para que pares
 /// adyacentes mantengan al menos `min_sep_deg` de separación, **sin
 /// que ningún glyph se aleje más de `max_shift_deg` de su posición