From 6139fc5c87ff4a5bbdcbfdb0c105a781270acdbc Mon Sep 17 00:00:00 2001 From: MacDue Date: Sat, 18 Jun 2022 01:40:24 +0100 Subject: [PATCH] LibGfx: Add AA dotted horizontal/vertical lines This adds simple dotted lines (horizontal/vertical only for now). There's a little number fudging added in to make sure the final dot is always drawn at the endpoint (for lines with at least a handful of dots). --- .../Libraries/LibGfx/AntiAliasingPainter.cpp | 44 +++++++++++++++++++ .../Libraries/LibGfx/AntiAliasingPainter.h | 2 + 2 files changed, 46 insertions(+) diff --git a/Userland/Libraries/LibGfx/AntiAliasingPainter.cpp b/Userland/Libraries/LibGfx/AntiAliasingPainter.cpp index 62a1d835ef..358e68803a 100644 --- a/Userland/Libraries/LibGfx/AntiAliasingPainter.cpp +++ b/Userland/Libraries/LibGfx/AntiAliasingPainter.cpp @@ -123,8 +123,52 @@ void Gfx::AntiAliasingPainter::draw_aliased_line(FloatPoint const& actual_from, draw_anti_aliased_line(actual_from, actual_to, color, thickness, style, alternate_color); } +void Gfx::AntiAliasingPainter::draw_dotted_line(IntPoint point1, IntPoint point2, Gfx::Color color, int thickness) +{ + // AA circles don't really work below a radius of 2px. + if (thickness < 4) + return m_underlying_painter.draw_line(point1, point2, color, thickness, Painter::LineStyle::Dotted); + + auto draw_spaced_dots = [&](int start, int end, auto to_point) { + int step = thickness * 2; + if (start > end) + swap(start, end); + int delta = end - start; + int dots = delta / step; + if (dots == 0) + return; + int fudge_per_dot = 0; + int extra_fudge = 0; + if (dots > 3) { + // Fudge the numbers so the last dot is drawn at the `end' point (otherwise you can get lines cuts short). + // You need at least a handful of dots to do this. + int fudge = delta % step; + fudge_per_dot = fudge / dots; + extra_fudge = fudge % dots; + } + for (int dot = start; dot <= end; dot += (step + fudge_per_dot + (extra_fudge > 0))) { + fill_circle(to_point(dot), thickness / 2, color); + --extra_fudge; + } + }; + + if (point1.y() == point2.y()) { + draw_spaced_dots(point1.x(), point2.x(), [&](int dot_x) { + return IntPoint { dot_x, point1.y() }; + }); + } else if (point1.x() == point2.x()) { + draw_spaced_dots(point1.y(), point2.y(), [&](int dot_y) { + return IntPoint { point1.x(), dot_y }; + }); + } else { + TODO(); + } +} + void Gfx::AntiAliasingPainter::draw_line(FloatPoint const& actual_from, FloatPoint const& actual_to, Color color, float thickness, Gfx::Painter::LineStyle style, Color alternate_color) { + if (style == Painter::LineStyle::Dotted) + return draw_dotted_line(actual_from.to_rounded(), actual_to.to_rounded(), color, static_cast(round(thickness))); draw_anti_aliased_line(actual_from, actual_to, color, thickness, style, alternate_color); } diff --git a/Userland/Libraries/LibGfx/AntiAliasingPainter.h b/Userland/Libraries/LibGfx/AntiAliasingPainter.h index 5ef372bf81..0dad8aab31 100644 --- a/Userland/Libraries/LibGfx/AntiAliasingPainter.h +++ b/Userland/Libraries/LibGfx/AntiAliasingPainter.h @@ -71,6 +71,8 @@ private: Range draw_ellipse_part(IntPoint a_rect, int radius_a, int radius_b, Color, bool flip_x_and_y, Optional x_clip, BlendMode blend_mode); + void draw_dotted_line(IntPoint, IntPoint, Gfx::Color, int thickness); + enum class AntiAliasPolicy { OnlyEnds, Full,