ellipse.rs - icy_draw - icy_draw is the successor to mystic draw. fork / mirror
(HTM) git clone https://git.drkhsh.at/icy_draw.git
(DIR) Log
(DIR) Files
(DIR) Refs
(DIR) README
(DIR) LICENSE
---
ellipse.rs (3118B)
---
1 use egui::ahash::HashSet;
2 use icy_engine::Position;
3 use icy_engine_egui::BufferView;
4
5 use super::{plot_point, BrushMode, ColorMode, PointRole};
6
7 fn get_ellipse_points(from: Position, to: Position) -> Vec<Position> {
8 let mut result = Vec::new();
9
10 let rx = (from.x - to.x).abs() / 2;
11 let ry = (from.y - to.y).abs() / 2;
12
13 let xc = (from.x + to.x) / 2;
14 let yc = (from.y + to.y) / 2;
15
16 let mut x = 0;
17 let mut y = ry;
18
19 let mut d1 = (ry * ry) - (rx * rx * ry) + (rx * rx) / 4;
20 let mut dx = 2 * ry * ry * x;
21 let mut dy = 2 * rx * rx * y;
22
23 while dx < dy {
24 result.push(Position::new(-x + xc, y + yc));
25 result.push(Position::new(x + xc, y + yc));
26 result.push(Position::new(-x + xc, -y + yc));
27 result.push(Position::new(x + xc, -y + yc));
28
29 if d1 < 0 {
30 x += 1;
31 dx += 2 * ry * ry;
32 d1 += dx + (ry * ry);
33 } else {
34 x += 1;
35 y -= 1;
36 dx += 2 * ry * ry;
37 dy -= 2 * rx * rx;
38 d1 += dx - dy + (ry * ry);
39 }
40 }
41
42 let mut d2 = ((ry * ry) * ((x/*+ 0.5f*/) * (x/*+ 0.5f*/))) + ((rx * rx) * ((y - 1) * (y - 1))) - (rx * rx * ry * ry);
43
44 while y >= 0 {
45 result.push(Position::new(-x + xc, y + yc));
46 result.push(Position::new(x + xc, y + yc));
47 result.push(Position::new(-x + xc, -y + yc));
48 result.push(Position::new(x + xc, -y + yc));
49 if d2 > 0 {
50 y -= 1;
51 dy -= 2 * rx * rx;
52 d2 += (rx * rx) - dy;
53 } else {
54 y -= 1;
55 x += 1;
56 dx += 2 * ry * ry;
57 dy -= 2 * rx * rx;
58 d2 += dx - dy + (rx * rx);
59 }
60 }
61 result
62 }
63
64 pub fn draw_ellipse(buffer_view: &mut BufferView, from: impl Into<Position>, to: impl Into<Position>, mode: BrushMode, color_mode: ColorMode) {
65 let mut from = from.into();
66 let mut to = to.into();
67 let mut y_mul = 1;
68 if !matches!(mode, BrushMode::HalfBlock) {
69 from.y /= 2;
70 to.y /= 2;
71 y_mul = 2;
72 }
73 let mut visited = HashSet::default();
74 for point in get_ellipse_points(from, to) {
75 let pos = (point.x, point.y * y_mul);
76 if visited.insert(pos) {
77 plot_point(buffer_view, pos, mode.clone(), color_mode, PointRole::Line);
78 }
79 }
80 }
81
82 pub fn fill_ellipse(buffer_view: &mut BufferView, from: impl Into<Position>, to: impl Into<Position>, mode: BrushMode, color_mode: ColorMode) {
83 let mut from = from.into();
84 let mut to = to.into();
85 let mut y_mul = 1;
86 if !matches!(mode, BrushMode::HalfBlock) {
87 from.y /= 2;
88 to.y /= 2;
89 y_mul = 2;
90 }
91 let points = get_ellipse_points(from, to);
92 let mut visited = HashSet::default();
93
94 for i in 0..points.len() / 2 {
95 let mut x1 = points[i * 2];
96 let x2 = points[i * 2 + 1];
97 if !visited.insert(x1.y) {
98 continue;
99 }
100
101 while x1.x < x2.x {
102 plot_point(buffer_view, (x1.x, x1.y * y_mul), mode.clone(), color_mode, PointRole::Line);
103
104 x1.x += 1;
105 }
106 }
107 }