diff --git a/olcPixelGameEngine.h b/olcPixelGameEngine.h index a180715..3c2e079 100644 --- a/olcPixelGameEngine.h +++ b/olcPixelGameEngine.h @@ -2128,23 +2128,18 @@ namespace olc void PixelGameEngine::FillArc(int32_t iterations, int32_t centreX, int32_t centreY, int32_t x0, int32_t y0, int32_t x1, int32_t y1, int32_t radius, olc::Pixel p) { if (!iterations) return; - //Get points int32_t midX = (x0 + x1) >> 1; int32_t midY = (y0 + y1) >> 1; int32_t arcX = radius * cos(atan2(midY - centreY, midX - centreX)) + centreX; int32_t arcY = radius * sin(atan2(midY - centreY, midX - centreX)) + centreY; - //Fill triangle FillTriangle(x0, y0, x1, y1, arcX, arcY, p); - //Recur FillArc(iterations - 1, centreX, centreY, x0, y0, arcX, arcY, radius, p); FillArc(iterations - 1, centreX, centreY, x1, y1, arcX, arcY, radius, p); - return; } void PixelGameEngine::FillCircle(int32_t x, int32_t y, int32_t radius, Pixel p) { // Thanks to IanM-Matrix1 #PR121 if (radius < 0 || x < -radius || y < -radius || x - GetDrawTargetWidth() > radius || y - GetDrawTargetHeight() > radius) return; - if (radius==0) { Draw(x, y, p); @@ -2156,95 +2151,66 @@ namespace olc if (radius > height || radius > width) { //This can be modified for higher precision - const int32_t ITERATIONS = 4; - - //Currently unprotected against overflow - //Check if all four points are within circle + const int32_t ITERATIONS = 1; + //Check if all four corners are within circle const bool topLeft = (x)*(x)+(y)*(y) <= radius * radius; const bool topRight = (x - width)*(x - width) + (y)*(y) <= radius * radius; const bool bottomLeft = (x)*(x)+(y - height)*(y - height) <= radius * radius; const bool bottomRight = (x - width)*(x - width) + (y - height)*(y - height) <= radius * radius; - - //Four Points inside circle - if ( - bottomRight && - topRight && - bottomLeft && - topLeft - ) + int32_t yRight = y + (topLeft?1:-1)*sqrt(radius*radius - (width - x)*(width - x)); + int32_t yLeft = y + (topLeft?1:-1)*sqrt(radius*radius-x*x); + int32_t xTop = x + (topLeft?1:-1)*sqrt(radius*radius - (height - y)*(height - y)); + int32_t xBottom = x + (topLeft?1:-1)*sqrt(radius*radius - y * y); + //Four corners inside circle + if (bottomRight && topRight && bottomLeft && topLeft) { Clear(p); return; } - //Three Points inside circle + //Three corners inside circle else if (topLeft + topRight + bottomRight + bottomLeft == 3) { + int32_t yIntercept = y + ((topLeft&&topRight)?1:-1)*sqrt(radius*radius - ((topLeft&&bottomLeft)?(width-x)*(width-x):(x*x))); + int32_t xIntercept = x + ((topLeft&&bottomLeft)?1:-1)*sqrt(radius*radius - ((topLeft&&topRight)?(height-y)*(height-y):(y*y))); if (!topLeft) { FillTriangle(width, 0, width, height, 0, height, p); - - int32_t yLeft = y - sqrt(radius*radius - x*x); - int32_t xTop = x - sqrt(radius*radius - y * y); - - FillTriangle(0, height, 0, yLeft, xTop, 0,p); - FillTriangle(0,height,xTop,0,width,0, p); - - //Fill arc - FillArc(ITERATIONS, x, y, 0, yLeft, xTop, 0, radius, p); - + FillTriangle(0, height, 0, yIntercept, xIntercept, 0,p); + FillTriangle(0,height,xIntercept,0,width,0, p); + FillArc(ITERATIONS, x, y, 0, yIntercept, xIntercept, 0, radius, p); return; } else if (!topRight) { FillTriangle(0,0, width, height, 0, height, p); - - int32_t yRight = y - sqrt(radius*radius - (width-x) * (width - x)); - int32_t xTop = x + sqrt(radius*radius - y*y); - - FillTriangle(0, 0, xTop, 0, width, yRight, p); - FillTriangle(0, 0, width, yRight, width, height, p); - - FillArc(ITERATIONS, x, y, width, yRight, xTop, 0, radius, p); - + FillTriangle(0, 0, xIntercept, 0, width, yIntercept, p); + FillTriangle(0, 0, width, yIntercept, width, height, p); + FillArc(ITERATIONS, x, y, width, yIntercept, xIntercept, 0, radius, p); return; } else if (!bottomLeft) { FillTriangle(0, 0, width, 0, width, height, p); - - int32_t yLeft = y + sqrt(radius*radius - x * x); - int32_t xBottom = x - sqrt(radius*radius - (height - y) * (height - y)); - - FillTriangle(0, yLeft, xBottom, height, width, height, p); - FillTriangle(0, 0, 0, yLeft, width, height, p); - - FillArc(ITERATIONS, x, y, 0, yLeft, xBottom, height, radius, p); - + FillTriangle(0, yIntercept, xIntercept, height, width, height, p); + FillTriangle(0, 0, 0, yIntercept, width, height, p); + FillArc(ITERATIONS, x, y, 0, yIntercept, xIntercept, height, radius, p); return; } else //!bottomRight { FillTriangle(0, 0, width, 0, 0, height, p); - - int32_t yRight = y + sqrt(radius*radius - (width - x) * (width - x)); - int32_t xBottom = x + sqrt(radius*radius - (height - y) * (height - y)); - - FillTriangle(0, height, width, 0, width, yRight,p); - FillTriangle(0, height, xBottom, height, width, yRight, p); - - FillArc(ITERATIONS, x, y, width, yRight, xBottom, height, radius, p); - + FillTriangle(0, height, width, 0, width, yIntercept,p); + FillTriangle(0, height, xIntercept, height, width, yIntercept, p); + FillArc(ITERATIONS, x, y, width, yIntercept, xIntercept, height, radius, p); return; } } - //Two points inside circle + //Two corners inside circle else if (topLeft + topRight + bottomRight + bottomLeft == 2) { if (topLeft && topRight) { - int32_t yRight = y + sqrt(radius*radius - (width - x)*(width - x)); - int32_t yLeft = y + sqrt(radius*radius - x * x); - if (x > width / 2) + if (yRight > yLeft) { FillRect(0, 0, width, yLeft, p); FillTriangle(0, yLeft, width, yLeft, width, yRight, p); @@ -2259,9 +2225,7 @@ namespace olc } else if (topLeft && bottomLeft) { - int32_t xTop = x + sqrt(radius*radius - (height - y)*(height - y)); - int32_t xBottom = x + sqrt(radius*radius - y * y); - if (y > height / 2) + if (xTop > xBottom) { FillRect(0, 0, xBottom, height, p); FillTriangle(xBottom, 0, xBottom, height, xTop, height, p); @@ -2276,9 +2240,7 @@ namespace olc } else if (bottomRight && topRight) { - int32_t xTop = x - sqrt(radius*radius - (height - y)*(height - y)); - int32_t xBottom = x - sqrt(radius*radius - y * y); - if (y > height / 2) + if (xBottom > xTop) { FillTriangle(xBottom, 0, xTop, height, xBottom, height, p); FillRect(xBottom, 0, width, height, p); @@ -2293,9 +2255,7 @@ namespace olc } else //bottomRight && bottomLeft { - int32_t yLeft = y - sqrt(radius*radius - x * x); - int32_t yRight = y - sqrt(radius*radius - (width - x)*(width - x)); - if (x > width / 2) + if (yLeft > yRight) { FillRect(0, yLeft, width, height, p); FillTriangle(0, yLeft, width, yLeft, width, yRight, p); @@ -2309,48 +2269,37 @@ namespace olc return; } } - //One Point inside circle + //One corner inside circle else if (topLeft) { - int32_t yLeft = y + sqrt(radius*radius - x * x); - int32_t xTop = x + sqrt(radius*radius - y*y); - + xTop = x + sqrt(radius*radius - y*y); FillTriangle(0, 0, xTop, 0, 0, yLeft, p); - FillArc(ITERATIONS, x, y, xTop, 0, 0, yLeft, radius, p); return; } else if (topRight) { - int32_t yRight = y + sqrt(radius*radius - (width-x) * (width - x)); - int32_t xTop = x - sqrt(radius*radius - y * y); - + yRight = y + sqrt(radius*radius - (width-x) * (width - x)); + xTop = x - sqrt(radius*radius - y * y); FillTriangle(xTop, 0, width, 0, width, yRight, p); - FillArc(ITERATIONS, x, y, xTop, 0, width, yRight, radius, p); return; } else if (bottomRight) { - int32_t yRight = y - sqrt(radius*radius - (width - x) * (width - x)); - int32_t xBottom = x - sqrt(radius*radius - (height-y) * (height - y)); - + xBottom = x - sqrt(radius*radius - (height-y) * (height - y)); FillTriangle(xBottom, height, width, height, width, yRight, p); - FillArc(ITERATIONS, x, y, xBottom, height, width, yRight, radius, p); return; } else if (bottomLeft) { - int32_t yLeft = y - sqrt(radius*radius - x*x); - int32_t xBottom = x + sqrt(radius*radius - (height - y) * (height - y)); - + xBottom = x + sqrt(radius*radius - (height - y) * (height - y)); FillTriangle(0, yLeft, 0, height, xBottom, height, p); - FillArc(ITERATIONS, x, y, xBottom, height, 0, yLeft, radius, p); return; } - //No points inside circle + //No corners inside circle else { //Do extra checks on the y's @@ -2358,9 +2307,7 @@ namespace olc { int32_t yLeft1 = y - sqrt(radius*radius - x * x); int32_t yLeft2 = y + sqrt(radius*radius - x * x); - if (yLeft1 < 0 || yLeft2 < 0 || yLeft1 > height || yLeft2 > height) return; - FillArc(ITERATIONS, x, y, 0, yLeft1, 0, yLeft2, radius, p); return; } @@ -2368,9 +2315,7 @@ namespace olc { int32_t yRight1 = y - sqrt(radius*radius - (width-x) * (width - x)); int32_t yRight2 = y + sqrt(radius*radius - (width - x) * (width - x)); - if (yRight1 < 0 || yRight2 < 0 || yRight1 > height || yRight2 > height) return; - FillArc(ITERATIONS, x, y, width, yRight1, width, yRight2, radius, p); return; } @@ -2378,9 +2323,7 @@ namespace olc { int32_t xTop1 = x - sqrt(radius*radius - y * y); int32_t xTop2 = x + sqrt(radius*radius - y * y); - if (xTop1 < 0 || xTop2 < 0 || xTop1 > width || xTop2 > width) return; - FillArc(ITERATIONS, x, y, xTop1, 0, xTop2, 0, radius, p); return; } @@ -2388,18 +2331,12 @@ namespace olc { int32_t xBottom1 = x - sqrt(radius*radius - (height - y)*(height - y)); int32_t xBottom2 = x + sqrt(radius*radius - (height - y)*(height - y)); - if (xBottom1 < 0 || xBottom2 < 0 || xBottom1 > width || xBottom2 > width) return; - FillArc(ITERATIONS, x, y, xBottom1, height, xBottom2, height, radius, p); return; } - - //overflow return; - } - goto standardCircleFill; } else