Skip to main content

path_kit/
lib.rs

1//! # path-kit
2//!
3//! 基于 Skia PathOps 和 PathKit 的 Rust 路径运算库,提供 safe 的 API 封装。
4//! A Rust path operations library based on Skia PathOps and PathKit with safe API wrappers.
5//!
6//! ## 功能 / Features
7//!
8//! - **路径构建**:[`Path`]、[`PathBuilder`];线段、二次/三次贝塞尔、矩形、椭圆、圆、圆角矩形、RRect
9//!   Path construction: [`Path`], [`PathBuilder`]; lines, quad/cubic bezier, rect, oval, circle, round rect, RRect
10//! - **路径布尔运算**:并集、交集、差集、异或
11//!   Path boolean operations: union, intersect, difference, xor
12//! - **路径简化、包围盒**:`simplify`, `path.tight_bounds`, `pathops_tight_bounds`
13//!   Path simplification and tight bounds computation
14//! - **路径变换**:[`Path::transform`]、[`Path::transformed`]、[`Matrix`](`SkMatrix`)
15//!   Affine/perspective transform via [`Path::transform`], [`Path::transformed`], [`Matrix`]
16//! - **路径迭代**:按动词遍历 Move/Line/Quad/Cubic/Close
17//!   Path iteration over verbs and points
18//! - **描边**:将路径转为描边轮廓
19//!   Stroke: convert path to stroked outline
20//!
21//! ## 线程安全 / Thread safety
22//!
23//! 当前未保证 `Send` / `Sync`,请勿跨线程共享 `Path`、`Matrix`、`RRect`、`StrokeRec`、`Paint` 等封装 C++ 的类型。
24//! `Send` / `Sync` are not guaranteed; do not share `Path`, `Matrix`, `RRect`, `StrokeRec`, `Paint`, or other C++-backed handles across threads.
25//!
26//! ## 文档 / Documentation
27//!
28//! - **[docs.rs/path-kit](https://docs.rs/path-kit)**:托管 API 参考与 rustdoc。 *Hosted API reference and rustdoc.*
29//! - **[CHANGELOG.md](https://github.com/songhuaixu/path-kit/blob/master/CHANGELOG.md)**:版本变更记录。 *Version history in the repo.*
30//! - 本地:`cargo doc --open`。 *Locally: run `cargo doc --open`.*
31//!
32//! ## 类型概览 / Types
33//!
34//! | 类型 | 说明 · Description |
35//! |------|-------------------|
36//! | [`Path`] | 路径 · Path |
37//! | [`PathBuilder`] | 路径构建器(`SkPathBuilder`,`snapshot` / `detach`)· Path builder (`SkPathBuilder`, `snapshot` / `detach`) |
38//! | [`Rect`] | 矩形 · Axis-aligned rectangle |
39//! | [`RRect`] | 圆角矩形(四角独立半径)· Rounded rect (per-corner radii) |
40//! | [`Point`] | 二维点 · 2D point |
41//! | [`Matrix`] / [`ScaleToFit`] / [`matrix_type`] / [`coeff`] | 3×3 矩阵(`SkMatrix`)、缩放适配、类型位、系数下标 · 3×3 transform, scale-to-fit, type bits, coeff indices |
42//! | [`Direction`] | 绘制方向 Cw/Ccw · Fill direction clockwise / counter-clockwise |
43//! | [`RectCorner`] | 矩形起始角 · Starting corner when adding a rect |
44//! | [`PathOp`] | 布尔运算类型 · Path boolean operation kind |
45//! | [`PathFillType`] | 填充规则(winding / even-odd / inverse 等)· Fill rule variants |
46//! | [`PathVerb`] / [`PathVerbItem`] | 路径动词枚举 / 迭代项 · Path verb enum / iterator items |
47//! | [`PathMeasure`] | 长度、位置与切线、分段提取 · Length, pos/tan, segment extraction |
48//! | [`OpBuilder`] | 批量布尔运算(`SkOpBuilder`)· Batch boolean ops (`SkOpBuilder`) |
49//! | [`path_op`] / [`simplify`] / [`pathops_tight_bounds`] | 两路径布尔、简化、pathops 紧包围盒 · Binary op, simplify, pathops tight bounds |
50//! | [`StrokeRec`] / [`StrokeStyle`] | 描边参数与样式快照 · Stroke parameters and style snapshot |
51//! | [`StrokeCap`] | 线端 Butt/Round/Square · Stroke end cap |
52//! | [`StrokeJoin`] | 转角 Miter/Round/Bevel · Stroke corner join |
53//! | [`Paint`] | 绘图参数(Style、Stroke 等)· Paint / stroke parameters (`SkPaint`) |
54//! | [`PaintStyle`] | 填充/描边样式 · Fill / stroke / stroke-and-fill |
55//! | [`CornerPathEffect`] / [`DashPathEffect`] | 圆角 / 虚线效果 · Corner / dash path effects |
56//! | [`RRectType`] | 圆角矩形类型(`SkRRect::Type`)· RRect classification |
57//!
58//! ## 示例 / Examples
59//!
60//! ### 路径布尔运算 / Path boolean ops
61//!
62//! ```rust
63//! use path_kit::{Path, Rect, Direction, RectCorner, PathOp, path_op, OpBuilder};
64//!
65//! let mut path1 = Path::new();
66//! path1.add_rect(&Rect::new(0.0, 0.0, 100.0, 100.0), Direction::Cw, RectCorner::UpperLeft);
67//!
68//! let mut path2 = Path::new();
69//! path2.add_rect(&Rect::new(50.0, 50.0, 150.0, 150.0), Direction::Cw, RectCorner::UpperLeft);
70//!
71//! let union = path_op(&path1, &path2, PathOp::Union).unwrap();
72//!
73//! // 批量运算 / Batch operations (use add_ref to avoid clone when reusing paths)
74//! let result = OpBuilder::new()
75//!     .add_ref(&path1, PathOp::Union)
76//!     .add_ref(&path2, PathOp::Union)
77//!     .resolve()
78//!     .unwrap();
79//! ```
80//!
81//! ### 矩阵与路径变换 / Matrix and path transform
82//!
83//! ```rust
84//! use path_kit::{Matrix, Path};
85//!
86//! let mut path = Path::new();
87//! path.move_to(0.0, 0.0).line_to(100.0, 0.0).line_to(100.0, 100.0).close();
88//!
89//! let mut m = Matrix::identity();
90//! m.pre_translate(10.0, 5.0).pre_scale(2.0, 2.0);
91//! path.transform(&m);
92//!
93//! // Or keep the original: `let out = path.transformed(&m);`
94//! ```
95//!
96//! ### PathBuilder · 增量构建 / Incremental path build
97//!
98//! ```rust
99//! use path_kit::PathBuilder;
100//!
101//! let mut b = PathBuilder::new();
102//! b.move_to(0.0, 0.0).line_to(50.0, 40.0).line_to(0.0, 40.0).close();
103//! let _copy = b.snapshot(); // builder unchanged
104//! let _owned = b.detach(); // builder reset; geometry moved into `Path`
105//! ```
106//!
107//! ### 圆角矩形 RRect / Rounded rect with per-corner radii
108//!
109//! ```rust
110//! use path_kit::{Path, Rect, RRect, Radii, Direction, RectCorner};
111//!
112//! // 统一圆角 / Uniform radii
113//! let rr = RRect::from_rect_xy(&Rect::new(0.0, 0.0, 100.0, 50.0), 10.0, 10.0);
114//! let mut path = Path::new();
115//! path.add_rrect(&rr, Direction::Cw);
116//!
117//! // 四角独立半径 / Per-corner radii
118//! let radii = [
119//!     Radii { x: 10.0, y: 10.0 },
120//!     Radii { x: 20.0, y: 10.0 },
121//!     Radii { x: 10.0, y: 20.0 },
122//!     Radii { x: 5.0, y: 5.0 },
123//! ];
124//! let rr2 = RRect::from_rect_radii(&Rect::new(0.0, 0.0, 80.0, 60.0), &radii);
125//! path.add_rrect(&rr2, Direction::Ccw);
126//! ```
127//!
128//! ### 路径迭代 / Path iteration
129//!
130//! ```rust
131//! use path_kit::{Path, PathVerbItem};
132//!
133//! let mut path = Path::new();
134//! path.move_to(0.0, 0.0).line_to(100.0, 0.0).line_to(100.0, 100.0).close();
135//!
136//! for item in path.iter(false) {
137//!     match item {
138//!         PathVerbItem::Move(p) => println!("Move to {:?}", p),
139//!         PathVerbItem::Line(from, to) => println!("Line {:?} -> {:?}", from, to),
140//!         PathVerbItem::Quad(c, to) => println!("Quad {:?} -> {:?}", c, to),
141//!         PathVerbItem::Cubic(c1, c2, to) => println!("Cubic -> {:?}", to),
142//!         PathVerbItem::Close => println!("Close"),
143//!         _ => {}
144//!     }
145//! }
146//! ```
147//!
148//! ### 描边 / Stroke
149//!
150//! ```rust
151//! use path_kit::{Path, StrokeRec};
152//!
153//! let rec = StrokeRec::new_stroke(4.0, false);
154//! let mut path = Path::new();
155//! path.move_to(0.0, 0.0).line_to(100.0, 0.0);
156//! let stroked = rec.apply_to_path(&path).unwrap();
157//! ```
158//!
159//! ### Paint · 描边转填充轮廓 / Stroke to fill outline (`get_fill_path`)
160//!
161//! ```rust
162//! use path_kit::{Paint, PaintStyle, Path};
163//!
164//! let mut paint = Paint::new();
165//! paint.set_style(PaintStyle::Stroke);
166//! paint.set_stroke_width(4.0);
167//! let mut path = Path::new();
168//! path.move_to(0.0, 0.0).line_to(100.0, 0.0);
169//! let stroked_as_fill = paint.get_fill_path(&path).unwrap();
170//! assert!(stroked_as_fill.count_verbs() >= path.count_verbs());
171//! ```
172//!
173//! ### 路径测量 / Path measure
174//!
175//! ```rust
176//! use path_kit::{Path, PathMeasure};
177//!
178//! let mut path = Path::new();
179//! path.move_to(0.0, 0.0).line_to(100.0, 0.0);
180//! let mut measure = PathMeasure::from_path(&path, false, 1.0);
181//! let len = measure.length();           // ~100
182//! let (pos, tan) = measure.pos_tan(50.0).unwrap();  // position & tangent at midpoint
183//! let mut segment = Path::new();
184//! measure.get_segment(25.0, 75.0, &mut segment, true);  // extract sub-path
185//! ```
186//!
187//! ### 路径简化与包围盒 / Simplify and bounds
188//!
189//! ```rust
190//! use path_kit::{Path, simplify, pathops_tight_bounds};
191//!
192//! let mut path = Path::new();
193//! path.move_to(0.0, 0.0)
194//!     .line_to(100.0, 0.0)
195//!     .line_to(100.0, 100.0)
196//!     .line_to(50.0, 50.0)
197//!     .line_to(0.0, 100.0)
198//!     .close();
199//!
200//! let simplified = simplify(&path).unwrap();
201//! let bounds = pathops_tight_bounds(&path).unwrap();  // or path.tight_bounds() for infallible
202//! ```
203
204/// PathKit(Skia PathOps)与 C++ 的 cxx 桥接(仅内部使用)。
205/// PathKit C++ interop via cxx (internal only).
206#[doc(hidden)]
207pub(crate) mod bridge;
208
209mod corner_path_effect;
210mod dash_path_effect;
211mod op_builder;
212mod ops;
213mod path;
214mod path_builder;
215mod path_iter;
216mod path_measure;
217mod path_fill_type;
218mod matrix;
219mod point;
220mod rect;
221mod rrect;
222mod paint;
223mod stroke_rec;
224
225pub use bridge::ffi::Direction;
226pub use bridge::ffi::PathOp;
227pub use bridge::ffi::RectCorner;
228pub use bridge::ffi::RRectType;
229
230impl Default for Direction {
231    fn default() -> Self {
232        Self::Cw
233    }
234}
235
236impl Default for RectCorner {
237    fn default() -> Self {
238        Self::UpperLeft
239    }
240}
241
242pub use corner_path_effect::CornerPathEffect;
243pub use dash_path_effect::DashPathEffect;
244pub use op_builder::OpBuilder;
245pub use ops::{path_op, pathops_tight_bounds, simplify};
246pub use matrix::{Matrix, ScaleToFit, coeff, matrix_type};
247pub use path::Path;
248pub use path_builder::PathBuilder;
249pub use path_fill_type::PathFillType;
250pub use path_iter::{PathIter, PathVerb, PathVerbItem};
251pub use path_measure::PathMeasure;
252pub use point::Point;
253pub use rect::Rect;
254pub use rrect::{Radii, RRect};
255pub use paint::{Paint, PaintStyle};
256pub use stroke_rec::{StrokeCap, StrokeJoin, StrokeRec, StrokeStyle};
257
258#[cfg(test)]
259mod tests;