Концентрические окружности

Содержание :: Циклы :: Концентрические окружности

Теперь рассмотрим как вывести набор кругов вложенных друг в друга с одним центром но с разными радиусами. Давайте сперва представим как можно вывести несколько кругов последовательно вызывая функцию отрисовки круга DrawEllipse

// рисуем первый круг
float Radius1 = 10;
DrawEllipse(Pens.Black, CenterX - Radius1, CenterY - Radius1, 2 * Radius1, 2 * Radius1);

// рисуем второй круг
float Radius2 = 20;
DrawEllipse(Pens.Black, CenterX - Radius2, CenterY - Radius2, 2 * Radius2, 2 * Radius2);

// рисуем третий круг
float Radius3 = 30;
DrawEllipse(Pens.Black, CenterX - Radius3, CenterY - Radius3, 2 * Radius3, 2 * Radius3);

 .... // и так далее в зависисмости сколько крпугов нужно вывести

Если внимательно посмотреть на эти три блока то можно увидеть, что они практически полностью идентичны, отличаются только радиусы (каждый следующий радиус увеличивается на 10 от предыдущего). Такие наборы инструкций где один параметр (или несколько) меняется по определнному закону удобно завернуть в цикл.

В некоторых случаях, применяется обратная процедура, развертка (размотка) цикла (loop unrolling). Когда либо увеличивается количество однотипных операций внутри цикла и количество итераций цикла уменьшается, либо когда цикл убирается совсем. Это продвинутые техники оптимизации, которые используются профессинальными программистами.
Дополнительная информация

Как мы видим количество строчек инструкций кода строго равно количеству выводимых кругов. Этот подход не универсальный, т.к. он статичный. Если мне потребуется изменить количество выводимых кругов, то мне придется переписывать программу и компилировать ее заново. Если потребуется менять количество кругов динамически в ходе работы программы (например количество рисуемых кругов должен задавать пользователь и мы не знаем заранее сколько их будет), то без использования цикла сделать это правильно невозможно в-принципе.  

Давайте перепишем код и воспользуемся гибким способом с использованием цикла for (цикл со счетчиком)

Объявим необходимые переменные

float Radius = 50;//стартовый радиус первого выводимого круга
float Step = 10;// шаг приращения радиуса каждого следующего выводимого круга
int Qty = 15; // количество выводимых кругов

Расчитаем центр нашего окна используя ClientSize

var centerX = ClientSize.Width / 2;
var centerY = ClientSize.Height / 2;

var radius = Radius;

for (int i = 0; i < Qty; i++) //выполним цикл Qty раз
{
    gr.DrawEllipse(Pens.Black, centerX - radius, centerY - radius, radius * 2, radius * 2);
    radius += Step; // на каждой итерации цикла увеличиваем наш радиус на Step
}

Вставив и запустив данный пример мы увидим следующую картинку:

 

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


Упражнения

  • Убрать локальную переменную radius, заменить расчет текущего радиуса используя только счетчик i
  • Заменит счетчик i (индекс текущего круга) на счетчик radius в цикле for.