Метод numIterations(double, double) реализует итеративную функцию для фрактала Мандельброта. Константу с максимальным количеством итераций можно определить следующим образом:
public static final int MAX_ITERATIONS = 2000;
Затем вы сможете ссылаться на эту переменную в вашей реализации.
Обратите внимание на то, что у Java нет подходящего типа данных для комплексных чисел, поэтому необходимо будет реализовать итеративную функцию, используя отдельные переменные для действительной и мнимой частей. (Вы можете реализовать отдельный класс для комплексных чисел.) Ваш алгоритм должен обладать быстродействием, например, не стоит сравнивать |z|
с 2; сравните |z|2 с 22 для того, чтобы избежать сложных и медленных вычислений квадратного корня. Также не стоит использовать метод Math.pow ()
для вычисления небольших степеней, лучше перемножьте значение, иначе ваш быстродействие вашего кода сильно упадет.
В случае, если алгоритм дошел до значения MAX_ITERATIONS нужно вернуть -1, чтобы показать, что точка не выходит за границы.
Ваши задачи
Создайте класс FractalExplorer, который позволит вам исследовать различные области фрактала, путем его создания, отображения через графический интерфейс Swing и обработки событий, вызванных взаимодействием приложения с пользователем.
Как видно их приведенных выше изображений пользовательского интерфейса, FractalExplorer очень прост, он состоит из JFrame, который в свою очередь содержит объект JImageDisplay, который отображает фрактал,и объект
JButton для сброса изображения, необходимый для отображения целого фрактала. Данный макет можно создать, установив для фрейма BorderLayout,
затем поместив отображение в центр макета и кнопку сброса в "южной" части макета.
Класс FractalExplorer должен отслеживать несколько важных полей
для состояния программы:
1)Целое число «размер экрана», которое является шириной и высотой отображения в пикселях. (Отображение фрактала будет квадратным.)
2)Ссылка JImageDisplay, для обновления отображения в разных методах в процессе вычисления фрактала.
3)Объект FractalGenerator. Будет использоваться ссылка на базовый класс для отображения других видов фракталов в будущем.
4)Объект Rectangle2D.Double, указывающий диапазона комплексной плоскости, которая выводится на экран.
Все вышеприведенные поля будут иметь тип доступа private.
У класса должен быть конструктор, который принимает значение размера отображения в качестве аргумента, затем сохраняет это значение в соответствующем поле, а также инициализирует объекты диапазона и фрактального генератора. Данный конструктор не должен устанавливать какие-
либо компоненты Swing; они будут установлены в следующем методе.
Создайте метод createAndShowGUI (), который инициализирует графический интерфейс Swing: JFrame, содержащий объект JimageDisplay, и
кнопку для сброса отображения. Используйте java.awt.BorderLayout для содержимого окна; добавьте объект отображения изображения в позицию
BorderLayout.CENTER и кнопку в позицию BorderLayout.SOUTH.
Вам необходимо дать окну подходящий заголовок и обеспечить операцию закрытия окна по умолчанию (см. метод
JFrame.setDefaultCloseOperation ()).
После того, как компоненты пользовательского интерфейса инициализированы и размещены, добавьте следующую последовательность операций:
frame.pack (); frame.setVisible (true);
frame.setResizable (false);
Данные операции правильно разметят содержимое окна, сделают его видимым (окна первоначально не отображаются при их создании для того,
чтобы можно было сконфигурировать их прежде, чем выводить на экран), и
затем запретят изменение размеров окна.
Реализуйте вспомогательный метод с типом доступа private для вывода на экран фрактала, можете дать ему имя drawFractal (). Этот метод должен циклически проходить через каждый пиксель в отображении (т.е.
значения x и y будут меняться от 0 до размера отображения), и сделайте следующее:
Вычислите количество итераций для соответствующих координат в области отображения фрактала. Вы можете определить координаты с плавающей точкой для определенного набора координат пикселей, используя вспомогательный метод FractalGenerator.getCoord (); например, чтобы получить координату x, соответствующую координате пикселя X, сделайте следующее:
//x - пиксельная координата; xCoord - координата в пространстве фрактала
double xCoord = FractalGenerator.getCoord (range.x, range.x + range.width, displaySize, x);
Если число итераций равно -1 (т.е. точка не выходит за границы,
установите пиксель в черный цвет (для rgb значение 0). Иначе выберите значение цвета, основанное на количестве итераций. Можно также для этого использовать цветовое пространство HSV: поскольку значение цвета варьируется от 0 до 1, получается плавная последовательность цветов от красного к желтому, зеленому, синему, фиолетовому и затем обратно к красному! Для этого вы можете использовать следующий фрагмент:
float hue = 0.7f + (float) numIters / 200f;
int rgbColor = Color.HSBtoRGB(hue, 1f, 1f);
Если вы придумали другой способ отображения пикселей в зависимости
от количества итераций, попробуйте реализовать его!
Отображение необходимо обновлять в соответствии с цветом для каждого пикселя.
После того, как вы закончили отрисовывать все пиксели, вам необходимо обновить JimageDisplay в соответствии с текущим изображением.
Для этого вызовите функцию repaint() для компонента. В случае, если вы не воспользуетесь данным методом, изображение на экране не будет обновляться!
Создайте внутренний класс для обработки событий
java.awt.event.ActionListener от кнопки сброса. Обработчик должен сбросить диапазон к начальному, определенному генератором, а затем перерисовать фрактал.
После того, как вы создали этот класс, обновите метод createAndShowGUI
().
Создайте другой внутренний класс для обработки событий
java.awt.event.MouseListener с дисплея. Вам необходимо обработать события от мыши, поэтому вы должны унаследовать этот внутренний класс от класса
MouseAdapterAWT. При получении события о щелчке мышью, класс должен отобразить пиксельные кооринаты щелчка в область фрактала, а затем вызвать метод генератора recenterAndZoomRange() с координатами, по которым щелкнули, и масштабом 0.5. Таким образом, нажимая на какое-либо место на фрактальном отображении, вы увеличиваете его!
Не забывайте перерисовывать фрактал после того, как вы меняете область фрактала.
Далее обновите метод createAndShowGUI (), чтобы зарегистрировать экземпляр этого обработчика в компоненте фрактального отображения.
В заключении, вам необходимо создать статический метод main()
для FractalExplorer так, чтобы можно было его запустить. В main необходимо
будет сделать:
Инициализировать новый экземпляр класса FractalExplorer с
размером отображения 800.
Вызовите метод createAndShowGUI () класса FractalExplorer.
Вызовите метод drawFractal() класса FractalExplorer для отображения начального представления.
После выполнения приведенных выше действий, вы сможете детально рассмотреть фрактал Мандельброта. Если вы увеличите масштаб, то вы можете столкнуться с двумя проблемами:
Во-первых, вы сможете заметить, что в конечном итоге уровень детализации заканчивается; это вызвано тем, что в таком случае необходимо более 2000 итераций для поиска точки во множестве Мандельброта! Можно увеличить максимальное количество итераций, но это приведет к замедлению работы алгоритма.
Во-вторых, при сильном увеличении масштаба, вы столкнетесь с пиксельным выводом отображения! Это вызвано тем, что вы работаете в пределе того, что могут предоставить значения с плавающей запятой с двойной точностью.
При рисовании фрактала экран ненадолго зависает. Следующая
лабораторная работа будет направлена на решение данной проблемы.