2016-10-11 15 views
3

Я хотел нарисовать круг с использованием graphics.h на C++, но не напрямую с помощью функции circle(). Круг, который я хочу использовать, использует меньшие круги, так как это точки, то есть Меньшие круги будут представлять собой окружность большего круга. Поэтому я подумал, что если я сделал что-то вроде этого, он будет работать:Использование формулы стандартного прямоугольного круга для рисования круга в графическом режиме (C++)

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

Это когда я использую graphics.h на Turbo C++ как это компилятор мы учимся в школе с.

Я знаю, что это древний.

Итак, теоретически, поскольку вложенные циклы проверяют все точки на экране и рисуют небольшой круг в каждой точке, которая удовлетворяет только круговому уравнению, я думал, что получаю большой круг радиуса, чья окружность состоит из меньших кругов, которые я делаю в цикле for.

Однако, когда я пытаюсь программу, я получаю четыре гиперболы (все указывает по направлению к центру экрана), и когда я увеличить радиус, то pointiness (за неимением лучшего слова) увеличения гиперболы, пока, наконец, , когда радиус равен 256 или больше, два гиперболы сверху и снизу пересекаются, чтобы сделать большой крест на моем экране, например: «Вот и все, пользователь, я сдаюсь!»

Я пришел к значению 256, как я заметил, что радиус был кратным 4 фигурам, которые выглядели ... лучше?

Я довольно долго искал решение, но не мог получить ответы, поэтому я здесь.

Любые предложения ???

EDIT >> Вот грубая схема выхода я получил ...

This is the rough output

+0

Можете ли вы добавить скриншот или два из сломанного выхода? –

+0

Имеют ли maxx и maxy границы экрана? –

+0

@JasonC В настоящее время я работаю над своим ноутбуком, у которого нет Turbo C++, поэтому я не могу получить скриншоты, а мой настольный компьютер довольно далеко, поэтому я не могу. Сожалею. Вот почему я попытался изо всех сил описать выход ... – Zac

ответ

4

Есть две проблемы в вашем коде:

Во-первых: Вы должны действительно назвать initgraphперед тем вы называете getmaxx и getmaxy, в противном случае они не обязательно будут возвращать правильные размеры графического режима. Это может быть или не быть способным фактором в зависимости от вашей настройки.

Во-вторых, и самое главное: В Turbo C++, ИНТ 16-бит. Например, здесь окружность с радиусом 100 (после того, как предыдущий выпуск initgraph заказ был фиксированным):

enter image description here

Примечание паразитные круги в четырех углах. Если мы делаем немного отладки и добавить некоторые распечатки (полезная стратегия, которую вы должны спиливать для дальнейшего использования):

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, не показано выше фрагмент):

enter image description here

В частности, что круг в точке (63, 139) является одним из углов. Если вы делаете математику, вы видите, что:

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

И так как ваши Интс являются 16-бит, 75536 по модулю 65536 = 10000 = значение, которое в конечном итоге вычисляется = 100 = круг, где оно не должно быть.

Простое решение этой проблемы является просто изменить соответствующие переменные long:

  • Maxx, MAXY
  • х, у
  • Н, К

Итак:

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

А затем вы будете в конечном итоге с правильным выходом:

enter image description here

Примечание, конечно, нравится other answers point out, так как вы используете Интс, вы пропустите много очков. Это может быть или не быть нормально, но некоторые значения будут давать значительно более низкие результаты (например, радиус 256 только имеет 4 целочисленных решения). Если хотите, вы можете ввести допуск. Вы также можете использовать a more direct approach, но это может привести к поражению цели вашего упражнения с помощью формулы Картезианского круга. Если вы в этом разбираетесь, вот 24-страничный документ, содержащий кучу обсуждений, доказательств и свойств около integers that are the sum of two squares.

Я не знаю достаточно о Turbo C++, чтобы узнать, можете ли вы использовать 32-битные ints, я оставлю это как упражнение для вас.

+0

Да, поскольку я написал код непосредственно на Stack Overflow, не проверив исходный код, который я сделал, я сделал глупую ошибку «вызов getmaxx, y перед переходом в графический режим», спасибо, что указали это. И WOW, я знал о 16-битных значениях int, но я никогда не обращал внимания на эту деталь раньше, и мне никогда не приходило в голову, что это может быть основной причиной! Теперь код работает нормально. Это было потрясающе. Большое спасибо!И спасибо за распечатку, я тоже это вспомню! – Zac

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) 
+0

На данный момент я не смогу проверьте, так как я не могу получить доступ к другому компьютеру, но не могли бы вы объяснить немного больше? Я предполагаю, что вы имеете в виду, так как экран является сеткой пикселей, многие точки, которые должны удовлетворять уравнению, не будут связаны с тем, что использование типа данных int недостаточно точно для координат? Или это допуск, используемый для удаления окружностей, сформированных дополнительно (как часть других 3 гипербола) – Zac

+0

@ Zac, это первый. Если круг проходит через квадрат, образованный четырьмя пикселями, но не пересекается ни с одним из них, тогда ваш алгоритм не будет отображать круг. Введение толерантности решает это, поскольку вы проверяете небольшое расстояние вместо точного пересечения. –

+0

Это не объясняет гиперболы. –

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)); 

где mx, my - центр большого круга

+0

Это определенно интересный подход (это может быть ключом к моему следующему проекту на C++ >>> Создание маленьких кружков появляется и исчезает в порядке появления на окружности больших кругов), я рассмотрю его. Благодаря! – Zac