Search code examples
c++geometryturbo-c++cartesian-coordinatesbgi

Using Standard Cartesian Circle formula to draw circle in graphics mode (C++)


I wanted to draw a circle using graphics.h in C++, but not directly using the circle() function. The circle I want to draw uses smaller circles as it's points i.e. The smaller circles would constitute the circumference of the larger circle. So I thought, if I did something like this, it would work:

    {
        int radius = 4;


        // Points at which smaller circles would be drawn
        int x, y;


        int maxx = getmaxx();
        int maxy = getmaxy();

        // Co-ordinates of center of the larger circle (centre of the screen)
        int h = maxx/2;
        int k = maxy/2;

        //Cartesian cirle formula >> (X-h)^2 + (Y-k)^2 = radius^2

        //Effectively, this nested loop goes through every single coordinate on the screen

        int gmode = DETECT;
        int gdriver;

        initgraph(&gmode, &gdriver, "");

        for(x = 0; x<maxx; x++)
        {
            for(y = 0; y<maxy; y++)
            {
             if((((x-h)*(x-h)) + ((y-k)*(y-k))) == (radius*radius))
             { 
                 circle(x, y, 5) //Draw smaller circle with radius 5 
             }                   //at points which satisfy circle equation only!
            }
        }
    getch();
    }

This is when I'm using graphics.h on Turbo C++ as this is the compiler we're learning with at school.

I know it's ancient.

So, theoretically, since the nested for loops check all the points on the screen, and draw a small circle at every point that satisfies the circle equation only, I thought I would get a large circle of radius as entered, whose circumference constitutes of the smaller circles I make in the for loop.

However, when I try the program, I get four hyperbolas (all pointing towards the center of the screen) and when I increase the radius, the pointiness (for lack of a better word) of the hyperbolas increase, until finally, when the radius is 256 or more, the two hyperbolas on the top and bottom intersect to make a large cross on my screen like : "That's it, user, I give up!"

I came to the value 256 as I noticed that of the radius was a multiple of 4 the figures looked ... better?

I looked around for a solution for quite some time, but couldn't get any answers, so here I am.

Any suggestions???

EDIT >> Here's a rough diagram of the output I got...

This is the rough output


Solution

  • There are two issues in your code:

    First: You should really call initgraph before you call getmaxx and getmaxy, otherwise they will not necessarily return the correct dimensions of the graphics mode. This may or may not be a contributing factor depending on your setup.

    Second, and most importantly: In Turbo C++, int is 16-bit. For example, here is circle with radius 100 (after the previous initgraph order issue was fixed):

    enter image description here

    Note the stray circles in the four corners. If we do a little debugging and add some print-outs (a useful strategy that you should file away for future reference):

    if((((x-h)*(x-h)) + ((y-k)*(y-k))) == (radius*radius))
    {
        printf(": (%d-%d)^2 + (%d-%d)^2 = %d^2\n", x, h, y, k, radius);
        circle(x, y, 5); //Draw smaller circle with radius 
    }                   //at points which satisfy circle equation only!
    

    You can see what's happening (first line is maxx and maxy, not shown in above snippet):

    enter image description here

    In particular that circle at (63, 139) is one of the corners. If you do the math, you see that:

    (63 - 319)2 + (139 - 239)2 = 75536

    And since your ints are 16-bit, 75536 modulo 65536 = 10000 = the value that ends up being calculated = 1002 = a circle where it shouldn't be.

    An easy solution to this is to just change the relevant variables to long:

    • maxx, maxy
    • x, y
    • h, k

    So:

    long x, y;
    ...
    initgraph(...);
    ...
    long maxx = getmaxx();
    long maxy = getmaxy();
    ...
    long h = maxx / 2;
    long k = maxy / 2;
    

    And then you'll end up with correct output:

    enter image description here

    Note of course that like other answers point out, since you are using ints, you'll miss a lot of points. This may or may not be OK, but some values will produce noticeably poorer results (e.g. radius 256 only seems to have 4 integer solutions). You could introduce a tolerance if you want. You could also use a more direct approach but that might defeat the purpose of your exercise with the Cartesian circle formula. If you're into this sort of thing, here is a 24-page document containing a bunch of discussion, proofs, and properties about integers that are the sum of two squares.

    I don't know enough about Turbo C++ to know if you can make it use 32-bit ints, I'll leave that as an exercise to you.