path_offset/path/subpath.rs
1use lyon::path::{Event, Iter as PathIter}; // 引入 lyon 的 Event 和迭代器类型 Iter,并重命名为 PathIter 以免混淆
2
3/// 一个迭代器,可以将一个包含多个图形的路径分解成单个的子路径。
4///
5/// 这个结构体及其 Iterator 实现,封装了从一个连续的路径事件流中
6/// 提取出独立子路径(从 Begin 到 End)的复杂状态管理逻辑。
7pub struct SubpathIter<'a> {
8 /// 持有对底层 lyon 路径事件流的迭代器。
9 iter: PathIter<'a>,
10}
11
12impl<'a> Iterator for SubpathIter<'a> {
13 // 每次迭代,我们都希望能产出一个完整的、我们自己的 Path 类型
14 type Item = super::Path;
15
16 /// 实现 next() 方法,这是迭代器的核心。
17 /// 每次调用,它会尝试构建并返回下一个完整的子路径。
18 fn next(&mut self) -> Option<Self::Item> {
19 // 这个 next() 方法的逻辑,是您提供的原始 for 循环的直接翻译。
20
21 // 1. 创建一个 Path Builder 来构建子路径。
22 // 我们从流中寻找下一个 `Begin` 事件来启动它。
23 let mut builder;
24 if let Some(event) = self.iter.find(|e| matches!(e, Event::Begin { .. })) {
25 if let Event::Begin { at } = event {
26 // 找到了起点,初始化 builder
27 let mut b = lyon::path::Path::builder();
28 b.begin(at);
29 builder = b;
30 } else {
31 // 理论上不可能发生,因为 find 已经保证了是 Begin
32 return None;
33 }
34 } else {
35 // 如果在整个事件流中再也找不到 Begin 事件,说明迭代结束了。
36 return None;
37 }
38
39 // 2. 既然已经有了启动的 builder,我们继续消耗事件流,
40 // 直到遇到对应的 `End` 事件。
41 for event in &mut self.iter {
42 match event {
43 Event::Line { to, .. } => {
44 builder.line_to(to);
45 }
46 Event::Quadratic { ctrl, to, .. } => {
47 builder.quadratic_bezier_to(ctrl, to);
48 }
49 Event::Cubic {
50 ctrl1, ctrl2, to, ..
51 } => {
52 builder.cubic_bezier_to(ctrl1, ctrl2, to);
53 }
54 Event::End { close, .. } => {
55 // 遇到了 End,一个子路径构建完成。
56 if close {
57 builder.close();
58 }
59 // 构建出 lyon::path::Path,包装成我们自己的 Path,然后返回。
60 // next() 方法的本次执行到此结束。
61 return Some(super::Path {
62 inner: builder.build(),
63 });
64 }
65 Event::Begin { .. } => {
66 // 如果在找到 End 之前又遇到了 Begin,
67 // 这意味着上一个子路径没有正常结束。
68 // 根据原始逻辑,我们应该结束当前构建并开始新的。
69 // 在迭代器模式下,最简单的处理方式是就此打住,
70 // 让下一次 next() 调用来处理这个新的 Begin 事件。
71 // 但这意味着我们可能会丢失一个未闭合的路径。
72 //
73 // 为了忠实于您的原始代码(它会隐式地丢弃未完成的路径),
74 // 我们在这里直接 break,然后返回 None。
75 break;
76 }
77 }
78 }
79
80 // 如果 for 循环正常结束(意味着迭代器耗尽了),
81 // 但我们还没返回,说明最后一个子路径没有 End 事件。
82 // 您的原始代码会忽略这种情况,所以我们也返回 None。
83 None
84 }
85}
86
87/// 为我们自己的 Path 类型的引用实现 IntoIterator trait。
88/// 这使得可以直接在 for 循环中使用 `&Path`。
89impl<'a> IntoIterator for &'a super::Path {
90 type Item = super::Path;
91 type IntoIter = SubpathIter<'a>;
92
93 /// 定义如何从一个 `&Path` 创建出我们的 `SubpathIter` 迭代器。
94 fn into_iter(self) -> Self::IntoIter {
95 SubpathIter {
96 iter: self.inner.iter(),
97 }
98 }
99}