From d7f45712171edfe60bc43480b81a166b48252c8d Mon Sep 17 00:00:00 2001 From: yeqing Date: Sat, 28 Feb 2026 18:44:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=AE=9E=E7=8E=B0=E6=A4=AD=E5=9C=86?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/mscanvas.rs | 67 +++++++++++++++++++++++++++++++++++++++++++++++++ src/paint.rs | 25 ++++++++++++++++++ 2 files changed, 92 insertions(+) diff --git a/src/mscanvas.rs b/src/mscanvas.rs index a2909c7..e2a9751 100644 --- a/src/mscanvas.rs +++ b/src/mscanvas.rs @@ -653,6 +653,73 @@ impl MSCanvas { self.bezier(points); } + pub fn ellipse(&mut self, center: Point, rx: f32, ry: f32) { + let mut x = 0.0; + let mut y = ry; // 初始时将y设置为半高 + + // 计算初始决策参数 + let mut decision = ry * ry - rx * rx * ry + rx * rx / 4.0; + + while ry * ry * x < rx * rx * y { + // 在每个阶段,根据对称性绘制四个方向上的点 + self.draw_pixel_at(Point::new(center.x + x, center.y + y)); + self.draw_pixel_at(Point::new(center.x - x, center.y + y)); + self.draw_pixel_at(Point::new(center.x + x, center.y - y)); + self.draw_pixel_at(Point::new(center.x - x, center.y - y)); + + if decision < 0.0 { + x += 1.0; + decision += 2.0 * ry * ry * x + ry * ry; + } else { + x += 1.0; + y -= 1.0; + decision += 2.0 * ry * ry * x - 2.0 * rx * rx * y + ry * ry; + } + } + + decision = + ry * ry * (x + 0.5) * (x + 0.5) + rx * rx * (y - 1.0) * (y - 1.0) - rx * rx * ry * ry; + + while y > 0.0 { + // 同样地,根据对称性绘制四个方向上的点 + self.draw_pixel_at(Point::new(center.x + x, center.y + y)); + self.draw_pixel_at(Point::new(center.x - x, center.y + y)); + self.draw_pixel_at(Point::new(center.x + x, center.y - y)); + self.draw_pixel_at(Point::new(center.x - x, center.y - y)); + + if decision > 0.0 { + y -= 1.0; + decision += rx * rx - 2.0 * rx * rx * y; + } else { + x += 1.0; + y -= 1.0; + decision += 2.0 * ry * ry * x - 2.0 * rx * rx * y + rx * rx; + } + } + } + + pub fn ellipse1(&mut self, p1: Point, p2: Point) { + let mut rx = (p2.x - p1.x) / 2.0; + let mut ry = (p2.y - p1.y) / 2.0; + if rx > 0.0 && ry > 0.0 { + let center = Point::new(p1.x + rx, p1.y + ry); + self.ellipse(center, rx, ry); + } else if rx < 0.0 && ry < 0.0 { + rx = -rx; + ry = -ry; + let center = Point::new(p1.x - rx, p1.y - ry); + self.ellipse(center, rx, ry); + } else if ry < 0.0 { + ry = -ry; + let center = Point::new(p1.x + rx, p1.y - ry); + self.ellipse(center, rx, ry); + } else { + rx = -rx; + let center = Point::new(p1.x - rx, p1.y + ry); + self.ellipse(center, rx, ry); + } + } + pub fn begin_path(&mut self) { self.path2d = Path2D::new(); } diff --git a/src/paint.rs b/src/paint.rs index 085c83c..9dd4cab 100644 --- a/src/paint.rs +++ b/src/paint.rs @@ -447,6 +447,9 @@ impl PaintApp { Tool::Polygon => { self.update_with_polygon(message); } + Tool::Ellipse => { + self.update_with_ellipse(message); + } _ => {} } @@ -794,6 +797,28 @@ impl PaintApp { } } + pub fn update_with_ellipse(&mut self, message: Message) { + match message { + Message::MousePressed(pos) => { + self.is_drawing = true; + self.canvas.save_pixels(); + self.begin_point = pos; + } + Message::MouseReleased(pos) => { + self.is_drawing = false; + self.begin_point = pos; + } + Message::MouseMoved(pos) => { + if self.is_drawing { + self.canvas.restore_pixels(); + self.canvas.ellipse1(self.begin_point, pos); + self.dirty = true; + } + } + _ => {} + } + } + // endregion pub fn update_tool_states(&mut self, tool: Tool) {