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 } } pub fn invert(&self) -> Self { Self::new(255 - self.r, 255 - self.g, 255 - self.b, self.a) } } #[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 RectSelection { /// 左上角坐标 x: i32, y: i32, w: i32, h: i32, pixels: Vec, } impl RectSelection { pub fn new(x: i32, y: i32, w: i32, h: i32, pixels: Vec) -> RectSelection { Self { x, y, w, h, pixels } } pub fn contains(&self, p: Point) -> bool { let x = p.x as i32; let y = p.y as i32; !(x < self.x || y < self.y || x >= self.x + self.w || y >= self.y + self.h) } pub fn move_offset(&mut self, offset_x: i32, offset_y: i32) { self.x += offset_x; self.y += offset_y; } pub fn size(&self) -> (i32, i32) { (self.w, self.h) } pub fn position(&self) -> (i32, i32) { (self.x, self.y) } } pub struct MSCanvas { width: i32, height: i32, /// 原始像素数据:RGBA 格式 /// 长度 = width * height * 4 pixels: Vec, pixels_bak: Vec, fill_color: MSColor, stroke_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(), fill_color: MSColor::BLACK, stroke_color: MSColor::WHITE, line_width: 1, path2d: Path2D::new(), } } pub fn line_width(&mut self, line_width: i32) -> &mut Self { self.line_width = line_width; self } pub fn fill_color(&mut self, color: MSColor) -> &mut Self { self.fill_color = color; self } pub fn stroke_color(&mut self, color: MSColor) -> &mut Self { self.stroke_color = color; self } pub fn size(&self) -> (i32, i32) { (self.width, self.height) } pub fn get_pixels_ref(&self) -> &[u8] { &self.pixels } 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) -> Option { // 边界检查 if x < 0 || x >= self.width || y < 0 || y >= self.height { return None; } let index = ((y * self.width + x) * 4) as usize; Some(MSColor::new( self.pixels[index], self.pixels[index + 1], self.pixels[index + 2], self.pixels[index + 3], )) } pub fn pixel_is(&self, x: i32, y: i32, color: MSColor) -> bool { match self.pixel_at(x, y) { Some(c) => c == color, None => false, } } pub fn select_rect(&self, x: i32, y: i32, w: i32, h: i32, is_transparent_white: bool) -> RectSelection { let mut result = vec![255; (w * h * 4) as usize]; let mut index = 0; let default_color = if is_transparent_white { MSColor::ZERO } else { MSColor::WHITE }; for yi in y..(y + h) { for xi in x..(x + w) { let mut color = self.pixel_at(xi, yi).unwrap_or(default_color); if is_transparent_white && color == MSColor::WHITE { color = MSColor::ZERO; } result[index] = color.r; result[index + 1] = color.g; result[index + 2] = color.b; result[index + 3] = color.a; index += 4; } } RectSelection::new(x, y, w, h, result) } pub fn overlay_pixels(&mut self, canvas: &MSCanvas) -> Vec { let mut pixels = canvas.get_pixels(); let width = canvas.width.min(self.width) as usize; let height = canvas.height.min(self.height) as usize; let src_stride = self.width as usize * 4; let dst_stride = canvas.width as usize * 4; // ⚠️ Bug fix: use canvas.width, not `width` for y in 0..height { let src_row = &self.pixels[y * src_stride..y * src_stride + width * 4]; let dst_row = &mut pixels[y * dst_stride..y * dst_stride + width * 4]; // Process 4 pixels at a time (16 bytes) for better auto-vectorization let chunks = width / 4; let remainder = width % 4; for chunk in 0..chunks { let base = chunk * 16; // Check alpha bytes for 4 pixels at once let a0 = src_row[base + 3]; let a1 = src_row[base + 7]; let a2 = src_row[base + 11]; let a3 = src_row[base + 15]; if a0 | a1 | a2 | a3 != 0 { // At least one pixel is non-transparent if a0 != 0 && a1 != 0 && a2 != 0 && a3 != 0 { // All 4 pixels are non-transparent — bulk copy 16 bytes dst_row[base..base + 16].copy_from_slice(&src_row[base..base + 16]); } else { // Mixed — copy individually for i in 0..4 { let off = base + i * 4; if src_row[off + 3] != 0 { dst_row[off..off + 4].copy_from_slice(&src_row[off..off + 4]); } } } } // else: all 4 transparent — skip entirely } // Handle remaining pixels for x in (chunks * 4)..width { let off = x * 4; if src_row[off + 3] != 0 { dst_row[off..off + 4].copy_from_slice(&src_row[off..off + 4]); } } } pixels } } #[allow(unused)] impl MSCanvas { pub fn fill_pixel_at(&mut self, point: Point) { let Point { x, y } = point; self.fill_pixel_at1(x as i32, y as i32); } pub fn stroke_pixel_at(&mut self, point: Point) { let Point { x, y } = point; self.stroke_pixel_at1(x as i32, y as i32); } fn fill_pixel_at1(&mut self, x: i32, y: 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.fill_color.r; // R self.pixels[index + 1] = self.fill_color.g; // G self.pixels[index + 2] = self.fill_color.b; // B self.pixels[index + 3] = self.fill_color.a; // A } fn stroke_pixel_at1(&mut self, x: i32, y: 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.stroke_color.r; // R self.pixels[index + 1] = self.stroke_color.g; // G self.pixels[index + 2] = self.stroke_color.b; // B self.pixels[index + 3] = self.stroke_color.a; // A } fn draw_column_with_color(&mut self, ys: i32, ye: i32, x: i32, color: MSColor) { if x < 0 || x >= self.width { return; } let ys = ys.clamp(0, self.height - 1); let ye = ye.clamp(0, self.height); for y in ys..ye { 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_row_with_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); 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 } } fn fill_column(&mut self, ys: i32, ye: i32, x: i32) { self.draw_column_with_color(ys, ye, x, self.fill_color); } fn fill_row(&mut self, xs: i32, xe: i32, y: i32) { self.draw_row_with_color(xs, xe, y, self.fill_color); } fn stroke_column(&mut self, ys: i32, ye: i32, x: i32) { self.draw_column_with_color(ys, ye, x, self.stroke_color); } fn stroke_row(&mut self, xs: i32, xe: i32, y: i32) { self.draw_row_with_color(xs, xe, y, self.stroke_color); } pub fn fill_pixels(&mut self, points: Vec) { for point in points { self.fill_pixel_at(point); } } pub fn fill_pixels_i32(&mut self, points: Vec>) { for point in points { self.fill_pixel_at1(point.x, point.y); } } pub fn stroke_cross(&mut self, point: Point) { let Point { x, y } = point; let r = 10; for dy in -r..=r { self.stroke_pixel_at(Point::new(point.x, point.y + dy as f32)); } for dx in -r..=r { self.stroke_pixel_at(Point::new(point.x + dx as f32, point.y)); } } pub fn brush_circle(&mut self, center: Point) { if self.line_width <= 1 { self.fill_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.fill_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.fill_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.fill_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.fill_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.fill_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.fill_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) { let start_x = begin.x as i32; let start_y = begin.y as i32; let target_color = self.pixel_at(start_x, start_y).unwrap_or(MSColor::ZERO); if target_color == self.fill_color { return; } let mut scan_points = vec![(start_x, start_y)]; let width = self.width; let height = self.height; while let Some((x, y)) = scan_points.pop() { if x < 0 || x >= self.width || y < 0 || y >= self.height { continue; } if self.pixel_is(x, y, target_color) { self.fill_pixel_at1(x, y); 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); } } } pub fn fill_scanline(&mut self, begin: Point) { 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).unwrap_or(MSColor::ZERO); if target_color == self.fill_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_is(lx - 1, y, target_color) { lx -= 1; } // 向右扩展 rx while rx + 1 < width && self.pixel_is(rx + 1, y, target_color) { rx += 1; } // 填充当前行 [lx, rx] for x in lx..=rx { self.fill_pixel_at1(x, y); } // 检查上一行 (y - 1) if y - 1 >= 0 { let mut x = lx; while x <= rx { if self.pixel_is(x, y - 1, target_color) { let span_start = x; // 跳过连续的目标色块 while x <= rx && self.pixel_is(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_is(x, y + 1, target_color) { let span_start = x; while x <= rx && self.pixel_is(x, y + 1, target_color) { x += 1; } stack.push((y + 1, span_start, x - 1)); } else { x += 1; } } } } } /// 圆弧从 x 轴方向开始计算, start_angle end_angle 为弧度,counterclockwise 是否逆时针方向 pub fn stroke_arc( &mut self, center: Point, radius: f32, start_angle: f32, end_angle: f32, counterclockwise: bool, ) { if radius <= 1.0 { self.fill_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.stroke_pixel_at1(x, y); } } } } 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_stroke_color(&mut self, x: i32, y: i32, width: i32, height: i32) { let old_fill_color = self.fill_color; self.fill_color(self.stroke_color); for yi in y..(y + height) { self.fill_row(x, x + width, yi); } self.fill_color(old_fill_color); } pub fn fill_rect(&mut self, x: i32, y: i32, width: i32, height: i32) { for yi in y..(y + height) { self.fill_row(x, x + width, yi); } } pub fn fill_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.fill_rect(x as i32, y as i32, width as i32, height as i32); } /// 填充一个圆角矩形 /// - 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.fill_pixel_at1(px, py); continue; } if py >= min_y + radius_int && py <= max_y - radius_int { // 在上下圆角之间的水平带 → 一定在内部 self.fill_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.fill_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 stroke_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_stroke_color(x as i32, y as i32, width as i32, height as i32); return; } self.fill_rect_stroke_color( (x + radius) as i32, y as i32, (width - 2.0 * radius) as i32, self.line_width, ); self.fill_rect_stroke_color( (x + radius) as i32, (y + height) as i32 - self.line_width, (width - 2.0 * radius) as i32, self.line_width, ); self.fill_rect_stroke_color( x as i32, (y + radius) as i32, self.line_width, (height - 2.0 * radius) as i32, ); self.fill_rect_stroke_color( (x + width) as i32 - self.line_width, (y + radius) as i32, self.line_width, (height - 2.0 * radius) as i32, ); self.stroke_arc( Point::new(x + radius, y + radius), radius, std::f32::consts::PI, std::f32::consts::PI + std::f32::consts::FRAC_PI_2, false, ); self.stroke_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.stroke_arc( Point::new(x + radius, y + height - 1.0 - radius), radius, std::f32::consts::FRAC_PI_2, std::f32::consts::PI, false, ); self.stroke_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 stroke_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.stroke_round_rect(x, y, width, height, radius); } pub fn stroke_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_stroke_color(x, y, width, height); return; } self.fill_rect_stroke_color(x, y, width, self.line_width); self.fill_rect_stroke_color(x, y + height - self.line_width, width, self.line_width); self.fill_rect_stroke_color(x, y, self.line_width, height); self.fill_rect_stroke_color(x + width - self.line_width, y, self.line_width, height); } pub fn stroke_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.stroke_rect(x as i32, y as i32, width as i32, height as i32); } pub fn stroke_dashed_rect( &mut self, x: i32, y: i32, width: i32, height: i32, dash_length: i32, gap_length: i32, ) { let mut is_dash = true; // 上下两边边框 for dx in (x..x + width).step_by((dash_length + gap_length) as usize) { if is_dash { self.stroke_row(dx, dx + dash_length, y); self.stroke_row(dx, dx + dash_length, y + height - 1); } is_dash = !is_dash; } // 左右两边边框 for dy in (y..y + height).step_by((dash_length + gap_length) as usize) { if is_dash { self.stroke_column(dy, dy + dash_length, x); self.stroke_column(dy, dy + dash_length, x + width - 1); } is_dash = !is_dash; } } pub fn stroke_dashed_rect1(&mut self, p1: Point, p2: Point, dash_length: i32, gap_length: i32) { 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.stroke_dashed_rect( x as i32, y as i32, width as i32, height as i32, dash_length, gap_length, ); } pub fn clear(&mut self) { self.pixels.fill(255); } pub fn clear_zero(&mut self) { self.pixels.fill(0); } 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); 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.fill_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); } /// 绘制带线宽的椭圆(描边) /// - center: 椭圆中心 /// - rx, ry: 椭圆的水平/垂直半径(指中心线位置) pub fn stroke_ellipse(&mut self, center: Point, rx: f32, ry: f32) { if self.line_width <= 0 || rx <= 0.0 || ry <= 0.0 { return; } // 外椭圆半径(膨胀) let outer_rx = rx; let outer_ry = ry; // 内椭圆半径(收缩)——不能为负 let inner_rx = (rx - self.line_width as f32).max(0.0); let inner_ry = (ry - self.line_width as f32).max(0.0); // 计算包围矩形(基于外椭圆) let min_x = (center.x - outer_rx).ceil() as i32; let max_x = (center.x + outer_rx).floor() as i32; let min_y = (center.y - outer_ry).ceil() as i32; let max_y = (center.y + outer_ry).floor() as i32; // 预计算外椭圆参数 let outer_rx2 = outer_rx * outer_rx; let outer_ry2 = outer_ry * outer_ry; let outer_threshold = outer_rx2 * outer_ry2; // 预计算内椭圆参数(仅当存在内区域时) let (inner_rx2, inner_ry2, inner_threshold) = if inner_rx > 0.0 && inner_ry > 0.0 { let rx2 = inner_rx * inner_rx; let ry2 = inner_ry * inner_ry; (rx2, ry2, rx2 * ry2) } else { (0.0, 0.0, -1.0) // inner_threshold < 0 表示无内区域(实心圆) }; for y in min_y..=max_y { for x in min_x..=max_x { let dx = x as f32 - center.x; let dy = y as f32 - center.y; // 判断是否在外椭圆内 let outer_val = dx * dx * outer_ry2 + dy * dy * outer_rx2; if outer_val > outer_threshold { continue; // 在外椭圆外 } // 判断是否在内椭圆内(如果是,则跳过) if inner_threshold >= 0.0 { let inner_val = dx * dx * inner_ry2 + dy * dy * inner_rx2; if inner_val <= inner_threshold { continue; // 在内椭圆内 → 不绘制(空心) } } // 否则:在外椭圆内,且不在内椭圆内 → 属于描边区域 self.stroke_pixel_at1(x, y); } } } pub fn stroke_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.stroke_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.stroke_ellipse(center, rx, ry); } else if ry < 0.0 { ry = -ry; let center = Point::new(p1.x + rx, p1.y - ry); self.stroke_ellipse(center, rx, ry); } else { rx = -rx; let center = Point::new(p1.x - rx, p1.y + ry); self.stroke_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; let ry = ry; // 计算包围矩形(整数边界) let min_x = (center.x - rx).ceil() as i32; let max_x = (center.x + rx).floor() as i32; let min_y = (center.y - ry).ceil() as i32; let max_y = (center.y + 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; let dy = y as f32 - center.y; // 判断是否在椭圆内:dx²/ rx² + dy²/ ry² <= 1 // 等价于:dx² * ry² + dy² * rx² <= rx² * ry² if dx * dx * ry2 + dy * dy * rx2 <= rxy2 { self.fill_pixel_at1(x, y); } } } } 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); } } fn rasterize_polygon(&mut self, points: &[Point]) -> Vec> { let mut result = Vec::new(); if points.len() < 3 { return result; } // 计算 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 { result.push(Point::new(x, y)); } } } // 5. 更新活动边的 x(为下一行准备) for edge in &mut active_edges { edge.x += edge.dx_dy; } } result } /// 填充一个简单多边形(支持凹多边形) pub fn fill_polygon(&mut self, points: &[Point]) { let filled_points = self.rasterize_polygon(points); self.fill_pixels_i32(filled_points); } 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[..]); } pub fn draw_rect_selection(&mut self, x: i32, y: i32, rect: &RectSelection) { // 边界检查 if x >= self.width || y >= self.height { return; } // 考虑矩形四边出界的情况 let w = (rect.w).min(self.width - x).min(rect.w + x); let h = (rect.h).min(self.height - y).min(rect.h + y); if w == 0 || h == 0 { return; } let mut src_offset_x = 0usize; let mut src_offset_y = 0usize; if x < 0 { src_offset_x = (-x) as usize; } if y < 0 { src_offset_y = (-y) as usize; } let x = x.max(0) as usize; let y = y.max(0) as usize; let w = w as usize; let h = h as usize; let width = self.width as usize; for dy in 0..h { for dx in 0..w { let src_index = ((dy + src_offset_y) * rect.w as usize + dx + src_offset_x) * 4; if rect.pixels[src_index + 3] == 0 { continue; } let dst_index = ((y + dy) * width + x + dx) * 4; self.pixels[dst_index] = rect.pixels[src_index]; self.pixels[dst_index + 1] = rect.pixels[src_index + 1]; self.pixels[dst_index + 2] = rect.pixels[src_index + 2]; self.pixels[dst_index + 3] = rect.pixels[src_index + 3]; } } } } 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_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 }