feat(cosmobiologia): corpus — capa de composición por evidencia vecina
La capa de composición, resuelta con honestidad. El producto numérico de perfiles (Hadamard y parientes) se descarta: da falsos —una dimensión en 0 nunca «se enciende»— y, sobre todo, un perfil compuesto es una conjetura, no evidencia. En su lugar, `Corpus::evidencia_relacionada`: para una combinación SIN pasaje propio, junta la evidencia VECINA —pasajes que comparten un componente (el planeta, el signo, la casa, el tipo de aspecto)—, agrupada por lo que comparten. No sintetiza un texto; son citas reales de contextos parecidos para que el astrólogo componga él. En la rueda 2D, el panel de la tajada ahora muestra, bajo los pasajes directos, una sección «Composición» con esa evidencia vecina por cada combinación sin texto propio. 16 tests del corpus (2 nuevos) + 2 del engine verdes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -41,8 +41,9 @@ use gpui::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use cosmobiologia_engine::{
|
use cosmobiologia_engine::{
|
||||||
corpus_inputs, Corpus, Dominio, Geometry, GrTrigger, Layer, LayerKind, Pasaje,
|
combinaciones_de_carta, corpus_inputs, rebanar_por_dominio, CombinacionId, Corpus,
|
||||||
Rectificacion, RenderModel, UranianGroup, OUTER_RING_MODULES,
|
Dominio, EvidenciaVecina, Geometry, GrTrigger, Layer, LayerKind, Pasaje, Rectificacion,
|
||||||
|
RenderModel, UranianGroup, OUTER_RING_MODULES,
|
||||||
};
|
};
|
||||||
use cosmobiologia_model::{ChartId, ContactId, GroupId};
|
use cosmobiologia_model::{ChartId, ContactId, GroupId};
|
||||||
use cosmobiologia_render::{compose_sphere, DrawCommand, Palette, SphereOpts, SphereView};
|
use cosmobiologia_render::{compose_sphere, DrawCommand, Palette, SphereOpts, SphereView};
|
||||||
@@ -986,6 +987,17 @@ fn domain_label(d: Dominio) -> &'static str {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Lo computado del corpus para la tajada activa: los pasajes con texto
|
||||||
|
/// propio (`directos`), las combinaciones sin texto con su evidencia
|
||||||
|
/// vecina (`compuestos` — la capa de composición), y los grados de los
|
||||||
|
/// cuerpos a resaltar en la rueda.
|
||||||
|
struct CorpusView<'a> {
|
||||||
|
dominio: Dominio,
|
||||||
|
directos: Vec<&'a Pasaje>,
|
||||||
|
compuestos: Vec<(CombinacionId, Vec<EvidenciaVecina<'a>>)>,
|
||||||
|
degs: Vec<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Capa transparente sobre la rueda que dibuja un anillo de resalte en
|
/// Capa transparente sobre la rueda que dibuja un anillo de resalte en
|
||||||
/// cada cuerpo de la tajada activa.
|
/// cada cuerpo de la tajada activa.
|
||||||
fn corpus_highlight_canvas(degs: Vec<f32>, asc: f32, rot: f32, color: Hsla) -> impl IntoElement {
|
fn corpus_highlight_canvas(degs: Vec<f32>, asc: f32, rot: f32, color: Hsla) -> impl IntoElement {
|
||||||
@@ -1005,8 +1017,41 @@ fn corpus_highlight_canvas(degs: Vec<f32>, asc: f32, rot: f32, color: Hsla) -> i
|
|||||||
.size_full()
|
.size_full()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// El panel lateral con los pasajes de la tajada activa.
|
/// Una tarjeta de pasaje: combinación, texto citado y fuente.
|
||||||
fn corpus_panel(theme: &Theme, dom: Dominio, pasajes: &[&Pasaje]) -> impl IntoElement {
|
fn passage_card(theme: &Theme, p: &Pasaje) -> gpui::Div {
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.flex_col()
|
||||||
|
.gap(px(3.0))
|
||||||
|
.p(px(8.0))
|
||||||
|
.rounded(px(5.0))
|
||||||
|
.bg(theme.bg_panel.clone())
|
||||||
|
.border_1()
|
||||||
|
.border_color(theme.border)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.text_size(px(9.0))
|
||||||
|
.text_color(theme.fg_muted)
|
||||||
|
.child(SharedString::from(p.combinacion.to_string())),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.text_size(px(11.0))
|
||||||
|
.text_color(theme.fg_text)
|
||||||
|
.child(SharedString::from(p.texto.clone())),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.text_size(px(9.0))
|
||||||
|
.text_color(theme.fg_muted)
|
||||||
|
.child(SharedString::from(format!("— {}", p.fuente))),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// El panel lateral de la tajada activa: los pasajes con texto propio
|
||||||
|
/// y, debajo, la composición — evidencia vecina de las combinaciones
|
||||||
|
/// sin pasaje.
|
||||||
|
fn corpus_panel(theme: &Theme, cv: &CorpusView<'_>) -> impl IntoElement {
|
||||||
let mut list = div()
|
let mut list = div()
|
||||||
.id("corpus-panel")
|
.id("corpus-panel")
|
||||||
.flex()
|
.flex()
|
||||||
@@ -1025,59 +1070,87 @@ fn corpus_panel(theme: &Theme, dom: Dominio, pasajes: &[&Pasaje]) -> impl IntoEl
|
|||||||
.flex_row()
|
.flex_row()
|
||||||
.items_center()
|
.items_center()
|
||||||
.gap(px(6.0))
|
.gap(px(6.0))
|
||||||
.child(div().w(px(10.0)).h(px(10.0)).rounded_full().bg(domain_color(dom)))
|
.child(
|
||||||
|
div()
|
||||||
|
.w(px(10.0))
|
||||||
|
.h(px(10.0))
|
||||||
|
.rounded_full()
|
||||||
|
.bg(domain_color(cv.dominio)),
|
||||||
|
)
|
||||||
.child(
|
.child(
|
||||||
div()
|
div()
|
||||||
.text_size(px(13.0))
|
.text_size(px(13.0))
|
||||||
.text_color(theme.fg_text)
|
.text_color(theme.fg_text)
|
||||||
.child(SharedString::from(format!(
|
.child(SharedString::from(format!(
|
||||||
"Tajada {} · {} pasajes",
|
"Tajada {} · {} pasajes",
|
||||||
domain_label(dom),
|
domain_label(cv.dominio),
|
||||||
pasajes.len()
|
cv.directos.len()
|
||||||
))),
|
))),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if pasajes.is_empty() {
|
|
||||||
|
if cv.directos.is_empty() && cv.compuestos.is_empty() {
|
||||||
list = list.child(
|
list = list.child(
|
||||||
div()
|
div()
|
||||||
.text_size(px(11.0))
|
.text_size(px(11.0))
|
||||||
.text_color(theme.fg_muted)
|
.text_color(theme.fg_muted)
|
||||||
.child(
|
.child(
|
||||||
"Sin pasajes para esta tajada todavía. Escribilos en \
|
"Sin nada del corpus para esta tajada. Escribí pasajes en \
|
||||||
corpus.ron — ver la GUIA del corpus.",
|
corpus.ron — ver la GUIA del corpus.",
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
for p in pasajes {
|
for p in &cv.directos {
|
||||||
list = list.child(
|
list = list.child(passage_card(theme, p));
|
||||||
div()
|
}
|
||||||
.flex()
|
|
||||||
.flex_col()
|
// Capa de composición: evidencia vecina, citada. NO sintetizada.
|
||||||
.gap(px(3.0))
|
if !cv.compuestos.is_empty() {
|
||||||
.p(px(8.0))
|
list = list
|
||||||
.rounded(px(5.0))
|
.child(
|
||||||
.bg(theme.bg_panel.clone())
|
div()
|
||||||
.border_1()
|
.mt(px(6.0))
|
||||||
.border_color(theme.border)
|
.text_size(px(11.0))
|
||||||
.child(
|
.text_color(theme.fg_text)
|
||||||
|
.child("Composición — combinaciones sin pasaje propio"),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.text_size(px(9.0))
|
||||||
|
.text_color(theme.fg_muted)
|
||||||
|
.child("Evidencia vecina, citada — el corpus no sintetiza; componés vos."),
|
||||||
|
);
|
||||||
|
for (combo, evs) in &cv.compuestos {
|
||||||
|
list = list.child(
|
||||||
|
div()
|
||||||
|
.mt(px(3.0))
|
||||||
|
.text_size(px(10.0))
|
||||||
|
.text_color(theme.fg_text)
|
||||||
|
.child(SharedString::from(combo.to_string())),
|
||||||
|
);
|
||||||
|
for ev in evs {
|
||||||
|
list = list.child(
|
||||||
div()
|
div()
|
||||||
.text_size(px(9.0))
|
.text_size(px(9.0))
|
||||||
.text_color(theme.fg_muted)
|
.text_color(theme.fg_muted)
|
||||||
.child(SharedString::from(p.combinacion.to_string())),
|
.child(SharedString::from(format!("vecinos · comparte {}", ev.comparte))),
|
||||||
)
|
);
|
||||||
.child(
|
for p in ev.pasajes.iter().take(3) {
|
||||||
div()
|
list = list.child(passage_card(theme, p));
|
||||||
.text_size(px(11.0))
|
}
|
||||||
.text_color(theme.fg_text)
|
if ev.pasajes.len() > 3 {
|
||||||
.child(SharedString::from(p.texto.clone())),
|
list = list.child(
|
||||||
)
|
div()
|
||||||
.child(
|
.text_size(px(9.0))
|
||||||
div()
|
.text_color(theme.fg_muted)
|
||||||
.text_size(px(9.0))
|
.child(SharedString::from(format!(
|
||||||
.text_color(theme.fg_muted)
|
"… +{} más",
|
||||||
.child(SharedString::from(format!("— {}", p.fuente))),
|
ev.pasajes.len() - 3
|
||||||
),
|
))),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
list
|
list
|
||||||
}
|
}
|
||||||
@@ -1094,32 +1167,45 @@ impl Render for AstrologyCanvas {
|
|||||||
let focus = self.focus_handle.clone();
|
let focus = self.focus_handle.clone();
|
||||||
|
|
||||||
// Vista del corpus: con una tajada elegida sobre la rueda 2D, se
|
// Vista del corpus: con una tajada elegida sobre la rueda 2D, se
|
||||||
// calcula la interpretación por dominio (pasajes + cuerpos a
|
// separan las combinaciones del dominio en las que tienen pasaje
|
||||||
// resaltar). Los `&Pasaje` toman prestado de `state.corpus`.
|
// propio y las que sólo tienen evidencia vecina (composición).
|
||||||
let corpus_view: Option<(Dominio, Vec<&Pasaje>, Vec<f32>)> =
|
// Todo toma prestado de `state.corpus`.
|
||||||
match &self.state.mode {
|
let corpus_view: Option<CorpusView<'_>> = match &self.state.mode {
|
||||||
CanvasMode::Wheel { render } if !self.state.sphere_3d => {
|
CanvasMode::Wheel { render } if !self.state.sphere_3d => {
|
||||||
self.state.corpus_domain.and_then(|dom| {
|
self.state.corpus_domain.and_then(|dom| {
|
||||||
let corpus = self.state.corpus.as_ref()?;
|
let corpus = self.state.corpus.as_ref()?;
|
||||||
let (col, asp) = corpus_inputs(render);
|
let (col, asp) = corpus_inputs(render);
|
||||||
let por_dom = corpus.interpretar_por_dominio(&col, &asp);
|
let combos = combinaciones_de_carta(&col, &asp);
|
||||||
let pasajes = por_dom.get(&dom).cloned().unwrap_or_default();
|
let tajadas = rebanar_por_dominio(&col, &combos);
|
||||||
let degs: Vec<f32> = render
|
let dom_combos = tajadas.get(&dom).cloned().unwrap_or_default();
|
||||||
.layers
|
let mut directos = Vec::new();
|
||||||
.iter()
|
let mut compuestos = Vec::new();
|
||||||
.filter(|l| {
|
for c in &dom_combos {
|
||||||
matches!(l.kind, LayerKind::Bodies)
|
let p = corpus.pasajes_de(c);
|
||||||
&& l.module_id == "natal"
|
if p.is_empty() {
|
||||||
})
|
let ev = corpus.evidencia_relacionada(c);
|
||||||
.flat_map(|l| l.glyphs.iter())
|
if !ev.is_empty() {
|
||||||
.filter(|g| g.house.and_then(Dominio::de_casa) == Some(dom))
|
compuestos.push((c.clone(), ev));
|
||||||
.map(|g| g.deg)
|
}
|
||||||
.collect();
|
} else {
|
||||||
Some((dom, pasajes, degs))
|
directos.extend(p);
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
_ => None,
|
let degs: Vec<f32> = render
|
||||||
};
|
.layers
|
||||||
|
.iter()
|
||||||
|
.filter(|l| {
|
||||||
|
matches!(l.kind, LayerKind::Bodies) && l.module_id == "natal"
|
||||||
|
})
|
||||||
|
.flat_map(|l| l.glyphs.iter())
|
||||||
|
.filter(|g| g.house.and_then(Dominio::de_casa) == Some(dom))
|
||||||
|
.map(|g| g.deg)
|
||||||
|
.collect();
|
||||||
|
Some(CorpusView { dominio: dom, directos, compuestos, degs })
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
let body = match &self.state.mode {
|
let body = match &self.state.mode {
|
||||||
CanvasMode::Empty => render_empty(&theme),
|
CanvasMode::Empty => render_empty(&theme),
|
||||||
@@ -1151,11 +1237,11 @@ impl Render for AstrologyCanvas {
|
|||||||
);
|
);
|
||||||
// Capa de resalte de la tajada activa, encima de la rueda.
|
// Capa de resalte de la tajada activa, encima de la rueda.
|
||||||
match &corpus_view {
|
match &corpus_view {
|
||||||
Some((dom, _, degs)) => wheel.child(corpus_highlight_canvas(
|
Some(cv) => wheel.child(corpus_highlight_canvas(
|
||||||
degs.clone(),
|
cv.degs.clone(),
|
||||||
render.ascendant_deg,
|
render.ascendant_deg,
|
||||||
self.state.view_rotation_deg,
|
self.state.view_rotation_deg,
|
||||||
domain_color(*dom),
|
domain_color(cv.dominio),
|
||||||
)),
|
)),
|
||||||
None => wheel,
|
None => wheel,
|
||||||
}
|
}
|
||||||
@@ -1163,9 +1249,7 @@ impl Render for AstrologyCanvas {
|
|||||||
CanvasMode::Thumbnails { items, .. } => render_thumbnails(&theme, items),
|
CanvasMode::Thumbnails { items, .. } => render_thumbnails(&theme, items),
|
||||||
};
|
};
|
||||||
|
|
||||||
let corpus_side = corpus_view
|
let corpus_side = corpus_view.as_ref().map(|cv| corpus_panel(&theme, cv));
|
||||||
.as_ref()
|
|
||||||
.map(|(dom, pasajes, _)| corpus_panel(&theme, *dom, pasajes));
|
|
||||||
|
|
||||||
// Botón flotante 2D ⇄ 3D — visible solo con una carta cargada.
|
// Botón flotante 2D ⇄ 3D — visible solo con una carta cargada.
|
||||||
// Muestra el modo al que se cambiará, no el activo.
|
// Muestra el modo al que se cambiará, no el activo.
|
||||||
|
|||||||
@@ -319,6 +319,34 @@ pub struct Pasaje {
|
|||||||
pub dominio: Option<Dominio>,
|
pub dominio: Option<Dominio>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Evidencia **vecina** de una combinación que no tiene pasaje propio:
|
||||||
|
/// pasajes del corpus que comparten uno de sus componentes (el planeta,
|
||||||
|
/// el signo, la casa, o el tipo de aspecto).
|
||||||
|
///
|
||||||
|
/// Es la respuesta honesta al problema de la «composición». El corpus
|
||||||
|
/// **no sintetiza** un texto para una combinación no escrita —eso sería
|
||||||
|
/// inventar—. Tampoco multiplica perfiles numéricos: el producto
|
||||||
|
/// Hadamard (y parientes) se descartó porque da falsos (una dimensión
|
||||||
|
/// en 0 nunca «se enciende») y, sobre todo, porque un perfil compuesto
|
||||||
|
/// es una conjetura, no evidencia. Lo que sí es honesto: traer las
|
||||||
|
/// citas reales de contextos parecidos y que el astrólogo componga él.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct EvidenciaVecina<'a> {
|
||||||
|
/// Qué componente comparten — `"planeta mars"`, `"signo virgo"`,
|
||||||
|
/// `"casa 6"`, `"aspecto square"`.
|
||||||
|
pub comparte: String,
|
||||||
|
pub pasajes: Vec<&'a Pasaje>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `true` si la combinación involucra a ese planeta, en cualquier rol.
|
||||||
|
fn combinacion_usa_planeta(c: &CombinacionId, planeta: &str) -> bool {
|
||||||
|
match c {
|
||||||
|
CombinacionId::PlanetaSigno { planeta: p, .. } => p == planeta,
|
||||||
|
CombinacionId::PlanetaCasa { planeta: p, .. } => p == planeta,
|
||||||
|
CombinacionId::Aspecto { a, b, .. } => a == planeta || b == planeta,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// El corpus completo: la ontología de arquetipos + los pasajes.
|
/// El corpus completo: la ontología de arquetipos + los pasajes.
|
||||||
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
|
||||||
pub struct Corpus {
|
pub struct Corpus {
|
||||||
@@ -395,6 +423,69 @@ impl Corpus {
|
|||||||
.cloned()
|
.cloned()
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Pasajes cuya combinación cumple un predicado.
|
||||||
|
fn pasajes_donde(&self, pred: impl Fn(&CombinacionId) -> bool) -> Vec<&Pasaje> {
|
||||||
|
self.pasajes.iter().filter(|p| pred(&p.combinacion)).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// La **capa de composición**, hecha con honestidad: para una
|
||||||
|
/// combinación SIN pasaje propio, junta la evidencia vecina —
|
||||||
|
/// pasajes que comparten uno de sus componentes—. No sintetiza un
|
||||||
|
/// texto ni compone perfiles; son citas reales de contextos
|
||||||
|
/// parecidos, agrupadas por el componente que comparten, para que
|
||||||
|
/// el astrólogo componga. Si la combinación SÍ tiene pasaje propio,
|
||||||
|
/// devuelve vacío — no hace falta. Ver [`EvidenciaVecina`].
|
||||||
|
pub fn evidencia_relacionada(&self, id: &CombinacionId) -> Vec<EvidenciaVecina<'_>> {
|
||||||
|
if !self.pasajes_de(id).is_empty() {
|
||||||
|
return Vec::new();
|
||||||
|
}
|
||||||
|
let mut grupos: Vec<EvidenciaVecina<'_>> = Vec::new();
|
||||||
|
match id {
|
||||||
|
CombinacionId::PlanetaSigno { planeta, signo } => {
|
||||||
|
grupos.push(EvidenciaVecina {
|
||||||
|
comparte: format!("planeta {planeta}"),
|
||||||
|
pasajes: self.pasajes_donde(|c| combinacion_usa_planeta(c, planeta)),
|
||||||
|
});
|
||||||
|
grupos.push(EvidenciaVecina {
|
||||||
|
comparte: format!("signo {signo}"),
|
||||||
|
pasajes: self.pasajes_donde(|c| {
|
||||||
|
matches!(c, CombinacionId::PlanetaSigno { signo: s, .. } if s == signo)
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
CombinacionId::PlanetaCasa { planeta, casa } => {
|
||||||
|
grupos.push(EvidenciaVecina {
|
||||||
|
comparte: format!("planeta {planeta}"),
|
||||||
|
pasajes: self.pasajes_donde(|c| combinacion_usa_planeta(c, planeta)),
|
||||||
|
});
|
||||||
|
grupos.push(EvidenciaVecina {
|
||||||
|
comparte: format!("casa {casa}"),
|
||||||
|
pasajes: self.pasajes_donde(|c| {
|
||||||
|
matches!(c, CombinacionId::PlanetaCasa { casa: k, .. } if k == casa)
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
CombinacionId::Aspecto { a, kind, b } => {
|
||||||
|
grupos.push(EvidenciaVecina {
|
||||||
|
comparte: format!("aspecto {kind}"),
|
||||||
|
pasajes: self.pasajes_donde(|c| {
|
||||||
|
matches!(c, CombinacionId::Aspecto { kind: k, .. } if k == kind)
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
grupos.push(EvidenciaVecina {
|
||||||
|
comparte: format!("planeta {a}"),
|
||||||
|
pasajes: self.pasajes_donde(|c| combinacion_usa_planeta(c, a)),
|
||||||
|
});
|
||||||
|
grupos.push(EvidenciaVecina {
|
||||||
|
comparte: format!("planeta {b}"),
|
||||||
|
pasajes: self.pasajes_donde(|c| combinacion_usa_planeta(c, b)),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
grupos.retain(|g| !g.pasajes.is_empty());
|
||||||
|
grupos
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@@ -608,4 +699,32 @@ mod tests {
|
|||||||
assert_eq!(p.len(), 1);
|
assert_eq!(p.len(), 1);
|
||||||
assert_eq!(p[0].dominio, Some(Dominio::Psiquico));
|
assert_eq!(p[0].dominio, Some(Dominio::Psiquico));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn evidencia_relacionada_junta_vecinos_por_componente() {
|
||||||
|
let corpus = Corpus {
|
||||||
|
arquetipos: Vec::new(),
|
||||||
|
pasajes: vec![
|
||||||
|
pasaje(CombinacionId::planeta_signo("mars", "virgo"), "marte cirujano"),
|
||||||
|
pasaje(CombinacionId::planeta_signo("mars", "aries"), "marte crudo"),
|
||||||
|
pasaje(CombinacionId::planeta_signo("venus", "gemini"), "venus locuaz"),
|
||||||
|
],
|
||||||
|
};
|
||||||
|
// mars·gemini no tiene pasaje propio → evidencia vecina.
|
||||||
|
let ev = corpus.evidencia_relacionada(&CombinacionId::planeta_signo("mars", "gemini"));
|
||||||
|
let mars = ev.iter().find(|g| g.comparte == "planeta mars").unwrap();
|
||||||
|
assert_eq!(mars.pasajes.len(), 2, "marte en otros signos");
|
||||||
|
let gem = ev.iter().find(|g| g.comparte == "signo gemini").unwrap();
|
||||||
|
assert_eq!(gem.pasajes.len(), 1, "otros planetas en géminis");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn evidencia_relacionada_vacia_si_hay_pasaje_propio() {
|
||||||
|
let corpus = Corpus {
|
||||||
|
arquetipos: Vec::new(),
|
||||||
|
pasajes: vec![pasaje(CombinacionId::planeta_signo("mars", "virgo"), "x")],
|
||||||
|
};
|
||||||
|
let ev = corpus.evidencia_relacionada(&CombinacionId::planeta_signo("mars", "virgo"));
|
||||||
|
assert!(ev.is_empty(), "con pasaje propio no se busca evidencia vecina");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ pub use cosmobiologia_render::{
|
|||||||
// El engine lo reexporta para que el shell y el canvas trabajen los
|
// El engine lo reexporta para que el shell y el canvas trabajen los
|
||||||
// pasajes sin importar el crate aparte.
|
// pasajes sin importar el crate aparte.
|
||||||
pub use cosmobiologia_corpus::{
|
pub use cosmobiologia_corpus::{
|
||||||
AspectoEnCarta, Colocacion, CombinacionId, Corpus, Dominio, Pasaje,
|
combinaciones_de_carta, rebanar_por_dominio, AspectoEnCarta, Colocacion, CombinacionId,
|
||||||
|
Corpus, Dominio, EvidenciaVecina, Pasaje,
|
||||||
};
|
};
|
||||||
|
|
||||||
// `Chart` reexportado arriba es lo que `PipelineRequest::Synastry`
|
// `Chart` reexportado arriba es lo que `PipelineRequest::Synastry`
|
||||||
|
|||||||
Reference in New Issue
Block a user