Advertisement

How to draw a circle

Started by October 12, 2002 03:32 PM
5 comments, last by 23yrold3yrold 22 years, 4 months ago
I''m making a little paint program and ... well, the above pretty much spells it out I already have a few options (like Bresenham''s) but most of these only draw circles with odd widths/heights. Can anyone spell out for the math moron an algorithm for drawing circles/ellipses of any size, ideally an algorithm that needs only the bounding box coordinates?? Chris Barry (crbarry at mts.net) My Personal Programming Depot

Jesus saves ... the rest of you take 2d4 fire damage.

for (float angle = 0.0; angle<360; angle++)
{
x = x-radius * cos(angle);
y = y-radius * sin(angle);
PlotPixel(x,y);
}

The above code will give you a circle (if x-radius == y-radius), but it's slow, and not a perfect circle (you will get some holes for bigger circles). For a paint program, where you have to draw circles really quick, you may want to use available libraries, if any.


My compiler generates one error message: "does not compile."

[edited by - nicho_tedja on October 12, 2002 5:09:29 PM]
My compiler generates one error message: "does not compile."
Advertisement
Sure thing

cos() and sin() can do the job for you. The idea is that using vectors, you can draw the unit circle. Translate & manipulate it a bit => taadaa In pseudo code it would be something like

void pixel( int x, int y );for(int i = 0; i < 360; i++) {  pixel( static_cast(widthOfCircle*cos( i*3.14/180)), static_cast(heightOfCircle*sin(i*3.14/180)) );} 


long Temp1 = 0.0, Temp2 = 0.0;
for(int Angle)= 0; Angle < 360; Angle++
Temp1 = sin(Angle * 3.14 / 180);
Temp2 = cos(Angle * 3.14 / 180);

Here is some VB code I just knocked up, it doesn't use any trig functions at all, only a single division and some multiplications. Basically, it just simulates a particle in circluar motion, under the effect of a constant centre seeking force. It only draws circles at the origin, but I'm sure you are smart enough to figure out how to add an offset


    Const PI As Single = 3.14159265358979Sub DrawCircle(r As Single, PicBox As PictureBox)    Dim x As Single, y As Single    Dim vx As Single, vy As Single    Dim ax As Single, ay As Single        Dim i As Single    Dim Inc As Single        'Increment - smaller increment takes longer    Inc = 1 / r        'Initial position (r, 0)    x = r    y = 0        'Initial velocity (0, r)    vx = 0    vy = r        'Initial acceleration    ax = -x * Inc    ay = 0            For i = 0 To PI / 2 Step Inc        'Move particle        x = x + vx * Inc        y = y + vy * Inc                'Adjust velocity        vx = vx + ax        vy = vy + ay                'Adjust acceleration (accelerate towards centre)        ax = -x * Inc        ay = -y * Inc                'Draw points in each quadrant        PicBox.PSet (x, y)        PicBox.PSet (-x, y)        PicBox.PSet (x, -y)        PicBox.PSet (-x, -y)    NextEnd Sub  


I was also thinking of something along the lines of:


        Sub DrawCircle(r As Single, PicBox As PictureBox)    Dim x As Single, y As Single        x = -r + 0.01    Do        y = Sqr(r * r - x * x)                PicBox.PSet (x, y)        PicBox.PSet (-x, y)        PicBox.PSet (x, -y)        PicBox.PSet (-x, -y)                x = x + Abs(y / x)            Loop Until x >= 0End Sub  


But, it is imperfect (has holes at top until I can find a better way of incrementing x) and it would also be slower (has a Square root for every tick).

EDIT: If you have any problem with a particular line of VB code, just give me a bell. Pset is the pixel plotting command in case you couldn't work it out.


[edited by - ragonastick on October 13, 2002 3:37:18 AM]
Trying is the first step towards failure.
Aw, I just reread your question, you want a circle/ellipse which will fit a bounding box. In that case, I would definately stick with the first method I posted, but we need to modify the initial velocity and position.

The new source:


  Sub DrawEllipse(a As Single, b As Single, PicBox As PictureBox)    Dim x As Single, y As Single    Dim vx As Single, vy As Single    Dim ax As Single, ay As Single    Dim i As Single    Dim Inc As Single        ''Increment - smaller increment takes longer    Inc = 1 / Sqr(a * a + b * b)        ''Initial position (r, 0)    x = a    y = 0        ''Initial velocity (0, b)    vx = 0    vy = b        ''Initial acceleration    ax = -x * Inc    ay = 0        For i = 0 To PI / 2 Step Inc        ''Move particle        x = x + vx * Inc        y = y + vy * Inc                ''Adjust velocity        vx = vx + ax        vy = vy + ay                ''Adjust acceleration (accelerate towards centre)        ax = -x * Inc        ay = -y * Inc                ''Draw points in each quadrant        PicBox.PSet (x, y)        PicBox.PSet (-x, y)        PicBox.PSet (x, -y)        PicBox.PSet (-x, -y)    NextEnd Sub  


a is the radius of the horizontal axis and b is the radius of the vertical radius.

The method I''m using to calculate the Increment is mainly based on intuition, so it may be incorrect for the ''optimum'' ellipse. It ''feels'' right though

When you go to fit one of these ellipses in a bounding box, first, find the midpoint of the bounding box:

MidX = (X1 + X2) * 0.5
MidY = (Y1 + Y2) * 0.5

Then:
a = Abs(X1 - MidX)
b = Abs(Y1 - MidY)

Use MidX and MidY to offset the ellipse.

Actually, I don''t think you even need the absolute value here unless you are drawing parts of a circle. Oh yeah - in the for loop, it is measuring in radians if you do want to draw arcs and stuff, just get rid of the 4 quadrant optimisation and only draw when i is in the correct range.
Trying is the first step towards failure.
Advertisement
Whoa, lotsa help ^_^ Much appreciated; I''ll give this stuff a whirl.

Chris Barry (crbarry at mts.net)
My Personal Programming Depot

Jesus saves ... the rest of you take 2d4 fire damage.

This topic is closed to new replies.

Advertisement