Fix broken matrices with alignment and optimize code while we're at it (#935)

This commit is contained in:
Alex Saveau 2023-04-24 02:16:13 -07:00 committed by GitHub
parent 5ccc687619
commit bc802bd8fb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 86 additions and 94 deletions

View File

@ -15,10 +15,16 @@ impl LayoutMath for AlignPointElem {
} }
} }
pub(super) struct AlignmentResult {
pub points: Vec<Abs>,
pub width: Abs,
}
/// Determine the position of the alignment points. /// Determine the position of the alignment points.
pub(super) fn alignments(rows: &[MathRow]) -> Vec<Abs> { pub(super) fn alignments(rows: &[MathRow]) -> AlignmentResult {
let mut widths = Vec::<Abs>::new(); let mut widths = Vec::<Abs>::new();
let mut pending_width = Abs::zero();
for row in rows { for row in rows {
let mut width = Abs::zero(); let mut width = Abs::zero();
let mut alignment_index = 0; let mut alignment_index = 0;
@ -28,6 +34,7 @@ pub(super) fn alignments(rows: &[MathRow]) -> Vec<Abs> {
widths[alignment_index].set_max(width); widths[alignment_index].set_max(width);
} else { } else {
widths.push(width); widths.push(width);
pending_width = Abs::zero();
} }
width = Abs::zero(); width = Abs::zero();
alignment_index += 1; alignment_index += 1;
@ -35,6 +42,7 @@ pub(super) fn alignments(rows: &[MathRow]) -> Vec<Abs> {
width += fragment.width(); width += fragment.width();
} }
} }
pending_width.set_max(width);
} }
let mut points = widths; let mut points = widths;
@ -42,5 +50,8 @@ pub(super) fn alignments(rows: &[MathRow]) -> Vec<Abs> {
let prev = points[i - 1]; let prev = points[i - 1];
points[i] += prev; points[i] += prev;
} }
points AlignmentResult {
width: points.last().copied().unwrap_or_default() + pending_width,
points,
}
} }

View File

