Files
mspaint/src/mscanvas.rs

968 lines
29 KiB
Rust
Raw Normal View History

2026-02-26 19:38:34 +08:00
use iced::Point;
2026-02-28 14:32:39 +08:00
use rand::prelude::*;
2026-02-26 19:38:34 +08:00
#[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,
};
}
2026-02-28 18:29:32 +08:00
pub struct Path2D {
points: Vec<Point>,
}
impl Path2D {
pub fn new() -> Self {
Self { points: vec![] }
}
pub fn push(&mut self, point: Point) {
self.points.push(point);
}
}
2026-02-26 19:38:34 +08:00
pub struct MSCanvas {
width: i32,
height: i32,
2026-02-27 22:29:17 +08:00
/// 原始像素数据RGBA 格式
/// 长度 = width * height * 4
2026-02-26 19:38:34 +08:00
pixels: Vec<u8>,
pixels_bak: Vec<u8>,
2026-02-27 22:29:17 +08:00
/// 当前笔画颜色
2026-02-26 19:38:34 +08:00
color: MSColor,
2026-02-27 22:29:17 +08:00
line_width: i32,
2026-02-28 18:29:32 +08:00
path2d: Path2D,
2026-02-26 19:38:34 +08:00
}
#[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(),
color: MSColor::BLACK,
2026-02-27 22:29:17 +08:00
line_width: 1,
2026-02-28 18:29:32 +08:00
path2d: Path2D::new(),
2026-02-26 19:38:34 +08:00
}
}
pub fn set_color(&mut self, color: MSColor) {
self.color = color;
}
2026-02-27 22:29:17 +08:00
pub fn set_line_width(&mut self, line_width: i32) {
self.line_width = line_width;
2026-02-26 19:38:34 +08:00
}
}
#[allow(unused)]
impl MSCanvas {
2026-02-27 22:29:17 +08:00
pub fn size(&self) -> (i32, i32) {
(self.width, self.height)
}
2026-02-26 19:38:34 +08:00
pub fn get_pixels(&self) -> Vec<u8> {
self.pixels.clone()
}
2026-02-28 01:09:51 +08:00
pub fn get_pixels_scale(&self, scale: i32) -> Vec<u8> {
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
2026-02-28 01:09:51 +08:00
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
}
2026-02-26 19:38:34 +08:00
pub fn pixel_at(&self, x: i32, y: i32) -> MSColor {
// 边界检查
if x < 0 || x >= self.width || y < 0 || y >= self.height as i32 {
return MSColor::ZERO;
}
let index = ((y * self.width + x) * 4) as usize;
MSColor::new(
self.pixels[index],
self.pixels[index + 1],
self.pixels[index + 2],
self.pixels[index + 3],
)
}
pub fn draw_pixel_at(&mut self, point: Point) {
let Point { x, y } = point;
let x = x 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.color.r; // R
self.pixels[index + 1] = self.color.g; // G
self.pixels[index + 2] = self.color.b; // B
self.pixels[index + 3] = self.color.a; // A
}
2026-02-28 01:09:51 +08:00
pub fn draw_pixel_color_at(&mut self, point: Point, color: MSColor) {
let Point { x, y } = point;
let x = x 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] = color.r; // R
self.pixels[index + 1] = color.g; // G
self.pixels[index + 2] = color.b; // B
self.pixels[index + 3] = color.a; // A
}
2026-02-26 19:38:34 +08:00
fn draw_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.color.r; // R
self.pixels[index + 1] = self.color.g; // G
self.pixels[index + 2] = self.color.b; // B
self.pixels[index + 3] = self.color.a; // A
}
pub fn draw_pixel_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 as i32);
let y = y;
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] = self.color.r; // R
self.pixels[index + 1] = self.color.g; // G
self.pixels[index + 2] = self.color.b; // B
self.pixels[index + 3] = self.color.a; // A
}
}
pub fn draw_pixels(&mut self, points: Vec<Point>) {
for point in points {
self.draw_pixel_at(point);
}
}
2026-02-28 01:09:51 +08:00
pub fn draw_cross_color(&mut self, point: Point, color: MSColor) {
let Point { x, y } = point;
2026-03-01 17:38:11 +08:00
let r = 10;
2026-02-28 01:09:51 +08:00
for dy in -r..=r {
self.draw_pixel_color_at(Point::new(point.x, point.y + dy as f32), color);
}
for dx in -r..=r {
self.draw_pixel_color_at(Point::new(point.x + dx as f32, point.y), color);
}
}
2026-02-27 22:29:17 +08:00
pub fn brush_circle(&mut self, center: Point) {
if self.line_width <= 1 {
2026-02-26 19:38:34 +08:00
self.draw_pixel_at(center);
return;
}
2026-02-27 22:29:17 +08:00
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 {
2026-02-26 19:38:34 +08:00
if (dx * dx + dy * dy) as f32 <= square {
self.draw_pixel_at(Point::new(center.x + dx as f32, center.y + dy as f32));
}
}
}
}
2026-02-27 22:29:17 +08:00
pub fn brush_square(&mut self, center: Point) {
if self.line_width <= 1 {
self.draw_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.draw_pixel_at(Point::new(center.x + dx as f32, center.y + dy as f32));
}
}
}
2026-02-28 01:09:51 +08:00
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.draw_pixel_at(Point::new(
center.x - (d as f32) + (dx as f32),
center.y - d as f32,
));
}
2026-02-28 01:09:51 +08:00
}
}
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.draw_pixel_at(Point::new(
center.x + d as f32 + (dx as f32),
center.y - d as f32,
));
}
2026-02-28 01:09:51 +08:00
}
}
2026-02-26 19:38:34 +08:00
fn bresenham_line(&mut self, begin: Point, end: Point) -> Vec<Point> {
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.draw_pixel_at(point);
}
}
2026-02-27 22:29:17 +08:00
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<F>(&mut self, begin: Point, end: Point, brush_fn: F)
where
F: Fn(&mut MSCanvas, Point) -> (),
{
2026-02-26 19:38:34 +08:00
let points = self.bresenham_line(begin, end);
for point in points {
2026-02-27 22:29:17 +08:00
brush_fn(self, point);
2026-02-26 19:38:34 +08:00
}
}
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) -> (i32, i32) {
let start_x = begin.x as i32;
let start_y = begin.y as i32;
let target_color = self.pixel_at(start_x, start_y);
if target_color == self.color {
return (0, 0);
}
let mut scan_points = vec![(start_x, start_y)];
let width = self.width;
let height = self.height;
let mut iter_count = 0;
let mut fill_count = 0;
while let Some((x, y)) = scan_points.pop() {
iter_count += 1;
if x < 0 || x >= self.width || y < 0 || y >= self.height {
continue;
}
if self.pixel_at(x, y) == target_color {
self.draw_pixel_at1(x, y);
fill_count += 1;
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);
}
}
(iter_count, fill_count)
}
pub fn fill_scanline(&mut self, begin: Point) -> (i32, i32) {
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 (0, 0);
}
let target_color = self.pixel_at(start_x, start_y);
if target_color == (self.color) {
return (0, 0);
}
// 栈中存储 (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;
}
// 向右扩展 rx
while rx + 1 < width && self.pixel_at(rx + 1, y) == target_color {
rx += 1;
}
// 填充当前行 [lx, rx]
for x in lx..=rx {
self.draw_pixel_at1(x, y);
fill_count += 1;
}
// 检查上一行 (y - 1)
if y - 1 >= 0 {
let mut x = lx;
while x <= rx {
if self.pixel_at(x, y - 1) == target_color {
let span_start = x;
// 跳过连续的目标色块
while x <= rx && self.pixel_at(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_at(x, y + 1) == target_color {
let span_start = x;
while x <= rx && self.pixel_at(x, y + 1) == target_color {
x += 1;
}
stack.push((y + 1, span_start, x - 1));
} else {
x += 1;
}
}
}
}
(iter_count, fill_count)
}
2026-03-01 17:38:11 +08:00
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 是否逆时针方向
pub fn arc(
&mut self,
center: Point,
radius: f32,
start_angle: f32,
end_angle: f32,
counterclockwise: bool,
) {
if radius <= 1.0 {
self.draw_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 color = MSColor::new(
(255 + self.color.r) / 2,
self.color.g,
self.color.b,
self.color.a,
);
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.draw_pixel_at(Point::new(x as f32, y as f32));
}
}
}
}
2026-02-27 22:29:17 +08:00
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);
}
}
pub fn fill_rect(&mut self, x: i32, y: i32, width: i32, height: i32) {
for yi in y..(y + height) {
self.draw_pixel_row(x, x + width, yi);
}
}
2026-03-01 17:38:11 +08:00
pub fn 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;
}
self.fill_rect(
(x + radius) as i32,
y as i32,
(width - 2.0 * radius) as i32,
self.line_width,
);
self.fill_rect(
(x + radius) as i32,
(y + height) as i32 - self.line_width,
(width - 2.0 * radius) as i32,
self.line_width,
);
self.fill_rect(
x as i32,
(y + radius) as i32,
self.line_width,
(height - 2.0 * radius) as i32,
);
self.fill_rect(
(x + width) as i32 - self.line_width,
(y + radius) as i32,
self.line_width,
(height - 2.0 * radius) as i32,
);
self.arc(
Point::new(x + radius, y + radius),
radius,
std::f32::consts::PI,
std::f32::consts::PI + std::f32::consts::FRAC_PI_2,
false,
);
self.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.arc(
Point::new(x + radius, y + height - 1.0 - radius),
radius,
std::f32::consts::FRAC_PI_2,
std::f32::consts::PI,
false,
);
self.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 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.round_rect(x, y, width, height, radius);
}
2026-02-27 22:29:17 +08:00
pub fn stroke_rect(&mut self, x: i32, y: i32, width: i32, height: i32) {
2026-02-28 01:09:51 +08:00
if width < 2 * self.line_width || height < 2 * self.line_width {
self.fill_rect(x, y, width, height);
return;
}
2026-02-27 22:29:17 +08:00
self.fill_rect(x, y, width, self.line_width);
self.fill_rect(x, y + height - self.line_width, width, self.line_width);
self.fill_rect(x, y, self.line_width, height);
self.fill_rect(x + width - self.line_width, y, self.line_width, height);
2026-02-26 19:38:34 +08:00
}
2026-02-27 22:29:17 +08:00
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);
2026-02-26 19:38:34 +08:00
}
pub fn clear(&mut self) {
self.pixels.fill(255);
}
2026-02-27 22:29:17 +08:00
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 as i32);
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
}
}
2026-02-28 14:32:39 +08:00
/// 实现喷枪效果的函数
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.draw_pixel_at(point);
}
}
}
2026-02-28 16:17:17 +08:00
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<Point> = 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<Point>) {
// 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.001;
}
}
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);
}
2026-02-28 18:29:32 +08:00
2026-02-28 18:44:50 +08:00
pub fn ellipse(&mut self, center: Point, rx: f32, ry: f32) {
let mut x = 0.0;
let mut y = ry; // 初始时将y设置为半高
// 计算初始决策参数
let mut decision = ry * ry - rx * rx * ry + rx * rx / 4.0;
while ry * ry * x < rx * rx * y {
// 在每个阶段,根据对称性绘制四个方向上的点
self.draw_pixel_at(Point::new(center.x + x, center.y + y));
self.draw_pixel_at(Point::new(center.x - x, center.y + y));
self.draw_pixel_at(Point::new(center.x + x, center.y - y));
self.draw_pixel_at(Point::new(center.x - x, center.y - y));
if decision < 0.0 {
x += 1.0;
decision += 2.0 * ry * ry * x + ry * ry;
} else {
x += 1.0;
y -= 1.0;
decision += 2.0 * ry * ry * x - 2.0 * rx * rx * y + ry * ry;
}
}
decision =
ry * ry * (x + 0.5) * (x + 0.5) + rx * rx * (y - 1.0) * (y - 1.0) - rx * rx * ry * ry;
while y > 0.0 {
// 同样地,根据对称性绘制四个方向上的点
self.draw_pixel_at(Point::new(center.x + x, center.y + y));
self.draw_pixel_at(Point::new(center.x - x, center.y + y));
self.draw_pixel_at(Point::new(center.x + x, center.y - y));
self.draw_pixel_at(Point::new(center.x - x, center.y - y));
if decision > 0.0 {
y -= 1.0;
decision += rx * rx - 2.0 * rx * rx * y;
} else {
x += 1.0;
y -= 1.0;
decision += 2.0 * ry * ry * x - 2.0 * rx * rx * y + rx * rx;
}
}
}
pub fn 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.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.ellipse(center, rx, ry);
} else if ry < 0.0 {
ry = -ry;
let center = Point::new(p1.x + rx, p1.y - ry);
self.ellipse(center, rx, ry);
} else {
rx = -rx;
let center = Point::new(p1.x - rx, p1.y + ry);
self.ellipse(center, rx, ry);
}
}
2026-02-28 18:29:32 +08:00
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]);
}
}
2026-02-28 16:17:17 +08:00
}
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)
2026-02-26 19:38:34 +08:00
}
2026-03-01 17:38:11 +08:00
/// 将弧度规范到 [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
}