feat(tahuantinsuyu): "Guardar como…" en Tránsito y Progresada
Extiende el patrón de F4 a dos módulos más:
- **Tránsito**: nuevo `Control::Action "💾 Guardar tránsito como
carta libre"`. Captura el momento actual (UTC `now()`) anclado
a las coordenadas del natal. Label `{natal} transito · YYYY-MM-DD
HH:MM UTC`. Útil para "qué pasaba en el cielo de Pedro ahora
mismo, pegado como carta".
- **Progresada secundaria**: análogo, sufijo `prog-{N}a`. El
birth_data del Chart resultante es REAL (natal_instant + N días
simbólicos × 86400 s), así que cuando se computa de nuevo como
natal produce las posiciones progresadas correctas. El usuario
edita el slider, click → la carta queda guardada como libre
para después persistir.
Backend:
- Dos funciones nuevas en `tahuantinsuyu-engine`:
`compute_transit_chart(chart)` y
`compute_progression_chart(chart, age)`. Reusan
`parse_iso8601_components` (introducido en el commit del PR).
- En el shell: nuevo helper `insert_derived_free_chart(source,
birth, label)` que el callsite de PR ahora reusa (refactor
pequeño).
Sobre solar_arc y primary_directions:
- NO se agrega el botón. SA y PD son transformaciones matemáticas
puras — un Chart natal computado en el "momento dirigido" daría
posiciones distintas a las dirigidas (porque SA rota uniforme y
PD es función de RA, no de longitud eclíptica). Para guardarlas
haría falta extender `Chart` con un kind
`Derived { source, transform, params }` que el engine sepa
rehidratar al render. TODO en otra fase.
Tests: 10 verdes (sin cambios en los paths probados).
This commit is contained in:
@@ -1314,9 +1314,92 @@ impl Shell {
|
||||
/// Otros módulos overlay (progression, solar_arc, primary_directions)
|
||||
/// son extensión natural — TODO.
|
||||
fn on_panel_action(&mut self, module_id: String, key: String, cx: &mut Context<Self>) {
|
||||
if module_id == "planetary_return" && key == "save_as_free" {
|
||||
self.save_planetary_return_as_free(cx);
|
||||
if key != "save_as_free" {
|
||||
return;
|
||||
}
|
||||
match module_id.as_str() {
|
||||
"planetary_return" => self.save_planetary_return_as_free(cx),
|
||||
"transit" => self.save_transit_as_free(cx),
|
||||
"progression" => self.save_progression_as_free(cx),
|
||||
// Solar arc y direcciones primarias son transformaciones
|
||||
// matemáticas puras (no tienen un birth_data real
|
||||
// equivalente — un Chart natal computado en el "momento
|
||||
// SA" daría posiciones distintas a las dirigidas). Para
|
||||
// guardarlas haría falta extender Chart con un kind
|
||||
// `Derived { source, transform, params }` que el engine
|
||||
// sepa rehidratar. TODO.
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
/// Snapshot del cielo en este instante anclado al lugar del
|
||||
/// natal. Sufijo `transito-{fecha}`. Útil para guardar "qué
|
||||
/// estaba pasando ahora en la carta de Pedro".
|
||||
fn save_transit_as_free(&mut self, cx: &mut Context<Self>) {
|
||||
let Some(natal) = self.current_chart.as_ref() else {
|
||||
eprintln!("[shell] save_transit: sin carta activa");
|
||||
return;
|
||||
};
|
||||
if natal.id == ChartId::default() {
|
||||
eprintln!("[shell] save_transit: la carta activa es libre");
|
||||
return;
|
||||
}
|
||||
match tahuantinsuyu_engine::compute_transit_chart(natal) {
|
||||
Ok((birth, instant_label)) => {
|
||||
let label = format!("{} transito · {}", natal.label, instant_label);
|
||||
self.insert_derived_free_chart(natal.clone(), birth, label, cx);
|
||||
}
|
||||
Err(e) => eprintln!("[shell] compute_transit_chart: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
/// Carta progresada secundaria a la edad del slider. La
|
||||
/// progresada es natal + N días simbólicos; el Chart resultante
|
||||
/// tiene un birth_data REAL (no simbólico) — cuando se computa
|
||||
/// como natal de nuevo, da las posiciones progresadas correctas.
|
||||
/// Sufijo `prog-{N}a`.
|
||||
fn save_progression_as_free(&mut self, cx: &mut Context<Self>) {
|
||||
let Some(natal) = self.current_chart.as_ref() else {
|
||||
eprintln!("[shell] save_progression: sin carta activa");
|
||||
return;
|
||||
};
|
||||
if natal.id == ChartId::default() {
|
||||
eprintln!("[shell] save_progression: la carta activa es libre");
|
||||
return;
|
||||
}
|
||||
let age = self.module_age_or_current("progression");
|
||||
match tahuantinsuyu_engine::compute_progression_chart(natal, age) {
|
||||
Ok((birth, instant_label)) => {
|
||||
let label = format!(
|
||||
"{} prog-{:.0}a · {}",
|
||||
natal.label, age, instant_label
|
||||
);
|
||||
self.insert_derived_free_chart(natal.clone(), birth, label, cx);
|
||||
}
|
||||
Err(e) => eprintln!("[shell] compute_progression_chart: {}", e),
|
||||
}
|
||||
}
|
||||
|
||||
/// Inserta un Chart derivado (transit/progression/PR) como
|
||||
/// FreeChart conservando contact/kind/related/config del natal
|
||||
/// original. El id es sintético; el usuario puede después
|
||||
/// "Guardar como…" para persistirlo bajo un contacto.
|
||||
fn insert_derived_free_chart(
|
||||
&mut self,
|
||||
source_natal: Chart,
|
||||
new_birth: StoredBirthData,
|
||||
new_label: String,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
let id = FreeChartId(format!("free-{}", self.next_free_id));
|
||||
self.next_free_id += 1;
|
||||
let mut chart = source_natal;
|
||||
chart.id = ChartId::default();
|
||||
chart.label = new_label;
|
||||
chart.birth_data = new_birth;
|
||||
self.free_charts.insert(id.clone(), chart);
|
||||
self.push_free_charts_to_tree(cx);
|
||||
self.apply_selection(TreeSelection::FreeChart(id), cx);
|
||||
}
|
||||
|
||||
/// Computa la carta del retorno planetario actual (con cuerpo +
|
||||
@@ -1364,15 +1447,7 @@ impl Shell {
|
||||
"{} {}-{:.0}a · {}",
|
||||
natal.label, suffix, age, instant_label
|
||||
);
|
||||
let id = FreeChartId(format!("free-{}", self.next_free_id));
|
||||
self.next_free_id += 1;
|
||||
let mut chart = natal.clone();
|
||||
chart.id = ChartId::default();
|
||||
chart.label = label;
|
||||
chart.birth_data = birth;
|
||||
self.free_charts.insert(id.clone(), chart);
|
||||
self.push_free_charts_to_tree(cx);
|
||||
self.apply_selection(TreeSelection::FreeChart(id), cx);
|
||||
self.insert_derived_free_chart(natal.clone(), birth, label, cx);
|
||||
}
|
||||
Err(e) => {
|
||||
eprintln!("[shell] compute_planetary_return_chart: {}", e);
|
||||
|
||||
Reference in New Issue
Block a user