From 845b7bd0b43a6271bff36ecd825c6d18fb80130d Mon Sep 17 00:00:00 2001 From: Michael Mikovsky <77305074+Astatin3@users.noreply.github.com> Date: Wed, 24 Sep 2025 09:59:38 -0600 Subject: [PATCH] Make lineargroups center properly --- src/consts.rs | 2 +- src/element/functions.rs | 11 ++-- src/element/rasterizer.rs | 87 +++++++++++++++++++++---------- src/main.rs | 106 -------------------------------------- 4 files changed, 67 insertions(+), 139 deletions(-) diff --git a/src/consts.rs b/src/consts.rs index 4180000..5386d66 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -2,7 +2,7 @@ pub static LINE_WIDTH: f32 = 0.02; // Global scale pub static MIN_LOCAL_SCALE: f32 = 0.1; // Global scale -pub static FRACTION_SCALE: f32 = 0.95; // Local scale +pub static FRACTION_SCALE: f32 = 0.8; // Local scale pub static FRACTION_PADDING: f32 = 0.2; // global scale pub static SUPERSCRIPT_SCALE: f32 = 0.6; // local scale diff --git a/src/element/functions.rs b/src/element/functions.rs index d61ddb9..e7f5dbe 100644 --- a/src/element/functions.rs +++ b/src/element/functions.rs @@ -10,6 +10,11 @@ fn assert_args(n: usize, start: usize, end: usize, err: &str) -> Result<(), Stri } } +fn derive_symbol(symbol_str: &str, args: &Vec>) -> Result { + assert_args(args.len(), 0, 0, "Symbol cannot take in any args!")?; + + Ok(KElement::Text(symbol_str.to_string())) +} impl KElement { pub fn from_function(name: &str, args: &Vec>) -> Result { @@ -22,11 +27,7 @@ impl KElement { lower: Rc::new(Self::parse_object(&args[1])?) }) } - "pm" => { - assert_args(args.len(), 0, 0, "Symbol cannot take in any args!")?; - - Ok(KElement::Text("±".to_string())) - } + "pm" => derive_symbol("±", args), _ => Err(format!("Invalid function: \\{}", name)) } } diff --git a/src/element/rasterizer.rs b/src/element/rasterizer.rs index b2af521..649b936 100644 --- a/src/element/rasterizer.rs +++ b/src/element/rasterizer.rs @@ -7,23 +7,38 @@ impl KElement { pub fn rasterize(&self, globals: &mut RusTeX, current_scale: f32) -> Bitmap { match self { KElement::LinearGroup(elems) => { - let (mut totalx, mut maxy) = (0,0); + let (mut totalx, mut mintop, mut maxbottom): (usize, usize, usize) = (0,0,0); let mut positions = Vec::new(); + for elem in elems { - let (x,y) = elem.get_bounds(globals, current_scale); - positions.push((totalx,y)); - totalx += x; - maxy = maxy.max(y); + let (width, height, centery) = elem.get_bounds(globals, current_scale); + let top = centery; + let bottom = height - centery; + + positions.push((totalx, centery)); + + mintop = mintop.max(top); + maxbottom = maxbottom.max(bottom); + totalx += width; } - let mut bitmap = Bitmap::new(totalx, maxy); + let height = maxbottom + mintop; + + + let mut bitmap = Bitmap::new(totalx, height); for i in 0..elems.len() { let elem = &elems[i]; let pos = positions[i]; let new_bitmap = elem.rasterize(globals, current_scale); // println!("{:?} {:?} {:?}", (bitmap.width, bitmap.height), pos, (new_bitmap.width, new_bitmap.height)); - bitmap.overlay(&new_bitmap, pos.0, (maxy-pos.1)/2); + // let center = (center - pos.2) / 2; + // let center = 0; + // println!("{}, {}, {}", center, 0, maxy); + + let y = mintop - pos.1; + + bitmap.overlay(&new_bitmap, pos.0, y); } bitmap @@ -39,8 +54,8 @@ impl KElement { }, KElement::Fraction{upper,lower} => { let padding = (FRACTION_PADDING * current_scale) as usize; - let (ax,ay) = upper.get_bounds(globals, current_scale * FRACTION_SCALE); - let (bx,by) = lower.get_bounds(globals, current_scale * FRACTION_SCALE); + let (ax,ay, _) = upper.get_bounds(globals, current_scale * FRACTION_SCALE); + let (bx,by, _) = lower.get_bounds(globals, current_scale * FRACTION_SCALE); let (width, height) = ( ax.max(bx) + padding*2, @@ -70,12 +85,12 @@ impl KElement { } KElement::SuperSub{inner, upper, lower} => { - let (ax, ay) = inner.get_bounds(globals, current_scale); + let (ax, ay, _) = inner.get_bounds(globals, current_scale); if upper.is_some() && lower.is_some() { todo!(); } else if upper.is_some() { let upper = upper.as_ref().unwrap(); - let (bx, by) = upper.get_bounds(globals, current_scale * SUPERSCRIPT_SCALE); + let (bx, by, _) = upper.get_bounds(globals, current_scale * SUPERSCRIPT_SCALE); let yoffset = (by as f32*SUPERSCRIPT_Y_OFFSET) as usize; let (width, height) = ( @@ -97,16 +112,10 @@ impl KElement { } } } - pub fn get_bounds(&self, globals: &mut RusTeX, current_scale: f32) -> (usize, usize) { + pub fn get_bounds(&self, globals: &mut RusTeX, current_scale: f32) -> (usize, usize, usize) { match self { KElement::LinearGroup(elems) => { - let (mut totalx, mut maxy) = (0,0); - for elem in elems { - let (x,y) = elem.get_bounds(globals, current_scale); - totalx += x; - maxy = maxy.max(y); - } - (totalx, maxy) + bounds_of_linear_group(elems, globals, current_scale) } KElement::Integer(i) => { measure_text_bounds(&mut globals.layout, &i.to_string(), current_scale) @@ -118,22 +127,24 @@ impl KElement { measure_text_bounds(&mut globals.layout, &str, current_scale) }, KElement::Fraction{upper,lower} => { - let (ax,ay) = upper.get_bounds(globals, current_scale * FRACTION_SCALE); - let (bx,by) = lower.get_bounds(globals, current_scale * FRACTION_SCALE); + let (ax,ay, _) = upper.get_bounds(globals, current_scale * FRACTION_SCALE); + let (bx,by, _) = lower.get_bounds(globals, current_scale * FRACTION_SCALE); ( (ax.max(bx)) + 2*(FRACTION_PADDING * current_scale) as usize, - ay+by + (FRACTION_PADDING * current_scale) as usize + ay+by + (FRACTION_PADDING * current_scale) as usize, + ay + (FRACTION_PADDING * current_scale) as usize, ) }, KElement::SuperSub{inner, upper, lower} => { - let (ax, ay) = inner.get_bounds(globals, current_scale); + let (ax, ay, center) = inner.get_bounds(globals, current_scale); if upper.is_some() && lower.is_some() { todo!(); } else if upper.is_some() { - let (bx, by) = upper.as_ref().unwrap().get_bounds(globals, current_scale * SUPERSCRIPT_SCALE); + let (bx, by, _) = upper.as_ref().unwrap().get_bounds(globals, current_scale * SUPERSCRIPT_SCALE); ( ax+bx, - ay + (by as f32*SUPERSCRIPT_Y_OFFSET) as usize + ay + (by as f32*SUPERSCRIPT_Y_OFFSET) as usize, + center + (by as f32*SUPERSCRIPT_Y_OFFSET) as usize ) } else if lower.is_some() { todo!(); @@ -147,6 +158,28 @@ impl KElement { } } +fn bounds_of_linear_group(elems: &Vec, globals: &mut RusTeX, current_scale: f32) -> (usize, usize, usize) { + // let common_centery = elems[0].get_bounds(globals, current_scale); + + let (mut totalx, mut mintop, mut maxbottom): (usize, usize, usize) = (0,0,0); + for elem in elems { + let (width, height, centery) = elem.get_bounds(globals, current_scale); + totalx += width; + let top = centery; + let bottom = height - centery; + + + mintop = mintop.max(top); + maxbottom = maxbottom.max(bottom); + } + + ( + totalx, + maxbottom + mintop, + mintop + ) +} + // impl KSymbol { // // pub fn get_max_bounds(&self) -> (f32, f32) { // // match self { @@ -165,7 +198,7 @@ impl KElement { // } // } -fn measure_text_bounds(layout: &mut Layout, text: &str, scale:f32) -> (usize, usize) { +fn measure_text_bounds(layout: &mut Layout, text: &str, scale:f32) -> (usize, usize, usize) { layout.clear(); layout.append(&FONTS, &TextStyle::new(text, scale, 0)); @@ -175,7 +208,7 @@ fn measure_text_bounds(layout: &mut Layout, text: &str, scale:f32) -> (usize, us height = height.max(glyph.y as usize + glyph.height); } - (width, height) + (width, height, height/2) } diff --git a/src/main.rs b/src/main.rs index 5ca5e2e..435bc03 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,8 +5,6 @@ mod element; mod bitmap; mod consts; -use std::{rc::Rc, time::Instant}; - use fontdue::{layout::{CoordinateSystem, Layout, LayoutSettings}}; use crate::{bitmap::Bitmap, element::{KElement}}; @@ -16,8 +14,6 @@ fn main() -> Result<(), std::fmt::Error> { } fn parse_test() -> Result<(), std::fmt::Error> { - // Test the quadratic formula - // let tex_input = r"x=\frac{-b\pm\sqrt{b^2 - 4ac}}{2a}"; let tex_input = &std::env::args().nth(1).unwrap(); match KElement::parse(tex_input) { @@ -28,111 +24,9 @@ fn parse_test() -> Result<(), std::fmt::Error> { Err(e) => println!("Error: {}", e), } - // println!("Parsing: {}", tex_input); - - // match parser::parse(tex_input) { - // Ok(result) => { - // println!("Parsed result:"); - // for (i, obj) in result.iter().enumerate() { - // println!(" [{}]: {:#?}", i, obj); - // } - // } - // Err(e) => { - // println!("Error parsing TeX: {}", e); - // } - // } - - // // Test some other examples - // let examples = vec![ - // "a^2", - // r"\frac{12.34a+b}{2}", - // r"\sqrt{x}", - // "x_{a^2}^{2^a}", - // "(a+b)^2", - // ]; - - // for example in examples { - // println!("\n--- Parsing: {} ---", example); - // match parser.parse(example) { - // Ok(result) => { - // for obj in result { - // println!("{:#?}", obj); - // } - // } - // Err(e) => println!("Error: {}", e), - // } - // } - Ok(()) } -// fn raster_test() -> Result<(), std::fmt::Error> { -// let start = Instant::now(); - -// let mut rustex = RusTeX::new(TeXSettings { scale: 100. }); - -// let element = - -// KElement::Superscript(Rc::new( -// KElement::LinearGroup(vec![ -// KElement::Fraction( -// Rc::new(KElement::LinearGroup(vec![ -// KElement::Integer(123), -// KElement::Text("*".to_string()), -// KElement::Superscript( -// Rc::new(KElement::Integer(123)), -// Rc::new(KElement::Fraction( -// Rc::new(KElement::Integer(5)), -// Rc::new(KElement::Integer(2))) -// ), -// ) -// ])), -// Rc::new(KElement::Integer(12)) -// ), -// // KElement::Integer(12), -// // KElement::Integer(12), -// KElement::Decimal(12.34), -// KElement::Fraction( -// Rc::new(KElement::Fraction( -// Rc::new(KElement::Integer(123)), -// Rc::new(KElement::Integer(12))) -// ), -// Rc::new(KElement::Fraction( -// Rc::new(KElement::Integer(123)), -// Rc::new(KElement::Fraction( -// Rc::new(KElement::Integer(123)), -// Rc::new(KElement::Fraction( -// Rc::new(KElement::Integer(123)), -// Rc::new(KElement::Fraction( -// Rc::new(KElement::Integer(123)), -// Rc::new(KElement::Fraction( -// Rc::new(KElement::Integer(123)), -// Rc::new(KElement::Fraction( -// Rc::new(KElement::Integer(123)), -// Rc::new(KElement::Fraction( -// Rc::new(KElement::Integer(123)), -// Rc::new(KElement::Decimal(1234.5678)) -// )) -// )) -// )) -// )) -// )) -// )) -// )), -// ), -// ])), Rc::new(KElement::Decimal(12.34))); - -// // rustex.add_text(&TextStyle::new("testi12345ng! e^23", 100.0, 0)); -// let bitmap = rustex.rasterize(element); - -// println!("Rasterizing time: {:?}", start.elapsed()); - -// bitmap.print(); - -// // print_bitmap(&bitmap, width, height); - -// Ok(()) -// } struct RusTeX { pub settings: TeXSettings,