Фракталы в математике и пример на Java


В математике фрактал - это любая из класса сложных геометрических фигур, которые обычно имеют “дробную размерность”, понятие, впервые введенное математиком Феликсом Хаусдорфом в 1918 году. Фракталы отличаются от простых фигур классической или евклидовой геометрии — квадрата, круга, сферы и так далее. Они способны описывать многие объекты неправильной формы или пространственно неоднородные явления в природе, такие как береговые линии и горные хребты. Термин фрактал, происходящий от латинского слова fractus (“фрагментированный” или “сломанный”), был введен математиком польского происхождения Бенуа Б. Мандельбротом.

Одно из самых ранних применений фракталов появилось задолго до того, как был использован этот термин. Льюис Фрай Ричардсон был английским математиком в начале 20 века, изучавшим протяженность береговой линии Англии. Он рассудил, что длина береговой линии зависит от длины измерительного инструмента. Измерьте с помощью мерила, вы получите одно число, но измерьте с помощью более подробной линейки длиной в фут, которая учитывает больше неровностей береговой линии, и вы получите большее число, и так далее.

Доведите это до логического завершения, и вы получите бесконечно длинную береговую линию, содержащую конечное пространство, тот же парадокс, выдвинутый Хельге фон Кохом в "Снежинке Коха". Этот фрактал включает в себя взятие треугольника и превращение центральной трети каждого сегмента в треугольную выпуклость таким образом, чтобы фрактал был симметричным. Каждый выступ, конечно, длиннее исходного сегмента, но все же содержит конечное пространство внутри.

снежинка коха

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

Все фракталы демонстрируют определенную степень так называемого самоподобия. Это означает, что по мере того, как вы все ближе и ближе вглядываетесь в детали фрактала, вы можете увидеть точную копию целого. Папоротник - классический пример. Посмотрите на него. Видите ветви, отходящие от главного стебля? Каждая из этих ветвей похожа на весь лист. Они самоподобны оригиналу, только в меньшем масштабе.

Эти самоподобные паттерны являются результатом простого уравнения или математического утверждения. Фракталы создаются путем повторения этого уравнения через цикл обратной связи в процессе, называемом итерацией, где результаты одной итерации формируют входное значение для следующей. Например, если вы посмотрите на внутреннюю часть раковины наутилуса, вы увидите, что каждая камера раковины в основном является точной копией предыдущей камеры, только меньше по мере того, как вы прослеживаете их от внешней стороны к внутренней.

Фракталы также рекурсивны, независимо от масштаба. Вы когда-нибудь заходили в гардеробную магазина и оказывались в окружении зеркал? Хорошо это или плохо, но вы смотрите на бесконечно рекурсивный образ самого себя.

Создание фракталов на Java

Есть разные типы фракталов. Давайте набросаем программку на Java, демонстрирующую фрактал Мандельброта. Состоять она будет из четрех классов. В итоге получим что-то типа этого:

java фрактал мандельброта

Класс JImageDisplay даст возможность нам отображать наши фракталы. Он является производным от javax.swing.JComponent.

package lab4eclipce;

import javax.swing.*;
import java.awt.image.*;
import java.awt.*;

class JImageDisplay extends JComponent
{
    /**
     * Экземпляр буферизованного изображения.
      * Управляет изображением, содержимое которого мы можем писать.
     */ 
    private BufferedImage displayImage;
    
    /**
     * Метод получения отображаемого изображения из другого класса.
     */
    public BufferedImage getImage() {
        return displayImage;
    }
    
    /**
      * Конструктор принимает целые значения ширины и высоты и инициализирует
       * его объект BufferedImage должен быть новым изображением с такой шириной и высотой
       * типа изображения TYPE_INT_RGB.
      */
    public JImageDisplay(int width, int height) {
        displayImage = new BufferedImage(width, height,
        BufferedImage.TYPE_INT_RGB);
        
        /** 
         * Вызваем метод setPreferredSize() родительского класса
          * с заданной шириной и высотой.
         */
        Dimension imageDimension = new Dimension(width, height);
        super.setPreferredSize(imageDimension);
        
    }
    /**
     * Реализация суперкласса paintComponent(g) вызывает так, что границы и
      * черты нарисованы правильно. Затем изображение втягивается в компонент.
     */
    @Override
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        g.drawImage(displayImage, 0, 0, displayImage.getWidth(),
        displayImage.getHeight(), null);
    }
    /**
     * Устанавливает все пиксели в данных изображения черными.
     */
    public void clearImage()
    {
        int[] blankArray = new int[getWidth() * getHeight()];
        displayImage.setRGB(0, 0, getWidth(), getHeight(), blankArray, 0, 1);
    }
    /**
     * Устанавливает пиксель определенного цвета.
     */
    public void drawPixel(int x, int y, int rgbColor)
    {
        displayImage.setRGB(x, y, rgbColor);
    }
}
Класс FractalGenerator предоставляет общий интерфейс и операции для генераторов фракталов, которые можно просмотреть в FractalExplorer.

