mirror of
https://github.com/geekammo/MicroView-Arduino-Library.git
synced 2026-02-22 12:31:22 +01:00
Merge pull request #21 from ben-zen/circle_drawing
Improved circleFill() drawing
This commit is contained in:
@@ -604,47 +604,62 @@ void MicroView::circleFill(uint8_t x0, uint8_t y0, uint8_t radius) {
|
||||
|
||||
/** \brief Draw filled circle with color and mode.
|
||||
|
||||
Draw filled circle with radius using color and mode at x,y of the screen buffer.
|
||||
Draw filled circle with radius using color and mode at x,y of the screen
|
||||
buffer. Uses the Bresenham circle algorithm with a few modifications to
|
||||
paint the circle without overlapping draw operations.
|
||||
*/
|
||||
void MicroView::circleFill(uint8_t x0, uint8_t y0, uint8_t radius, uint8_t color, uint8_t mode) {
|
||||
// Don't bother trying to draw something totally offscreen
|
||||
if (x0 - radius >= LCDWIDTH || y0 - radius >= LCDHEIGHT) {
|
||||
return;
|
||||
}
|
||||
|
||||
// High-level algorithm overview:
|
||||
// Scan horizontally from left to right, then top to bottom, checking if each pixel
|
||||
// is within the circle. We use uint16_t's because even the small screen squares beyond 8 bits.
|
||||
uint16_t radiusSq = radius * radius;
|
||||
|
||||
// Optimization: define the start and end onscreen
|
||||
uint16_t xStart = max(0, x0-radius);
|
||||
uint16_t xEnd = min(LCDWIDTH-1, x0+radius);
|
||||
uint16_t yStart = max(0, y0-radius);
|
||||
uint16_t yEnd = min(LCDHEIGHT-1, y0+radius);
|
||||
|
||||
// scan horizontally...
|
||||
for (uint16_t x = xStart; x <= xEnd; ++x) {
|
||||
// Optimization: Record where if we have intersected the circle on this vertical
|
||||
// scan. Once we have intersected, then don't intersect anymore, don't bother
|
||||
// drawing; we've exited the circle.
|
||||
bool intersected = false;
|
||||
|
||||
// Optimization: relative x squared only changes with the outer loop/the horizontal scan.
|
||||
uint16_t rx2 = (x-x0) * (x-x0);
|
||||
|
||||
// Scan vertically...
|
||||
for (uint16_t y = yStart; y <= yEnd; ++y) {
|
||||
uint16_t ry2 = (y-y0) * (y-y0);
|
||||
if (rx2 + ry2 <= radiusSq) {
|
||||
pixel(x, y, color, mode);
|
||||
intersected = true;
|
||||
void MicroView::circleFill(uint8_t x0, uint8_t y0, uint8_t radius, uint8_t
|
||||
color, uint8_t mode) {
|
||||
int8_t x = radius;
|
||||
int8_t y = 0;
|
||||
int8_t radiusError = 1 - x;
|
||||
int8_t y_last = y0 + x;
|
||||
int8_t y_low;
|
||||
int8_t x_alt;
|
||||
int8_t x_alt_max;
|
||||
while (x >= y) {
|
||||
pixel(x + x0, y + y0, color, mode);
|
||||
x_alt = (x0 - x);
|
||||
x_alt_max = x0 + x;
|
||||
while (x_alt < x_alt_max) {
|
||||
pixel(x_alt, y + y0, color, mode);
|
||||
x_alt++;
|
||||
}
|
||||
if (y != x) {
|
||||
pixel(y + x0, x + y0, color, mode);
|
||||
pixel(y + x0, y0 - x, color, mode);
|
||||
}
|
||||
if (y != 0) {
|
||||
pixel(x + x0, y0 - y, color, mode);
|
||||
x_alt = (x0 - x);
|
||||
x_alt_max = x0 + x;
|
||||
while (x_alt < x_alt_max) {
|
||||
pixel(x_alt, y0 - y, color, mode);
|
||||
x_alt++;
|
||||
}
|
||||
else if (intersected) {
|
||||
// We've left the circle. Move on to the next horizontal scan line.
|
||||
break;
|
||||
if (y != x) {
|
||||
pixel(x0 - y, x + y0, color, mode);
|
||||
pixel(x0 - y, y0 - x, color, mode);
|
||||
if (y_last > y0 + x) {
|
||||
x_alt = x0 - y + 1;
|
||||
x_alt_max = x0 + y;
|
||||
y_last = y0 + x;
|
||||
y_low = y0 - x;
|
||||
while (x_alt < x_alt_max) {
|
||||
pixel(x_alt, y_last, color, mode);
|
||||
pixel(x_alt, y_low, color, mode);
|
||||
x_alt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
y++;
|
||||
if (radiusError<0) {
|
||||
radiusError += 2 * y + 1;
|
||||
} else {
|
||||
x--;
|
||||
radiusError += 2 * (y - x + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user