refactor(monorepo): reorganización lógica + renames + SDDs + split CHANGELOG
Reorganización física de crates/: - core/ (mezclaba 6 propósitos) se divide en protocol/, init/, runtime/, compat/ - shared/ (3 crates) se redistribuye en protocol/ e init/ - lapaloma (sub-módulo de ui_engine) se promueve a modules/pineal/ Renames de proyectos: - shipote → shuma (runtime de sandboxes) - nouser → akasha (explorador de Mónadas) - yahweh → nahual (motor GPUI, antes ui_engine/) - lapaloma → pineal (data-viz agnóstica) Fraccionamiento UI → core agnóstico: - vista-core (DeckState + snap, 175 LOC, 5 tests verdes) - barra-core (Task + render_html + sanitize, 90 LOC, 5 tests verdes) - vista-web y barra-web ahora son thin DOM bindings Documentación nueva: - 16 SDDs por subdirectorio (≤80 LOC c/u): protocol/init/runtime/compat + 10 módulos + apps/ - docs/STATUS.md con cifras reales por proyecto - docs/ROADMAP.md con plan a finalización (6 hitos, ~6-8 semanas) - CHANGELOG.md particionado en docs/changelog/<proyecto>.md (7 buckets) Automatización: - scripts/reorg.py — script idempotente que: git mv directorios, renombra package names, recomputa path = refs, reescribe imports rust, actualiza workspace Cargo.toml. Soporta --dry-run. - scripts/split-changelog.py — particiona CHANGELOG por componente. Validación: - cargo check --workspace pasa (124 crates + 2 nuevos cores). - 10 tests adicionales (5 en vista-core + 5 en barra-core) verdes. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,153 @@
|
||||
//! Escalas value→pixel para series cartesianas.
|
||||
//!
|
||||
//! La proyección no se aplica sobre los datos (eso rompería el
|
||||
//! P2 zero-alloc — habría que reescribir todo el buffer por frame).
|
||||
//! Las escalas devuelven el `(scale_x, scale_y, translate_x,
|
||||
//! translate_y)` que el painter mete en un transform GPU. Los
|
||||
//! datos quedan intactos.
|
||||
|
||||
/// Trait común a Linear / Log / Time. Cada implementación traduce
|
||||
/// un valor de dominio a posición normalizada `[0, 1]` (que luego
|
||||
/// el painter mapea al pixel range del plot).
|
||||
pub trait Scale {
|
||||
fn to_norm(&self, value: f64) -> f64;
|
||||
fn from_norm(&self, norm: f64) -> f64;
|
||||
fn domain(&self) -> (f64, f64);
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct LinearScale {
|
||||
min: f64,
|
||||
max: f64,
|
||||
}
|
||||
|
||||
impl LinearScale {
|
||||
pub fn new(min: f64, max: f64) -> Self {
|
||||
debug_assert!(max > min, "LinearScale: max debe ser > min");
|
||||
Self { min, max }
|
||||
}
|
||||
}
|
||||
|
||||
impl Scale for LinearScale {
|
||||
fn to_norm(&self, v: f64) -> f64 {
|
||||
(v - self.min) / (self.max - self.min)
|
||||
}
|
||||
fn from_norm(&self, n: f64) -> f64 {
|
||||
self.min + n * (self.max - self.min)
|
||||
}
|
||||
fn domain(&self) -> (f64, f64) {
|
||||
(self.min, self.max)
|
||||
}
|
||||
}
|
||||
|
||||
/// Escala logarítmica base e. `min` y `max` deben ser positivos.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct LogScale {
|
||||
log_min: f64,
|
||||
log_max: f64,
|
||||
min: f64,
|
||||
max: f64,
|
||||
}
|
||||
|
||||
impl LogScale {
|
||||
pub fn new(min: f64, max: f64) -> Self {
|
||||
debug_assert!(min > 0.0 && max > min, "LogScale: 0 < min < max");
|
||||
Self {
|
||||
log_min: min.ln(),
|
||||
log_max: max.ln(),
|
||||
min,
|
||||
max,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Scale for LogScale {
|
||||
fn to_norm(&self, v: f64) -> f64 {
|
||||
(v.ln() - self.log_min) / (self.log_max - self.log_min)
|
||||
}
|
||||
fn from_norm(&self, n: f64) -> f64 {
|
||||
(self.log_min + n * (self.log_max - self.log_min)).exp()
|
||||
}
|
||||
fn domain(&self) -> (f64, f64) {
|
||||
(self.min, self.max)
|
||||
}
|
||||
}
|
||||
|
||||
/// Escala temporal sobre epoch ms. Internamente lineal.
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct TimeScale {
|
||||
inner: LinearScale,
|
||||
}
|
||||
|
||||
impl TimeScale {
|
||||
pub fn new(min_epoch_ms: f64, max_epoch_ms: f64) -> Self {
|
||||
Self {
|
||||
inner: LinearScale::new(min_epoch_ms, max_epoch_ms),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Scale for TimeScale {
|
||||
fn to_norm(&self, v: f64) -> f64 {
|
||||
self.inner.to_norm(v)
|
||||
}
|
||||
fn from_norm(&self, n: f64) -> f64 {
|
||||
self.inner.from_norm(n)
|
||||
}
|
||||
fn domain(&self) -> (f64, f64) {
|
||||
self.inner.domain()
|
||||
}
|
||||
}
|
||||
|
||||
/// Wilkinson "nice numbers" — devuelve el step ideal en `{1, 2, 5} × 10^k`
|
||||
/// para que un rango `[min, max]` tenga ~`target_ticks` divisiones.
|
||||
pub fn nice_step(min: f64, max: f64, target_ticks: usize) -> f64 {
|
||||
debug_assert!(max > min && target_ticks > 0);
|
||||
let raw = (max - min) / target_ticks as f64;
|
||||
let mag = 10f64.powf(raw.log10().floor());
|
||||
let norm = raw / mag;
|
||||
let nice = if norm < 1.5 {
|
||||
1.0
|
||||
} else if norm < 3.0 {
|
||||
2.0
|
||||
} else if norm < 7.0 {
|
||||
5.0
|
||||
} else {
|
||||
10.0
|
||||
};
|
||||
nice * mag
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn linear_roundtrip() {
|
||||
let s = LinearScale::new(10.0, 20.0);
|
||||
assert!((s.to_norm(15.0) - 0.5).abs() < 1e-9);
|
||||
assert!((s.from_norm(0.5) - 15.0).abs() < 1e-9);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn log_roundtrip() {
|
||||
let s = LogScale::new(1.0, 1000.0);
|
||||
// 10 está a 1/3 del camino en log10. ln(10)/ln(1000) = 1/3.
|
||||
assert!((s.to_norm(10.0) - 1.0 / 3.0).abs() < 1e-9);
|
||||
assert!((s.from_norm(2.0 / 3.0) - 100.0).abs() < 1e-9);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn nice_step_es_potencia() {
|
||||
// 100/5 = 20 — exact match para el branch nice=2.0 · mag=10.
|
||||
assert!((nice_step(0.0, 100.0, 5) - 20.0).abs() < 1e-9);
|
||||
// 1.0/10 = 0.1 — branch nice=1.0 · mag=0.1.
|
||||
assert!((nice_step(0.0, 1.0, 10) - 0.1).abs() < 1e-9);
|
||||
// 14/5 = 2.8 — branch nice=2.0 (1.5 ≤ norm < 3) · mag=1.
|
||||
assert!((nice_step(0.0, 14.0, 5) - 2.0).abs() < 1e-9);
|
||||
// 7/5 = 1.4 — cae bajo 1.5 → snap a 1.0 · mag=1 = 1.0.
|
||||
assert!((nice_step(0.0, 7.0, 5) - 1.0).abs() < 1e-9);
|
||||
// 50/5 = 10 — branch nice=10 · mag=1 = 10. (Equivalente a 1·10.)
|
||||
assert!((nice_step(0.0, 50.0, 5) - 10.0).abs() < 1e-9);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user