feat: 实现曲线功能
This commit is contained in:
@@ -599,4 +599,48 @@ impl MSCanvas {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn recursive_bezier(&mut self, control_points: &[Point], t: f32) -> Point {
|
||||||
|
// Implement de Casteljau's algorithm
|
||||||
|
let n = control_points.len();
|
||||||
|
if n == 1 {
|
||||||
|
return control_points[0];
|
||||||
|
}
|
||||||
|
let mut new_points: Vec<Point> = Vec::with_capacity(n - 1);
|
||||||
|
for i in 0..(n - 1) {
|
||||||
|
let p0 = control_points[i];
|
||||||
|
let p1 = control_points[i + 1];
|
||||||
|
let point = point_add(point_muln(p0, 1.0 - t), point_muln(p1, t));
|
||||||
|
new_points.push(point);
|
||||||
|
}
|
||||||
|
self.recursive_bezier(&new_points[..], t)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn bezier(&mut self, control_points: Vec<Point>) {
|
||||||
|
// Iterate through all t = 0 to t = 1 with small steps, and call de Casteljau's recursive Bezier algorithm.
|
||||||
|
let mut t = 0.0;
|
||||||
|
while t <= 1.0 {
|
||||||
|
let point = self.recursive_bezier(&control_points, t);
|
||||||
|
self.brush_circle(point);
|
||||||
|
t += 0.001;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn quadratic_bezier(&mut self, begin: Point, end: Point, p1: Point) {
|
||||||
|
let points = vec![begin, p1, end];
|
||||||
|
self.bezier(points);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cubic_bezier(&mut self, begin: Point, end: Point, p1: Point, p2: Point) {
|
||||||
|
let points = vec![begin, p1, p2, end];
|
||||||
|
self.bezier(points);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn point_muln(point: Point, t: f32) -> Point {
|
||||||
|
Point::new(point.x * t, point.y * t)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn point_add(p1: Point, p2: Point) -> Point {
|
||||||
|
Point::new(p1.x + p2.x, p1.y + p2.y)
|
||||||
}
|
}
|
||||||
|
|||||||
71
src/paint.rs
71
src/paint.rs
@@ -207,16 +207,23 @@ struct PaintApp {
|
|||||||
|
|
||||||
canvas: MSCanvas,
|
canvas: MSCanvas,
|
||||||
|
|
||||||
// 是否正在绘制
|
/// 是否正在绘制
|
||||||
is_drawing: bool,
|
is_drawing: bool,
|
||||||
|
|
||||||
|
/// pencil brush line curve rectangle
|
||||||
begin_point: Point,
|
begin_point: Point,
|
||||||
|
/// curve
|
||||||
|
end_point: Point,
|
||||||
|
|
||||||
// 用于显示的图像句柄缓存
|
/// 贝塞尔曲线控制
|
||||||
// 每次像素变化后需要重新生成
|
is_controlling: bool,
|
||||||
|
control_points: Vec<Point>,
|
||||||
|
|
||||||
|
/// 用于显示的图像句柄缓存
|
||||||
|
/// 每次像素变化后需要重新生成
|
||||||
image_handle: image::Handle,
|
image_handle: image::Handle,
|
||||||
|
|
||||||
// 标记像素是否被修改,用于优化图像句柄的生成
|
/// 标记像素是否被修改,用于优化图像句柄的生成
|
||||||
dirty: bool,
|
dirty: bool,
|
||||||
|
|
||||||
config: Config,
|
config: Config,
|
||||||
@@ -239,6 +246,9 @@ impl PaintApp {
|
|||||||
canvas,
|
canvas,
|
||||||
is_drawing: false,
|
is_drawing: false,
|
||||||
begin_point: Point::ORIGIN,
|
begin_point: Point::ORIGIN,
|
||||||
|
end_point: Point::ORIGIN,
|
||||||
|
is_controlling: false,
|
||||||
|
control_points: Vec::with_capacity(2),
|
||||||
image_handle: image::Handle::from_rgba(width as u32, height as u32, pixels),
|
image_handle: image::Handle::from_rgba(width as u32, height as u32, pixels),
|
||||||
dirty: false,
|
dirty: false,
|
||||||
config,
|
config,
|
||||||
@@ -392,6 +402,9 @@ impl PaintApp {
|
|||||||
Tool::Line => {
|
Tool::Line => {
|
||||||
self.update_with_line(message);
|
self.update_with_line(message);
|
||||||
}
|
}
|
||||||
|
Tool::Curve => {
|
||||||
|
self.update_with_curve(message);
|
||||||
|
}
|
||||||
Tool::Rectangle => {
|
Tool::Rectangle => {
|
||||||
self.update_with_rectangle(message);
|
self.update_with_rectangle(message);
|
||||||
}
|
}
|
||||||
@@ -471,7 +484,7 @@ impl PaintApp {
|
|||||||
_ => None,
|
_ => None,
|
||||||
});
|
});
|
||||||
let tick = time::every(milliseconds(50)).map(Message::Tick);
|
let tick = time::every(milliseconds(50)).map(Message::Tick);
|
||||||
return Subscription::batch(vec![ev, tick]);
|
Subscription::batch(vec![ev, tick])
|
||||||
}
|
}
|
||||||
|
|
||||||
// endregion
|
// endregion
|
||||||
@@ -629,6 +642,54 @@ impl PaintApp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_with_curve(&mut self, message: Message) {
|
||||||
|
match message {
|
||||||
|
Message::MousePressed(pos) => {
|
||||||
|
if self.is_controlling {
|
||||||
|
if self.control_points.len() == 0 {
|
||||||
|
self.canvas.restore_pixels();
|
||||||
|
self.canvas
|
||||||
|
.quadratic_bezier(self.begin_point, self.end_point, pos);
|
||||||
|
self.control_points.push(pos);
|
||||||
|
} else {
|
||||||
|
self.canvas.restore_pixels();
|
||||||
|
self.canvas.cubic_bezier(
|
||||||
|
self.begin_point,
|
||||||
|
self.end_point,
|
||||||
|
self.control_points[0],
|
||||||
|
pos,
|
||||||
|
);
|
||||||
|
self.control_points.push(pos);
|
||||||
|
}
|
||||||
|
self.dirty = true;
|
||||||
|
} else {
|
||||||
|
self.is_drawing = true;
|
||||||
|
self.canvas.save_pixels();
|
||||||
|
self.begin_point = pos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message::MouseReleased(pos) => {
|
||||||
|
if self.control_points.len() == 0 {
|
||||||
|
self.is_drawing = false;
|
||||||
|
self.end_point = pos;
|
||||||
|
self.is_controlling = true;
|
||||||
|
} else if self.control_points.len() == 2 {
|
||||||
|
self.control_points.clear();
|
||||||
|
self.is_controlling = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Message::MouseMoved(pos) => {
|
||||||
|
if self.is_drawing {
|
||||||
|
self.canvas.restore_pixels();
|
||||||
|
self.canvas
|
||||||
|
.draw_line_with_circle_brush(self.begin_point, pos);
|
||||||
|
self.dirty = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn update_with_rectangle(&mut self, message: Message) {
|
pub fn update_with_rectangle(&mut self, message: Message) {
|
||||||
match message {
|
match message {
|
||||||
Message::MousePressed(pos) => {
|
Message::MousePressed(pos) => {
|
||||||
|
|||||||
Reference in New Issue
Block a user