package lab4eclipce;

import java.awt.geom.Rectangle2D;

public abstract class FractalGenerator {

    /**
     * Эта статическая вспомогательная функция принимает целочисленную координату и преобразует ее 
     * в значение двойной точности, соответствующее определенному диапазону.  
     * Он используется для преобразования координат пикселей в 
     * значения двойной точности для вычисления фракталов и т.д.
     *
     * @param rangeMin - минимальное значение
     * @param rangeMax - максимальнео значение диапазона
     *
     * @param size размер измерения, из которого берется координата пикселя.
     * Например, это может быть ширина изображения или высота изображения.
     *
     * @param coord - это координата.
     *        Координата должна находиться в диапазоне [0, size].
     */
    public static double getCoord(double rangeMin, double rangeMax,
        int size, int coord) {

        assert size > 0;
        assert coord >= 0 && coord < size;

        double range = rangeMax - rangeMin;
        return rangeMin + (range * (double) coord / (double) size);
    }


    /**
     * Задает указанный прямоугольник, содержащий начальный диапазон, 
     * подходящий для создаваемого фрактала.
     */
    public abstract void getInitialRange(Rectangle2D.Double range);


    /**
     * Обновляет текущий диапазон, который должен быть центрирован по указанным координатам
     * и увеличен или уменьшен на указанный коэффициент масштабирования.
     */
    public void recenterAndZoomRange(Rectangle2D.Double range,
        double centerX, double centerY, double scale) {

        double newWidth = range.width * scale;
        double newHeight = range.height * scale;

        range.x = centerX - newWidth / 2;
        range.y = centerY - newHeight / 2;
        range.width = newWidth;
        range.height = newHeight;
    }


    /**
     * Учитывая координаты <em>x</em> + <em>iy</em> в комплексной плоскости,
     * вычисляет и возвращает количество итераций, прежде чем фрактальная
     * функция покинет ограничивающую область для этой точки. 
     */
    public abstract int numIterations(double x, double y);
    
}
Этот класс является подклассом FractalGenerator. Он используется для вычисления Фрактала Мандельброта.

package lab4eclipce;

import java.awt.geom.Rectangle2D;

public class Mandelbrot extends FractalGenerator
{
    /**
     * Константа для количества максимальных итераций.
     */
    public static final int MAX_ITERATIONS = 2500;
    
    /**
     * Этот метод позволяет генератору фракталов указать, какая часть
      * комплексной плоскости наиболее интересен для фрактала.
      * Ему передается объект прямоугольника, и метод изменяет
      * поля прямоугольника, чтобы показать правильный начальный диапазон для фрактала.
      * Эта реализация устанавливает начальный диапазон в (-2 - 1.5i) - (1 + 1.5i)
      * или x = -3, y = -1,7, width = height = 4. 
     */
    public void getInitialRange(Rectangle2D.Double range)
    {
        range.x = -3;
        range.y = -1.7;
        range.width = 4;
        range.height = 4;
    }
    
    /**
     * Этот метод реализует итерационную функцию для фрактала Мандельброта.
      * Требуется два числа double для действительной и мнимой частей комплекса
      * plane и возвращаетcz количество итераций для соответствующей
      * координаты.
     */
    public int numIterations(double x, double y)
    {
        /** Start with iterations at 0. */
        int iteration = 0;
        /** Initialize zreal and zimaginary. */
        double zreal = 0;
        double zimaginary = 0;
        
        /**
         * Вычисляем Zn = Zn-1 ^ 2 + c, где значения представляют собой комплексные числа, представленные
          * по zreal и zimaginary, Z0 = 0, а c - особая точка в
          * фрактал, который мы показываем (заданный x и y). Это повторяется
          * до Z ^ 2> 4 (абсолютное значение Z больше 2) или максимум
          * достигнуто количество итераций.
         */
        while (iteration < MAX_ITERATIONS &&
               zreal * zreal + zimaginary * zimaginary < 4)
        {
            double zrealUpdated = zreal * zreal - zimaginary * zimaginary + x;
            double zimaginaryUpdated = 2 * zreal * zimaginary + y;
            zreal = zrealUpdated;
            zimaginary = zimaginaryUpdated;
            iteration += 1;
        }
        
        /**
         * Если количество максимальных итераций достигнуто, возвращаем -1, чтобы
          * указать, что точка не вышла за границу.
         */
        if (iteration == MAX_ITERATIONS)
        {
            return -1;
        }
        
        return iteration;
    }
    
