Игра в хаос и треугольник Серпинского на C#


Игра "Хаос" - это метод создания фрактальных изображений путем построения случайных точек внутри многоугольника в соответствии с простым набором правил. В этой статье мы будем использовать игру в хаос для создания треугольника Серпинского с использованием C# и Windows Forms.

Игра в Хаос

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

Как только начальное условие известно, для создания фрактала выполняется повторяющийся процесс. Сначала выбирается случайная вершина в многоугольнике. Затем текущее положение или начальное положение для первой итерации соединяется с положением аттрактора воображаемой прямой линией. Текущее положение перемещается вдоль этой линии на долю расстояния между двумя точками, и на рисунке отображается новое положение.

Треугольник Серпинского

Треугольник Серпинского - это фрактал, который был впервые описан польским математиком Вацлавом Серпинским. При отображении он выглядит как треугольник, разделенный на четыре секции, каждая из которых составляет половину высоты и ширины оригинала. Центральный треугольник перевернут и может рассматриваться как отверстие на изображении. Каждый из трех внешних треугольников представляет собой уменьшенную версию всей фигуры с собственным центральным отверстием. Этот шаблон повторяется бесконечно, чтобы получить результат, аналогичный показанному на рисунке ниже:

Треугольник Серпинского
Треугольник Серпинского

Существуют различные методы, с помощью которых можно создать треугольник Серпинского. Одним из них является использование игры хаоса с тремя аттракторами, расположенными в трех вершинах равностороннего треугольника. При перемещении текущей позиции к аттрактору перемещаемая величина всегда равна половине расстояния между текущей точкой и выбранной вершиной. Таким образом, шаги по созданию фрактала заключаются в следующем:

  1. Определите три точки.
  2. Выберите начальную позицию.
  3. Случайным образом выберите один из трех аттракторов.
  4. Переместите текущее положение на полпути к выбранному положению аттрактора и постройте точку.
  5. Вернитесь к шагу 3.
Рисование треугольника Серпинского

В оставшейся части этой статьи мы создадим программу на C# для создания треугольника Серпинского. Программа, которую мы разработаем, - это та, которая использовалась для создания изображения выше.

Создание проекта

Для начала создайте проект Windows Forms. Мы будем использовать форму по умолчанию для отображения треугольника, рисуя непосредственно на поверхности формы. Откройте форму по умолчанию и измените ее свойство BackColor на белый. Мы запустим процесс генерации фрактала в ответ на нажатие кнопки, поэтому добавьте кнопку в форму и нанесите на нее подходящую метку, используя свойство Text.

Переменные области действия на уровне класса

Во время создания изображения есть три элемента, которые будут использоваться различными методами. Первый - генератор псевдослучайных чисел, который будет использоваться для определения направления движения во время каждой итерации игры в хаос. Во-вторых, нам нужно удерживать позиции трех вершин равностороннего треугольника. Мы можем хранить их в небольшом массиве точечных структур. Наконец, еще одна точечная структура сохранит текущую позицию.

Чтобы объявить переменные для этих элементов, добавьте в класс следующие переменные области действия на уровне класса:

Random _randomiser = new Random();
private Point[] _points;
private Point _currentLocation;
Определение размера треугольника

Размер треугольника должен быть как можно больше, чтобы можно было отобразить максимальную детализацию. Тем не менее, мы хотим убедиться, что треугольник является равносторонним и расположен в центре клиентской области формы. Чтобы определить максимально возможный размер, мы должны рассмотреть соотношение между высотой и шириной любого равностороннего треугольника. Предполагая, что основание треугольника выровнено по горизонтали, ширина будет такой же, как длина одной из сторон. Высота будет равна ширине, умноженной на половину квадратного корня из трех.

Мы можем добавить метод в форму для расчета коэффициента, добавив следующий код:

private double HeightWidthRatio()
{
    return Math.Sqrt(3) / 2;
}
С помощью легко доступного соотношения мы можем определить максимальный размер треугольника, сравнивая полную ширину клиентской области формы и ее высоту, деленную на соотношение. Меньшее из этих двух значений является наибольшим размером. Следующий метод должен быть добавлен в класс формы для вычисления размера треугольника. Обратите внимание, что высота уменьшается на два перед возвратом. Это позволит создать небольшую границу по краю фрактала.

private int SideLength()
{
    int height = (int)Math.Min(
        (double)ClientSize.Width, ClientSize.Height / HeightWidthRatio());
    return (int)height - 2;
}
Установка расположения вершин

