Vector and case layout
This commit is contained in:
parent
a0146b5b9b
commit
953bdc1859
@ -1,5 +1,8 @@
|
||||
use super::*;
|
||||
|
||||
const ROW_GAP: Em = Em::new(0.5);
|
||||
const VERTICAL_PADDING: Ratio = Ratio::new(0.1);
|
||||
|
||||
/// # Vector
|
||||
/// A column vector.
|
||||
///
|
||||
@ -18,7 +21,7 @@ use super::*;
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[capable(LayoutMath)]
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct VecNode(Vec<Content>);
|
||||
|
||||
@ -47,52 +50,13 @@ impl VecNode {
|
||||
}
|
||||
}
|
||||
|
||||
impl Texify for VecNode {
|
||||
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
||||
let kind = match t.styles.get(Self::DELIM) {
|
||||
Delimiter::Paren => "pmatrix",
|
||||
Delimiter::Bracket => "bmatrix",
|
||||
Delimiter::Brace => "Bmatrix",
|
||||
Delimiter::Bar => "vmatrix",
|
||||
};
|
||||
|
||||
t.push_str("\\begin{");
|
||||
t.push_str(kind);
|
||||
t.push_str("}");
|
||||
|
||||
for component in &self.0 {
|
||||
component.texify(t)?;
|
||||
t.push_str("\\\\");
|
||||
}
|
||||
t.push_str("\\end{");
|
||||
t.push_str(kind);
|
||||
t.push_str("}");
|
||||
|
||||
Ok(())
|
||||
impl LayoutMath for VecNode {
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
let delim = ctx.outer.get(Self::DELIM);
|
||||
layout(ctx, &self.0, Align::Center, Some(delim.open()), Some(delim.close()))
|
||||
}
|
||||
}
|
||||
|
||||
/// A vector / matrix delimiter.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum Delimiter {
|
||||
Paren,
|
||||
Bracket,
|
||||
Brace,
|
||||
Bar,
|
||||
}
|
||||
|
||||
castable! {
|
||||
Delimiter,
|
||||
/// Delimit the vector with parentheses.
|
||||
"(" => Self::Paren,
|
||||
/// Delimit the vector with brackets.
|
||||
"[" => Self::Bracket,
|
||||
/// Delimit the vector with curly braces.
|
||||
"{" => Self::Brace,
|
||||
/// Delimit the vector with vertical bars.
|
||||
"|" => Self::Bar,
|
||||
}
|
||||
|
||||
/// # Cases
|
||||
/// A case distinction.
|
||||
///
|
||||
@ -113,7 +77,7 @@ castable! {
|
||||
/// ## Category
|
||||
/// math
|
||||
#[func]
|
||||
#[capable(Texify)]
|
||||
#[capable(LayoutMath)]
|
||||
#[derive(Debug, Hash)]
|
||||
pub struct CasesNode(Vec<Content>);
|
||||
|
||||
@ -133,14 +97,132 @@ impl CasesNode {
|
||||
}
|
||||
}
|
||||
|
||||
impl Texify for CasesNode {
|
||||
fn texify(&self, t: &mut Texifier) -> SourceResult<()> {
|
||||
t.push_str("\\begin{cases}");
|
||||
for component in &self.0 {
|
||||
component.texify(t)?;
|
||||
t.push_str("\\\\");
|
||||
}
|
||||
t.push_str("\\end{cases}");
|
||||
Ok(())
|
||||
impl LayoutMath for CasesNode {
|
||||
fn layout_math(&self, ctx: &mut MathContext) -> SourceResult<()> {
|
||||
layout(ctx, &self.0, Align::Left, Some('{'), None)
|
||||
}
|
||||
}
|
||||
|
||||
/// A vector / matrix delimiter.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum Delimiter {
|
||||
Paren,
|
||||
Bracket,
|
||||
Brace,
|
||||
Bar,
|
||||
DoubleBar,
|
||||
}
|
||||
|
||||
impl Delimiter {
|
||||
/// The delimiter's opening character.
|
||||
fn open(self) -> char {
|
||||
match self {
|
||||
Self::Paren => '(',
|
||||
Self::Bracket => '[',
|
||||
Self::Brace => '{',
|
||||
Self::Bar => '|',
|
||||
Self::DoubleBar => '‖',
|
||||
}
|
||||
}
|
||||
|
||||
/// The delimiter's closing character.
|
||||
fn close(self) -> char {
|
||||
match self {
|
||||
Self::Paren => ')',
|
||||
Self::Bracket => ']',
|
||||
Self::Brace => '}',
|
||||
Self::Bar => '|',
|
||||
Self::DoubleBar => '‖',
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
castable! {
|
||||
Delimiter,
|
||||
/// Delimit the vector with parentheses.
|
||||
"(" => Self::Paren,
|
||||
/// Delimit the vector with brackets.
|
||||
"[" => Self::Bracket,
|
||||
/// Delimit the vector with curly braces.
|
||||
"{" => Self::Brace,
|
||||
/// Delimit the vector with vertical bars.
|
||||
"|" => Self::Bar,
|
||||
/// Delimit the vector with double vertical bars.
|
||||
"||" => Self::DoubleBar,
|
||||
}
|
||||
|
||||
/// Layout a matrix.
|
||||
fn layout(
|
||||
ctx: &mut MathContext,
|
||||
elements: &[Content],
|
||||
align: Align,
|
||||
left: Option<char>,
|
||||
right: Option<char>,
|
||||
) -> SourceResult<()> {
|
||||
let axis = scaled!(ctx, axis_height);
|
||||
let gap = ROW_GAP.scaled(ctx);
|
||||
|
||||
ctx.style(ctx.style.for_denominator());
|
||||
let mut rows = vec![];
|
||||
for element in elements {
|
||||
rows.push(ctx.layout_row(element)?);
|
||||
}
|
||||
ctx.unstyle();
|
||||
|
||||
if let Some(left) = left {
|
||||
ctx.push(GlyphFragment::new(ctx, left));
|
||||
}
|
||||
|
||||
let mut frame = stack(ctx, rows, align, gap, 0);
|
||||
frame.set_baseline(frame.height() / 2.0 + axis);
|
||||
|
||||
ctx.push(frame);
|
||||
|
||||
if let Some(right) = right {
|
||||
ctx.push(GlyphFragment::new(ctx, right));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Stack rows on top of each other.
|
||||
///
|
||||
/// Add a `gap` between each row and uses the baseline of the `baseline`th
|
||||
/// row for the whole frame.
|
||||
pub(super) fn stack(
|
||||
ctx: &MathContext,
|
||||
rows: Vec<MathRow>,
|
||||
align: Align,
|
||||
gap: Abs,
|
||||
baseline: usize,
|
||||
) -> Frame {
|
||||
let mut width = Abs::zero();
|
||||
let mut height = rows.len().saturating_sub(1) as f64 * gap;
|
||||
|
||||
let points = alignments(&rows);
|
||||
let rows: Vec<_> =
|
||||
rows.into_iter().map(|row| row.to_line_frame(ctx, &points)).collect();
|
||||
|
||||
for row in &rows {
|
||||
height += row.height();
|
||||
width.set_max(row.width());
|
||||
}
|
||||
|
||||
let extra = VERTICAL_PADDING.of(height);
|
||||
height += extra;
|
||||
|
||||
let mut y = extra / 2.0;
|
||||
let mut frame = Frame::new(Size::new(width, height));
|
||||
|
||||
for (i, row) in rows.into_iter().enumerate() {
|
||||
let x = align.position(width - row.width());
|
||||
let pos = Point::new(x, y);
|
||||
if i == baseline {
|
||||
frame.set_baseline(y + row.baseline());
|
||||
}
|
||||
y += row.height() + gap;
|
||||
frame.push_frame(pos, row);
|
||||
}
|
||||
|
||||
frame
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user