Рисование фракталов через L-системы и черепашью графику

Рисование фракталов через L-системы и черепашью графику

Фракталы — это геометрические фигуры, которые могут быть разделены на части, каждая из которых является уменьшенной копией целого. Одним из способов создания фракталов является использование L-систем (систем переписывания строк) и черепашьей графики. В этой статье мы рассмотрим, что такое L-системы и черепашьи графики, как они работают вместе, и как реализовать программу для рисования фракталов на языке программирования D.

Что такое L-системы?

L-системы, или системы Линдемаера, были предложены биологом Аристидом Линдемаром в 1968 году для моделирования роста растений. L-системы основаны на переписывании строк согласно набору правил.

Основные компоненты L-системы:

  1. Алфавит: множество символов, которые могут появляться в строках.
  2. Аксиома: начальная строка.
  3. Набор правил переписывания: определяет, как каждый символ в строке заменяется новыми символами.

Пример L-системы:

  • Алфавит: F, +, -
  • Аксиома: F
  • Правила: F -> F+F-F-F+F

Что такое черепашья графика?

Черепашья графика — это метод программирования векторной графики, в котором «черепаха» перемещается по экрану, рисуя линии. Черепаха обладает состоянием, включающим положение, направление и цвет пера.

Основные команды черепашки:

  • F: двигаться вперед на определенное расстояние, рисуя линию.
  • +: повернуть направо на заданный угол.
  • -: повернуть налево на заданный угол.

Работа L-систем и черепашьей графики вместе

L-системы генерируют строки, которые интерпретируются командами черепахи для рисования фракталов. Сначала мы создаем строку с помощью L-системы, затем используем эту строку для управления движением черепахи.

Реализация программы на языке D

Внутренняя структура данных

Для реализации L-системы и черепашьей графики нам понадобятся следующие структуры данных:

  • Строка для хранения текущего состояния L-системы.
  • Список команд черепахи.
  • Позиция и угол направления черепахи.

Реализация класса «Черепаха»

import std.stdio;
import std.math;
import std.array;
import std.conv;
import std.string;
import std.algorithm;
import std.range;

struct Point {
    double x, y;
}

class Turtle {
    private Point position;
    private double angle;
    private double stepSize;
    private double angleIncrement;

    this(double startX, double startY, double startAngle, double step, double angleInc) {
        position = Point(startX, startY);
        angle = startAngle;
        stepSize = step;
        angleIncrement = angleInc;
    }

    void moveForward() {
        double rad = angle * PI / 180.0;
        position.x += stepSize * cos(rad);
        position.y += stepSize * sin(rad);
        writeln("Move to (", position.x, ", ", position.y, ")");
    }

    void turnRight() {
        angle -= angleIncrement;
    }

    void turnLeft() {
        angle += angleIncrement;
    }

    void interpretCommands(string commands) {
        foreach (char cmd; commands) {
            switch (cmd) {
                case 'F':
                    moveForward();
                    break;
                case '+':
                    turnRight();
                    break;
                case '-':
                    turnLeft();
                    break;
            }
        }
    }
}

class LSystem {
    string axiom;
    string[] rules;
    int iterations;

    this(string ax, string[] rls, int iter) {
        axiom = ax;
        rules = rls;
        iterations = iter;
    }

    string generate() {
        string current = axiom;
        foreach (int i; 0 .. iterations) {
            current = rewrite(current);
        }
        return current;
    }

    string rewrite(string str) {
        string result;
        foreach (char ch; str) {
            bool replaced = false;
            foreach (rule; rules) {
                if (ch == rule[0]) {
                    result ~= rule[2 .. $];
                    replaced = true;
                    break;
                }
            }
            if (!replaced) {
                result ~= ch;
            }
        }
        return result;
    }
}

void main() {
    string[] rules = ["F -> F+F-F-F+F"];
    LSystem ls = new LSystem("F", rules, 4);
    string result = ls.generate();
    writeln("Generated string: ", result);

    Turtle turtle = new Turtle(0.0, 0.0, 0.0, 5.0, 90.0);
    turtle.interpretCommands(result);
}

Пояснение к коду

  1. Структура Point: используется для хранения координат точки (x, y).
  2. Класс Turtle: реализует черепаху с методами moveForward, turnRight, turnLeft и interpretCommands.
  • moveForward: вычисляет новые координаты черепахи и перемещает её вперед.
  • turnRight и turnLeft: изменяют угол направления черепахи.
  • interpretCommands: интерпретирует строку команд и вызывает соответствующие методы.
  1. Класс LSystem: реализует L-систему с методами generate и rewrite.
  • generate: генерирует строку на основе начальной аксиомы и правил переписывания.
  • rewrite: переписывает строку по заданным правилам.

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


Карпов Ярослав

Автор статьи:

Обновлено:

23.05.2024


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *