path_offset/offset/
flo_curves.rs

1use flo_curves::{
2    bezier::{
3        curve_is_tiny, fit_curve, offset,
4        path::{path_remove_interior_points, BezierPath, BezierPathFactory, SimpleBezierPath},
5        walk_curve_evenly, Curve,
6    },
7    BezierCurve, Coord2,
8};
9
10use crate::{
11    error::{PathError, Result},
12    offset::Offset,
13    path::Path,
14};
15
16pub struct FloCurvesOffset {
17    curves: Vec<Curve<Coord2>>,
18}
19
20impl FloCurvesOffset {
21    pub fn new(path: &Path, offset_distance: f64) -> Self {
22        FloCurvesOffset {
23            curves: SimpleBezierPath::from(path)
24                .to_curves()
25                .into_iter()
26                .flat_map(|curve| offset(&curve, -offset_distance, -offset_distance))
27                .filter(|curve| !curve_is_tiny(curve))
28                .collect::<Vec<_>>(),
29        }
30    }
31
32    pub fn curves(&self) -> &Vec<Curve<Coord2>> {
33        &self.curves
34    }
35}
36
37impl Offset for FloCurvesOffset {
38    fn offset_path(&self) -> Result<Path> {
39        let offset_points = self
40            .curves
41            .iter()
42            .flat_map(|curve| sample_curve(curve))
43            .collect::<Vec<_>>();
44
45        let fitted_curve =
46            fit_curve::<Curve<Coord2>>(&offset_points, 1.0).ok_or(PathError::FitCurve)?;
47
48        let offset_toolpath = SimpleBezierPath::from_connected_curves(
49            fitted_curve
50                .into_iter()
51                .filter(|curve| !curve_is_tiny(curve)),
52        );
53
54        let clean_offset_toolpath: SimpleBezierPath =
55            path_remove_interior_points(&vec![offset_toolpath], 0.01)
56                .into_iter()
57                .next()
58                .ok_or(PathError::CleanPath)?;
59
60        Ok(Path::from(&clean_offset_toolpath))
61    }
62}
63
64/// 对贝塞尔曲线进行采样,返回一组代表性点
65fn sample_curve(curve: &Curve<Coord2>) -> Vec<Coord2> {
66    let max_error = 0.01;
67    let distance = 0.1;
68
69    // 对每段采样结果取中点(t=0.5),作为最终采样点
70    walk_curve_evenly(curve, distance, max_error)
71        .map(|section| section.point_at_pos(0.5))
72        .collect::<Vec<_>>()
73}