Матрица статей        Список статей        Всячина        Контакты       

L-системы

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

Рассмотрим получение строки. Задаётся начальная строка, называемая также аксиомой или инициатором, и набор правил, задающих на что заменять символы строки. Например, для снежинки Коха начальная строка имеет вид F++F++F, а правило имеет вид F → F-F++F-F.

Далее на каждом шаге одновременно заменются все символы строки согласно правилам. Для снежинки Коха имеем: F++F++F → F-F++F-F++F-F++F-F++F-F++F-F. На следующем шаге получим: F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F+F++F-F++F-F++F-F-F-F++F-F++F-F++F-F-F-F++F-F.

Продолжаем данный процесс заданное число шагов.

package ru.xaoc.fractalworld.lsystems;

import java.util.HashMap;
import java.util.Map;

public class LSystem {
    private String first;
    private Map rules;

    public LSystem(String first, Map rules) {
        this.first = first;
        this.rules = rules;
    }

    public LSystem(String first, String[][] rules) {
        this.first = first;
        this.rules = new HashMap();
        for (int i = 0; i < rules.length; ++i) {
           this.rules.put(rules[i][0].charAt(0), rules[i][1]);
        }
    }

    private String apply(String string) {
        StringBuilder result = new StringBuilder();
        for (int i = 0; i < string.length(); ++i) {
            if (rules.containsKey(string.charAt(i))) {
                result.append(rules.get(string.charAt(i)));
            } else {
                result.append(string.charAt(i));
            }
        }
        return result.toString();
    }

    public String getResult(int depth) {
        String result = first;
        for (int i = 0; i < depth; ++i) {
            result = this.apply(result);
        }
        return result;
    }
}

Состояние черепашки будем описывать тремя параметрами . Символы строки будем интерпретировать следующим образом:
F — переместиться вперёд на один шаг, прорисовывая след,
b — переместиться вперёд на один шаг, не оставляя следа, иногда вместо b используют G,
+ — уменьшить угол на заданную величину ,
- — увеличить угол на заданную величину ,
[ — запомнить состояние черепашки в стеке,
] — взять в качестве состояния черепашки последний элемент стека, и вытолкнуть этот элемент из стека.

package ru.xaoc.fractalworld.lsystems;

import java.util.Stack;

public class Turtle {

    private final Canvas canvas;
    private State state;
    private Stack memory = new Stack();
    private final double stepLength;
    private final double deltaAngle;

    public Turtle(Canvas canvas, double stepLength, double deltaAngle) {
        this.canvas = canvas;
        this.stepLength = stepLength;
        this.deltaAngle = deltaAngle;
    }

    public void draw(String string, State first) {
        state = first;
        for (int i = 0; i < string.length(); ++i) {
            switch (string.charAt(i)) {
                case 'F':
                    drawStep();
                    break;
                case 'b':
                    moveStep();
                    break;
                case '+':
                    rotateRight();
                    break;
                case '-':
                    rotateLeft();
                    break;
                case '[':
                    pushState();
                    break;
                case ']':
                    popState();
                    break;
                default:
                    break;
            }
        }
    }

    private void drawStep() {
        double oldX = state.getX();
        double oldY = state.getY();
        double angle = state.getAngle();
        double newX = oldX + Math.cos(angle) * stepLength;
        double newY = oldY - Math.sin(angle) * stepLength;
        canvas.drawLine(oldX, oldY, newX, newY);
        state = new State(newX, newY, angle);
    }

    private void moveStep() {
        double oldX = state.getX();
        double oldY = state.getY();
        double angle = state.getAngle();
        double newX = oldX + Math.cos(angle) * stepLength;
        double newY = oldY - Math.sin(angle) * stepLength;
        state = new State(newX, newY, angle);
    }

    private void rotateRight() {
        double x = state.getX();
        double y = state.getY();
        double oldAngle = state.getAngle();
        double newAngle = oldAngle - deltaAngle;
        state = new State(x, y, newAngle);
    }

    private void rotateLeft() {
        double x = state.getX();
        double y = state.getY();
        double oldAngle = state.getAngle();
        double newAngle = oldAngle + deltaAngle;
        state = new State(x, y, newAngle);
    }

    private void pushState() {
        memory.push(state);
    }

    private void popState() {
        state = memory.lastElement();
        memory.pop();
    }
}
package ru.xaoc.fractalworld.lsystems;

public class State {
    private double x;
    private double y;
    private double angle;

    public State(double x, double y, double angle) {
        this.x = x;
        this.y = y;
        this.angle = angle;
    }

    public double getX() {
        return x;
    }

    public double getY() {
        return y;
    }

    public double getAngle() {
        return angle;
    }
}

Скачайте весь исходный код.

Смотрите также:

Ссылки: