use iced::{Color, Point}; use rand::prelude::*; #[derive(Debug, Clone, Copy, PartialEq)] pub struct MSColor { r: u8, g: u8, b: u8, a: u8, } #[allow(unused)] impl MSColor { fn new(r: u8, g: u8, b: u8, a: u8) -> Self { Self { r, g, b, a } } pub const ZERO: MSColor = MSColor { r: 0, g: 0, b: 0, a: 0, }; pub const BLACK: MSColor = MSColor { r: 0, g: 0, b: 0, a: 255, }; pub const WHITE: MSColor = MSColor { r: 255, g: 255, b: 255, a: 255, }; pub const RED: MSColor = MSColor { r: 255, g: 0, b: 0, a: 255, }; pub const GREEN: MSColor = MSColor { r: 0, g: 255, b: 0, a: 255, }; pub const BLUE: MSColor = MSColor { r: 0, g: 0, b: 255, a: 255, }; pub fn into_color(self) -> Color { Color::from_rgba8(self.r, self.g, self.b, (self.a / 255) as f32) } /// rgb 十六进制 pub fn from_hex(n: i32) -> Self { let r = (n >> 16) as u8; let g = (n >> 8) as u8; let b = n as u8; Self { r, g, b, a: 0xff } } } #[derive(Clone, Copy, PartialEq)] struct Edge { y_max: i32, // 边的最大 y(不包含) x: f32, // 当前扫描线 y 处的 x 值 dx_dy: f32, // 1 / slope = Δx / Δy } impl Edge { fn new(p1: Point, p2: Point) -> Option { // 确保 p1.y <= p2.y let (top, bottom) = if p1.y < p2.y { (p1, p2) } else { (p2, p1) }; // 忽略水平边(不会贡献交点) if (top.y - bottom.y).abs() < f32::EPSILON { return None; } let dx = (bottom.x - top.x); let dy = (bottom.y - top.y); let dx_dy = dx / dy; Some(Edge { y_max: bottom.y as i32, x: top.x, dx_dy, }) } } pub struct Path2D { points: Vec, } impl Path2D { pub fn new() -> Self { Self { points: vec![] } } pub fn push(&mut self, point: Point) { self.points.push(point); } } pub struct MSCanvas { width: i32, height: i32, /// 原始像素数据:RGBA 格式 /// 长度 = width * height * 4 pixels: Vec, pixels_bak: Vec, /// 当前笔画颜色 foreground_color: MSColor, background_color: MSColor, line_width: i32, path2d: Path2D, } #[allow(unused)] impl MSCanvas { pub fn new(width: i32, height: i32) -> Self { Self { width, height, pixels: vec![255; (width * height * 4) as usize], pixels_bak: Vec::new(), foreground_color: MSColor::BLACK, background_color: MSColor::WHITE, line_width: 1, path2d: Path2D::new(), } } pub fn set_foreground_color(&mut self, color: MSColor) { self.foreground_color = color; } pub fn set_background_color(&mut self, color: MSColor) { self.background_color = color; } pub fn set_line_width(&mut self, line_width: i32) { self.line_width = line_width; } } #[allow(unused)] impl MSCanvas { pub fn size(&self) -> (i32, i32) { (self.width, self.height) } pub fn get_pixels(&self) -> Vec { self.pixels.clone() } pub fn get_pixels_scale(&self, scale: i32) -> Vec { if scale <= 1 { return self.pixels.clone(); } let dst_width = self.width * scale; let dst_height = self.height * scale; let mut dst = vec![0; (dst_width * dst_height * 4) as usize]; // RGBA for y in 0..self.height { for x in 0..self.width { // 源像素索引 let src_idx = ((y * self.width + x) * 4) as usize; // 源像素颜色 let r = self.pixels[src_idx]; let g = self.pixels[src_idx + 1]; let b = self.pixels[src_idx + 2]; let a = self.pixels[src_idx + 3]; // 在目标图像中填充 scale×scale 区域 for dy in 0..scale { for dx in 0..scale { let dst_x = x * scale + dx; let dst_y = y * scale + dy; let dst_idx = ((dst_y * dst_width + dst_x) * 4) as usize; dst[dst_idx] = r; dst[dst_idx + 1] = g; dst[dst_idx + 2] = b; dst[dst_idx + 3] = a; } } } } dst } pub fn pixel_at(&self, x: i32, y: i32) -> MSColor { // 边界检查 if x < 0 || x >= self.width || y < 0 || y >= self.height as i32 { return MSColor::ZERO; } let index = ((y * self.width + x) * 4) as usize; MSColor::new( self.pixels[index], self.pixels[index + 1], self.pixels[index + 2], self.pixels[index + 3], ) } pub fn draw_pixel_at(&mut self, point: Point) { let Point { x, y } = point; let x = x as i32; let y = y as i32; // 边界检查 if x < 0 || x >= self.width || y < 0 || y >= self.height { return; } // 计算索引:(y * width + x) * 4 let index = ((y * self.width + x) * 4) as usize; // 写入 RGBA 数据 // 注意:Color 的 r, g, b, a 是 0.0 - 1.0,需要转为 0 - 255 self.pixels[index] = self.foreground_color.r; // R self.pixels[index + 1] = self.foreground_color.g; // G self.pixels[index + 2] = self.foreground_color.b; // B self.pixels[index + 3] = self.foreground_color.a; // A } pub fn draw_pixel_color_at(&mut self, point: Point, color: MSColor) { let Point { x, y } = point; let x = x as i32; let y = y as i32; // 边界检查 if x < 0 || x >= self.width || y < 0 || y >= self.height { return; } // 计算索引:(y * width + x) * 4 let index = ((y * self.width + x) * 4) as usize; // 写入 RGBA 数据 // 注意:Color 的 r, g, b, a 是 0.0 - 1.0,需要转为 0 - 255 self.pixels[index] = color.r; // R self.pixels[index + 1] = color.g; // G self.pixels[index + 2] = color.b; // B self.pixels[index + 3] = color.a; // A } fn draw_pixel_color_at1(&mut self, x: i32, y: i32, color: MSColor) { // 边界检查 if x < 0 || x >= self.width || y < 0 || y >= self.height { return; } // 计算索引:(y * width + x) * 4 let index = ((y * self.width + x) * 4) as usize; // 写入 RGBA 数据 // 注意:Color 的 r, g, b, a 是 0.0 - 1.0,需要转为 0 - 255 self.pixels[index] = color.r; // R self.pixels[index + 1] = color.g; // G self.pixels[index + 2] = color.b; // B self.pixels[index + 3] = color.a; // A } fn draw_pixel_at1(&mut self, x: i32, y: i32) { self.draw_pixel_color_at1(x, y, self.foreground_color); } pub fn draw_pixel_row(&mut self, xs: i32, xe: i32, y: i32) { self.draw_pixel_row_color(xs, xe, y, self.foreground_color); } pub fn draw_pixel_row_color(&mut self, xs: i32, xe: i32, y: i32, color: MSColor) { if y < 0 || y >= self.height { return; } let xs = xs.clamp(0, self.width - 1); let xe = xe.clamp(0, self.width as i32); let y = y; for x in xs..xe { let index = ((y * self.width + x) * 4) as usize; // 写入 RGBA 数据 // 注意:Color 的 r, g, b, a 是 0.0 - 1.0,需要转为 0 - 255 self.pixels[index] = color.r; // R self.pixels[index + 1] = color.g; // G self.pixels[index + 2] = color.b; // B self.pixels[index + 3] = color.a; // A } } pub fn draw_pixels(&mut self, points: Vec) { for point in points { self.draw_pixel_at(point); } } pub fn draw_cross_color(&mut self, point: Point, color: MSColor) { let Point { x, y } = point; let r = 10; for dy in -r..=r { self.draw_pixel_color_at(Point::new(point.x, point.y + dy as f32), color); } for dx in -r..=r { self.draw_pixel_color_at(Point::new(point.x + dx as f32, point.y), color); } } pub fn brush_circle(&mut self, center: Point) { if self.line_width <= 1 { self.draw_pixel_at(center); return; } let square = (self.line_width as f32) * (self.line_width as f32) / 4.0; let l = self.line_width / 2; let r = self.line_width - l; for dy in -l..r { for dx in -l..r { if (dx * dx + dy * dy) as f32 <= square { self.draw_pixel_at(Point::new(center.x + dx as f32, center.y + dy as f32)); } } } } pub fn brush_square(&mut self, center: Point) { if self.line_width <= 1 { self.draw_pixel_at(center); return; } let l = self.line_width / 2; let r = self.line_width - l; for dy in -l..r { for dx in -l..r { self.draw_pixel_at(Point::new(center.x + dx as f32, center.y + dy as f32)); } } } pub fn brush_slash(&mut self, center: Point) { let r = self.line_width / 2; let l = self.line_width - r; // 左右扩展,填补线条的空白 for dx in 0..2 { for d in -l..r { self.draw_pixel_at(Point::new( center.x - (d as f32) + (dx as f32), center.y - d as f32, )); } } } pub fn brush_backslash(&mut self, center: Point) { let r = self.line_width / 2; let l = self.line_width - r; // 左右扩展,填补线条的空白 for dx in 0..2 { for d in -l..r { self.draw_pixel_at(Point::new( center.x + d as f32 + (dx as f32), center.y - d as f32, )); } } } fn bresenham_line(&mut self, begin: Point, end: Point) -> Vec { let x1 = begin.x; let y1 = begin.y; let x2 = end.x; let y2 = end.y; let dx = (x2 - x1); let dy = (y2 - y1); let dx1 = dx.abs(); let dy1 = dy.abs(); let mut px = 2.0 * dy1 - dx1; let mut py = 2.0 * dx1 - dy1; let mut x; let mut y; let xe; let ye; let mut points = Vec::new(); if dy1 <= dx1 { if dx >= 0.0 { x = x1; y = y1; xe = x2; ye = y2; } else { x = x2; y = y2; xe = x1; ye = y1; } points.push(Point::new(x, y)); while x < xe { x += 1.0; if px < 0.0 { px = px + 2.0 * dy1; } else { if (dx < 0.0 && dy < 0.0) || (dx > 0.0 && dy > 0.0) { y = y + 1.0; } else { y = y - 1.0; } px = px + 2.0 * (dy1 - dx1); } points.push(Point::new(x, y)); } } else { if dy >= 0.0 { x = x1; y = y1; ye = y2; xe = x2; } else { x = x2; y = y2; ye = y1; xe = x1; } points.push(Point::new(x, y)); while y < ye { y = y + 1.0; if py <= 0.0 { py = py + 2.0 * dx1; } else { if (dx < 0.0 && dy < 0.0) || (dx > 0.0 && dy > 0.0) { x = x + 1.0; } else { x = x - 1.0; } py = py + 2.0 * (dx1 - dy1); } points.push(Point::new(x, y)); } } points.push(Point::new(xe, ye)); points } pub fn draw_line(&mut self, begin: Point, end: Point) { let points = self.bresenham_line(begin, end); for point in points { self.draw_pixel_at(point); } } pub fn draw_line_with_circle_brush(&mut self, begin: Point, end: Point) { self.draw_line_with(begin, end, MSCanvas::brush_circle); } pub fn draw_line_with_square_brush(&mut self, begin: Point, end: Point) { self.draw_line_with(begin, end, MSCanvas::brush_square); } pub fn draw_line_with(&mut self, begin: Point, end: Point, brush_fn: F) where F: Fn(&mut MSCanvas, Point) -> (), { let points = self.bresenham_line(begin, end); for point in points { brush_fn(self, point); } } pub fn save_pixels(&mut self) { self.pixels_bak = self.pixels.clone(); } pub fn restore_pixels(&mut self) { self.pixels = self.pixels_bak.clone(); } pub fn fill_slow(&mut self, begin: Point) -> (i32, i32) { let start_x = begin.x as i32; let start_y = begin.y as i32; let target_color = self.pixel_at(start_x, start_y); if target_color == self.foreground_color { return (0, 0); } let mut scan_points = vec![(start_x, start_y)]; let width = self.width; let height = self.height; let mut iter_count = 0; let mut fill_count = 0; while let Some((x, y)) = scan_points.pop() { iter_count += 1; if x < 0 || x >= self.width || y < 0 || y >= self.height { continue; } if self.pixel_at(x, y) == target_color { self.draw_pixel_at1(x, y); fill_count += 1; let p1 = (x - 1, y); let p2 = (x + 1, y); let p3 = (x, y - 1); let p4 = (x, y + 1); scan_points.push(p1); scan_points.push(p2); scan_points.push(p3); scan_points.push(p4); } } (iter_count, fill_count) } fn fill_scanline_with_color(&mut self, begin: Point, color: MSColor) { let start_x = begin.x as i32; let start_y = begin.y as i32; let width = self.width; let height = self.height; // 边界检查 if start_x < 0 || start_x >= width || start_y < 0 || start_y >= height { return; } let target_color = self.pixel_at(start_x, start_y); if target_color == color { return; } // 栈中存储 (y, x1, x2):表示第 y 行从 x1 到 x2(含)需要向上/下扫描 let mut stack = vec![(start_y, start_x, start_x)]; while let Some((y, mut lx, mut rx)) = stack.pop() { // 向左扩展 lx while lx - 1 >= 0 && self.pixel_at(lx - 1, y) == target_color { lx -= 1; } // 向右扩展 rx while rx + 1 < width && self.pixel_at(rx + 1, y) == target_color { rx += 1; } // 填充当前行 [lx, rx] for x in lx..=rx { self.draw_pixel_color_at1(x, y, color); } // 检查上一行 (y - 1) if y - 1 >= 0 { let mut x = lx; while x <= rx { if self.pixel_at(x, y - 1) == target_color { let span_start = x; // 跳过连续的目标色块 while x <= rx && self.pixel_at(x, y - 1) == target_color { x += 1; } // 将这个 span 入栈(用于后续处理上一行的上一行) stack.push((y - 1, span_start, x - 1)); } else { x += 1; } } } // 检查下一行 (y + 1) if y + 1 < height { let mut x = lx; while x <= rx { if self.pixel_at(x, y + 1) == target_color { let span_start = x; while x <= rx && self.pixel_at(x, y + 1) == target_color { x += 1; } stack.push((y + 1, span_start, x - 1)); } else { x += 1; } } } } } pub fn fill_scanline(&mut self, begin: Point) { self.fill_scanline_with_color(begin, self.foreground_color); } pub fn arc_1px( &mut self, center: Point, radius: f32, start_angle: f32, end_angle: f32, counterclockwise: bool, ) { if radius <= 0.0 { return; } // 根据半径确定步长,步长越小曲线越平滑 // 圆周长约为 2πr,每像素对应的角度步长约为 1/r 弧度 let step = (1.0 / radius).max(0.001_f32); // 将角度规范化,确保 start_angle 和 end_angle 在合理范围内 let (start, end) = if counterclockwise { // 逆时针:角度递减,将区间转成递增处理 // 逆时针从 start_angle 到 end_angle,等价于顺时针从 end_angle 到 start_angle let mut s = end_angle; let mut e = start_angle; // 保证 e >= s while e < s { e += std::f32::consts::TAU; } (s, e) } else { // 顺时针:角度递增 let mut s = start_angle; let mut e = end_angle; // 保证 e >= s while e < s { e += std::f32::consts::TAU; } (s, e) }; // 沿角度步进,绘制每个像素点 let mut angle = start; while angle <= end + step { let a = angle.min(end); let x = center.x + radius * a.cos(); let y = center.y + radius * a.sin(); self.draw_pixel_at(Point::new(x, y)); angle += step; } } /// 圆弧从 x 轴方向开始计算, start_angle end_angle 为弧度,counterclockwise 是否逆时针方向 pub fn arc( &mut self, center: Point, radius: f32, start_angle: f32, end_angle: f32, counterclockwise: bool, ) { if radius <= 1.0 { self.draw_pixel_at(center); return; } let start_angle = normalize_radian(start_angle); let end_angle = normalize_radian(end_angle); let full_circle = (start_angle - end_angle).abs() < f32::EPSILON; let min_x = ((center.x - radius) as i32).max(0); let max_x = ((center.x + radius) as i32).min(self.width - 1); let min_y = ((center.y - radius) as i32).max(0); let max_y = ((center.y + radius) as i32).min(self.height - 1); let min_r = (radius - self.line_width as f32).max(0.0); let max_r = radius + 0.05; let min_sq = min_r * min_r; let max_sq = max_r * max_r; let center_x = center.x as i32; let center_y = center.y as i32; for y in min_y..=max_y { for x in min_x..=max_x { let dx = (x - center_x) as f32; let dy = (y - center_y) as f32; let dist_sq = dx * dx + dy * dy; // 判断点是不是在扇区内 if dist_sq > max_sq || dist_sq <= min_sq { continue; } // 判断角度是不是在扇区内 let theta = dy.atan2(dx); let theta = normalize_radian(theta); if full_circle || (counterclockwise && (theta >= end_angle || theta <= start_angle)) || (!counterclockwise && theta >= start_angle && theta <= end_angle) { self.draw_pixel_at(Point::new(x as f32, y as f32)); } } } } pub fn clear_rect(&mut self, x: i32, y: i32, width: i32, height: i32) { for yi in y..(y + height) { self.clear_row(x, x + width, yi); } } fn fill_rect_color(&mut self, x: i32, y: i32, width: i32, height: i32, color: MSColor) { for yi in y..(y + height) { self.draw_pixel_row_color(x, x + width, yi, color); } } fn fill_rect_foreground_color(&mut self, x: i32, y: i32, width: i32, height: i32) { self.fill_rect_color(x, y, width, height, self.foreground_color); } pub fn fill_rect(&mut self, x: i32, y: i32, width: i32, height: i32) { self.fill_rect_color(x, y, width, height, self.background_color) } /// 填充一个圆角矩形 /// - x, y: 左上角坐标 /// - width, height: 尺寸(必须 > 0) /// - radius: 圆角半径(会被 clamp 到合理范围) pub fn fill_round_rect(&mut self, x: f32, y: f32, width: f32, height: f32, radius: f32) { if (width as i32) <= 2 * self.line_width || (height as i32) <= 2 * self.line_width || width <= 2.0 * radius || height <= 2.0 * radius { self.fill_rect(x as i32, y as i32, width as i32, height as i32); return; } let min_x = x; let max_x = x + width - 1.0; let min_y = y; let max_y = y + height - 1.0; // 预计算四个圆角的圆心 let corners = [ ((x + radius) as i32, (y + radius) as i32), // 左上 ((x + width - 1.0 - radius) as i32, (y + radius) as i32), // 右上 ( (x + width - 1.0 - radius) as i32, (y + height - 1.0 - radius) as i32, ), // 右下 ((x + radius) as i32, (y + height - 1.0 - radius) as i32), // 左下 ]; let min_x = min_x as i32; let max_x = max_x as i32; let min_y = min_y as i32; let max_y = max_y as i32; let radius_sq = (radius + 0.05) * (radius + 0.05); let radius_int = radius as i32; for py in min_y..=max_y { for px in min_x..=max_x { // 判断是否在“直边区域”(无需检查圆角) if px >= min_x + radius_int && px <= max_x - radius_int { // 在左右圆角之间的竖直带 → 一定在内部 self.draw_pixel_at1(px, py); continue; } if py >= min_y + radius_int && py <= max_y - radius_int { // 在上下圆角之间的水平带 → 一定在内部 self.draw_pixel_at1(px, py); continue; } // 否则,点位于四个角落之一,需检查是否在四分之一圆内 let in_corner = // 左上角区域 (distance_sq1((px, py), corners[0]) <= radius_sq) || // 右上角区域 (distance_sq1((px, py), corners[1]) <= radius_sq) || // 右下角区域 (distance_sq1((px, py), corners[2]) <= radius_sq) || // 左下角区域 (distance_sq1((px, py), corners[3]) <= radius_sq); if in_corner { self.draw_pixel_at1(px, py); } } } } pub fn fill_round_rect1(&mut self, p1: Point, p2: Point, radius: f32) { let mut x = p1.x; let mut y = p1.y; let mut width = (p2.x - p1.x); let mut height = (p2.y - p1.y); if width < 0.0 && height < 0.0 { x = p2.x; y = p2.y; width = (p1.x - p2.x); height = (p1.y - p2.y); } else if width < 0.0 { x += width; width = -width; } else if height < 0.0 { y += height; height = -height; } self.fill_round_rect(x, y, width, height, radius); } pub fn round_rect(&mut self, x: f32, y: f32, width: f32, height: f32, radius: f32) { if (width as i32) < 2 * self.line_width || (height as i32) < 2 * self.line_width || width < 2.0 * radius || height < 2.0 * radius { self.fill_rect(x as i32, y as i32, width as i32, height as i32); return; } self.fill_rect_foreground_color( (x + radius) as i32, y as i32, (width - 2.0 * radius) as i32, self.line_width, ); self.fill_rect_foreground_color( (x + radius) as i32, (y + height) as i32 - self.line_width, (width - 2.0 * radius) as i32, self.line_width, ); self.fill_rect_foreground_color( x as i32, (y + radius) as i32, self.line_width, (height - 2.0 * radius) as i32, ); self.fill_rect_foreground_color( (x + width) as i32 - self.line_width, (y + radius) as i32, self.line_width, (height - 2.0 * radius) as i32, ); self.arc( Point::new(x + radius, y + radius), radius, std::f32::consts::PI, std::f32::consts::PI + std::f32::consts::FRAC_PI_2, false, ); self.arc( Point::new(x + width - 1.0 - radius, y + radius), radius, 0.0, std::f32::consts::PI + std::f32::consts::FRAC_PI_2, true, ); self.arc( Point::new(x + radius, y + height - 1.0 - radius), radius, std::f32::consts::FRAC_PI_2, std::f32::consts::PI, false, ); self.arc( Point::new(x + width - 1.0 - radius, y + height - 1.0 - radius), radius, 0.0, std::f32::consts::FRAC_PI_2, false, ); } pub fn round_rect1(&mut self, p1: Point, p2: Point, radius: f32) { let mut x = p1.x; let mut y = p1.y; let mut width = (p2.x - p1.x); let mut height = (p2.y - p1.y); if width < 0.0 && height < 0.0 { x = p2.x; y = p2.y; width = (p1.x - p2.x); height = (p1.y - p2.y); } else if width < 0.0 { x += width; width = -width; } else if height < 0.0 { y += height; height = -height; } self.round_rect(x, y, width, height, radius); } pub fn rect(&mut self, x: i32, y: i32, width: i32, height: i32) { if width < 2 * self.line_width || height < 2 * self.line_width { self.fill_rect_foreground_color(x, y, width, height); return; } self.fill_rect_foreground_color(x, y, width, self.line_width); self.fill_rect_foreground_color(x, y + height - self.line_width, width, self.line_width); self.fill_rect_foreground_color(x, y, self.line_width, height); self.fill_rect_foreground_color(x + width - self.line_width, y, self.line_width, height); } pub fn rect1(&mut self, p1: Point, p2: Point) { let mut x = p1.x; let mut y = p1.y; let mut width = (p2.x - p1.x); let mut height = (p2.y - p1.y); if width < 0.0 && height < 0.0 { x = p2.x; y = p2.y; width = (p1.x - p2.x); height = (p1.y - p2.y); } else if width < 0.0 { x += width; width = -width; } else if height < 0.0 { y += height; height = -height; } self.rect(x as i32, y as i32, width as i32, height as i32); } pub fn clear(&mut self) { self.pixels.fill(255); } pub fn clear_row(&mut self, xs: i32, xe: i32, y: i32) { if y < 0 || y >= self.height { return; } let xs = xs.clamp(0, self.width - 1); let xe = xe.clamp(0, self.width as i32); for x in xs..xe { let index = ((y * self.width + x) * 4) as usize; // 写入 RGBA 数据 // 注意:Color 的 r, g, b, a 是 0.0 - 1.0,需要转为 0 - 255 self.pixels[index] = 255; // R self.pixels[index + 1] = 255; // G self.pixels[index + 2] = 255; // B self.pixels[index + 3] = 255; // A } } /// 实现喷枪效果的函数 pub fn spray_paint(&mut self, center: Point, radius: i32, density: u32) { let mut rng = rand::rng(); for _ in 0..density { // 在给定半径内随机产生偏移量 let offset_x = rng.random_range(-radius..=radius); let offset_y = rng.random_range(-radius..=radius); // 确保我们只在圆形区域内绘制,而非整个正方形区域 if (offset_x * offset_x + offset_y * offset_y) <= (radius * radius) { let point = Point::new(center.x + offset_x as f32, center.y + offset_y as f32); self.draw_pixel_at(point); } } } 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 = 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) { // 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.0005; } } 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); } 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); } } /// 填充一个椭圆 /// - center: 椭圆中心 /// - rx: 水平半径(必须 >= 0) /// - ry: 垂直半径(必须 >= 0) pub fn fill_ellipse(&mut self, center: Point, rx: f32, ry: f32) { if rx <= 0.0 || ry <= 0.0 { return; } let rx = rx as f32; let ry = ry as f32; // 计算包围矩形(整数边界) let min_x = (center.x as f32 - rx).ceil() as i32; let max_x = (center.x as f32 + rx).floor() as i32; let min_y = (center.y as f32 - ry).ceil() as i32; let max_y = (center.y as f32 + ry).floor() as i32; // 预计算常量:rx², ry², rx² * ry² let rx2 = rx * rx; let ry2 = ry * ry; let rxy2 = rx2 * ry2; // 右边阈值 for y in min_y..=max_y { for x in min_x..=max_x { let dx = x as f32 - center.x as f32; let dy = y as f32 - center.y as f32; // 判断是否在椭圆内:dx²/ rx² + dy²/ ry² <= 1 // 等价于:dx² * ry² + dy² * rx² <= rx² * ry² if dx * dx * ry2 + dy * dy * rx2 <= rxy2 { self.draw_pixel_color_at1(x, y, self.background_color); } } } } pub fn fill_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.fill_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.fill_ellipse(center, rx, ry); } else if ry < 0.0 { ry = -ry; let center = Point::new(p1.x + rx, p1.y - ry); self.fill_ellipse(center, rx, ry); } else { rx = -rx; let center = Point::new(p1.x - rx, p1.y + ry); self.fill_ellipse(center, rx, ry); } } /// 填充一个简单多边形(支持凹多边形) pub fn fill_polygon(&mut self, points: &[Point]) { if points.len() < 3 { return; } // 计算 y 范围 let min_y = points.iter().map(|p| p.y as i32).min().unwrap_or(0); let max_y = points.iter().map(|p| p.y as i32).max().unwrap_or(0); // 构建边表(Edge Table):按 ymin 分组 let mut edge_table: Vec> = vec![Vec::new(); (max_y - min_y + 1) as usize]; for i in 0..points.len() { let p1 = points[i]; let p2 = points[(i + 1) % points.len()]; if let Some(edge) = Edge::new(p1, p2) { let idx = (edge.x as i32).min(max_y).max(min_y); // 实际应使用 top.y // 正确做法:使用 top.y 作为插入位置 let top_y = p1.y.min(p2.y) as i32; if top_y >= min_y && top_y <= max_y { edge_table[(top_y - min_y) as usize].push(edge); } } } // 活动边表(Active Edge List),按 x 排序 let mut active_edges: Vec = Vec::new(); // 从 min_y 到 max_y 扫描每一行 for y in min_y..=max_y { let y_idx = (y - min_y) as usize; // 1. 添加新边(y == ymin 的边) if y_idx < edge_table.len() { active_edges.append(&mut edge_table[y_idx]); } // 2. 移除 y >= y_max 的边 active_edges.retain(|e| y < e.y_max); // 3. 按 x 排序 active_edges.sort_by(|a, b| a.x.partial_cmp(&b.x).unwrap_or(std::cmp::Ordering::Equal)); // 4. 成对填充像素 for i in (0..active_edges.len()).step_by(2) { if i + 1 < active_edges.len() { let x_start = active_edges[i].x.ceil() as i32; let x_end = active_edges[i + 1].x.floor() as i32; for x in x_start..=x_end { self.draw_pixel_color_at( Point::new(x as f32, y as f32), self.background_color, ); } } } // 5. 更新活动边的 x(为下一行准备) for edge in &mut active_edges { edge.x += edge.dx_dy; } } } pub fn begin_path(&mut self) { self.path2d = Path2D::new(); } pub fn close_path(&mut self) { let points = &self.path2d.points; if points.len() < 3 { return; } self.path2d.push(points[0]); } pub fn move_to(&mut self, point: Point) { self.path2d.push(point); } pub fn line_to(&mut self, point: Point) { self.path2d.push(point); } pub fn stroke(&mut self) { let mut points = self.path2d.points.clone(); if points.len() < 2 { return; } // 连线 for i in 0..(points.len() - 1) { self.draw_line_with_circle_brush(points[i], points[i + 1]); } } pub fn fill(&mut self) { let points = self.path2d.points.clone(); self.fill_polygon(&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) } /// 将弧度规范到 [0, 2π) fn normalize_radian(radian: f32) -> f32 { let mut r = radian; while r < 0.0 { r += std::f32::consts::TAU; } while r >= std::f32::consts::TAU { r -= std::f32::consts::TAU; } r } #[inline] /// 辅助函数:计算两点间距离的平方(避免开方) fn distance_sq(a: Point, b: Point) -> f32 { let dx = a.x - b.x; let dy = a.y - b.y; dx * dx + dy * dy } #[inline] /// 辅助函数:计算两点间距离的平方(避免开方) fn distance_sq1(a: (i32, i32), b: (i32, i32)) -> f32 { let dx = a.0 - b.0; let dy = a.1 - b.1; (dx * dx + dy * dy) as f32 }