    /**
     * Реализация toString() в этой реализации фрактала. Возвращает
      * название фрактала: «Мандельброт».
     */
    public String toString() {
        return "Mandelbrot";
    }

}
Класс FractalExplorer позволяет исследовать различные части фрактала с помощью создания и отображения графического интерфейса Swing и обработки событий, вызванных различными взаимодействиями с пользователем.

package lab4eclipce;

import java.awt.*;
import javax.swing.*;
import java.awt.geom.Rectangle2D;
import java.awt.event.*;
import javax.swing.JFileChooser.*;
import javax.swing.filechooser.*;
import javax.imageio.ImageIO.*;
import java.awt.image.*;

public class FractalExplorer
{
    /** Целочисленный размер отображения - это ширина и высота отображения в пикселях. **/
    private int displaySize;
    
    /**
     * Ссылка JImageDisplay для обновления отображения с помощью различных методов как
      * фрактал вычислен.
     */
    private JImageDisplay display;
    
    /** Объект FractalGenerator для каждого типа фрактала. **/
    private FractalGenerator fractal;
    
    /**
     * Объект Rectangle2D.Double, который определяет диапазон
      * то, что мы в настоящее время показываем. 
     */
    private Rectangle2D.Double range;
    
    /**
     * Конструктор, который принимает размер отображения, сохраняет его и
      * инициализирует объекты диапазона и фрактал-генератора.
     */
    public FractalExplorer(int size) {
        /** Размер дисплея  **/
        displaySize = size;
        
        /** Инициализирует фрактальный генератор и объекты диапазона. **/
        fractal = new Mandelbrot();
        range = new Rectangle2D.Double();
        fractal.getInitialRange(range);
        display = new JImageDisplay(displaySize, displaySize);
        
    }
    
    /**
     * Этот метод инициализирует графический интерфейс Swing с помощью JFrame, содержащего
      * Объект JImageDisplay и кнопку для очистки дисплея
     */
    public void createAndShowGUI()
    {
        /** Установите для frame использование java.awt.BorderLayout для своего содержимого. **/
        display.setLayout(new BorderLayout());
        JFrame myFrame = new JFrame("Fractal Explorer");
        
        /** Добавьте объект отображения изображения в
         * BorderLayout.CENTER position.
         */
        myFrame.add(display, BorderLayout.CENTER);
        
        /** Создаем кнопку очистки. **/
        JButton resetButton = new JButton("Reset");
        
        /** Экземпляр ButtonHandler на кнопке сброса. **/
        ButtonHandler resetHandler = new ButtonHandler();
        resetButton.addActionListener(resetHandler);
        
        /** Экземпляр MouseHandler в компоненте фрактального отображения. **/
        MouseHandler click = new MouseHandler();
        display.addMouseListener(click);
        
        /** Вызываем операцию закрытия фрейма по умолчанию на "выход".. **/
        myFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
     

        
        /**
         * Создаем новый объект JPanel, и добавляем панель в рамку в NORTH
          * позиции в макете.
         */
        JPanel myPanel = new JPanel();

        myFrame.add(myPanel, BorderLayout.NORTH);
        
        /**
         * Добавляем кнопку очистки
         */
        JPanel myBottomPanel = new JPanel();
        myBottomPanel.add(resetButton);
        myFrame.add(myBottomPanel, BorderLayout.SOUTH);


        
        
        /**
         * Размещаем содержимое фрейма, делаем его видимым и
          * запрещаем изменение размера окна.
         */
        myFrame.pack();
        myFrame.setVisible(true);
        myFrame.setResizable(false);
        
    }
    
