tiny-skia's path geometry (Path / PathBuilder / segments) ported to MoonBit
状态:0.1.0 可发。lib/path 一个实现包(数值 + 几何 + 路径 + 曲线几何 + 描边 + 虚线)齐了,lib 只做门面;语义面一律 Float;公开面按上游 lib.rs 收口(pub fn 321 → 239,内部助手全部 priv;宽高/长度按上游 u32/usize 用 UInt32, 上游 unwrap() 的 7 处转换不再折成 Option);门禁 22 绿 / 1 跳过(同门仓缺席)、moon test 170 条过。真值三层:上游源码里的字面量、上游现跑的 262 条读数 (tests/baselines/upstream_golden.mbt,生成物)、上游实现的逐行推导。现状、能力边界与 代码怎么分看 P0 · 现状与结构, 范围、判据、与上游的差异和踩过的坑看 P1 · 移植与对拍。
moon add TryAndRun-TvT/tiny-skia-path///|
test "库门面可用:画一条曲线、量它、再描边" {
// ① 一条拱形二次曲线:控制点 (50, 0) 远在弦外
let pb = @lib.path_builder_new()
@lib.PathBuilder::move_to(pb, 10.0, 50.0)
@lib.PathBuilder::quad_to(pb, 50.0, 0.0, 90.0, 50.0)
let path = @lib.path_builder_finish(pb).unwrap()
// ② 两个包围盒不是一回事:控制点包围盒的 top 是控制点的 0,
// 而曲线本身最高只到 25 —— 这就是 `compute_tight_bounds` 存在的理由
let loose = @lib.path_bounds(path)
assert_eq(loose.top(), 0.0, msg="控制点包围盒把控制点算进去了")
let tight = @lib.path_tight_bounds(path).unwrap()
assert_eq(tight.top(), 25.0, msg="紧包围盒是曲线真正到达的地方")
// ③ 描边:默认 width = 1,改成 4 再描
let stroke = @lib.stroke_with_width(@lib.stroke_new(), 4.0)
let outlined = @lib.path_stroke(path, stroke, 1.0).unwrap()
assert_true(outlined.verbs().length() > 0, msg="描边结果非空")
}| 路径 | 是什么 |
|---|---|
| lib/ | 库门面。rexport.mbt 导类型,facade.mbt 补自由函数转发 |
| lib/path/ | 几何 + 路径 + 曲线几何 + 描边 + 虚线(不含光栅)。方法形 API 在这里;文件怎么分见 P0 §3.1 |
| lib/path/scalar.mbt 等 | 数值面:SCALAR_*、饱和转换、浮点包装、有限性判据(原独立 num 包已并回) |
| tests/ | 黑盒测试与夹具:path_tests(21 条)· facade(1 条)· baselines(262 条上游读数,生成物);白盒 148 条在 lib/path/*_wbtest.mbt |
| scripts/ | 环境初始化与门禁。一条命令跑全量:bash scripts/gates.sh |
| docs/ | 导航面 + 两篇正文:现状与结构 P0 · 移植与对拍 P1 |
| AGENTS.md | 改代码前的硬性约定,先读这个 |
bash scripts/setup-toolchain.sh # 装齐 moon / python3 / cc+cargo(已装的跳过,幂等)
bash scripts/gates.sh # 全量门禁
STAGES="check test" bash scripts/gates.sh # 只跑指定阶段Install
Download ziptiny-skia's path geometry (Path / PathBuilder / segments) ported to MoonBit