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 }