![]() |
Матрица статей Список статей Всячина Контакты | ||||||||||||
|
Построение аттракторов СИФ с помощью алгоритма времени убегания
Для построения аттракторов СИФ существуют два наиболее распространённых
алгоритма: детерминированный и рандомизированный. Здесь мы рассмотри ещё
один способ построения аттракторов СИФ — алгоритм времени убегания.
Этот алгоритм очень часто используется для построения множества Жюлиа.
И получил он своё название из-за того, что цвет точки определяется
временем убегания на бесконечность — числом итераций.
Ниже рассказано, как по СИФ, заданной в комплексной форме,
получить отображение
Рассмотрим СИФ
В случае, если СИФ не является вполне несвязной, также можно определить
отображение Ниже приведена реализация алгоритма времени убегания на языке 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;
}
При этом для задания отображения
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));
}
}
Скачать: Смотрите также: Ссылки:
|