fast algorithm for drawing filled circles?

前端 未结 10 1166
清歌不尽
清歌不尽 2020-12-02 07:28

I am using Bresenham\'s circle algorithm for fast circle drawing. However, I also want to (at the request of the user) draw a filled circle.

Is there a fast and effi

10条回答
  •  被撕碎了的回忆
    2020-12-02 08:17

    Here's how I'm doing it:
    I'm using fixed point values with two bits precision (we have to manage half points and square values of half points)
    As mentionned in a previous answer, I'm also using square values instead of square roots.
    First, I'm detecting border limit of my circle in a 1/8th portion of the circle. I'm using symetric of these points to draw the 4 "borders" of the circle. Then I'm drawing the square inside the circle.

    Unlike the midpoint circle algorith, this one will work with even diameters (and with real numbers diameters too, with some little changes).

    Please forgive me if my explanations were not clear, I'm french ;)

    void DrawFilledCircle(int circleDiameter, int circlePosX, int circlePosY)
    {
        const int FULL = (1 << 2);
        const int HALF = (FULL >> 1);
    
        int size = (circleDiameter << 2);// fixed point value for size
        int ray = (size >> 1);
        int dY2;
        int ray2 = ray * ray;
        int posmin,posmax;
        int Y,X;
        int x = ((circleDiameter&1)==1) ? ray : ray - HALF;
        int y = HALF;
        circlePosX -= (circleDiameter>>1);
        circlePosY -= (circleDiameter>>1);
    
        for (;; y+=FULL)
        {
            dY2 = (ray - y) * (ray - y);
    
            for (;; x-=FULL)
            {
                if (dY2 + (ray - x) * (ray - x) <= ray2) continue;
    
                if (x < y)
                {
                    Y = (y >> 2);
                    posmin = Y;
                    posmax = circleDiameter - Y;
    
                    // Draw inside square and leave
                    while (Y < posmax)
                    {
                        for (X = posmin; X < posmax; X++)
                            setPixel(circlePosX+X, circlePosY+Y);
                        Y++;
                    }
                    // Just for a better understanding, the while loop does the same thing as:
                    // DrawSquare(circlePosX+Y, circlePosY+Y, circleDiameter - 2*Y);
                    return;
                }
    
                // Draw the 4 borders
                X = (x >> 2) + 1;
                Y = y >> 2;
                posmax = circleDiameter - X;
                int mirrorY = circleDiameter - Y - 1;
    
                while (X < posmax)
                {
                    setPixel(circlePosX+X, circlePosY+Y);
                    setPixel(circlePosX+X, circlePosY+mirrorY);
                    setPixel(circlePosX+Y, circlePosY+X);
                    setPixel(circlePosX+mirrorY, circlePosY+X);
                    X++;
                }
                // Just for a better understanding, the while loop does the same thing as:
                // int lineSize = circleDiameter - X*2;
                // Upper border:
                // DrawHorizontalLine(circlePosX+X, circlePosY+Y, lineSize);
                // Lower border:
                // DrawHorizontalLine(circlePosX+X, circlePosY+mirrorY, lineSize);
                // Left border:
                // DrawVerticalLine(circlePosX+Y, circlePosY+X, lineSize);
                // Right border:
                // DrawVerticalLine(circlePosX+mirrorY, circlePosY+X, lineSize);
    
                break;
            }
        }
    }
    
    void DrawSquare(int x, int y, int size)
    {
        for( int i=0 ; i

    To use non-integer diameter, you can increase precision of fixed point or use double values. It should even be possible to make a sort of anti-alias depending on the difference between dY2 + (ray - x) * (ray - x) and ray2 (dx² + dy² and r²)

提交回复
热议问题