Compare commits

...

2 Commits

Author SHA1 Message Date
8ca7c52cb1 feat: 实现椭圆填充功能 2026-03-03 01:28:48 +08:00
1174019eff fix: 画好的多边形颜色改变 2026-03-03 01:00:06 +08:00
2 changed files with 77 additions and 17 deletions

View File

@@ -261,7 +261,7 @@ impl MSCanvas {
self.pixels[index + 3] = color.a; // A self.pixels[index + 3] = color.a; // A
} }
fn draw_pixel_at1(&mut self, x: i32, y: i32) { fn draw_pixel_color_at1(&mut self, x: i32, y: i32, color: MSColor) {
// 边界检查 // 边界检查
if x < 0 || x >= self.width || y < 0 || y >= self.height { if x < 0 || x >= self.width || y < 0 || y >= self.height {
return; return;
@@ -271,10 +271,14 @@ impl MSCanvas {
// 写入 RGBA 数据 // 写入 RGBA 数据
// 注意Color 的 r, g, b, a 是 0.0 - 1.0,需要转为 0 - 255 // 注意Color 的 r, g, b, a 是 0.0 - 1.0,需要转为 0 - 255
self.pixels[index] = self.foreground_color.r; // R self.pixels[index] = color.r; // R
self.pixels[index + 1] = self.foreground_color.g; // G self.pixels[index + 1] = color.g; // G
self.pixels[index + 2] = self.foreground_color.b; // B self.pixels[index + 2] = color.b; // B
self.pixels[index + 3] = self.foreground_color.a; // A 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) { pub fn draw_pixel_row(&mut self, xs: i32, xe: i32, y: i32) {
@@ -525,7 +529,7 @@ impl MSCanvas {
(iter_count, fill_count) (iter_count, fill_count)
} }
pub fn fill_scanline(&mut self, begin: Point) -> (i32, i32) { fn fill_scanline_with_color(&mut self, begin: Point, color: MSColor) {
let start_x = begin.x as i32; let start_x = begin.x as i32;
let start_y = begin.y as i32; let start_y = begin.y as i32;
let width = self.width; let width = self.width;
@@ -533,22 +537,18 @@ impl MSCanvas {
// 边界检查 // 边界检查
if start_x < 0 || start_x >= width || start_y < 0 || start_y >= height { if start_x < 0 || start_x >= width || start_y < 0 || start_y >= height {
return (0, 0); return;
} }
let target_color = self.pixel_at(start_x, start_y); let target_color = self.pixel_at(start_x, start_y);
if target_color == (self.foreground_color) { if target_color == color {
return (0, 0); return;
} }
// 栈中存储 (y, x1, x2):表示第 y 行从 x1 到 x2需要向上/下扫描 // 栈中存储 (y, x1, x2):表示第 y 行从 x1 到 x2需要向上/下扫描
let mut stack = vec![(start_y, start_x, start_x)]; let mut stack = vec![(start_y, start_x, start_x)];
let mut iter_count = 0;
let mut fill_count = 0;
while let Some((y, mut lx, mut rx)) = stack.pop() { while let Some((y, mut lx, mut rx)) = stack.pop() {
iter_count += 1;
// 向左扩展 lx // 向左扩展 lx
while lx - 1 >= 0 && self.pixel_at(lx - 1, y) == target_color { while lx - 1 >= 0 && self.pixel_at(lx - 1, y) == target_color {
lx -= 1; lx -= 1;
@@ -560,8 +560,7 @@ impl MSCanvas {
// 填充当前行 [lx, rx] // 填充当前行 [lx, rx]
for x in lx..=rx { for x in lx..=rx {
self.draw_pixel_at1(x, y); self.draw_pixel_color_at1(x, y, color);
fill_count += 1;
} }
// 检查上一行 (y - 1) // 检查上一行 (y - 1)
@@ -598,8 +597,10 @@ impl MSCanvas {
} }
} }
} }
}
(iter_count, fill_count) pub fn fill_scanline(&mut self, begin: Point) {
self.fill_scanline_with_color(begin, self.foreground_color);
} }
pub fn arc_1px( pub fn arc_1px(
@@ -1074,6 +1075,65 @@ impl MSCanvas {
} }
} }
/// 填充一个椭圆
/// - 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]) { pub fn fill_polygon(&mut self, points: &[Point]) {
if points.len() < 3 { if points.len() < 3 {

View File

@@ -1003,7 +1003,7 @@ impl PaintApp {
if idx >= self.tool_states.len() { if idx >= self.tool_states.len() {
return; return;
} }
if self.tool_selected == Tool::Polygon { if self.tool_selected == Tool::Polygon && self.control_state != ControlState::Zero {
// 切换到其他工具,闭合路径 // 切换到其他工具,闭合路径
self.canvas.close_path(); self.canvas.close_path();
self.canvas.stroke(); self.canvas.stroke();