Pad matrix cell to make matrix have a consistent height (#4153)
@ -22,7 +22,7 @@ use crate::visualize::{FixedStroke, Geometry, LineCap, Shape, Stroke};
|
|||||||
|
|
||||||
use super::delimiter_alignment;
|
use super::delimiter_alignment;
|
||||||
|
|
||||||
const DEFAULT_ROW_GAP: Em = Em::new(0.5);
|
const DEFAULT_ROW_GAP: Em = Em::new(0.2);
|
||||||
const DEFAULT_COL_GAP: Em = Em::new(0.5);
|
const DEFAULT_COL_GAP: Em = Em::new(0.5);
|
||||||
const VERTICAL_PADDING: Ratio = Ratio::new(0.1);
|
const VERTICAL_PADDING: Ratio = Ratio::new(0.1);
|
||||||
const DEFAULT_STROKE_THICKNESS: Em = Em::new(0.05);
|
const DEFAULT_STROKE_THICKNESS: Em = Em::new(0.05);
|
||||||
@ -441,8 +441,12 @@ fn layout_vec_body(
|
|||||||
for child in column {
|
for child in column {
|
||||||
flat.push(ctx.layout_into_run(child, styles.chain(&denom_style))?);
|
flat.push(ctx.layout_into_run(child, styles.chain(&denom_style))?);
|
||||||
}
|
}
|
||||||
|
// We pad ascent and descent with the ascent and descent of the paren
|
||||||
Ok(stack(flat, align, gap, 0, alternator))
|
// to ensure that normal vectors are aligned with others unless they are
|
||||||
|
// way too big.
|
||||||
|
let paren =
|
||||||
|
GlyphFragment::new(ctx, styles.chain(&denom_style), '(', Span::detached());
|
||||||
|
Ok(stack(flat, align, gap, 0, alternator, Some((paren.ascent, paren.descent))))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Layout the inner contents of a matrix.
|
/// Layout the inner contents of a matrix.
|
||||||
@ -499,12 +503,18 @@ fn layout_mat_body(
|
|||||||
let mut cols = vec![vec![]; ncols];
|
let mut cols = vec![vec![]; ncols];
|
||||||
|
|
||||||
let denom_style = style_for_denominator(styles);
|
let denom_style = style_for_denominator(styles);
|
||||||
|
// We pad ascent and descent with the ascent and descent of the paren
|
||||||
|
// to ensure that normal matrices are aligned with others unless they are
|
||||||
|
// way too big.
|
||||||
|
let paren =
|
||||||
|
GlyphFragment::new(ctx, styles.chain(&denom_style), '(', Span::detached());
|
||||||
|
|
||||||
for (row, (ascent, descent)) in rows.iter().zip(&mut heights) {
|
for (row, (ascent, descent)) in rows.iter().zip(&mut heights) {
|
||||||
for (cell, col) in row.iter().zip(&mut cols) {
|
for (cell, col) in row.iter().zip(&mut cols) {
|
||||||
let cell = ctx.layout_into_run(cell, styles.chain(&denom_style))?;
|
let cell = ctx.layout_into_run(cell, styles.chain(&denom_style))?;
|
||||||
|
|
||||||
ascent.set_max(cell.ascent());
|
ascent.set_max(cell.ascent().max(paren.ascent));
|
||||||
descent.set_max(cell.descent());
|
descent.set_max(cell.descent().max(paren.descent));
|
||||||
|
|
||||||
col.push(cell);
|
col.push(cell);
|
||||||
}
|
}
|
||||||
|
@ -291,8 +291,14 @@ fn layout_underoverspreader(
|
|||||||
baseline = rows.len() - 1;
|
baseline = rows.len() - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let frame =
|
let frame = stack(
|
||||||
stack(rows, FixedAlignment::Center, gap, baseline, LeftRightAlternator::Right);
|
rows,
|
||||||
|
FixedAlignment::Center,
|
||||||
|
gap,
|
||||||
|
baseline,
|
||||||
|
LeftRightAlternator::Right,
|
||||||
|
None,
|
||||||
|
);
|
||||||
ctx.push(FrameFragment::new(ctx, styles, frame).with_class(body_class));
|
ctx.push(FrameFragment::new(ctx, styles, frame).with_class(body_class));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -309,6 +315,7 @@ pub(super) fn stack(
|
|||||||
gap: Abs,
|
gap: Abs,
|
||||||
baseline: usize,
|
baseline: usize,
|
||||||
alternator: LeftRightAlternator,
|
alternator: LeftRightAlternator,
|
||||||
|
minimum_ascent_descent: Option<(Abs, Abs)>,
|
||||||
) -> Frame {
|
) -> Frame {
|
||||||
let rows: Vec<_> = rows.into_iter().flat_map(|r| r.rows()).collect();
|
let rows: Vec<_> = rows.into_iter().flat_map(|r| r.rows()).collect();
|
||||||
let AlignmentResult { points, width } = alignments(&rows);
|
let AlignmentResult { points, width } = alignments(&rows);
|
||||||
@ -317,20 +324,27 @@ pub(super) fn stack(
|
|||||||
.map(|row| row.into_line_frame(&points, alternator))
|
.map(|row| row.into_line_frame(&points, alternator))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
let padded_height = |height: Abs| {
|
||||||
|
height.max(minimum_ascent_descent.map_or(Abs::zero(), |(a, d)| a + d))
|
||||||
|
};
|
||||||
|
|
||||||
let mut frame = Frame::soft(Size::new(
|
let mut frame = Frame::soft(Size::new(
|
||||||
width,
|
width,
|
||||||
rows.iter().map(|row| row.height()).sum::<Abs>()
|
rows.iter().map(|row| padded_height(row.height())).sum::<Abs>()
|
||||||
+ rows.len().saturating_sub(1) as f64 * gap,
|
+ rows.len().saturating_sub(1) as f64 * gap,
|
||||||
));
|
));
|
||||||
|
|
||||||
let mut y = Abs::zero();
|
let mut y = Abs::zero();
|
||||||
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());
|
||||||
let pos = Point::new(x, y);
|
let ascent_padded_part = minimum_ascent_descent
|
||||||
|
.map_or(Abs::zero(), |(a, _)| (a - row.ascent()))
|
||||||
|
.max(Abs::zero());
|
||||||
|
let pos = Point::new(x, y + ascent_padded_part);
|
||||||
if i == baseline {
|
if i == baseline {
|
||||||
frame.set_baseline(y + row.baseline());
|
frame.set_baseline(y + row.baseline() + ascent_padded_part);
|
||||||
}
|
}
|
||||||
y += row.height() + gap;
|
y += padded_height(row.height()) + gap;
|
||||||
frame.push_frame(pos, row);
|
frame.push_frame(pos, row);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.5 KiB |
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
tests/ref/issue-1617-mat-align.png
Normal file
After Width: | Height: | Size: 3.3 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 669 B After Width: | Height: | Size: 674 B |
Before Width: | Height: | Size: 757 B After Width: | Height: | Size: 1.3 KiB |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.2 KiB |
Before Width: | Height: | Size: 578 B After Width: | Height: | Size: 568 B |
Before Width: | Height: | Size: 796 B After Width: | Height: | Size: 793 B |
Before Width: | Height: | Size: 308 B After Width: | Height: | Size: 343 B |
Before Width: | Height: | Size: 285 B After Width: | Height: | Size: 340 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 984 B |
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 908 B After Width: | Height: | Size: 1009 B |
Before Width: | Height: | Size: 896 B After Width: | Height: | Size: 992 B |
Before Width: | Height: | Size: 916 B After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 930 B After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.8 KiB |
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.5 KiB |
Before Width: | Height: | Size: 837 B After Width: | Height: | Size: 802 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 580 B After Width: | Height: | Size: 620 B |
Before Width: | Height: | Size: 1.9 KiB After Width: | Height: | Size: 2.1 KiB |
Before Width: | Height: | Size: 521 B After Width: | Height: | Size: 552 B |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 3.2 KiB |
Before Width: | Height: | Size: 489 B After Width: | Height: | Size: 496 B |
Before Width: | Height: | Size: 493 B After Width: | Height: | Size: 489 B |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 898 B After Width: | Height: | Size: 882 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
Before Width: | Height: | Size: 770 B After Width: | Height: | Size: 784 B |
Before Width: | Height: | Size: 908 B After Width: | Height: | Size: 1009 B |
Before Width: | Height: | Size: 196 B After Width: | Height: | Size: 203 B |
Before Width: | Height: | Size: 397 B After Width: | Height: | Size: 420 B |
Before Width: | Height: | Size: 591 B After Width: | Height: | Size: 620 B |
@ -212,3 +212,18 @@ $ mat(delim: angle.r, 1, 2; 3, 4) $
|
|||||||
--- math-mat-delims-pair ---
|
--- math-mat-delims-pair ---
|
||||||
$ mat(delim: #(none, "["), 1, 2; 3, 4) $
|
$ mat(delim: #(none, "["), 1, 2; 3, 4) $
|
||||||
$ mat(delim: #(sym.angle.r, sym.bracket.double.r), 1, 2; 3, 4) $
|
$ mat(delim: #(sym.angle.r, sym.bracket.double.r), 1, 2; 3, 4) $
|
||||||
|
|
||||||
|
--- issue-1617-mat-align ---
|
||||||
|
#set page(width: auto)
|
||||||
|
$ mat(a, b; c, d) mat(x; y) $
|
||||||
|
|
||||||
|
$ x mat(a; c) + y mat(b; d)
|
||||||
|
= mat(a x+b y; c x+d y) $
|
||||||
|
|
||||||
|
$ mat(
|
||||||
|
-d_0, lambda_0, 0, 0, dots;
|
||||||
|
mu_1, -d_1, lambda_1, 0, dots;
|
||||||
|
0, mu_2, -d_2, lambda_2, dots;
|
||||||
|
dots.v, dots.v, dots.v, dots.v, dots.down;
|
||||||
|
)
|
||||||
|
mat(p_0; p_1; p_2; dots.v) $
|
||||||
|