Replaced body of previous circleFill() method in the MicroView class, in preparation for a pull request.

This commit is contained in:
ben-zen
2014-09-23 21:14:20 -07:00
parent c86b454924
commit 68f0c20fd5

View File

@@ -606,46 +606,60 @@ void MicroView::circleFill(uint8_t x0, uint8_t y0, uint8_t radius) {
Draw filled circle with radius using color and mode at x,y of the screen buffer.
*/
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.
int16_t rx2 = (x-x0) * (x-x0);
// Scan vertically...
for (uint16_t y = yStart; y <= yEnd; ++y) {
int16_t ry2 = (y-y0) * (y-y0);
if (rx2 + ry2 <= radiusSq) {
pixel(x, y, color, mode);
intersected = true;
}
else if (intersected) {
// We've left the circle. Move on to the next horizontal scan line.
break;
}
}
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) { // Fill the line between these two points
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++;
}
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);
}
}
}
/** \brief Get LCD height.