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
|
use scene::FreeformPathPoint;
use tiny_skia::{Path, PathBuilder};
fn local_to_canvas(
x: f64,
y: f64,
center_x: f64,
center_y: f64,
rotation: f64,
scale: f64,
width: f64,
height: f64,
) -> (f64, f64) {
let canvas_center_x = width / 2.0 + center_x * width;
let canvas_center_y = height / 2.0 + center_y * height;
let scaled_x = x * width * scale;
let scaled_y = y * height * scale;
let angle_rad = rotation.to_radians();
let cos = angle_rad.cos();
let sin = angle_rad.sin();
(
canvas_center_x + scaled_x * cos - scaled_y * sin,
canvas_center_y + scaled_x * sin + scaled_y * cos,
)
}
#[allow(clippy::too_many_arguments)]
pub fn build_freeform_path(
points: &[FreeformPathPoint],
center_x: f64,
center_y: f64,
rotation: f64,
scale: f64,
width: f64,
height: f64,
closed: bool,
) -> Option<Path> {
if points.is_empty() {
return None;
}
let to_canvas = |x: f64, y: f64| {
local_to_canvas(x, y, center_x, center_y, rotation, scale, width, height)
};
let anchors: Vec<((f64, f64), (f64, f64), (f64, f64))> = points
.iter()
.map(|point| {
(
to_canvas(point.x, point.y),
to_canvas(point.x + point.in_x, point.y + point.in_y),
to_canvas(point.x + point.out_x, point.y + point.out_y),
)
})
.collect();
let mut builder = PathBuilder::new();
builder.move_to(anchors[0].0 .0 as f32, anchors[0].0 .1 as f32);
for index in 1..anchors.len() {
let previous = anchors[index - 1];
let current = anchors[index];
builder.cubic_to(
previous.2 .0 as f32,
previous.2 .1 as f32,
current.1 .0 as f32,
current.1 .1 as f32,
current.0 .0 as f32,
current.0 .1 as f32,
);
}
if closed && anchors.len() > 1 {
let last = anchors[anchors.len() - 1];
let first = anchors[0];
builder.cubic_to(
last.2 .0 as f32,
last.2 .1 as f32,
first.1 .0 as f32,
first.1 .1 as f32,
first.0 .0 as f32,
first.0 .1 as f32,
);
builder.close();
}
builder.finish()
}
|