Make lineargroups center properly

This commit is contained in:
Michael Mikovsky
2025-09-24 09:59:38 -06:00
parent 0ef040d5c3
commit 845b7bd0b4
4 changed files with 67 additions and 139 deletions
+1 -1
View File
@@ -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
+6 -5
View File
@@ -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<Vec<ParsedObject>>) -> Result<KElement, String> {
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<Vec<ParsedObject>>) -> Result<KElement, String> {
@@ -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))
}
}
+60 -27
View File
@@ -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<KElement>, 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)
}
-106
View File
@@ -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,