121f19b915
Tres problemas reportados sobre la pasada anterior: 1. **Planetas pisándose**: el "spread por centroides" dejaba a los miembros de cada cluster en sus posiciones REALES, así que pares en conjunción cerrada (5° real, disk ≈ 10°) seguían con discos solapados. Solución: spread directo sobre TODOS los glyphs, no solo sobre centroides. 2. **Empuje propagado a planetas lejanos** (era el motivo original de tirar el "spread directo"): ahora controlado con un **cap por glyph**: `max_shift_deg`. Ningún display puede alejarse más de `disk_angular` grados de su raw — un cluster denso no "empuja" a planetas que estaban lejos. El residual sube cuando el cap impide alcanzar el min_sep, y los discos se encogen. 3. **Algoritmo greedy oscilaba**: el empuje aplicado par-a-par reordenaba los displays a mitad de la pasada y nunca convergía (`tight_cluster_gets_spread` terminaba con 6.5° de diff cuando se pedían 10°). Reemplazado por **physics-step**: se acumulan las fuerzas de todos los pares en una pasada, se aplican con `damping = 0.6`, se clampea cada display al rango ±max_shift. 80 iteraciones convergen siempre. 4. **Labels repetidos en pares cercanos**: el threshold del cluster compartido era min(4°, disk_angular*0.5). Para discos de 10° angular, eso daba 4° — dos planetas a 5° formaban clusters separados, cada uno con su pill diciendo casi lo mismo. Subido a `disk_angular * 1.2` → pares a <12° comparten label. Nuevos tests: - `shift_is_bounded`: con max_shift=2°, ningún glyph se aleja más. - `distant_planet_unaffected_by_dense_cluster`: cluster denso en 100° + planeta solo en 200° → el de 200° se queda a <5° de raw. Total 11 tests verdes (6 spread + 5 coord). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>