From d2372464a28d9ce8e6b78dc538c38759b54dddbb Mon Sep 17 00:00:00 2001 From: Lucas CHOLLET Date: Sun, 1 Jan 2023 15:55:57 +0100 Subject: [PATCH] LibGfx: Put the Midpoint Ellipse Algorithm in its own function --- Userland/Libraries/LibGfx/Painter.cpp | 101 ++++++++++++++------------ 1 file changed, 53 insertions(+), 48 deletions(-) diff --git a/Userland/Libraries/LibGfx/Painter.cpp b/Userland/Libraries/LibGfx/Painter.cpp index a8133e433b..f604804e4b 100644 --- a/Userland/Libraries/LibGfx/Painter.cpp +++ b/Userland/Libraries/LibGfx/Painter.cpp @@ -472,6 +472,55 @@ void Painter::draw_circle_arc_intersecting(IntRect const& a_rect, IntPoint cente return draw_circle_arc_intersecting(a_rect, center, radius - 1, color, thickness - 1); } +// The callback will only be called for a quarter of the ellipse, the user is intended to deduce other points. +// As the coordinate space is relative to the center of the rectangle, it's simply (x, y), (x, -y), (-x, y) and (-x, -y). +static void on_each_ellipse_point(IntRect const& rect, Function&& callback) +{ + // Note: This is an implementation of the Midpoint Ellipse Algorithm. + double const a = rect.width() / 2; + double const a_square = a * a; + double const b = rect.height() / 2; + double const b_square = b * b; + + int x = 0; + auto y = static_cast(b); + + double dx = 2 * b_square * x; + double dy = 2 * a_square * y; + + // For region 1: + auto decision_parameter = b_square - a_square * b + .25 * a_square; + + while (dx < dy) { + callback({ x, y }); + + if (decision_parameter >= 0) { + y--; + dy -= 2 * a_square; + decision_parameter -= dy; + } + x++; + dx += 2 * b_square; + decision_parameter += dx + b_square; + } + + // For region 2: + decision_parameter = b_square * ((x + 0.5) * (x + 0.5)) + a_square * ((y - 1) * (y - 1)) - a_square * b_square; + + while (y >= 0) { + callback({ x, y }); + + if (decision_parameter <= 0) { + x++; + dx += 2 * b_square; + decision_parameter += dx; + } + y--; + dy -= 2 * a_square; + decision_parameter += a_square - dy; + } +} + void Painter::fill_ellipse(IntRect const& a_rect, Color color) { VERIFY(scale() == 1); // FIXME: Add scaling support. @@ -498,57 +547,13 @@ void Painter::draw_ellipse_intersecting(IntRect const& rect, Color color, int th auto const center = rect.center(); - auto const draw_real_world_x4 = [this, &color, thickness, center](int x, int y) { - IntPoint const directions[4] = { { x, y }, { x, -y }, { -x, y }, { -x, -y } }; - for (auto const& delta : directions) { + on_each_ellipse_point(rect, [this, &color, thickness, center](IntPoint position) { + IntPoint const directions[4] = { { position.x(), position.y() }, { position.x(), -position.y() }, { -position.x(), position.y() }, { -position.x(), -position.y() } }; + for (auto const delta : directions) { auto const point = center + delta; draw_line(point, point, color, thickness); } - }; - - // Note: This is an implementation of the Midpoint Ellipse Algorithm: - double const a = rect.width() / 2; - double const a_square = a * a; - double const b = rect.height() / 2; - double const b_square = b * b; - - int x = 0; - auto y = static_cast(b); - - double dx = 2 * b_square * x; - double dy = 2 * a_square * y; - - // For region 1: - auto decision_parameter = b_square - a_square * b + .25 * a_square; - - while (dx < dy) { - draw_real_world_x4(x, y); - - if (decision_parameter >= 0) { - y--; - dy -= 2 * a_square; - decision_parameter -= dy; - } - x++; - dx += 2 * b_square; - decision_parameter += dx + b_square; - } - - // For region 2: - decision_parameter = b_square * ((x + 0.5) * (x + 0.5)) + a_square * ((y - 1) * (y - 1)) - a_square * b_square; - - while (y >= 0) { - draw_real_world_x4(x, y); - - if (decision_parameter <= 0) { - x++; - dx += 2 * b_square; - decision_parameter += dx; - } - y--; - dy -= 2 * a_square; - decision_parameter += a_square - dy; - } + }); } template