Skip to content

Commit 0f42f98

Browse files
authored
Merge pull request #3140 from mzivic7/draw.aaline_width
Add draw.aaline width argument
2 parents d628234 + 6135daf commit 0f42f98

File tree

7 files changed

+217
-105
lines changed

7 files changed

+217
-105
lines changed

buildconfig/stubs/pygame/draw.pyi

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@ def aaline(
8282
color: ColorLike,
8383
start_pos: Point,
8484
end_pos: Point,
85+
width: int = 1,
8586
) -> Rect: ...
8687
def aalines(
8788
surface: Surface,
Loading

docs/reST/ref/code_examples/draw_module_example.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,10 @@
3030
# 5 pixels wide. Uses (r, g, b) color - medium sea green.
3131
pygame.draw.line(screen, (60, 179, 113), [0, 0], [50, 30], 5)
3232

33+
# Draw on the screen a green antialiased line from (0, 25) to (50, 55)
34+
# 5 pixels wide. Uses (r, g, b) color - medium sea green.
35+
pygame.draw.aaline(screen, (60, 179, 113), [0, 25], [50, 55], 5)
36+
3337
# Draw on the screen a green line from (0, 50) to (50, 80)
3438
# Because it is an antialiased line, it is 1 pixel wide.
3539
# Uses (r, g, b) color - medium sea green.

docs/reST/ref/draw.rst

Lines changed: 9 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -456,72 +456,10 @@ object around the draw calls (see :func:`pygame.Surface.lock` and
456456

457457
| :sl:`draw a straight antialiased line`
458458
| :sg:`aaline(surface, color, start_pos, end_pos) -> Rect`
459+
:sg:`aaline(surface, color, start_pos, end_pos, width=1) -> Rect`
459460
460-
Draws a straight antialiased line on the given surface.
461-
462-
The line has a thickness of one pixel and the endpoints have a height and
463-
width of one pixel each.
464-
465-
The way a line and its endpoints are drawn:
466-
If both endpoints are equal, only a single pixel is drawn (after
467-
rounding floats to nearest integer).
468-
469-
Otherwise if the line is not steep (i.e. if the length along the x-axis
470-
is greater than the height along the y-axis):
471-
472-
For each endpoint:
473-
474-
If ``x``, the endpoint's x-coordinate, is a whole number find
475-
which pixels would be covered by it and draw them.
476-
477-
Otherwise:
478-
479-
Calculate the position of the nearest point with a whole number
480-
for its x-coordinate, when extending the line past the
481-
endpoint.
482-
483-
Find which pixels would be covered and how much by that point.
484-
485-
If the endpoint is the left one, multiply the coverage by (1 -
486-
the decimal part of ``x``).
487-
488-
Otherwise multiply the coverage by the decimal part of ``x``.
489-
490-
Then draw those pixels.
491-
492-
*e.g.:*
493-
| The left endpoint of the line ``((1, 1.3), (5, 3))`` would
494-
cover 70% of the pixel ``(1, 1)`` and 30% of the pixel
495-
``(1, 2)`` while the right one would cover 100% of the
496-
pixel ``(5, 3)``.
497-
| The left endpoint of the line ``((1.2, 1.4), (4.6, 3.1))``
498-
would cover 56% *(i.e. 0.8 * 70%)* of the pixel ``(1, 1)``
499-
and 24% *(i.e. 0.8 * 30%)* of the pixel ``(1, 2)`` while
500-
the right one would cover 42% *(i.e. 0.6 * 70%)* of the
501-
pixel ``(5, 3)`` and 18% *(i.e. 0.6 * 30%)* of the pixel
502-
``(5, 4)`` while the right
503-
504-
Then for each point between the endpoints, along the line, whose
505-
x-coordinate is a whole number:
506-
507-
Find which pixels would be covered and how much by that point and
508-
draw them.
509-
510-
*e.g.:*
511-
| The points along the line ``((1, 1), (4, 2.5))`` would be
512-
``(2, 1.5)`` and ``(3, 2)`` and would cover 50% of the pixel
513-
``(2, 1)``, 50% of the pixel ``(2, 2)`` and 100% of the pixel
514-
``(3, 2)``.
515-
| The points along the line ``((1.2, 1.4), (4.6, 3.1))`` would
516-
be ``(2, 1.8)`` (covering 20% of the pixel ``(2, 1)`` and 80%
517-
of the pixel ``(2, 2)``), ``(3, 2.3)`` (covering 70% of the
518-
pixel ``(3, 2)`` and 30% of the pixel ``(3, 3)``) and ``(4,
519-
2.8)`` (covering 20% of the pixel ``(2, 1)`` and 80% of the
520-
pixel ``(2, 2)``)
521-
522-
Otherwise do the same for steep lines as for non-steep lines except
523-
along the y-axis instead of the x-axis (using ``y`` instead of ``x``,
524-
top instead of left and bottom instead of right).
461+
Draws a straight antialiased line on the given surface. There are no endcaps.
462+
For thick lines the ends are squared off.
525463

526464
.. note::
527465
Regarding float values for coordinates, a point with coordinate
@@ -543,6 +481,11 @@ object around the draw calls (see :func:`pygame.Surface.lock` and
543481
:param end_pos: end position of the line, (x, y)
544482
:type end_pos: tuple(int or float, int or float) or
545483
list(int or float, int or float) or Vector2(int or float, int or float)
484+
:param int width: (optional) used for line thickness
485+
486+
| if width >= 1, used for line thickness (default is 1)
487+
| if width < 1, nothing will be drawn
488+
|
546489
547490
:returns: a rect bounding the changed pixels, if nothing is drawn the
548491
bounding rect's position will be the ``start_pos`` parameter value (float
@@ -555,6 +498,7 @@ object around the draw calls (see :func:`pygame.Surface.lock` and
555498
.. versionchangedold:: 2.0.0 Added support for keyword arguments.
556499
.. versionchanged:: 2.4.0 Removed deprecated 'blend' argument
557500
.. versionchanged:: 2.5.0 ``blend`` argument readded for backcompat, but will always raise a deprecation exception when used
501+
.. versionchanged:: 2.5.2 Added line width
558502

559503
.. ## pygame.draw.aaline ##
560504

src_c/doc/draw_doc.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@
88
#define DOC_DRAW_ARC "arc(surface, color, rect, start_angle, stop_angle) -> Rect\narc(surface, color, rect, start_angle, stop_angle, width=1) -> Rect\ndraw an elliptical arc"
99
#define DOC_DRAW_LINE "line(surface, color, start_pos, end_pos) -> Rect\nline(surface, color, start_pos, end_pos, width=1) -> Rect\ndraw a straight line"
1010
#define DOC_DRAW_LINES "lines(surface, color, closed, points) -> Rect\nlines(surface, color, closed, points, width=1) -> Rect\ndraw multiple contiguous straight line segments"
11-
#define DOC_DRAW_AALINE "aaline(surface, color, start_pos, end_pos) -> Rect\ndraw a straight antialiased line"
11+
#define DOC_DRAW_AALINE "aaline(surface, color, start_pos, end_pos) -> Rect\naaline(surface, color, start_pos, end_pos, width=1) -> Rect\ndraw a straight antialiased line"
1212
#define DOC_DRAW_AALINES "aalines(surface, color, closed, points) -> Rect\ndraw multiple contiguous straight antialiased line segments"

src_c/draw.c

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,10 @@ draw_line_width(SDL_Surface *surf, Uint32 color, int x1, int y1, int x2,
4444
static void
4545
draw_line(SDL_Surface *surf, int x1, int y1, int x2, int y2, Uint32 color,
4646
int *drawn_area);
47+
void
48+
line_width_corners(float from_x, float from_y, float to_x, float to_y,
49+
int width, float *x1, float *y1, float *x2, float *y2,
50+
float *x3, float *y3, float *x4, float *y4);
4751
static void
4852
draw_aaline(SDL_Surface *surf, Uint32 color, float startx, float starty,
4953
float endx, float endy, int *drawn_area,
@@ -115,16 +119,17 @@ aaline(PyObject *self, PyObject *arg, PyObject *kwargs)
115119
PyObject *colorobj, *start, *end;
116120
SDL_Surface *surf = NULL;
117121
float startx, starty, endx, endy;
122+
int width = 1; /* Default width. */
118123
PyObject *blend = NULL;
119124
int drawn_area[4] = {INT_MAX, INT_MAX, INT_MIN,
120125
INT_MIN}; /* Used to store bounding box values */
121126
Uint32 color;
122-
static char *keywords[] = {"surface", "color", "start_pos",
123-
"end_pos", "blend", NULL};
127+
static char *keywords[] = {"surface", "color", "start_pos", "end_pos",
128+
"width", "blend", NULL};
124129

125-
if (!PyArg_ParseTupleAndKeywords(arg, kwargs, "O!OOO|O", keywords,
130+
if (!PyArg_ParseTupleAndKeywords(arg, kwargs, "O!OOO|iO", keywords,
126131
&pgSurface_Type, &surfobj, &colorobj,
127-
&start, &end, &blend)) {
132+
&start, &end, &width, &blend)) {
128133
return NULL; /* Exception already set. */
129134
}
130135

@@ -157,11 +162,27 @@ aaline(PyObject *self, PyObject *arg, PyObject *kwargs)
157162
return RAISE(PyExc_TypeError, "invalid end_pos argument");
158163
}
159164

165+
if (width < 1) {
166+
return pgRect_New4((int)startx, (int)starty, 0, 0);
167+
}
168+
160169
if (!pgSurface_Lock(surfobj)) {
161170
return RAISE(PyExc_RuntimeError, "error locking surface");
162171
}
163172

164-
draw_aaline(surf, color, startx, starty, endx, endy, drawn_area, 0, 0, 0);
173+
if (width > 1) {
174+
float x1, y1, x2, y2, x3, y3, x4, y4;
175+
line_width_corners(startx, starty, endx, endy, width, &x1, &y1, &x2,
176+
&y2, &x3, &y3, &x4, &y4);
177+
draw_line_width(surf, color, (int)startx, (int)starty, (int)endx,
178+
(int)endy, width, drawn_area);
179+
draw_aaline(surf, color, x1, y1, x2, y2, drawn_area, 0, 0, 0);
180+
draw_aaline(surf, color, x3, y3, x4, y4, drawn_area, 0, 0, 0);
181+
}
182+
else {
183+
draw_aaline(surf, color, startx, starty, endx, endy, drawn_area, 0, 0,
184+
0);
185+
}
165186

166187
if (!pgSurface_Unlock(surfobj)) {
167188
return RAISE(PyExc_RuntimeError, "error unlocking surface");
@@ -1836,6 +1857,39 @@ draw_line_width(SDL_Surface *surf, Uint32 color, int x1, int y1, int x2,
18361857
}
18371858
}
18381859

1860+
// Calculates 4 points, representing corners of draw_line_width()
1861+
// first two points assemble left line and second two - right line
1862+
void
1863+
line_width_corners(float from_x, float from_y, float to_x, float to_y,
1864+
int width, float *x1, float *y1, float *x2, float *y2,
1865+
float *x3, float *y3, float *x4, float *y4)
1866+
{
1867+
float aa_width = (float)width / 2;
1868+
float extra_width = (1.0f - (width % 2)) / 2;
1869+
int steep = fabs(to_x - from_x) <= fabs(to_y - from_y);
1870+
1871+
if (steep) {
1872+
*x1 = from_x + extra_width + aa_width;
1873+
*y1 = from_y;
1874+
*x2 = to_x + extra_width + aa_width;
1875+
*y2 = to_y;
1876+
*x3 = from_x + extra_width - aa_width;
1877+
*y3 = from_y;
1878+
*x4 = to_x + extra_width - aa_width;
1879+
*y4 = to_y;
1880+
}
1881+
else {
1882+
*x1 = from_x;
1883+
*y1 = from_y + extra_width + aa_width;
1884+
*x2 = to_x;
1885+
*y2 = to_y + extra_width + aa_width;
1886+
*x3 = from_x;
1887+
*y3 = from_y + extra_width - aa_width;
1888+
*x4 = to_x;
1889+
*y4 = to_y + extra_width - aa_width;
1890+
}
1891+
}
1892+
18391893
/* Algorithm modified from
18401894
* https://rosettacode.org/wiki/Bitmap/Bresenham%27s_line_algorithm
18411895
*/

0 commit comments

Comments
 (0)