使用标准笛卡尔圆公式在图形模式下绘制圆(C++)

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

我想在 C++ 中使用 graphics.h 画一个圆,而不是直接使用 circle() 函数。我要绘制的圆使用较小的圆作为点,即 较小的圆将构成较大圆的周长。所以我想,如果我做这样的事情,它会起作用:

    {
        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();
    }

这是我在 Turbo C++ 上使用 graphics.h 的时候,因为这是我们在学校学习的编译器。

我知道它很古老

所以,理论上,由于嵌套的 for 循环会检查屏幕上的所有点,并在每个满足圆方程的点处绘制一个小圆,我想我会得到一个输入的大半径圆,其圆周由我在 for 循环中制作的较小圆圈组成。

然而,当我尝试这个程序时,我得到了四个双曲线(都指向屏幕中心),当我增加半径时,pointiness(因为缺少一个更好的词)的双曲线增加,直到最后,当半径为 256 或更大时,顶部和底部的两条双曲线相交,在我的屏幕上形成一个大十字,如:"That's it, user, I give up!"

我发现值 256 是因为我注意到半径是 4 的倍数,这些数字看起来……更好?

我四处寻找解决方案很长一段时间,但没有得到任何答案,所以我来了。

有什么建议吗???

编辑 >> 这是我得到的输出的粗略图表...

首先,maxx 和 maxy 是整数,您使用一些表示屏幕边界的函数对其进行初始化,然后将它们用作函数。只需删除括号:

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

然后,您正在检查是否完全相等,以检查一个点是否在圆上。由于屏幕是像素网格,因此您的许多要点都将被遗漏。您需要添加一个公差,即您检查的点与实际圆之间的最大距离。所以改变这一行:

if(((x-h)*(x-h)) + ((y-k)*(y-k)) == radius*radius)

对此:

if(abs(((x-h)*(x-h)) + ((y-k)*(y-k)) - radius*radius) < 2)

引入一定程度的容忍度将解决问题。

但是检查图形中的所有点是不明智的window。你会改变一种方法吗?您可以完全不检查而绘制所需的小圆圈:

要填充所有大圆周(半径 RBig),您需要 NCircles 个半径 RSmall 的小圆

NCircles = round to integer (Pi / ArcSin(RSmall / RBig)); 

第i个小圆心在位置

cx = mx + Round(RBig * Cos(i * 2 * Pi / N)); 
cy = my + Round(RBig * Sin(i * 2 * Pi / N));

其中 mx, my - 大圆的中心

您的代码中有两个问题:

第一:在getmaxxgetmaxy调用initgraph之前,你真的应该先调用initgraph,否则它们不一定会return ] 图形模式的正确尺寸。这可能是也可能不是影响因素,具体取决于您的设置。

其次,也是最重要的:在 Turbo C++ 中,int 是 16 位的。例如,这里是半径为 100 的圆(在前面的 initgraph 命令之后问题已解决):

注意四个角上的杂散圆圈。如果我们进行一些调试并添加一些打印输出(一个有用的策略,您应该存档以备将来参考):

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!

您可以看到发生了什么(第一行是 maxx 和 maxy,上面的片段中没有显示):

特别是 (63, 139) 处的圆是其中一个角。如果你计算一下,你会看到:

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

并且由于您的整数是 16 位的,所以 75536 模 65536 = 10000 = 最终计算的值 = 1002 = 一个不应该出现的圆。

一个简单的解决方案是将相关变量更改为 long:

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

所以:

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

然后您将得到正确的输出:

当然要注意点赞, 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 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.

我对 Turbo C++ 的了解还不够,不知道您是否可以使用 32 位整数,我将把它留给您作为练习。