refactor: 重构 MSCanvas 颜色配置
This commit is contained in:
298
src/mscanvas.rs
298
src/mscanvas.rs
@@ -122,9 +122,8 @@ pub struct MSCanvas {
|
|||||||
pixels: Vec<u8>,
|
pixels: Vec<u8>,
|
||||||
pixels_bak: Vec<u8>,
|
pixels_bak: Vec<u8>,
|
||||||
|
|
||||||
/// 当前笔画颜色
|
fill_color: MSColor,
|
||||||
foreground_color: MSColor,
|
stroke_color: MSColor,
|
||||||
background_color: MSColor,
|
|
||||||
|
|
||||||
line_width: i32,
|
line_width: i32,
|
||||||
|
|
||||||
@@ -139,32 +138,32 @@ impl MSCanvas {
|
|||||||
height,
|
height,
|
||||||
pixels: vec![255; (width * height * 4) as usize],
|
pixels: vec![255; (width * height * 4) as usize],
|
||||||
pixels_bak: Vec::new(),
|
pixels_bak: Vec::new(),
|
||||||
foreground_color: MSColor::BLACK,
|
fill_color: MSColor::BLACK,
|
||||||
background_color: MSColor::WHITE,
|
stroke_color: MSColor::WHITE,
|
||||||
line_width: 1,
|
line_width: 1,
|
||||||
path2d: Path2D::new(),
|
path2d: Path2D::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_foreground_color(&mut self, color: MSColor) {
|
pub fn line_width(&mut self, line_width: i32) {
|
||||||
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;
|
self.line_width = line_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn fill_color(&mut self, color: MSColor) {
|
||||||
|
self.fill_color = color;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(unused)]
|
pub fn stroke_color(&mut self, color: MSColor) {
|
||||||
impl MSCanvas {
|
self.stroke_color = color;
|
||||||
|
}
|
||||||
pub fn size(&self) -> (i32, i32) {
|
pub fn size(&self) -> (i32, i32) {
|
||||||
(self.width, self.height)
|
(self.width, self.height)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_pixels_ref(&self) -> &[u8] {
|
||||||
|
&self.pixels
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_pixels(&self) -> Vec<u8> {
|
pub fn get_pixels(&self) -> Vec<u8> {
|
||||||
self.pixels.clone()
|
self.pixels.clone()
|
||||||
}
|
}
|
||||||
@@ -222,30 +221,21 @@ impl MSCanvas {
|
|||||||
self.pixels[index + 3],
|
self.pixels[index + 3],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn draw_pixel_at(&mut self, point: Point) {
|
#[allow(unused)]
|
||||||
|
impl MSCanvas {
|
||||||
|
pub fn fill_pixel_at(&mut self, point: Point) {
|
||||||
let Point { x, y } = point;
|
let Point { x, y } = point;
|
||||||
let x = x as i32;
|
self.fill_pixel_at1(x as i32, y 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) {
|
pub fn stroke_pixel_at(&mut self, point: Point) {
|
||||||
let Point { x, y } = point;
|
let Point { x, y } = point;
|
||||||
let x = x as i32;
|
self.stroke_pixel_at1(x as i32, y as i32);
|
||||||
let y = y as i32;
|
}
|
||||||
|
|
||||||
|
fn fill_pixel_at1(&mut self, x: i32, y: i32) {
|
||||||
// 边界检查
|
// 边界检查
|
||||||
if x < 0 || x >= self.width || y < 0 || y >= self.height {
|
if x < 0 || x >= self.width || y < 0 || y >= self.height {
|
||||||
return;
|
return;
|
||||||
@@ -255,13 +245,13 @@ 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] = color.r; // R
|
self.pixels[index] = self.fill_color.r; // R
|
||||||
self.pixels[index + 1] = color.g; // G
|
self.pixels[index + 1] = self.fill_color.g; // G
|
||||||
self.pixels[index + 2] = color.b; // B
|
self.pixels[index + 2] = self.fill_color.b; // B
|
||||||
self.pixels[index + 3] = color.a; // A
|
self.pixels[index + 3] = self.fill_color.a; // A
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_pixel_color_at1(&mut self, x: i32, y: i32, color: MSColor) {
|
fn stroke_pixel_at1(&mut self, x: i32, y: i32) {
|
||||||
// 边界检查
|
// 边界检查
|
||||||
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,60 +261,51 @@ 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] = color.r; // R
|
self.pixels[index] = self.stroke_color.r; // R
|
||||||
self.pixels[index + 1] = color.g; // G
|
self.pixels[index + 1] = self.stroke_color.g; // G
|
||||||
self.pixels[index + 2] = color.b; // B
|
self.pixels[index + 2] = self.stroke_color.b; // B
|
||||||
self.pixels[index + 3] = color.a; // A
|
self.pixels[index + 3] = self.stroke_color.a; // A
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_pixel_at1(&mut self, x: i32, y: i32) {
|
fn fill_row(&mut self, xs: i32, xe: 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 {
|
if y < 0 || y >= self.height {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let xs = xs.clamp(0, self.width - 1);
|
let xs = xs.clamp(0, self.width - 1);
|
||||||
let xe = xe.clamp(0, self.width as i32);
|
let xe = xe.clamp(0, self.width as i32);
|
||||||
let y = y;
|
|
||||||
for x in xs..xe {
|
for x in xs..xe {
|
||||||
let index = ((y * self.width + x) * 4) as usize;
|
let index = ((y * self.width + x) * 4) as usize;
|
||||||
|
|
||||||
// 写入 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] = color.r; // R
|
self.pixels[index] = self.fill_color.r; // R
|
||||||
self.pixels[index + 1] = color.g; // G
|
self.pixels[index + 1] = self.fill_color.g; // G
|
||||||
self.pixels[index + 2] = color.b; // B
|
self.pixels[index + 2] = self.fill_color.b; // B
|
||||||
self.pixels[index + 3] = color.a; // A
|
self.pixels[index + 3] = self.fill_color.a; // A
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_pixels(&mut self, points: Vec<Point>) {
|
pub fn fill_pixels(&mut self, points: Vec<Point>) {
|
||||||
for point in points {
|
for point in points {
|
||||||
self.draw_pixel_at(point);
|
self.fill_pixel_at(point);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn draw_cross_color(&mut self, point: Point, color: MSColor) {
|
pub fn stroke_cross_color(&mut self, point: Point) {
|
||||||
let Point { x, y } = point;
|
let Point { x, y } = point;
|
||||||
let r = 10;
|
let r = 10;
|
||||||
for dy in -r..=r {
|
for dy in -r..=r {
|
||||||
self.draw_pixel_color_at(Point::new(point.x, point.y + dy as f32), color);
|
self.stroke_pixel_at(Point::new(point.x, point.y + dy as f32));
|
||||||
}
|
}
|
||||||
for dx in -r..=r {
|
for dx in -r..=r {
|
||||||
self.draw_pixel_color_at(Point::new(point.x + dx as f32, point.y), color);
|
self.stroke_pixel_at(Point::new(point.x + dx as f32, point.y));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn brush_circle(&mut self, center: Point) {
|
pub fn brush_circle(&mut self, center: Point) {
|
||||||
if self.line_width <= 1 {
|
if self.line_width <= 1 {
|
||||||
self.draw_pixel_at(center);
|
self.fill_pixel_at(center);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let square = (self.line_width as f32) * (self.line_width as f32) / 4.0;
|
let square = (self.line_width as f32) * (self.line_width as f32) / 4.0;
|
||||||
@@ -333,7 +314,7 @@ impl MSCanvas {
|
|||||||
for dy in -l..r {
|
for dy in -l..r {
|
||||||
for dx in -l..r {
|
for dx in -l..r {
|
||||||
if (dx * dx + dy * dy) as f32 <= square {
|
if (dx * dx + dy * dy) as f32 <= square {
|
||||||
self.draw_pixel_at(Point::new(center.x + dx as f32, center.y + dy as f32));
|
self.fill_pixel_at(Point::new(center.x + dx as f32, center.y + dy as f32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -341,14 +322,14 @@ impl MSCanvas {
|
|||||||
|
|
||||||
pub fn brush_square(&mut self, center: Point) {
|
pub fn brush_square(&mut self, center: Point) {
|
||||||
if self.line_width <= 1 {
|
if self.line_width <= 1 {
|
||||||
self.draw_pixel_at(center);
|
self.fill_pixel_at(center);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let l = self.line_width / 2;
|
let l = self.line_width / 2;
|
||||||
let r = self.line_width - l;
|
let r = self.line_width - l;
|
||||||
for dy in -l..r {
|
for dy in -l..r {
|
||||||
for dx in -l..r {
|
for dx in -l..r {
|
||||||
self.draw_pixel_at(Point::new(center.x + dx as f32, center.y + dy as f32));
|
self.fill_pixel_at(Point::new(center.x + dx as f32, center.y + dy as f32));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -359,7 +340,7 @@ impl MSCanvas {
|
|||||||
// 左右扩展,填补线条的空白
|
// 左右扩展,填补线条的空白
|
||||||
for dx in 0..2 {
|
for dx in 0..2 {
|
||||||
for d in -l..r {
|
for d in -l..r {
|
||||||
self.draw_pixel_at(Point::new(
|
self.fill_pixel_at(Point::new(
|
||||||
center.x - (d as f32) + (dx as f32),
|
center.x - (d as f32) + (dx as f32),
|
||||||
center.y - d as f32,
|
center.y - d as f32,
|
||||||
));
|
));
|
||||||
@@ -373,7 +354,7 @@ impl MSCanvas {
|
|||||||
// 左右扩展,填补线条的空白
|
// 左右扩展,填补线条的空白
|
||||||
for dx in 0..2 {
|
for dx in 0..2 {
|
||||||
for d in -l..r {
|
for d in -l..r {
|
||||||
self.draw_pixel_at(Point::new(
|
self.fill_pixel_at(Point::new(
|
||||||
center.x + d as f32 + (dx as f32),
|
center.x + d as f32 + (dx as f32),
|
||||||
center.y - d as f32,
|
center.y - d as f32,
|
||||||
));
|
));
|
||||||
@@ -463,7 +444,7 @@ impl MSCanvas {
|
|||||||
pub fn draw_line(&mut self, begin: Point, end: Point) {
|
pub fn draw_line(&mut self, begin: Point, end: Point) {
|
||||||
let points = self.bresenham_line(begin, end);
|
let points = self.bresenham_line(begin, end);
|
||||||
for point in points {
|
for point in points {
|
||||||
self.draw_pixel_at(point);
|
self.fill_pixel_at(point);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -493,28 +474,23 @@ impl MSCanvas {
|
|||||||
self.pixels = self.pixels_bak.clone();
|
self.pixels = self.pixels_bak.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fill_slow(&mut self, begin: Point) -> (i32, i32) {
|
pub fn fill_slow(&mut self, begin: Point) {
|
||||||
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 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 == self.fill_color {
|
||||||
return (0, 0);
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut scan_points = vec![(start_x, start_y)];
|
let mut scan_points = vec![(start_x, start_y)];
|
||||||
let width = self.width;
|
let width = self.width;
|
||||||
let height = self.height;
|
let height = self.height;
|
||||||
let mut iter_count = 0;
|
|
||||||
let mut fill_count = 0;
|
|
||||||
while let Some((x, y)) = scan_points.pop() {
|
while let Some((x, y)) = scan_points.pop() {
|
||||||
iter_count += 1;
|
|
||||||
|
|
||||||
if x < 0 || x >= self.width || y < 0 || y >= self.height {
|
if x < 0 || x >= self.width || y < 0 || y >= self.height {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if self.pixel_at(x, y) == target_color {
|
if self.pixel_at(x, y) == target_color {
|
||||||
self.draw_pixel_at1(x, y);
|
self.fill_pixel_at1(x, y);
|
||||||
fill_count += 1;
|
|
||||||
|
|
||||||
let p1 = (x - 1, y);
|
let p1 = (x - 1, y);
|
||||||
let p2 = (x + 1, y);
|
let p2 = (x + 1, y);
|
||||||
@@ -526,10 +502,9 @@ impl MSCanvas {
|
|||||||
scan_points.push(p4);
|
scan_points.push(p4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(iter_count, fill_count)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fill_scanline_with_color(&mut self, begin: Point, color: MSColor) {
|
pub fn fill_scanline(&mut self, begin: Point) {
|
||||||
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;
|
||||||
@@ -541,7 +516,7 @@ impl MSCanvas {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let target_color = self.pixel_at(start_x, start_y);
|
let target_color = self.pixel_at(start_x, start_y);
|
||||||
if target_color == color {
|
if target_color == self.fill_color {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -560,7 +535,7 @@ impl MSCanvas {
|
|||||||
|
|
||||||
// 填充当前行 [lx, rx]
|
// 填充当前行 [lx, rx]
|
||||||
for x in lx..=rx {
|
for x in lx..=rx {
|
||||||
self.draw_pixel_color_at1(x, y, color);
|
self.fill_pixel_at1(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查上一行 (y - 1)
|
// 检查上一行 (y - 1)
|
||||||
@@ -599,61 +574,8 @@ impl MSCanvas {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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 是否逆时针方向
|
/// 圆弧从 x 轴方向开始计算, start_angle end_angle 为弧度,counterclockwise 是否逆时针方向
|
||||||
pub fn arc(
|
pub fn stroke_arc(
|
||||||
&mut self,
|
&mut self,
|
||||||
center: Point,
|
center: Point,
|
||||||
radius: f32,
|
radius: f32,
|
||||||
@@ -662,7 +584,7 @@ impl MSCanvas {
|
|||||||
counterclockwise: bool,
|
counterclockwise: bool,
|
||||||
) {
|
) {
|
||||||
if radius <= 1.0 {
|
if radius <= 1.0 {
|
||||||
self.draw_pixel_at(center);
|
self.fill_pixel_at(center);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -702,7 +624,7 @@ impl MSCanvas {
|
|||||||
|| (counterclockwise && (theta >= end_angle || theta <= start_angle))
|
|| (counterclockwise && (theta >= end_angle || theta <= start_angle))
|
||||||
|| (!counterclockwise && theta >= start_angle && theta <= end_angle)
|
|| (!counterclockwise && theta >= start_angle && theta <= end_angle)
|
||||||
{
|
{
|
||||||
self.draw_pixel_at(Point::new(x as f32, y as f32));
|
self.stroke_pixel_at1(x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -714,18 +636,19 @@ impl MSCanvas {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fill_rect_color(&mut self, x: i32, y: i32, width: i32, height: i32, color: MSColor) {
|
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) {
|
for yi in y..(y + height) {
|
||||||
self.draw_pixel_row_color(x, x + width, yi, color);
|
self.fill_row(x, x + width, yi);
|
||||||
}
|
}
|
||||||
}
|
self.fill_color(old_fill_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) {
|
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)
|
for yi in y..(y + height) {
|
||||||
|
self.fill_row(x, x + width, yi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 填充一个圆角矩形
|
/// 填充一个圆角矩形
|
||||||
@@ -769,12 +692,12 @@ impl MSCanvas {
|
|||||||
// 判断是否在“直边区域”(无需检查圆角)
|
// 判断是否在“直边区域”(无需检查圆角)
|
||||||
if px >= min_x + radius_int && px <= max_x - radius_int {
|
if px >= min_x + radius_int && px <= max_x - radius_int {
|
||||||
// 在左右圆角之间的竖直带 → 一定在内部
|
// 在左右圆角之间的竖直带 → 一定在内部
|
||||||
self.draw_pixel_at1(px, py);
|
self.fill_pixel_at1(px, py);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if py >= min_y + radius_int && py <= max_y - radius_int {
|
if py >= min_y + radius_int && py <= max_y - radius_int {
|
||||||
// 在上下圆角之间的水平带 → 一定在内部
|
// 在上下圆角之间的水平带 → 一定在内部
|
||||||
self.draw_pixel_at1(px, py);
|
self.fill_pixel_at1(px, py);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -790,7 +713,7 @@ impl MSCanvas {
|
|||||||
(distance_sq1((px, py), corners[3]) <= radius_sq);
|
(distance_sq1((px, py), corners[3]) <= radius_sq);
|
||||||
|
|
||||||
if in_corner {
|
if in_corner {
|
||||||
self.draw_pixel_at1(px, py);
|
self.fill_pixel_at1(px, py);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -816,63 +739,63 @@ impl MSCanvas {
|
|||||||
self.fill_round_rect(x, y, width, height, radius);
|
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) {
|
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
|
if (width as i32) < 2 * self.line_width
|
||||||
|| (height as i32) < 2 * self.line_width
|
|| (height as i32) < 2 * self.line_width
|
||||||
|| width < 2.0 * radius
|
|| width < 2.0 * radius
|
||||||
|| height < 2.0 * radius
|
|| height < 2.0 * radius
|
||||||
{
|
{
|
||||||
self.fill_rect(x as i32, y as i32, width as i32, height as i32);
|
self.fill_rect_stroke_color(x as i32, y as i32, width as i32, height as i32);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.fill_rect_foreground_color(
|
self.fill_rect_stroke_color(
|
||||||
(x + radius) as i32,
|
(x + radius) as i32,
|
||||||
y as i32,
|
y as i32,
|
||||||
(width - 2.0 * radius) as i32,
|
(width - 2.0 * radius) as i32,
|
||||||
self.line_width,
|
self.line_width,
|
||||||
);
|
);
|
||||||
self.fill_rect_foreground_color(
|
self.fill_rect_stroke_color(
|
||||||
(x + radius) as i32,
|
(x + radius) as i32,
|
||||||
(y + height) as i32 - self.line_width,
|
(y + height) as i32 - self.line_width,
|
||||||
(width - 2.0 * radius) as i32,
|
(width - 2.0 * radius) as i32,
|
||||||
self.line_width,
|
self.line_width,
|
||||||
);
|
);
|
||||||
self.fill_rect_foreground_color(
|
self.fill_rect_stroke_color(
|
||||||
x as i32,
|
x as i32,
|
||||||
(y + radius) as i32,
|
(y + radius) as i32,
|
||||||
self.line_width,
|
self.line_width,
|
||||||
(height - 2.0 * radius) as i32,
|
(height - 2.0 * radius) as i32,
|
||||||
);
|
);
|
||||||
self.fill_rect_foreground_color(
|
self.fill_rect_stroke_color(
|
||||||
(x + width) as i32 - self.line_width,
|
(x + width) as i32 - self.line_width,
|
||||||
(y + radius) as i32,
|
(y + radius) as i32,
|
||||||
self.line_width,
|
self.line_width,
|
||||||
(height - 2.0 * radius) as i32,
|
(height - 2.0 * radius) as i32,
|
||||||
);
|
);
|
||||||
|
|
||||||
self.arc(
|
self.stroke_arc(
|
||||||
Point::new(x + radius, y + radius),
|
Point::new(x + radius, y + radius),
|
||||||
radius,
|
radius,
|
||||||
std::f32::consts::PI,
|
std::f32::consts::PI,
|
||||||
std::f32::consts::PI + std::f32::consts::FRAC_PI_2,
|
std::f32::consts::PI + std::f32::consts::FRAC_PI_2,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
self.arc(
|
self.stroke_arc(
|
||||||
Point::new(x + width - 1.0 - radius, y + radius),
|
Point::new(x + width - 1.0 - radius, y + radius),
|
||||||
radius,
|
radius,
|
||||||
0.0,
|
0.0,
|
||||||
std::f32::consts::PI + std::f32::consts::FRAC_PI_2,
|
std::f32::consts::PI + std::f32::consts::FRAC_PI_2,
|
||||||
true,
|
true,
|
||||||
);
|
);
|
||||||
self.arc(
|
self.stroke_arc(
|
||||||
Point::new(x + radius, y + height - 1.0 - radius),
|
Point::new(x + radius, y + height - 1.0 - radius),
|
||||||
radius,
|
radius,
|
||||||
std::f32::consts::FRAC_PI_2,
|
std::f32::consts::FRAC_PI_2,
|
||||||
std::f32::consts::PI,
|
std::f32::consts::PI,
|
||||||
false,
|
false,
|
||||||
);
|
);
|
||||||
self.arc(
|
self.stroke_arc(
|
||||||
Point::new(x + width - 1.0 - radius, y + height - 1.0 - radius),
|
Point::new(x + width - 1.0 - radius, y + height - 1.0 - radius),
|
||||||
radius,
|
radius,
|
||||||
0.0,
|
0.0,
|
||||||
@@ -881,7 +804,7 @@ impl MSCanvas {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn round_rect1(&mut self, p1: Point, p2: Point, radius: f32) {
|
pub fn stroke_round_rect1(&mut self, p1: Point, p2: Point, radius: f32) {
|
||||||
let mut x = p1.x;
|
let mut x = p1.x;
|
||||||
let mut y = p1.y;
|
let mut y = p1.y;
|
||||||
let mut width = (p2.x - p1.x);
|
let mut width = (p2.x - p1.x);
|
||||||
@@ -898,21 +821,21 @@ impl MSCanvas {
|
|||||||
y += height;
|
y += height;
|
||||||
height = -height;
|
height = -height;
|
||||||
}
|
}
|
||||||
self.round_rect(x, y, width, height, radius);
|
self.stroke_round_rect(x, y, width, height, radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rect(&mut self, x: i32, y: i32, width: i32, height: i32) {
|
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 {
|
if width < 2 * self.line_width || height < 2 * self.line_width {
|
||||||
self.fill_rect_foreground_color(x, y, width, height);
|
self.fill_rect_stroke_color(x, y, width, height);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
self.fill_rect_foreground_color(x, y, width, self.line_width);
|
self.fill_rect_stroke_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_stroke_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_stroke_color(x, y, self.line_width, height);
|
||||||
self.fill_rect_foreground_color(x + width - self.line_width, y, self.line_width, height);
|
self.fill_rect_stroke_color(x + width - self.line_width, y, self.line_width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rect1(&mut self, p1: Point, p2: Point) {
|
pub fn stroke_rect1(&mut self, p1: Point, p2: Point) {
|
||||||
let mut x = p1.x;
|
let mut x = p1.x;
|
||||||
let mut y = p1.y;
|
let mut y = p1.y;
|
||||||
let mut width = (p2.x - p1.x);
|
let mut width = (p2.x - p1.x);
|
||||||
@@ -929,7 +852,7 @@ impl MSCanvas {
|
|||||||
y += height;
|
y += height;
|
||||||
height = -height;
|
height = -height;
|
||||||
}
|
}
|
||||||
self.rect(x as i32, y as i32, width as i32, height as i32);
|
self.stroke_rect(x as i32, y as i32, width as i32, height as i32);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
@@ -967,7 +890,7 @@ impl MSCanvas {
|
|||||||
// 确保我们只在圆形区域内绘制,而非整个正方形区域
|
// 确保我们只在圆形区域内绘制,而非整个正方形区域
|
||||||
if (offset_x * offset_x + offset_y * offset_y) <= (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);
|
let point = Point::new(center.x + offset_x as f32, center.y + offset_y as f32);
|
||||||
self.draw_pixel_at(point);
|
self.fill_pixel_at(point);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1008,7 +931,7 @@ impl MSCanvas {
|
|||||||
self.bezier(points);
|
self.bezier(points);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ellipse(&mut self, center: Point, rx: f32, ry: f32) {
|
pub fn stroke_ellipse(&mut self, center: Point, rx: f32, ry: f32) {
|
||||||
let mut x = 0.0;
|
let mut x = 0.0;
|
||||||
let mut y = ry; // 初始时将y设置为半高
|
let mut y = ry; // 初始时将y设置为半高
|
||||||
|
|
||||||
@@ -1017,10 +940,10 @@ impl MSCanvas {
|
|||||||
|
|
||||||
while ry * ry * x < rx * rx * y {
|
while ry * ry * x < rx * rx * y {
|
||||||
// 在每个阶段,根据对称性绘制四个方向上的点
|
// 在每个阶段,根据对称性绘制四个方向上的点
|
||||||
self.draw_pixel_at(Point::new(center.x + x, center.y + y));
|
self.stroke_pixel_at(Point::new(center.x + x, center.y + y));
|
||||||
self.draw_pixel_at(Point::new(center.x - x, center.y + y));
|
self.stroke_pixel_at(Point::new(center.x - x, center.y + y));
|
||||||
self.draw_pixel_at(Point::new(center.x + x, center.y - y));
|
self.stroke_pixel_at(Point::new(center.x + x, center.y - y));
|
||||||
self.draw_pixel_at(Point::new(center.x - x, center.y - y));
|
self.stroke_pixel_at(Point::new(center.x - x, center.y - y));
|
||||||
|
|
||||||
if decision < 0.0 {
|
if decision < 0.0 {
|
||||||
x += 1.0;
|
x += 1.0;
|
||||||
@@ -1037,10 +960,10 @@ impl MSCanvas {
|
|||||||
|
|
||||||
while y > 0.0 {
|
while y > 0.0 {
|
||||||
// 同样地,根据对称性绘制四个方向上的点
|
// 同样地,根据对称性绘制四个方向上的点
|
||||||
self.draw_pixel_at(Point::new(center.x + x, center.y + y));
|
self.stroke_pixel_at(Point::new(center.x + x, center.y + y));
|
||||||
self.draw_pixel_at(Point::new(center.x - x, center.y + y));
|
self.stroke_pixel_at(Point::new(center.x - x, center.y + y));
|
||||||
self.draw_pixel_at(Point::new(center.x + x, center.y - y));
|
self.stroke_pixel_at(Point::new(center.x + x, center.y - y));
|
||||||
self.draw_pixel_at(Point::new(center.x - x, center.y - y));
|
self.stroke_pixel_at(Point::new(center.x - x, center.y - y));
|
||||||
|
|
||||||
if decision > 0.0 {
|
if decision > 0.0 {
|
||||||
y -= 1.0;
|
y -= 1.0;
|
||||||
@@ -1053,25 +976,25 @@ impl MSCanvas {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ellipse1(&mut self, p1: Point, p2: Point) {
|
pub fn stroke_ellipse1(&mut self, p1: Point, p2: Point) {
|
||||||
let mut rx = (p2.x - p1.x) / 2.0;
|
let mut rx = (p2.x - p1.x) / 2.0;
|
||||||
let mut ry = (p2.y - p1.y) / 2.0;
|
let mut ry = (p2.y - p1.y) / 2.0;
|
||||||
if rx > 0.0 && ry > 0.0 {
|
if rx > 0.0 && ry > 0.0 {
|
||||||
let center = Point::new(p1.x + rx, p1.y + ry);
|
let center = Point::new(p1.x + rx, p1.y + ry);
|
||||||
self.ellipse(center, rx, ry);
|
self.stroke_ellipse(center, rx, ry);
|
||||||
} else if rx < 0.0 && ry < 0.0 {
|
} else if rx < 0.0 && ry < 0.0 {
|
||||||
rx = -rx;
|
rx = -rx;
|
||||||
ry = -ry;
|
ry = -ry;
|
||||||
let center = Point::new(p1.x - rx, p1.y - ry);
|
let center = Point::new(p1.x - rx, p1.y - ry);
|
||||||
self.ellipse(center, rx, ry);
|
self.stroke_ellipse(center, rx, ry);
|
||||||
} else if ry < 0.0 {
|
} else if ry < 0.0 {
|
||||||
ry = -ry;
|
ry = -ry;
|
||||||
let center = Point::new(p1.x + rx, p1.y - ry);
|
let center = Point::new(p1.x + rx, p1.y - ry);
|
||||||
self.ellipse(center, rx, ry);
|
self.stroke_ellipse(center, rx, ry);
|
||||||
} else {
|
} else {
|
||||||
rx = -rx;
|
rx = -rx;
|
||||||
let center = Point::new(p1.x - rx, p1.y + ry);
|
let center = Point::new(p1.x - rx, p1.y + ry);
|
||||||
self.ellipse(center, rx, ry);
|
self.stroke_ellipse(center, rx, ry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1106,7 +1029,7 @@ impl MSCanvas {
|
|||||||
// 判断是否在椭圆内:dx²/ rx² + dy²/ ry² <= 1
|
// 判断是否在椭圆内:dx²/ rx² + dy²/ ry² <= 1
|
||||||
// 等价于:dx² * ry² + dy² * rx² <= rx² * ry²
|
// 等价于:dx² * ry² + dy² * rx² <= rx² * ry²
|
||||||
if dx * dx * ry2 + dy * dy * rx2 <= rxy2 {
|
if dx * dx * ry2 + dy * dy * rx2 <= rxy2 {
|
||||||
self.draw_pixel_color_at1(x, y, self.background_color);
|
self.fill_pixel_at1(x, y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1184,10 +1107,7 @@ impl MSCanvas {
|
|||||||
let x_start = active_edges[i].x.ceil() as i32;
|
let x_start = active_edges[i].x.ceil() as i32;
|
||||||
let x_end = active_edges[i + 1].x.floor() as i32;
|
let x_end = active_edges[i + 1].x.floor() as i32;
|
||||||
for x in x_start..=x_end {
|
for x in x_start..=x_end {
|
||||||
self.draw_pixel_color_at(
|
self.fill_pixel_at1(x, y);
|
||||||
Point::new(x as f32, y as f32),
|
|
||||||
self.background_color,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
37
src/paint.rs
37
src/paint.rs
@@ -291,12 +291,11 @@ impl PaintApp {
|
|||||||
// region iced application
|
// region iced application
|
||||||
|
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
let mut canvas = MSCanvas::new(WIDTH as i32, HEIGHT as i32);
|
let canvas = MSCanvas::new(WIDTH as i32, HEIGHT as i32);
|
||||||
let (width, height) = canvas.size();
|
let (width, height) = canvas.size();
|
||||||
let pixels = canvas.get_pixels();
|
let pixels = canvas.get_pixels();
|
||||||
let config = Config::default();
|
|
||||||
canvas.set_line_width(config.line_width);
|
let mut ins = Self {
|
||||||
Self {
|
|
||||||
tool_states: [false; Tool::Count as usize],
|
tool_states: [false; Tool::Count as usize],
|
||||||
tool_selected: Tool::Count,
|
tool_selected: Tool::Count,
|
||||||
canvas,
|
canvas,
|
||||||
@@ -307,11 +306,17 @@ impl PaintApp {
|
|||||||
control_points: Vec::with_capacity(2),
|
control_points: Vec::with_capacity(2),
|
||||||
image_handle: image::Handle::from_rgba(width as u32, height as u32, pixels),
|
image_handle: image::Handle::from_rgba(width as u32, height as u32, pixels),
|
||||||
dirty: false,
|
dirty: false,
|
||||||
config,
|
config: Config::default(),
|
||||||
brush_selected: None,
|
brush_selected: None,
|
||||||
foreground_color: MSColor::BLACK,
|
foreground_color: MSColor::BLACK,
|
||||||
background_color: MSColor::WHITE,
|
background_color: MSColor::WHITE,
|
||||||
}
|
};
|
||||||
|
|
||||||
|
ins.canvas.fill_color(ins.foreground_color);
|
||||||
|
ins.canvas.stroke_color(ins.foreground_color);
|
||||||
|
ins.canvas.line_width(ins.config.line_width);
|
||||||
|
|
||||||
|
ins
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn view(&self) -> Column<'_, Message> {
|
pub fn view(&self) -> Column<'_, Message> {
|
||||||
@@ -577,13 +582,13 @@ impl PaintApp {
|
|||||||
Message::Increment(opt) => {
|
Message::Increment(opt) => {
|
||||||
self.config.incr(opt, 1);
|
self.config.incr(opt, 1);
|
||||||
if opt == ConfigOption::LineWidth {
|
if opt == ConfigOption::LineWidth {
|
||||||
self.canvas.set_line_width(self.config.line_width);
|
self.canvas.line_width(self.config.line_width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::Decrement(opt) => {
|
Message::Decrement(opt) => {
|
||||||
self.config.incr(opt, -1);
|
self.config.incr(opt, -1);
|
||||||
if opt == ConfigOption::LineWidth {
|
if opt == ConfigOption::LineWidth {
|
||||||
self.canvas.set_line_width(self.config.line_width);
|
self.canvas.line_width(self.config.line_width);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Message::BrushSelected(kind) => {
|
Message::BrushSelected(kind) => {
|
||||||
@@ -605,18 +610,18 @@ impl PaintApp {
|
|||||||
}
|
}
|
||||||
Message::ClickForegroundColor(color) => {
|
Message::ClickForegroundColor(color) => {
|
||||||
self.foreground_color = color;
|
self.foreground_color = color;
|
||||||
self.canvas.set_foreground_color(color);
|
self.canvas.stroke_color(color);
|
||||||
|
self.canvas.fill_color(color);
|
||||||
}
|
}
|
||||||
Message::ClickBackgroundColor(color) => {
|
Message::ClickBackgroundColor(color) => {
|
||||||
self.background_color = color;
|
self.background_color = color;
|
||||||
self.canvas.set_background_color(color);
|
|
||||||
}
|
}
|
||||||
Message::SwapForeBackColor => {
|
Message::SwapForeBackColor => {
|
||||||
let tmp = self.foreground_color;
|
let tmp = self.foreground_color;
|
||||||
self.foreground_color = self.background_color;
|
self.foreground_color = self.background_color;
|
||||||
self.background_color = tmp;
|
self.background_color = tmp;
|
||||||
self.canvas.set_foreground_color(self.foreground_color);
|
self.canvas.stroke_color(self.foreground_color);
|
||||||
self.canvas.set_background_color(self.background_color);
|
self.canvas.fill_color(self.foreground_color);
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
@@ -692,7 +697,7 @@ impl PaintApp {
|
|||||||
match message {
|
match message {
|
||||||
Message::MousePressed(pos) => {
|
Message::MousePressed(pos) => {
|
||||||
self.is_drawing = true;
|
self.is_drawing = true;
|
||||||
self.canvas.draw_pixel_at(pos);
|
self.canvas.fill_pixel_at(pos);
|
||||||
self.begin_point = pos;
|
self.begin_point = pos;
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
}
|
}
|
||||||
@@ -894,7 +899,7 @@ impl PaintApp {
|
|||||||
Message::MouseMoved(pos) => {
|
Message::MouseMoved(pos) => {
|
||||||
if self.is_drawing {
|
if self.is_drawing {
|
||||||
self.canvas.restore_pixels();
|
self.canvas.restore_pixels();
|
||||||
self.canvas.rect1(self.begin_point, pos);
|
self.canvas.stroke_rect1(self.begin_point, pos);
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -962,7 +967,7 @@ impl PaintApp {
|
|||||||
Message::MouseMoved(pos) => {
|
Message::MouseMoved(pos) => {
|
||||||
if self.is_drawing {
|
if self.is_drawing {
|
||||||
self.canvas.restore_pixels();
|
self.canvas.restore_pixels();
|
||||||
self.canvas.ellipse1(self.begin_point, pos);
|
self.canvas.stroke_ellipse1(self.begin_point, pos);
|
||||||
self.dirty = true;
|
self.dirty = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -984,7 +989,7 @@ impl PaintApp {
|
|||||||
Message::MouseMoved(pos) => {
|
Message::MouseMoved(pos) => {
|
||||||
if self.is_drawing {
|
if self.is_drawing {
|
||||||
self.canvas.restore_pixels();
|
self.canvas.restore_pixels();
|
||||||
self.canvas.round_rect1(
|
self.canvas.stroke_round_rect1(
|
||||||
self.begin_point,
|
self.begin_point,
|
||||||
pos,
|
pos,
|
||||||
self.config.rounded_radius as f32,
|
self.config.rounded_radius as f32,
|
||||||
|
|||||||
Reference in New Issue
Block a user