    /**
     * Приватный вспомогательный метод для отображения фрактала. Этот метод проходит
      * через каждый пиксель на дисплее и вычисляет количество
      * итераций для соответствующих координат во фрактале
      * Область отображения. Если количество итераций равно -1, установит цвет пикселя.
      * в черный. В противном случае выберет значение в зависимости от количества итераций.
      * Обновит дисплей цветом для каждого пикселя и перекрасит
      * JImageDisplay, когда все пиксели нарисованы.
     */
    private void drawFractal()
    {
        /**Проходим через каждый пиксель на дисплее **/
        for (int x=0; x<displaySize; x++){
            for (int y=0; y<displaySize; y++){
                
                /**
                 * Находим соответствующие координаты xCoord и yCoord
                  * в области отображения фрактала.
                 */
                double xCoord = fractal.getCoord(range.x,
                range.x + range.width, displaySize, x);
                double yCoord = fractal.getCoord(range.y,
                range.y + range.height, displaySize, y);
                
                /**
                 * Вычисляем количество итераций для координат в
                  * область отображения фрактала.
                 */
                int iteration = fractal.numIterations(xCoord, yCoord);
                
                /** If number of iterations is -1, set the pixel to black. **/
                if (iteration == -1){
                    display.drawPixel(x, y, 0);
                }
                
                else {
                    /**
                     * В противном случае выбераем значение оттенка на основе числа
                      * итераций.  
                     */
                    float hue = 0.6f + (float) iteration / 200f;
                    int rgbColor = Color.HSBtoRGB(hue, 1f, 1f);
                
                    /** Обновляем дисплей цветом для каждого пикселя. **/
                    display.drawPixel(x, y, rgbColor);
                }
                
            }
        }
        /**
         * Когда все пиксели будут нарисованы, перекрасим JImageDisplay, чтобы он соответствовал
          * текущее содержимому его изображения.
         */
        display.repaint();
    }
    /**
     * Внутренний класс для обработки событий ActionListener.
     */
    private class ButtonHandler implements ActionListener
    {
        public void actionPerformed(ActionEvent e)
        {
            /** Получаем источник действия. **/
            String command = e.getActionCommand();
                      
            /**
             * Если источником является кнопка сброса, сбросьте дисплей и нарисуйте
              * фрактал.
             */
           if (command.equals("Reset")) {
                fractal.getInitialRange(range);
                drawFractal();
            }
           
        }
    }
    
    /**
     * Внутренний класс для обработки событий MouseListener с дисплея.
     */
    private class MouseHandler extends MouseAdapter
    {
        /**
         * Когда обработчик получает событие щелчка мыши, он отображает пиксель-
          * координаты щелчка в области фрактала, который
          * отображается, а затем вызывает функцию RecenterAndZoomRange () генератора
          * метод с координатами, по которым был выполнен щелчок, и шкалой 0,5.
         */
        @Override
        public void mouseClicked(MouseEvent e)
        {
            /** Получаем координату x области отображения щелчка мыши. **/
            int x = e.getX();
            double xCoord = fractal.getCoord(range.x,
            range.x + range.width, displaySize, x);
            
            /** Получаем координату y области отображения щелчка мышью. **/
            int y = e.getY();
            double yCoord = fractal.getCoord(range.y,
            range.y + range.height, displaySize, y);
            
            /**
             * Вызывааем метод генератора RecenterAndZoomRange() с помощью
              * координаты, по которым был выполнен щелчок, и шкала 0,5.
             */
            fractal.recenterAndZoomRange(range, xCoord, yCoord, 0.5);
            
            /**
             * Перерисовываем фрактал после изменения отображаемой области.
             */
            drawFractal();
        }
    }
    
    /**
     * Статический метод main() для запуска FractalExplorer. Инициализирует новый
      * Экземпляр FractalExplorer с размером дисплея 600, вызывает
      * createAndShowGU () в объекте проводника, а затем вызывает
      * drawFractal() в проводнике, чтобы увидеть исходный вид.
     */
    public static void main(String[] args)
    {
        FractalExplorer displayExplorer = new FractalExplorer(600);
        displayExplorer.createAndShowGUI();
        displayExplorer.drawFractal();
    }
}
Автор этого материала - я - Пахолков Юрий. Я оказываю услуги по написанию программ на языках Java, C++, C# (а также консультирую по ним) и созданию сайтов. Работаю с сайтами на CMS OpenCart, WordPress, ModX и самописными. Кроме этого, работаю напрямую с JavaScript, PHP, CSS, HTML - то есть могу доработать ваш сайт или помочь с веб-программированием. Пишите сюда.

тегизаметки, java, математика, фрактал, изображения




Отправляя сообщение я подтверждаю, что ознакомлен и согласен с политикой конфиденциальности данного сайта.




Урок 3. Первая форма на Laravel
С. Визгорев - Chess Master (android), уровень 5, 2 сентября 2015
Поля и методы в Java: правила доступа к полям