2

我想在 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 循环中制作的小圆圈。

然而,当我尝试这个程序时,我得到了四个双曲线(都指向屏幕的中心),当我增加半径时,双曲线的尖度(因为没有更好的词)增加,直到最后,当半径是 256 或更多,上下两条双曲线相交在我的屏幕上形成一个大十字:“就是这样,用户,我放弃了!”

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

我四处寻找解决方案很长一段时间,但无法得到任何答案,所以我在这里。

有什么建议么???

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

这是粗略的输出

4

3 回答 3

4

您的代码中有两个问题:

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

其次,也是最重要的:在 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 = 最终计算的值 = 100 2 = 一个不应该出现的圆。

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

  • 最大,最大
  • x, y
  • h, k

所以:

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

然后你会得到正确的输出:

在此处输入图像描述

当然请注意,就像其他答案指出的那样,由于您使用的是整数,因此您会错过很多点。这可能会也可能不会,但某些值会产生明显较差的结果(例如,半径 256 似乎只有 4 个整数解)。如果你愿意,你可以引入一个容忍度。您也可以使用更直接的方法,但这可能会破坏您使用笛卡尔圆公式进行练习的目的。如果您喜欢这类事情,这里有一份 24 页的文档,其中包含一堆关于整数(两个平方和)的讨论、证明和属性。

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

于 2016-10-11T12:41:15.097 回答
1

首先,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)
于 2016-10-11T05:53:58.813 回答
1

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

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

要填充所有大圆周长(带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));

where mx, my- 大圆的中心

于 2016-10-11T09:06:00.537 回答