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

Построение аттракторов СИФ с помощью алгоритма времени убегания

Для построения аттракторов СИФ существуют два наиболее распространённых алгоритма: детерминированный и рандомизированный. Здесь мы рассмотри ещё один способ построения аттракторов СИФ — алгоритм времени убегания. Этот алгоритм очень часто используется для построения множества Жюлиа. И получил он своё название из-за того, что цвет точки определяется временем убегания на бесконечность — числом итераций. Ниже рассказано, как по СИФ, заданной в комплексной форме, получить отображение , которое и будет итерироваться.

Рассмотрим СИФ , заданную набором сжимающих отображений , . Пусть — аттрактор этой СИФ, все обратимы, вполне несвязна, то есть , . Разобъём множество на множества так, что . Положим

В случае, если СИФ не является вполне несвязной, также можно определить отображение , разбивая множество тем или иным способом.

Ниже приведена реализация алгоритма времени убегания на языке Java.

public class JuliaPainter implements Painter
{
private Rectangle2D getBounds()
{
	return new Rectangle2D.Double(-2, -2, 4, 4);
}

private AffineTransform getTransform()
{
	Rectangle2D rectangle = getBounds();
	double scale = Math.min((size.width - 2 * BORDER) / rectangle.getWidth(),
			(size.height - 2 * BORDER) / rectangle.getHeight());
	AffineTransform transform =
		AffineTransform.getTranslateInstance(
		-rectangle.getCenterX(), -rectangle.getCenterY());
	transform.preConcatenate(AffineTransform.getScaleInstance(
		scale, -scale));
	transform.preConcatenate(AffineTransform.getTranslateInstance(
		size.getCenterX(), size.getCenterY()));
	return transform;
}

public Image createImage() throws java.awt.geom.NoninvertibleTransformException
{
	BufferedImage image = new BufferedImage(size.width, size.height, 
		BufferedImage.TYPE_INT_RGB);
	Graphics graphics = image.getGraphics();
	graphics.setColor(Color.WHITE);
	graphics.fillRect(0, 0, size.width, size.height);
	AffineTransform resultTransform = new AffineTransform();
	resultTransform.concatenate(getTransform());
	Complex z;
	int n;
	for (int x = 0; x < size.width; ++x)
		for (int y = 0; y < size.height; ++y)
		{
			n = 0;
			Point2D point = resultTransform.inverseTransform(
				new Point2D.Double(x, y), null);
			z = new Complex(point.getX(), point.getY());
			while (Complex.abs(z) < MAX_Z && n < MAX_ITER)
			{
				z = map.map(z);
				++n;
			}
			image.setRGB((int)x, (int)y,
					colorer.getColor(n, z).getRGB());
		}
	return image;
}

public void setColorer(Colorer colorer)
{
	this.colorer = colorer;
}

public void setMap(Map map)
{
	this.map = map;
}

public void setSize(Rectangle size)
{
	this.size = size;
}

private Rectangle size = new Rectangle(640, 480);

private Colorer colorer = null;

private Map map = null;

private static final int BORDER = 20;

private static final int MAX_Z = 10;

private static final int MAX_ITER = 50;
}

При этом для задания отображения необходимо реализовать интерфейс Map. Например для классического множества Жюлиа эта реализация выглядит так:

public static class JuliaSet implements Painter.Map
{
	public JuliaSet(Complex c)
	{
		this.c = c;
	}

	public Complex map(Complex z)
	{
		return Complex.pow(z, 2).add(c);
	}

	private Complex c;
}

Рассмотрим СИФ, подобная которой использовалась в статье Фракталы из многоугольников:

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

Разобъём плоскость на части , , , как на рисунке ниже.

Определим функцию следующим образом:

 
public static class Polygon implements Painter.Map
{
	public Polygon(int n, double r)
	{
		this.n = n;
		this.r = r;
	}

	public Complex map(Complex z)
	{
		int k = (int)Math.floor(Complex.arg(z) / 2 / Math.PI * n + 0.5);
		return z.rotate(-2 * Math.PI * k / n).sub(1).div(r);
	}

	private int n;
	private double r;
}

Треугольник Серпинского Фрактал из шестиугольников

Немного усложним предыдущий пример. Рассмотрим СИФ, которая использовалась для построения фрактальных вихрей в статье Фрактальные вихри:

где , . Пример аттрактора приведён на рисунке.
Фрактальные вихри

Разобъём плоскость на части , , , как на рисунке ниже.

Тогда определим функцию следующим образом:

public static class Whirl implements Painter.Map
{
	public Whirl(int n, double r, double phi, double R)
	{
		this.n = n;
		this.r = r;
		this.phi = phi;
		this.R = R;
	}

	public Complex map(Complex z)
	{
		if (Complex.abs(z) < 1 - r / (1 - r))
			return z.div(R).rotate(-phi);
		int k = (int)Math.floor(Complex.arg(z) / 2 / Math.PI * n + 0.5);
		return z.rotate(-2 * Math.PI * k / n).sub(1).div(r);
	}

	private int n;
	private double r;
	private double phi;
	private double R;
}

Фрактальные вихри Фрактальные вихри

Рассмотрим систему итерируемых функций:

Аттрактор этой СИФ приведён на рисунке ниже.

Разобъём плоскость на три части , , как на рисунке ниже.


Положим

public static class Binary implements Painter.Map
{
	public Complex map(Complex z)
	{
		if (z.getReal() > 0 && z.getImag() < 0)
			return z.mul(2).add(new Complex(-1, 1));
		else if (z.getReal() > 0 && z.getImag() > 0)
			return z.mul(2).add(new Complex(-1, -1)).rotate(- Math.PI / 2);
		return z.mul(2).add(new Complex(1, 1));
	}
}


Скачать:

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

Ссылки:

  • Barnsley M. Fractals everywhere, Academic Press, Boston, 1988, 248—257.