From 1d47d41c011b6413f7d5ea2225570c32bac64431 Mon Sep 17 00:00:00 2001 From: Mustafa Quraish Date: Mon, 13 Sep 2021 07:01:10 -0400 Subject: [PATCH] PixelPaint: Fix Line/Rectangle second paint alignment with pixels The problem was a bit more complex than originally anticipated, and the root of the problem is that the "coordinates" of a pixel are actually the top left of the pixel, and when we're really zoomed in, the difference in editor coordinates of the top-left and the center of the pixel is significant. So, we need to offset the "start" point when we are painting on the editor to account for this, based on the current scale. This patch adds a `editor_stroke_position` in `Tool` which can be used to compute what point (in editor coords) we should use for a given pixel and it's corresponding stroke thickness. Note that this doesn't really work well with the ellipse, since that is drawn with a different mechanism. Using this new method with the `EllipseTool` seems to give the same (or slightly worse) results, so I have not changed anything there for now. --- Userland/Applications/PixelPaint/LineTool.cpp | 4 ++-- Userland/Applications/PixelPaint/RectangleTool.cpp | 4 ++-- Userland/Applications/PixelPaint/Tool.cpp | 8 ++++++++ Userland/Applications/PixelPaint/Tool.h | 2 ++ 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/Userland/Applications/PixelPaint/LineTool.cpp b/Userland/Applications/PixelPaint/LineTool.cpp index fa47a00170..c6171be741 100644 --- a/Userland/Applications/PixelPaint/LineTool.cpp +++ b/Userland/Applications/PixelPaint/LineTool.cpp @@ -108,8 +108,8 @@ void LineTool::on_second_paint(Layer const* layer, GUI::PaintEvent& event) GUI::Painter painter(*m_editor); painter.add_clip_rect(event.rect()); - auto preview_start = m_editor->layer_position_to_editor_position(*layer, m_line_start_position).to_type(); - auto preview_end = m_editor->layer_position_to_editor_position(*layer, m_line_end_position).to_type(); + auto preview_start = editor_stroke_position(m_line_start_position, m_thickness); + auto preview_end = editor_stroke_position(m_line_end_position, m_thickness); painter.draw_line(preview_start, preview_end, m_editor->color_for(m_drawing_button), AK::max(m_thickness * m_editor->scale(), 1)); } diff --git a/Userland/Applications/PixelPaint/RectangleTool.cpp b/Userland/Applications/PixelPaint/RectangleTool.cpp index f19b123e31..9b0821afdf 100644 --- a/Userland/Applications/PixelPaint/RectangleTool.cpp +++ b/Userland/Applications/PixelPaint/RectangleTool.cpp @@ -106,8 +106,8 @@ void RectangleTool::on_second_paint(Layer const* layer, GUI::PaintEvent& event) GUI::Painter painter(*m_editor); painter.add_clip_rect(event.rect()); - auto start_position = m_editor->layer_position_to_editor_position(*layer, m_rectangle_start_position).to_type(); - auto end_position = m_editor->layer_position_to_editor_position(*layer, m_rectangle_end_position).to_type(); + auto start_position = editor_stroke_position(m_rectangle_start_position, m_thickness); + auto end_position = editor_stroke_position(m_rectangle_end_position, m_thickness); draw_using(painter, start_position, end_position, AK::max(m_thickness * m_editor->scale(), 1)); } diff --git a/Userland/Applications/PixelPaint/Tool.cpp b/Userland/Applications/PixelPaint/Tool.cpp index 0d747807b0..5c2255d2ce 100644 --- a/Userland/Applications/PixelPaint/Tool.cpp +++ b/Userland/Applications/PixelPaint/Tool.cpp @@ -53,4 +53,12 @@ void Tool::on_keydown(GUI::KeyEvent& event) } } +Gfx::IntPoint Tool::editor_stroke_position(Gfx::IntPoint const& pixel_coords, int stroke_thickness) const +{ + auto position = m_editor->image_position_to_editor_position(pixel_coords); + auto offset = (stroke_thickness % 2 == 0) ? m_editor->scale() : m_editor->scale() / 2; + position = position.translated(offset, offset); + return position.to_type(); +} + } diff --git a/Userland/Applications/PixelPaint/Tool.h b/Userland/Applications/PixelPaint/Tool.h index be2d783166..4e65271956 100644 --- a/Userland/Applications/PixelPaint/Tool.h +++ b/Userland/Applications/PixelPaint/Tool.h @@ -76,6 +76,8 @@ protected: WeakPtr m_editor; RefPtr m_action; + virtual Gfx::IntPoint editor_stroke_position(Gfx::IntPoint const& pixel_coords, int stroke_thickness) const; + void set_primary_slider(GUI::ValueSlider* primary) { m_primary_slider = primary; } void set_secondary_slider(GUI::ValueSlider* secondary) { m_secondary_slider = secondary; }