From 16aa3b4aa138a6b1d01ee1753ce50df006b3a724 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Capello?= Date: Mon, 1 Sep 2025 17:41:05 -0300 Subject: [PATCH] Add rounded rectangle support (fix #2184) --- data/extensions/aseprite-theme/dark/sheet.png | Bin 17067 -> 17103 bytes data/extensions/aseprite-theme/dark/theme.xml | 1 + data/extensions/aseprite-theme/sheet.png | Bin 16183 -> 16209 bytes data/extensions/aseprite-theme/theme.xml | 1 + data/gui.xml | 2 + data/strings/en.ini | 1 + src/app/tools/controller.h | 4 + src/app/tools/controllers.h | 30 ++- src/app/tools/intertwine.cpp | 18 ++ src/app/tools/intertwine.h | 5 + src/app/tools/intertwiners.h | 142 ++++++++++++-- src/app/tools/tool_loop_modifiers.h | 3 +- src/app/ui/editor/editor.cpp | 4 +- src/app/ui/key.cpp | 5 + src/app/ui/key.h | 1 + src/doc/algo.cpp | 178 ++++++++++++++++++ src/doc/algo.h | 6 + 17 files changed, 384 insertions(+), 17 deletions(-) diff --git a/data/extensions/aseprite-theme/dark/sheet.png b/data/extensions/aseprite-theme/dark/sheet.png index 02bf218ac3d35c7ffa9b0a76ac053f6ecde7475b..c341df7e3502cc03863add267356f5f4aa1517af 100644 GIT binary patch delta 15970 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 delta 15968 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�y zjoeD|uGd+a$?t#9LnXIPUdcBsRni(QACoPg+gljibMEdk6Frt!u>5&tb|zg=6X+yQh5-B#kWD}Kta4z`vlj8=b?u$!#0D)Hrj1>87pw(<%ds+9M&PC8Ull6N>vt& z-2O7s`2CDb`E=2gsb>96Y;V-0nDtx|^m=}G!v2NWK6b{|`roF#o3zQz%&dF)m<7$u zOnN%OX-Wiv(s?ZKb|>=s@3X9PJfK05MkED}8REn|sw8}zvU_}Tu-2ZrXkv1)tRz-z z42X=6sUpn*82s64W$Yjmk>*olySfk)S>dd61q@;n@;=z@5LzJdIl)x~<~&&*qBd-# z&BfpZr8K>i~ddL_FPEL7$1>{G>=iyV{|V^fN>?wfbo=CRv!HI~6M zzcl3jKm}?=?i`Ag${rEM>W6V=S`#JO#_;Mvc>s zah^Gt#Uv>K{d5T*M1}P6`G)%8+KUJH-5C}>+cWj*oW?)?Z9{Q&=V{aZzSl6qKr+5=y5ueM~X>QEs^yn=Ji0 zxU>1j7Y*!qht@3M6N~LCzq1uE*Rv{c%L?*0y(Eaj|Hk;%`{m=ns{WGeU}Chq$iV0a-Z$|pQ@&5+dX0%Y4q&SSfJ!b_c|m>*Jb;%^4>9gEyXXu#${R$zbM7e zn*Ysm+(UVyOTXq*`#O!wm{^GNA~V2JmOwGDMrA@dZc$+@$n*Y}+du zU&b9g&pbU5p;JDV2v4@O9tZ=xqPS=bjh?W!2`f5`;qpDnPYE01nZeX|8qGvwuE~&Y z75L;U2@C6crlv{~u#rlG_qQgVgTtZ7_4wy`T(`M+cE82;#Bg3dKEhiKH1;K0rWhlt z)Vm7U6hu5gt$>^?UAik-lHx%|;<$T>aken^LYkg*`CU|80~C8rH;x&`^ z8&{+ra=W3Jf8#s@s>nJn8Z>KUG!t*|H88)Gsn?^hjrR$KG1g{bSrVEsd=bLV>;=CD zBiyk907?wR8C&!h{jroiB5Ez8`>FSrzs1x@9Tb1<{_P6x&aPPC;V}rb{#)Y7X6l?q z=IXP~yV_QnjPvMcRNAg<29eEAamo%mpGBm3gBf?lmY= z`k!+D2F>#4lJw#~mk+Yux a8Ks&#H%V9>2gti1keZT~VvW3I$o~Vlbi+9S diff --git a/data/extensions/aseprite-theme/dark/theme.xml b/data/extensions/aseprite-theme/dark/theme.xml index 434f2f7f4..5bd717f82 100644 --- a/data/extensions/aseprite-theme/dark/theme.xml +++ b/data/extensions/aseprite-theme/dark/theme.xml @@ -393,6 +393,7 @@ + diff --git a/data/extensions/aseprite-theme/sheet.png b/data/extensions/aseprite-theme/sheet.png index cf1bc6157e0f857f0ae9a2fc25c0e903723d6c9a..ce3647b7457f0c7a123b6328769b7624092770a6 100644 GIT binary patch delta 16075 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 + diff --git a/data/gui.xml b/data/gui.xml index 607be08c8..3f2a3be7b 100644 --- a/data/gui.xml +++ b/data/gui.xml @@ -678,6 +678,8 @@ + + diff --git a/data/strings/en.ini b/data/strings/en.ini index 0f9fc746b..380bf6ffe 100644 --- a/data/strings/en.ini +++ b/data/strings/en.ini @@ -1006,6 +1006,7 @@ move_origin = Move Origin square_aspect = Square Aspect draw_from_center = Draw From Center rotate_shape = Rotate Shape +corner_radius = Corner Radius trigger_left_mouse_button = Trigger Left Mouse Button trigger_right_mouse_button = Trigger Right Mouse Button ok = &OK diff --git a/src/app/tools/controller.h b/src/app/tools/controller.h index bf546367d..bb9587819 100644 --- a/src/app/tools/controller.h +++ b/src/app/tools/controller.h @@ -62,6 +62,10 @@ public: // Returns the angle for a shape-like intertwiner (rectangles, // ellipses, etc.). virtual double getShapeAngle() const { return 0.0; } + + // Returns the radius for each corner for a rectangle intertwiner when drawing + // rounded rectangles. + virtual int getCornerRadius() const { return 0; } }; }} // namespace app::tools diff --git a/src/app/tools/controllers.h b/src/app/tools/controllers.h index 1624db87e..feffc5a33 100644 --- a/src/app/tools/controllers.h +++ b/src/app/tools/controllers.h @@ -1,11 +1,15 @@ // Aseprite -// Copyright (C) 2019-2023 Igara Studio S.A. +// Copyright (C) 2019-2025 Igara Studio S.A. // Copyright (C) 2001-2018 David Capello // // This program is distributed under the terms of // the End-User License Agreement for Aseprite. #include "app/snap_to_grid.h" +#include "app/tools/controller.h" +#include "app/tools/intertwine.h" +#include "app/tools/tool_loop.h" +#include "app/tools/tool_loop_modifiers.h" #include "base/gcd.h" #include "base/pi.h" #include "fmt/format.h" @@ -135,6 +139,12 @@ public: if (MoveOriginCapability::isMovingOrigin(loop, stroke, pt)) return; + if ((int(loop->getModifiers()) & int(ToolLoopModifiers::kCornerRadius))) { + int dr = stroke[1].y - pt.y; + m_cornerRadius = ABS(m_lastCornerRadius + dr); + return; + } + if (!loop->getIntertwine()->snapByAngle() && int(loop->getModifiers()) & int(ToolLoopModifiers::kRotateShape)) { if ((int(loop->getModifiers()) & int(ToolLoopModifiers::kFromCenter))) { @@ -149,8 +159,13 @@ public: return; } - stroke[0] = m_first; - stroke[1] = pt; + if (m_lastCornerRadius != m_cornerRadius) { + m_lastCornerRadius = m_cornerRadius; + } + else { + stroke[0] = m_first; + stroke[1] = pt; + } bool isoAngle = false; @@ -277,11 +292,16 @@ public: text += fmt::format(" :angle: {:.1f}", 180.0 * angle / PI); } + if (hasCornerRadius()) { + text += fmt::format(" :corner_radius: {}", m_cornerRadius); + } + // Aspect ratio at the end text += fmt::format(" :aspect_ratio: {}:{}", w / gcd, h / gcd); } double getShapeAngle() const override { return m_angle; } + int getCornerRadius() const override { return m_cornerRadius; } private: void snapPointsToGridTiles(ToolLoop* loop, Stroke& stroke) @@ -301,6 +321,8 @@ private: bool hasAngle() const { return (ABS(m_angle) > 0.001); } + bool hasCornerRadius() const { return (ABS(m_cornerRadius) > 1); } + void onMoveOrigin(const Point& delta) override { m_first.x += delta.x; @@ -312,6 +334,8 @@ private: Stroke::Pt m_first; Stroke::Pt m_center; double m_angle; + int m_lastCornerRadius = 0; + int m_cornerRadius = 0; }; // Controls clicks for tools like polygon diff --git a/src/app/tools/intertwine.cpp b/src/app/tools/intertwine.cpp index 4a5104152..45bf853ff 100644 --- a/src/app/tools/intertwine.cpp +++ b/src/app/tools/intertwine.cpp @@ -18,6 +18,7 @@ #include "app/tools/tool_loop.h" #include "base/pi.h" #include "doc/algo.h" +#include "doc/algorithm/hline.h" #include "doc/layer.h" #include @@ -158,4 +159,21 @@ doc::AlgoLineWithAlgoPixel Intertwine::getLineAlgo(ToolLoop* loop, } } +// static +void Intertwine::doPointshapeCircle(int xm, int ym, int r, int sx, int sy, ToolLoop* loop, bool fill) +{ + if (fill) { + algo_circlefill(xm, ym, sx, sy, r, loop, (AlgoHLine)doPointshapeHline); + } + else { + algo_circle(xm, ym, sx, sy, r, loop, (AlgoPixel)doPointshapePoint); + } +} + +// static +void Intertwine::doPointshapeArc(int xm, int ym, double sa, double ea, int r, ToolLoop* loop) +{ + algo_arc(xm, ym, sa, ea, r, loop, (AlgoPixel)doPointshapePoint); +} + }} // namespace app::tools diff --git a/src/app/tools/intertwine.h b/src/app/tools/intertwine.h index 6f2d402a1..7ada914f8 100644 --- a/src/app/tools/intertwine.h +++ b/src/app/tools/intertwine.h @@ -60,6 +60,11 @@ protected: static doc::AlgoLineWithAlgoPixel getLineAlgo(ToolLoop* loop, const Stroke::Pt& a, const Stroke::Pt& b); + + static void + doPointshapeCircle(int xm, int ym, int r, int sx, int sy, ToolLoop* loop, bool fill = false); + + static void doPointshapeArc(int xm, int ym, double sa, double ea, int r, ToolLoop* loop); }; }} // namespace app::tools diff --git a/src/app/tools/intertwiners.h b/src/app/tools/intertwiners.h index 064643974..c0ae6d60d 100644 --- a/src/app/tools/intertwiners.h +++ b/src/app/tools/intertwiners.h @@ -5,8 +5,18 @@ // This program is distributed under the terms of // the End-User License Agreement for Aseprite. +#include "app/tools/controller.h" +#include "app/tools/intertwine.h" +#include "app/tools/point_shape.h" +#include "app/tools/tool_loop.h" +#include "app/tools/tool_loop_modifiers.h" #include "base/pi.h" +#include "doc/algorithm/polygon.h" #include "doc/layer_tilemap.h" +#include "gfx/point.h" +#include + +using namespace gfx; namespace app { namespace tools { @@ -183,22 +193,52 @@ public: std::swap(y1, y2); const double angle = loop->getController()->getShapeAngle(); + const int cornerRadius = loop->getController()->getCornerRadius(); if (ABS(angle) < 0.001) { - doPointshapeLineWithoutDynamics(x1, y1, x2, y1, loop); - doPointshapeLineWithoutDynamics(x1, y2, x2, y2, loop); + int r = 0; + if (cornerRadius > 1) { + int w = x2 - x1; + int h = y2 - y1; + int xm = x1 + w / 2; + int ym = y1 + h / 2; + r = std::min(w, std::min(h, 2 * cornerRadius)) / 2; + doPointshapeCircle(xm, ym, r, w - r * 2, h - r * 2, loop); + } - for (y = y1; y <= y2; y++) { + doPointshapeLineWithoutDynamics(x1 + r, y1, x2 - r, y1, loop); + doPointshapeLineWithoutDynamics(x1 + r, y2, x2 - r, y2, loop); + + for (y = y1 + r; y <= y2 - r; y++) { doPointshapePoint(x1, y, loop); doPointshapePoint(x2, y, loop); } } else { - Stroke p = rotateRectangle(x1, y1, x2, y2, angle); - int n = p.size(); - for (int i = 0; i + 1 < n; ++i) { - doPointshapeLine(p[i], p[i + 1], loop); + if (cornerRadius <= 1) { + Stroke p = rotateRectangle(x1, y1, x2, y2, angle); + int n = p.size(); + for (int i = 0; i + 1 < n; ++i) { + doPointshapeLine(p[i], p[i + 1], loop); + } + doPointshapeLine(p[n - 1], p[0], loop); + } + else { + int w = x2 - x1; + int h = y2 - y1; + int r = std::min(w, std::min(h, 2 * cornerRadius)) / 2; + Stroke p = rotateRectangle(x1, y1, x2, y2, angle, r); + int n = p.size(); + for (int i = 0; i + 1 < n; i += 3) { + doPointshapeLine(p[i], p[i + 1], loop); + } + const double ang_minus_PI_2 = base::fmod_radians(angle - PI / 2); + const double ang_plus_PI_2 = base::fmod_radians(angle + PI / 2); + const double ang_plus_PI = base::fmod_radians(angle + PI); + doPointshapeArc(p[2].x, p[2].y, ang_minus_PI_2, angle, r, loop); + doPointshapeArc(p[5].x, p[5].y, angle, ang_plus_PI_2, r, loop); + doPointshapeArc(p[8].x, p[8].y, ang_plus_PI_2, ang_plus_PI, r, loop); + doPointshapeArc(p[11].x, p[11].y, ang_plus_PI, ang_minus_PI_2, r, loop); } - doPointshapeLine(p[n - 1], p[0], loop); } } } @@ -224,14 +264,44 @@ public: std::swap(y1, y2); const double angle = loop->getController()->getShapeAngle(); + const int cornerRadius = loop->getController()->getCornerRadius(); if (ABS(angle) < 0.001) { - for (y = y1; y <= y2; y++) + int r = 0; + if (cornerRadius > 1) { + int w = x2 - x1; + int h = y2 - y1; + int xm = x1 + w / 2; + int ym = y1 + h / 2; + r = std::min(w, std::min(h, 2 * cornerRadius)) / 2; + doPointshapeCircle(xm, ym, r, w - r * 2, h - r * 2, loop, true); + + for (y = y1; y < y1 + r; y++) + doPointshapeLineWithoutDynamics(x1 + r, y, x2 - r, y, loop); + for (y = y2 - r + 1; y <= y2; y++) + doPointshapeLineWithoutDynamics(x1 + r, y, x2 - r, y, loop); + } + + for (y = y1 + r; y <= y2 - r; y++) doPointshapeLineWithoutDynamics(x1, y, x2, y, loop); } else { - Stroke p = rotateRectangle(x1, y1, x2, y2, angle); - auto v = p.toXYInts(); - doc::algorithm::polygon(v.size() / 2, &v[0], loop, (AlgoHLine)doPointshapeHline); + if (cornerRadius <= 1) { + Stroke p = rotateRectangle(x1, y1, x2, y2, angle); + auto v = p.toXYInts(); + doc::algorithm::polygon(v.size() / 2, &v[0], loop, (AlgoHLine)doPointshapeHline); + } + else { + int w = x2 - x1; + int h = y2 - y1; + int r = std::min(w, std::min(h, 2 * cornerRadius)) / 2; + Stroke p = rotateRectangle(x1, y1, x2, y2, angle, cornerRadius); + auto v = p.toXYInts(); + doc::algorithm::polygon(v.size() / 2, &v[0], loop, (AlgoHLine)doPointshapeHline); + doPointshapeCircle(p[2].x, p[2].y, r, 0, 0, loop, true); + doPointshapeCircle(p[5].x, p[5].y, r, 0, 0, loop, true); + doPointshapeCircle(p[8].x, p[8].y, r, 0, 0, loop, true); + doPointshapeCircle(p[11].x, p[11].y, r, 0, 0, loop, true); + } } } } @@ -274,6 +344,54 @@ private: stroke.addPoint(Point(cx - a * c + b * s, cy + a * s + b * c)); return stroke; } + + // Returns a stroke with the rotated points of a rectangle making room for a + // rounded corner of the specified radius, and with points where the center of + // each corner must be. + static Stroke rotateRectangle(int x1, int y1, int x2, int y2, double angle, int cornerRadius) + { + cornerRadius = std::max(cornerRadius, 0); + + int cx = (x1 + x2) / 2; + int cy = (y1 + y2) / 2; + int a = ((x2 - x1) / 2); + int b = ((y2 - y1) / 2); + int ai = a - cornerRadius; + int bi = b - cornerRadius; + + double s = -std::sin(angle); + double c = std::cos(angle); + + Stroke stroke; + // Top segment + stroke.addPoint(Point(cx - ai * c - b * s, cy + ai * s - b * c)); + stroke.addPoint(Point(cx + ai * c - b * s, cy - ai * s - b * c)); + + // Center for top-right corner + stroke.addPoint(Point(cx + ai * c - bi * s, cy - ai * s - bi * c)); + + // Right segment + stroke.addPoint(Point(cx + a * c - bi * s, cy - a * s - bi * c)); + stroke.addPoint(Point(cx + a * c + bi * s, cy - a * s + bi * c)); + + // Center for bottom-right corner + stroke.addPoint(Point(cx + ai * c + bi * s, cy - ai * s + bi * c)); + + // Bottom segment + stroke.addPoint(Point(cx + ai * c + b * s, cy - ai * s + b * c)); + stroke.addPoint(Point(cx - ai * c + b * s, cy + ai * s + b * c)); + + // Center for bottom-left corner + stroke.addPoint(Point(cx - ai * c + bi * s, cy + ai * s + bi * c)); + + // Left segment + stroke.addPoint(Point(cx - a * c + bi * s, cy + a * s + bi * c)); + stroke.addPoint(Point(cx - a * c - bi * s, cy + a * s - bi * c)); + + // Center for top-left corner + stroke.addPoint(Point(cx - ai * c - bi * s, cy + ai * s - bi * c)); + return stroke; + } }; class IntertwineAsEllipses : public Intertwine { diff --git a/src/app/tools/tool_loop_modifiers.h b/src/app/tools/tool_loop_modifiers.h index bb4ddf806..9adedca19 100644 --- a/src/app/tools/tool_loop_modifiers.h +++ b/src/app/tools/tool_loop_modifiers.h @@ -1,5 +1,5 @@ // Aseprite -// Copyright (C) 2018 Igara Studio S.A. +// Copyright (C) 2018-2025 Igara Studio S.A. // Copyright (C) 2016-2018 David Capello // // This program is distributed under the terms of @@ -21,6 +21,7 @@ enum class ToolLoopModifiers { kSquareAspect = 0x00000020, kFromCenter = 0x00000040, kRotateShape = 0x00000080, + kCornerRadius = 0x00000100, }; }} // namespace app::tools diff --git a/src/app/ui/editor/editor.cpp b/src/app/ui/editor/editor.cpp index 9ea6020ea..a0dc0fe00 100644 --- a/src/app/ui/editor/editor.cpp +++ b/src/app/ui/editor/editor.cpp @@ -1834,7 +1834,7 @@ void Editor::updateToolLoopModifiersIndicators(const bool firstFromMouseDown) // square-aspect/rotation/etc. only when the user presses the // modifier key again in the ToolLoop (and not before starting // the loop). So Alt+selection will add a selection, but - // willn't start the square-aspect until we press Alt key + // won't start the square-aspect until we press Alt key // again, or Alt+Shift+selection tool will subtract the // selection but will not start the rotation until we release // and press the Alt key again. @@ -1847,6 +1847,8 @@ void Editor::updateToolLoopModifiersIndicators(const bool firstFromMouseDown) modifiers |= int(tools::ToolLoopModifiers::kFromCenter); if (int(action & KeyAction::RotateShape)) modifiers |= int(tools::ToolLoopModifiers::kRotateShape); + if (int(action & KeyAction::CornerRadius)) + modifiers |= int(tools::ToolLoopModifiers::kCornerRadius); } } diff --git a/src/app/ui/key.cpp b/src/app/ui/key.cpp index e6df4cd2d..c4bef82ed 100644 --- a/src/app/ui/key.cpp +++ b/src/app/ui/key.cpp @@ -110,6 +110,10 @@ const std::vector& actions() I18N_KEY(rotate_shape), app::KeyAction::RotateShape, app::KeyContext::ShapeTool }, + { "CornerRadius", + I18N_KEY(corner_radius), + app::KeyAction::CornerRadius, + app::KeyContext::ShapeTool }, { "LeftMouseButton", I18N_KEY(trigger_left_mouse_button), app::KeyAction::LeftMouseButton, @@ -392,6 +396,7 @@ Key::Key(const KeyAction action, const KeyContext keyContext) case KeyAction::RotateShape: m_keycontext = KeyContext::ShapeTool; break; case KeyAction::LeftMouseButton: case KeyAction::RightMouseButton: m_keycontext = KeyContext::Any; break; + case KeyAction::CornerRadius: m_keycontext = KeyContext::ShapeTool; break; } } diff --git a/src/app/ui/key.h b/src/app/ui/key.h index edae25d32..2bbc6c5a4 100644 --- a/src/app/ui/key.h +++ b/src/app/ui/key.h @@ -64,6 +64,7 @@ enum class KeyAction { AngleSnapFromLastPoint = 0x00010000, RotateShape = 0x00020000, FineControl = 0x00040000, + CornerRadius = 0x00080000, }; enum class WheelAction { diff --git a/src/doc/algo.cpp b/src/doc/algo.cpp index 74f578b38..37765b817 100644 --- a/src/doc/algo.cpp +++ b/src/doc/algo.cpp @@ -12,6 +12,7 @@ #include "doc/algo.h" #include "base/debug.h" +#include "base/pi.h" #include #include @@ -180,6 +181,183 @@ void algo_line_continuous_with_fix_for_line_brush(int x0, } } +// Circle code based on Alois Zingl work released under the MIT +// license http://members.chello.at/easyfilter/bresenham.html +// +// Adapted for Aseprite by Igara Studio S.A. +// +// Draws a circle divided in 4 parts, separated sx pixels horizontally and sy +// pixels vertically: +// |---sx---| +// +// OOO OOO +// O O +// O O +// T +// | +// | +// sy xm,xy +// | +// | +// _ +// O O +// O O +// OOO OOO +// +// If sx and sy are 0, it draws a regular circle. +void algo_circle(int xm, int ym, int sx, int sy, int r, void* data, AlgoPixel proc) +{ + int x = -r, y = 0, err = 2 - 2 * r; /* II. Quadrant */ + sx = sx < 0 ? 0 : sx; + sy = sy < 0 ? 0 : sy; + int offsetx = sx / 2; + int offsety = sy / 2; + // Fix the position when sx or sy are not even. + int fixx = sx - 2 * offsetx; + int fixy = sy - 2 * offsety; + do { + proc(xm - x + offsetx + fixx, ym + y + offsety + fixy, data); /* I. Quadrant */ + proc(xm - y - offsetx, ym - x + offsety + fixy, data); /* II. Quadrant */ + proc(xm + x - offsetx, ym - y - offsety, data); /* III. Quadrant */ + proc(xm + y + offsetx + fixx, ym + x - offsety, data); /* IV. Quadrant */ + r = err; + if (r <= y) + err += ++y * 2 + 1; /* e_xy+e_y < 0 */ + if (r > x || err > y) + err += ++x * 2 + 1; /* e_xy+e_x > 0 or no 2nd y-step */ + } while (x < 0); +} + +// Same as algo_circle but with the parts filled. +void algo_circlefill(int xm, int ym, int sx, int sy, int r, void* data, AlgoHLine proc) +{ + int x = -r, y = 0, err = 2 - 2 * r; /* II. Quadrant */ + sx = sx < 0 ? 0 : sx; + sy = sy < 0 ? 0 : sy; + int offsetx = sx / 2; + int offsety = sy / 2; + // Fix the position when sx or sy are not even. + int fixx = sx - 2 * offsetx; + int fixy = sy - 2 * offsety; + do { + proc(xm, ym + y + offsety + fixy, xm - x + offsetx + fixx, data); /* I. Quadrant */ + proc(xm - y - offsetx, ym - x + offsety + fixy, xm, data); /* II. Quadrant */ + proc(xm + x - offsetx, ym - y - offsety, xm, data); /* III. Quadrant */ + proc(xm, ym + x - offsety, xm + y + offsetx + fixx, data); /* IV. Quadrant */ + r = err; + if (r <= y) + err += ++y * 2 + 1; /* e_xy+e_y < 0 */ + if (r > x || err > y) + err += ++x * 2 + 1; /* e_xy+e_x > 0 or no 2nd y-step */ + } while (x < 0); +} + +void algo_arc(int xm, int ym, double sa, double ea, int r, void* data, AlgoPixel proc) +{ + int sx = std::cos(sa) * r; + int ex = std::cos(ea) * r; + + int startQuadrant; + if (sa <= 0 && sa > -PI / 2) { + startQuadrant = 4; + } + else if (sa <= -PI / 2 && sa >= -PI) { + startQuadrant = 3; + } + else if (sa > 0 && sa < PI / 2) { + startQuadrant = 1; + } + else { + startQuadrant = 2; + } + + int endQuadrant; + if (ea <= 0 && ea > -PI / 2) { + endQuadrant = 4; + } + else if (ea <= -PI / 2 && ea >= -PI) { + endQuadrant = 3; + } + else if (ea > 0 && ea < PI / 2) { + endQuadrant = 1; + } + else { + endQuadrant = 2; + } + + // If start angle and end angle falls in the same quadrant we have to determine + // if we have to include the other quadrants or not since the arc is determined + // from start angle to end angle in clockwise direction. + bool includeQuadrant[4] = { false, false, false, false }; + if (startQuadrant == endQuadrant) { + // If start angle is greater than end angle, include all quadrants for drawing + if (sa > ea) { + includeQuadrant[0] = true; + includeQuadrant[1] = true; + includeQuadrant[2] = true; + includeQuadrant[3] = true; + } + else { + // start angle is less to or equal to end angle then only include one quadrant + // for drawing. + includeQuadrant[startQuadrant - 1] = true; + } + } + else { + for (int i = startQuadrant - 1; i < startQuadrant - 1 + 4; ++i) { + int q = i % 4; + includeQuadrant[q] = true; + if (q == endQuadrant - 1) + break; + } + } + + int x = -r, y = 0, err = 2 - 2 * r; /* II. Quadrant */ + do { + if (includeQuadrant[0]) { + if ((startQuadrant != 1 && endQuadrant != 1) || + (startQuadrant == 1 && endQuadrant != 1 && -x <= sx) || + (startQuadrant != 1 && endQuadrant == 1 && -x >= ex) || + (startQuadrant == 1 && endQuadrant == 1 && + ((sa <= ea && -x <= sx && -x >= ex) || (sa > ea && (-x <= sx || -x >= ex))))) + proc(xm - x, ym + y, data); /* I. Quadrant */ + } + + if (includeQuadrant[1]) { + if ((startQuadrant != 2 && endQuadrant != 2) || + (startQuadrant == 2 && endQuadrant != 2 && -y <= sx) || + (startQuadrant != 2 && endQuadrant == 2 && -y >= ex) || + (startQuadrant == 2 && endQuadrant == 2 && + ((sa <= ea && -y <= sx && -y >= ex) || (sa > ea && (-y <= sx || -y >= ex))))) + proc(xm - y, ym - x, data); /* II. Quadrant */ + } + + if (includeQuadrant[2]) { + if ((startQuadrant != 3 && endQuadrant != 3) || + (startQuadrant == 3 && endQuadrant != 3 && x >= sx) || + (startQuadrant != 3 && endQuadrant == 3 && x <= ex) || + (startQuadrant == 3 && endQuadrant == 3 && + ((sa <= ea && -x <= -sx && -x >= -ex) || (sa > ea && (-x <= -sx || -x >= -ex))))) + proc(xm + x, ym - y, data); /* III. Quadrant */ + } + + if (includeQuadrant[3]) { + if ((startQuadrant != 4 && endQuadrant != 4) || + (startQuadrant == 4 && endQuadrant != 4 && y >= sx) || + (startQuadrant != 4 && endQuadrant == 4 && y <= ex) || + (startQuadrant == 4 && endQuadrant == 4 && + ((sa <= ea && y >= sx && y <= ex) || (sa > ea && (y >= sx || y <= ex))))) + proc(xm + y, ym + x, data); /* IV. Quadrant */ + } + + r = err; + if (r <= y) + err += ++y * 2 + 1; /* e_xy+e_y < 0 */ + if (r > x || err > y) + err += ++x * 2 + 1; /* e_xy+e_x > 0 or no 2nd y-step */ + } while (x < 0); +} + static int adjust_ellipse_args(int& x0, int& y0, int& x1, int& y1, int& hPixels, int& vPixels) { // hPixels : straight horizontal pixels added to mid region of the ellipse. diff --git a/src/doc/algo.h b/src/doc/algo.h index a7985d2b9..7093b5644 100644 --- a/src/doc/algo.h +++ b/src/doc/algo.h @@ -48,6 +48,12 @@ void algo_line_continuous_with_fix_for_line_brush(int x1, void* data, AlgoPixel proc); +void algo_circle(int xm, int ym, int sx, int sy, int r, void* data, AlgoPixel proc); + +void algo_circlefill(int xm, int ym, int sx, int sy, int r, void* data, AlgoHLine proc); + +void algo_arc(int xm, int ym, double sa, double ea, int r, void* data, AlgoPixel proc); + void algo_ellipse(int x1, int y1, int x2,