feat: 实现椭圆填充功能

This commit is contained in:
2026-03-03 01:28:48 +08:00
parent 1174019eff
commit 8ca7c52cb1

View File

@@ -261,7 +261,7 @@ impl MSCanvas {
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 {
return;
@@ -271,10 +271,14 @@ impl MSCanvas {
// 写入 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
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) {
@@ -525,7 +529,7 @@ impl MSCanvas {
(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_y = begin.y as i32;
let width = self.width;
@@ -533,22 +537,18 @@ impl MSCanvas {
// 边界检查
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);
if target_color == (self.foreground_color) {
return (0, 0);
if target_color == color {
return;
}
// 栈中存储 (y, x1, x2):表示第 y 行从 x1 到 x2需要向上/下扫描
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() {
iter_count += 1;
// 向左扩展 lx
while lx - 1 >= 0 && self.pixel_at(lx - 1, y) == target_color {
lx -= 1;
@@ -560,8 +560,7 @@ impl MSCanvas {
// 填充当前行 [lx, rx]
for x in lx..=rx {
self.draw_pixel_at1(x, y);
fill_count += 1;
self.draw_pixel_color_at1(x, y, color);
}
// 检查上一行 (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(
@@ -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]) {
if points.len() < 3 {