Следующий метод рассчитает положения каждого из трех аттракторов, каждый из которых расположен в вершине треугольника. Эти значения будут основаны на размере треугольника и средней точке клиентской области формы. Средняя точка рассчитывается сначала с использованием половины высоты и ширины формы. Затем мы добавляем верхнюю вершину, которая будет нулевой точкой, координата X которой выровнена по вертикали со средней точкой, а координата Y равна половине высоты треугольника над средней точкой.

Две нижние вершины расположены на половине высоты треугольника ниже центра формы и на половине его ширины по обе стороны от этой точки. Это точки один и два в массиве.

private void SetPointLocations(int sideLength)
{
    Point midPoint = new Point(ClientSize.Width / 2, ClientSize.Height / 2);
    _points = new Point[3];
    _points[0] = new Point(midPoint.X,
        midPoint.Y - (int)(sideLength * HeightWidthRatio() / 2));
    _points[1] = new Point(midPoint.X - sideLength / 2,
        midPoint.Y + (int)(sideLength * HeightWidthRatio() / 2));
    _points[2] = new Point(midPoint.X + sideLength / 2,
        midPoint.Y + (int)(sideLength * HeightWidthRatio() / 2));
}
Построение графиков вершин

Следующая задача - создать метод построения положения вершин. Это достигается за счет использования цикла "для каждого" для построения положения каждой точки по очереди. Фактический рисунок будет выполнен другим методом, в данном случае называемым "Точка построения", так как он будет повторно использован для построения точек во время создания фрактала. Обратите внимание, что оба этих метода принимают параметр, содержащий графическую поверхность, на которой нужно рисовать. Это будет создано, когда пользователь нажмет на кнопку.

private void PlotPointLocations(Graphics g)
{
    foreach (Point p in _points)
    {
        PlotPoint(p, g);
    }
}
 
private void PlotPoint(Point p, Graphics g)
{
    Brush b = new SolidBrush(Color.Black);
    g.FillRectangle(b, p.X, p.Y, 1, 1);
}
Построение случайной точки

Предыдущие методы управляют инициализацией треугольника. Теперь мы можем создать методы, которые используются в цикле алгоритма для рисования фрактала. Метод DrawNextPoint будет управлять этим процессом, вызывая новый метод с именем "MoveTowardsRandomPoint", за которым следует вызов PlotPoint для размещения точки в текущем положении. Наконец, он вызывает приложение. Выполняйте события так, чтобы обновленный чертеж был виден.

MoveTowardsRandomPoint выбирает одну из трех вершин с помощью объекта рандомизатора. Затем он вычисляет положение, которое находится на полпути между текущим положением и выбранным аттрактором, и перемещается в эту точку. Добавьте два метода, описанных ниже, в класс формы:

private void DrawNextPoint(Graphics g)
{
    MoveTowardsRandomPoint();
    PlotPoint(_currentLocation, g);
    Application.DoEvents();
}
 
private void MoveTowardsRandomPoint()
{
    int moveTowards = _randomiser.Next(0,3);
    _currentLocation.X = (_currentLocation.X + _points[moveTowards].X) / 2;
    _currentLocation.Y = (_currentLocation.Y + _points[moveTowards].Y) / 2;
}
Создание цикла

Заключительная задача состоит в том, чтобы объединить все методы в событии нажатия кнопки формы. Добавьте приведенный ниже код в событие кнопки. Это начинается с получения графической области формы и размера треугольника. Размер используется для вычисления положений трех вершин и сохранения их в массиве. Как только три точки будут нанесены на график, будет задано начальное местоположение. В этом случае я использовал положение верхней вершины в качестве отправной точки.

Бесконечный цикл создается с помощью цикла while с условием, которое всегда будет истинным. В этом цикле повторно вызывается метод DrawNextPoint. В идеале вы должны создать цикл, который может быть остановлен пользователем.

Graphics g = CreateGraphics();
int sideLength = SideLength();
SetPointLocations(sideLength);
PlotPointLocations(g);
_currentLocation = new Point(_points[0].X, _points[0].Y);
 
while (true)
{
    DrawNextPoint(g);
}
Автор этого материала - я - Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML - то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.

тегизаметки, си шарп, графики, алгоритмы, изображения




Отправляя сообщение я подтверждаю, что ознакомлен и согласен с политикой конфиденциальности данного сайта.




Урок 19. Метод clone() и его альтернативы в Java
Перехват очереди печати на C#
Часто используемые команды git