Skip to content

Commit 928b6e7

Browse files
fix: fix bug with transparent circle fill (#480)
1 parent 692b155 commit 928b6e7

File tree

2 files changed

+70
-7
lines changed

2 files changed

+70
-7
lines changed

src/draw/__tests__/drawCircleOnImage.test.ts

+37
Original file line numberDiff line numberDiff line change
@@ -365,3 +365,40 @@ test('default options', () => {
365365
[0, 1, 0],
366366
]);
367367
});
368+
test('draw circle image with transparent color', () => {
369+
const image = testUtils.createGreyaImage([
370+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
371+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
372+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
373+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
374+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
375+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
376+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
377+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
378+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
379+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
380+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
381+
]);
382+
const center = { row: 5, column: 2 };
383+
const radius = 2;
384+
const received = image.drawCircle(center, radius, {
385+
fill: [255, 125],
386+
color: [255, 255],
387+
});
388+
389+
const expected = testUtils.createGreyaImage([
390+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
391+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
392+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
393+
[0, 0, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0],
394+
[255, 255, 255, 125, 255, 125, 255, 125, 255, 255, 0, 0, 0, 0, 0, 0],
395+
[255, 255, 255, 125, 255, 125, 255, 125, 255, 255, 0, 0, 0, 0, 0, 0],
396+
[255, 255, 255, 125, 255, 125, 255, 125, 255, 255, 0, 0, 0, 0, 0, 0],
397+
[0, 0, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0],
398+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
399+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
400+
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
401+
]);
402+
403+
expect(received).toMatchImage(expected);
404+
});

src/draw/drawCircleOnImage.ts

+33-7
Original file line numberDiff line numberDiff line change
@@ -73,25 +73,51 @@ export function drawCircleOnImage(
7373
if (radius === 1) {
7474
setBlendedVisiblePixel(newImage, center.column, center.row, fill);
7575
}
76+
//Starting points for the top and bottom row of the circle.
77+
let prevRow = center.row + radius;
78+
79+
let index = 0;
7680
circle(center.column, center.row, radius, (column: number, row: number) => {
7781
setBlendedVisiblePixel(newImage, column, row, color);
78-
79-
//todo: fill is not optimal we can fill symmetrically
80-
if (column - 1 > center.column) {
82+
// Filling the first line of the circle.
83+
if (index === 0) {
8184
newImage.drawLine(
8285
{ row, column: column - 1 },
83-
{ row, column: center.column },
86+
{
87+
row,
88+
column: center.column - (column - center.column - 1),
89+
},
8490
{ strokeColor: fill, out: newImage },
8591
);
86-
} else if (column + 1 < center.column) {
92+
}
93+
// The algorithm used is Bresenham's circle algorithm (@link https://www.geeksforgeeks.org/bresenhams-circle-drawing-algorithm/) to find points that constitute the circle outline. However, in this algorithm The circle is divided in 4 parts instead of 8: top, right, bottom and left.
94+
// The algorithm draws a point per quadrant until the circle is complete.
95+
// We use bottom (index % 4 === 1, quadrant 2) point of the outline to fill the circle with color.
96+
// Filling half of the circle.
97+
if (index % 4 === 1 && prevRow !== row) {
98+
// For quadrant 2, column < center.column
8799
newImage.drawLine(
88100
{ row, column: column + 1 },
89-
{ row, column: center.column },
101+
{
102+
row,
103+
column: center.column - (column - center.column + 1),
104+
},
105+
{ strokeColor: fill, out: newImage },
106+
);
107+
prevRow = row;
108+
// Filling top half of the circle.
109+
newImage.drawLine(
110+
{ row: center.row - (row - center.row), column: column + 1 },
111+
{
112+
row: center.row - (row - center.row),
113+
column: center.column - (column - center.column + 1),
114+
},
90115
{ strokeColor: fill, out: newImage },
91116
);
92117
}
118+
119+
index++;
93120
});
94121
}
95-
96122
return newImage;
97123
}

0 commit comments

Comments
 (0)