Registry / RepositoryTypeScriptRustPython
Rollpie
ReadmeFiles
Versions
Info
Download
0.2.0579.9 KB2026-09-150.1.1576.6 KB2026-09-12
Version
0.2.0
Copyright
Rollpie, Irohabook
Publisher
math
Published
2026-09-15
Size
579.9 KB
Downloads
2
Checksum
58312d92e63a92784e82a974317afd849e59d143a6320c3cc62faa0980834a7b
Dependencies
None

geometry.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
//! 括弧と中身の縦位置を数字で比べる

use suki::font::{self, Font};
use suki::layout::{Content, Placed};
use suki::node::Style;
use suki::{layout, parse};

fn main() {
    let loaded = font::load(std::fs::read("font/latinmodern-math.otf").unwrap()).unwrap();
    let units = font::units_per_em(&loaded);

    println!("括弧の字形が送り幅のどこに墨を置いているか");

    for character in ['(', ')', '[', '{'] {
        let base = font::glyph_of(&loaded, character).unwrap();
        let mut glyphs = vec![base];

        if let Some(growth) = font::vertical_growth(&loaded, base) {
            glyphs.extend(growth.variant.iter().take(4).map(|variant| variant.glyph));
        }

        for glyph in glyphs {
            let drawn = font::outline_of(&loaded, glyph);
            let (left, _, right, _) = suki::outline::bounds(&drawn);
            let advance = font::advance(&loaded, glyph);
            println!(
                "  {character} 字形 {glyph} 送り {advance:.3} 墨 {:.3}..{:.3} 左の余白 {:.3} 右の余白 {:.3}",
                left / units,
                right / units,
                left / units,
                advance - right / units
            );
        }
    }

    for source in [
        r"\left( \frac{a}{b} \right)",
        r"\begin{pmatrix} a & b \\ c & d \end{pmatrix}",
        r"\begin{bmatrix} 12 & 3 \\ 4 & 56 \end{bmatrix}",
    ] {
        let node = parse(source).unwrap();
        let placed = layout::layout(&node, &loaded, 1.0, Style::Auto, true);
        let Content::Group(row) = &placed.content else {continue};
        let Content::Group(parts) = &row[0].layout.content else {continue};
        println!("\n{source}");
        println!("  数式軸 {:.3}", font::constant(&loaded).axis_height);

        for (index, part) in parts.iter().enumerate() {
            let name = match index {
                0 => "左括弧",
                1 => "中身",
                _ => "右括弧",
            };
            report(name, part, &loaded);

            if index == 1 {
                if let Content::Group(cells) = &part.layout.content {
                    for cell in cells.iter().take(4) {
                        let ink = leftmost(&cell.layout, &loaded);
                        println!(
                            "      セル x {:.3} 幅 {:.3} 墨の左端 {:.3}",
                            part.x + cell.x,
                            cell.layout.width,
                            part.x + cell.x + ink
                        );
                    }
                }
            }
        }
    }
}

/// まとまりの中でいちばん左に墨が来る位置
fn leftmost(placed: &suki::layout::Layout, loaded: &Font) -> f64 {
    match &placed.content {
        Content::Glyph {glyph, size, ..} => font::bearing(loaded, *glyph).0 * size,
        Content::Group(children) => children
            .first()
            .map_or(0.0, |child| child.x + leftmost(&child.layout, loaded)),
        Content::Rule => 0.0,
    }
}


fn report(name: &str, part: &Placed, loaded: &Font) {
    let top = part.y - part.layout.height;
    let bottom = part.y + part.layout.depth;
    let middle = (top + bottom) / 2.0;
    let ink = match &part.layout.content {
        Content::Glyph {glyph, ..} => {
            let (height, depth) = font::extent(loaded, *glyph);
            format!(" 字形 {glyph} 墨 {:.3}..{:.3}", -height, depth)
        }
        _ => String::new(),
    };
    println!(
        "  {name} x {:.3} 幅 {:.3} 上 {top:.3} 下 {bottom:.3} 中央 {middle:.3}{ink}",
        part.x, part.layout.width
    );
}