@ -242,16 +242,13 @@ fn layout_mat_body(ctx: &mut MathContext, rows: &[Vec<Content>]) -> SourceResult
return Ok(Frame::new(Size::zero())); return Ok(Frame::new(Size::zero()));
} }
let mut widths = vec![Abs::zero(); ncols]; let mut heights = vec![(Abs::zero(), Abs::zero()); nrows];
let mut ascents = vec![Abs::zero(); nrows];
let mut descents = vec![Abs::zero(); nrows];
ctx.style(ctx.style.for_denominator()); ctx.style(ctx.style.for_denominator());
let mut cols = vec![vec![]; ncols]; let mut cols = vec![vec![]; ncols];
for ((row, ascent), descent) in rows.iter().zip(&mut ascents).zip(&mut descents) { for (row, (ascent, descent)) in rows.iter().zip(&mut heights) {
for ((cell, rcol), col) in row.iter().zip(&mut widths).zip(&mut cols) { for (cell, col) in row.iter().zip(&mut cols) {
let cell = ctx.layout_row(cell)?; let cell = ctx.layout_row(cell)?;
rcol.set_max(cell.width());
ascent.set_max(cell.ascent()); ascent.set_max(cell.ascent());
descent.set_max(cell.descent()); descent.set_max(cell.descent());
col.push(cell); col.push(cell);
@ -259,18 +256,15 @@ fn layout_mat_body(ctx: &mut MathContext, rows: &[Vec<Content>]) -> SourceResult
} }
ctx.unstyle(); ctx.unstyle();
let width = widths.iter().sum::<Abs>() + col_gap * (ncols - 1) as f64; let mut frame = Frame::new(Size::new(
let height = ascents.iter().sum::<Abs>() Abs::zero(),
+ descents.iter().sum::<Abs>() heights.iter().map(|&(a, b)| a + b).sum::<Abs>() + row_gap * (nrows - 1) as f64,
+ row_gap * (nrows - 1) as f64; ));
let size = Size::new(width, height);
let mut frame = Frame::new(size);
let mut x = Abs::zero(); let mut x = Abs::zero();
for (col, &rcol) in cols.into_iter().zip(&widths) { for col in cols {
let points = alignments(&col); let AlignmentResult { points, width: rcol } = alignments(&col);
let mut y = Abs::zero(); let mut y = Abs::zero();
for ((cell, &ascent), &descent) in col.into_iter().zip(&ascents).zip(&descents) { for (cell, &(ascent, descent)) in col.into_iter().zip(&heights) {
let cell = cell.into_aligned_frame(ctx, &points, Align::Center); let cell = cell.into_aligned_frame(ctx, &points, Align::Center);
let pos = Point::new( let pos = Point::new(
if points.is_empty() { x + (rcol - cell.width()) / 2.0 } else { x }, if points.is_empty() { x + (rcol - cell.width()) / 2.0 } else { x },
@ -281,6 +275,7 @@ fn layout_mat_body(ctx: &mut MathContext, rows: &[Vec<Content>]) -> SourceResult
} }
x += rcol + col_gap; x += rcol + col_gap;
} }
frame.size_mut().x = x - col_gap;
Ok(frame) Ok(frame)
} }

View File

@ -87,10 +87,6 @@ impl MathRow {
self.iter().map(MathFragment::width).sum() self.iter().map(MathFragment::width).sum()
} }
pub fn height(&self) -> Abs {
self.ascent() + self.descent()
}
pub fn ascent(&self) -> Abs { pub fn ascent(&self) -> Abs {
self.iter().map(MathFragment::ascent).max().unwrap_or_default() self.iter().map(MathFragment::ascent).max().unwrap_or_default()
} }
@ -136,8 +132,7 @@ impl MathRow {
rows.pop(); rows.pop();
} }
let width = rows.iter().map(|row| row.width()).max().unwrap_or_default(); let AlignmentResult { points, width } = alignments(&rows);
let points = alignments(&rows);
let mut frame = Frame::new(Size::zero()); let mut frame = Frame::new(Size::zero());
for (i, row) in rows.into_iter().enumerate() { for (i, row) in rows.into_iter().enumerate() {

View File

@ -242,22 +242,18 @@ pub(super) fn stack(
gap: Abs, gap: Abs,
baseline: usize, baseline: usize,
) -> Frame { ) -> Frame {
let mut width = Abs::zero(); let AlignmentResult { points, width } = alignments(&rows);
let mut height = rows.len().saturating_sub(1) as f64 * gap;
let points = alignments(&rows);
let rows: Vec<_> = rows let rows: Vec<_> = rows
.into_iter() .into_iter()
.map(|row| row.into_aligned_frame(ctx, &points, align)) .map(|row| row.into_aligned_frame(ctx, &points, align))
.collect(); .collect();
for row in &rows {
height += row.height();
width.set_max(row.width());
}
let mut y = Abs::zero(); let mut y = Abs::zero();
let mut frame = Frame::new(Size::new(width, height)); let mut frame = Frame::new(Size::new(
width,
rows.iter().map(|row| row.height()).sum::<Abs>()
+ rows.len().saturating_sub(1) as f64 * gap,
));
for (i, row) in rows.into_iter().enumerate() { for (i, row) in rows.into_iter().enumerate() {
let x = align.position(width - row.width()); let x = align.position(width - row.width());

Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -25,69 +25,9 @@ $
"left" \ "left" \
$ $
---
// Test alternating alignment.
$
"a" & "a a a" & "a a" \
"a a" & "a a" & "a" \
"a a a" & "a" & "a a a" \
$
---
// Test alternating alignment in a vector.
$ vec(
"a" & "a a a" & "a a",
"a a" & "a a" & "a",
"a a a" & "a" & "a a a",
) $
---
// Test alternating explicit alignment in a matrix.
$ mat(
"a" & "a a a" & "a a";
"a a" & "a a" & "a";
"a a a" & "a" & "a a a";
) $
---
// Test alignment in a matrix.
$ mat(
"a", "a a a", "a a";
"a a", "a a", "a";
"a a a", "a", "a a a";
) $
---
// Test explicit left alignment in a matrix.
$ mat(
&"a", &"a a a", &"a a";
&"a a", &"a a", &"a";
&"a a a", &"a", &"a a a";
) $
---
// Test explicit right alignment in a matrix.
$ mat(
"a"&, "a a a"&, "a a"&;
"a a"&, "a a"&, "a"&;
"a a a"&, "a"&, "a a a"&;
) $
--- ---
// Test #460 equations. // Test #460 equations.
$ $
a &=b & quad c&=d \ a &=b & quad c&=d \
e &=f & g&=h e &=f & g&=h
$ $
$ mat(&a+b,c;&d, e) $
$ mat(&a+b&,c;&d&, e) $
$ mat(&&&a+b,c;&&&d, e) $
$ mat(.&a+b&.,c;.....&d&....., e) $
---
// Test #454 equations.
$ mat(-1, 1, 1; 1, -1, 1; 1, 1, -1) $
$ mat(-1&, 1&, 1&; 1&, -1&, 1&; 1&, 1&, -1&) $
$ mat(-1&, 1&, 1&; 1, -1, 1; 1, 1, -1) $
$ mat(&-1, &1, &1; 1, -1, 1; 1, 1, -1) $

View File

@ -0,0 +1,55 @@
// Test matrix alignment math.
---
// Test alternating alignment in a vector.
$ vec(
"a" & "a a a" & "a a",
"a a" & "a a" & "a",
"a a a" & "a" & "a a a",
) $
---
// Test alternating explicit alignment in a matrix.
$ mat(
"a" & "a a a" & "a a";
"a a" & "a a" & "a";
"a a a" & "a" & "a a a";
) $
---
// Test alignment in a matrix.
$ mat(
"a", "a a a", "a a";
"a a", "a a", "a";
"a a a", "a", "a a a";
) $
---
// Test explicit left alignment in a matrix.
$ mat(
&"a", &"a a a", &"a a";
&"a a", &"a a", &"a";
&"a a a", &"a", &"a a a";
) $
---
// Test explicit right alignment in a matrix.
$ mat(
"a"&, "a a a"&, "a a"&;
"a a"&, "a a"&, "a"&;
"a a a"&, "a"&, "a a a"&;
) $
---
// Test #460 equations.
$ mat(&a+b,c;&d, e) $
$ mat(&a+b&,c;&d&, e) $
$ mat(&&&a+b,c;&&&d, e) $
$ mat(.&a+b&.,c;.....&d&....., e) $
---
// Test #454 equations.
$ mat(-1, 1, 1; 1, -1, 1; 1, 1, -1) $
$ mat(-1&, 1&, 1&; 1&, -1&, 1&; 1&, 1&, -1&) $
$ mat(-1&, 1&, 1&; 1, -1, 1; 1, 1, -1) $
$ mat(&-1, &1, &1; 1, -1, 1; 1, 1, -1) $