This was used in my new 3D printer Firmware, and it is proven the
fastest way for filled circle of a diameter from 1 to 43 pixel. If
larger is needed, the following memory block(or array) should be
extended following a structure I wont waste my time explaining...
If you have questions, or need larger diameter than 43, contact me, I
will help you drawing the fastest and perfect filled circles... or
Bresenham's circle drawing algorithm can be used above those
diameters, but having to fill the circle after, or incorporating the
fill into Bresenham's circle drawing algorithm, will only result in
slower fill circle than my code. I already benchmarked the different
codes, my solution is 4 to 5 times faster. As a test I have been
able to draw hundreds of filled circles of different size and colors
on a BigTreeTech tft24 1.1 running on a 1-core 72 Mhz cortex-m4
https://www.youtube.com/watch?v=7_Wp5yn3ADI
// this must be declared anywhere, as static or global
// as long as the function can access it !
uint8_t Rset[252]={
0,1,1,2,2,1,2,3,3,1,3,3,4,4,2,3,4,5,5,5,2,4,5,5,
6,6,6,2,4,5,6,6,7,7,7,2,4,5,6,7,7,8,8,8,2,5,6,7,
8,8,8,9,9,9,3,5,6,7,8,9,9,10,10,10,10,3,5,7,8,9,
9,10,10,11,11,11,11,3,5,7,8,9,10,10,11,11,12,12,
12,12,3,6,7,9,10,10,11,12,12,12,13,13,13,13,3,6,
8,9,10,11,12,12,13,13,13,14,14,14,14,3,6,8,9,10,
11,12,13,13,14,14,14,15,15,15,15,3,6,8,10,11,12,
13,13,14,14,15,15,15,16,16,16,16,4,7,8,10,11,12,
13,14,14,15,16,16,16,17,17,17,17,17,4,7,9,10,12,
13,14,14,15,16,16,17,17,17,18,18,18,18,18,4,7,9,
11,12,13,14,15,16,16,17,17,18,18,18,19,19,19,19,
19,7,9,11,12,13,15,15,16,17,18,18,19,19,20,20,20,
20,20,20,20,20,7,9,11,12,14,15,16,17,17,18,19,19
20,20,21,21,21,21,21,21,21,21};
// SOLUTION 1: (the fastest)
void FillCircle_v1(uint16_t x, uint16_t y, uint16_t r)
{
// all needed variables are created and set to their value...
uint16_t radius=(r<1) ? 1 : r ;
if (radius>21 ) {radius=21; }
uint16_t diam=(radius*2)+1;
uint16_t ymir=0, cur_y=0;
radius--; uint16_t target=(radius*radius+3*radius)/2; radius++;
// this part draws directly into the ILI94xx TFT buffer mem.
// using pointers..2 versions where you can draw
// pixels and lines with coordinates will follow
for (uint16_t yy=0; yy<diam; yy++)
{ ymir= (yy<=radius) ? yy+target : target+diam-(yy+1);
cur_y=y-radius+yy;
uint16_t *pixel=buffer_start_addr+x-Rset[ymir]+cur_y*buffer_width;
for (uint16_t xx= 0; xx<=(2*Rset[ymir]); xx++)
{ *pixel++ = CANVAS::draw_color; }}}
// SOLUTION 2: adaptable to any system that can
// add a pixel at a time: (drawpixel or add_pixel,etc_)
void FillCircle_v2(uint16_t x, uint16_t y, uint16_t r)
{
// all needed variables are created and set to their value...
uint16_t radius=(r<1) ? 1 : r ;
if (radius>21 ) {radius=21; }
uint16_t diam=(radius*2)+1;
uint16_t ymir=0, cur_y=0;
radius--; uint16_t target=(radius*radius+3*radius)/2; radius++;
for (uint16_t yy=0; yy<diam; yy++)
{ ymir= (yy<=radius) ? yy+target : target+diam-(yy+1);
cur_y=y-radius+yy;
uint16_t Pixel_x=x-Rset[ymir];
for (uint16_t xx= 0; xx<=(2*Rset[ymir]); xx++)
{ //use your add_pixel or draw_pixel here
// using those coordinates:
// X position will be... (Pixel_x+xx)
// Y position will be... (cur_y)
// and add those 3 brackets at the end
}}}
// SOLUTION 3: adaptable to any system that can draw fast
// horizontal lines
void FillCircle_v3(uint16_t x, uint16_t y, uint16_t r)
{
// all needed variables are created and set to their value...
uint16_t radius=(r<1) ? 1 : r ;
if (radius>21 ) {radius=21; }
uint16_t diam=(radius*2)+1;
uint16_t ymir=0, cur_y=0;
radius--; uint16_t target=(radius*radius+3*radius)/2; radius++;
for (uint16_t yy=0; yy<diam; yy++)
{ ymir= (yy<=radius) ? yy+target : target+diam-(yy+1);
cur_y=y-radius+yy;
uint16_t start_x=x-Rset[ymir];
uint16_t width_x=2*Rset[ymir];
// ... then use your best drawline function using those values:
// start_x: position X of the start of the line
// cur_y: position Y of the current line
// width_x: length of the line
// if you need a 2nd coordinate then :end_x=start_x+width_x
// and add those 2 brackets after !!!
}}