feat: 实现椭圆填充功能
This commit is contained in:
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user