二叉树递归分形,牛顿分形图案

简介: 二叉树递归分形,牛顿分形图案

1. 牛顿分形(Newton Fractal)

在复数域上使用牛顿迭代生成分形图像,函数公式F(z) = z^3 – 1在复数域上面有

三个根,一个是1,另外两个分别是复数-0.5+0.87i 与 -0.5 – 0.87i根据计算出来根

的值不同转换为RGB三种不同的颜色,根据迭代次数的多少设置颜色值的大小,

即颜色强度。

1338989322_9502.png


2. 曼德布罗特集合分形(Mandelbort Set Fractal) 使用复数函数公式F(z) = z^2 + c其中


c是一个复数

1338989392_4512.png

3. 递归分形树 (recursion tree)– 类似二叉树的递归生成树干,同时不断的缩小树干长

度,根据递归次数不同与角度不同可以得到不同的递归分形树,注意Java最大栈

深度是64,过度的归次数可能导致java栈溢出错误。递归次数建议不要超过32.

1338989500_2602.png

根据角度不同,可以生成不同的二叉递归树。


牛顿迭代与曼德尔波特分形算法需要复数范围内的加减乘除计算,请先google一下

然后就知道啦。本人实现的复数计算的类如下:

package com.gloomyfish.fractal;
 
public class Complex
{
  private float real;
  private float imaginary;
 
  public Complex(float paramFloat1, float paramFloat2)
  {
    this.real = paramFloat1;
    this.imaginary = paramFloat2;
  }
 
  public float real()
  {
    return this.real;
  }
 
  public float imaginary()
  {
    return this.imaginary;
  }
 
  public float modulus()
  {
    return (float)Math.sqrt(this.real * this.real + this.imaginary * this.imaginary);
  }
 
  public boolean equal(Complex paramComplex)
  {
    return ((this.real == paramComplex.real()) && (this.imaginary == paramComplex.imaginary()));
  }
 
  public Complex add(Complex paramComplex)
  {
    return new Complex(this.real + paramComplex.real(), this.imaginary + paramComplex.imaginary());
  }
 
  public Complex subtract(Complex paramComplex)
  {
    return new Complex(this.real - paramComplex.real(), this.imaginary - paramComplex.imaginary());
  }
 
  public Complex multiply(Complex paramComplex)
  {
    return new Complex(this.real * paramComplex.real() - (this.imaginary * paramComplex.imaginary()), this.real * paramComplex.imaginary() + this.imaginary * paramComplex.real());
  }
 
  public Complex divide(Complex paramComplex)
  {
    float f1 = paramComplex.real() * paramComplex.real() + paramComplex.imaginary() * paramComplex.imaginary();
    float f2 = (this.real * paramComplex.real() + this.imaginary * paramComplex.imaginary()) / f1;
    float f3 = (this.imaginary * paramComplex.real() - (this.real * paramComplex.imaginary())) / f1;
 
    return new Complex(f2, f3);
  }
 
  public String toString()
  {
    String str = (this.imaginary >= 0.0F) ? "+" : "-";
    return this.real + str + Math.abs(this.imaginary) + "i";
  }
}

牛顿分形的算法代码如下:

package com.gloomyfish.fractal;
 
public class NewtonFractal extends Fractal {
  private static final Complex ONE = new Complex(1.0F, 0.0F);
  private static final Complex THREE = new Complex(3.0F, 0.0F);
  public NewtonFractal(int widthImage, int heightImage) {
    super(widthImage, heightImage);
    
    // default start point and end point
    // primary group, 
    this.x1 = -1.0f;
    this.y1 = -1.0f;
    this.x2 = 1.0f;
    this.y2 = 1.0f;
    
    // second group
    //  this.x1 = -3.0f;
    //  this.y1 = -1.76f;
    //  this.x2 = 3.0f;
    //  this.y2 = 1.76f;
    // end comment
    
  }
 
  @Override
  public void BuildFractal() {
    int[] inPixels = new int[getWidth()*getHeight()];
        getRGB(fractalImage, 0, 0, getWidth(), getHeight(), inPixels );
        int index = 0;
        float xDelta = ((x2 - x1) / (float)width);
        float yDelta = ((y2 - y1) / (float)height);
        for(int row=0; row<height; row++) {
          int ta = 0, tr = 0, tg = 0, tb = 0;
          for(int col=0; col<width; col++) {
            Complex localComplex2;
                float f1 = this.x1 + col * xDelta;
                float f2 = this.y2 - (row * yDelta);
                Complex localComplex1 = new Complex(f1, f2);
 
                int k = 0;
                do {
                  Complex localComplex3 = localComplex1.multiply(localComplex1);
                  Complex localComplex4 = localComplex3.multiply(localComplex1);
 
                  localComplex2 = localComplex1;
                  localComplex1 = localComplex1.subtract(localComplex4.subtract(ONE).divide(THREE.multiply(localComplex3)));
                }
 
                while ((++k < MAX_ITERS) && (!(localComplex1.equal(localComplex2))));
 
                int l = 20 * k % 10; // keep value scope between 0 and 255
 
                // if root is 1 then
                if (localComplex1.real() > 0.0F)
                {
                  tr = tg = l;
                  tb = 255;
                }
                
                // if root is second complex = -0.5+0.87i
                else if (localComplex1.imaginary() > 0.0F)
                {
                  tr = tb = l;
                  tg = 255;
                }
                else
                {
                  tr = 255;
                  tg = tb = l;
                }
            
            index = row * width + col;
            ta = 255;
            inPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
          }
        }
        setRGB(fractalImage, 0, 0, getWidth(), getHeight(), inPixels);
  }
 
}

曼德尔波特分形算法如下:

package com.gloomyfish.fractal;
 
public class MandelbrotSetFractal extends Fractal {
  private float delta = 0.01f;
  public MandelbrotSetFractal(int widthImage, int heightImage) {
    super(widthImage, heightImage);
      this.delta = 0.01F;
      this.x1 = (-(this.width / 2) * this.delta);
      this.y1 = (-(this.height / 2) * this.delta);
      this.x2 = (-this.x1);
      this.y2 = (-this.y1);
  }
 
  @Override
  public void BuildFractal() {
    int[] inPixels = new int[getWidth()*getHeight()];
        getRGB(fractalImage, 0, 0, getWidth(), getHeight(), inPixels );
        int index = 0;
        for(int row=0; row<height; row++) {
          int ta = 0, tr = 0, tg = 0, tb = 0;
          float f1 = y2 - (row * delta);
          for(int col=0; col<width; col++) {
            float f5;
                int i1;
                float f2 = x1 + col * delta;
                Complex localComplex1 = new Complex(f2, f1);
                Complex localComplex2 = new Complex(0.0F, 0.0F);
 
                int k = 0;
                int l = 0;
                do
                {
                  localComplex2 = localComplex2.multiply(localComplex2).add(localComplex1);
                  f5 = localComplex2.modulus();
                  k = (f5 > 2.0F) ? 1 : 0; }
                while ((++l < 32) && (k == 0));
 
                index = row * width + col;
                if (k != 0) {
                  i1 = 255 - (255 * l / 32);
                  i1 = Math.min(i1, 240);
                  tr = tg = tb = i1;
                }
                else
                {
                  i1 = (int)(100.0F * f5) / 2 + 1;
 
                  int i2 = 101 * i1 & 0xFF;
                  int i3 = 149 * i1 & 0xFF;
                  int i4 = 199 * i1 & 0xFF;
                  tr = i2;
                  tg = i3;
                  tb = i4;
                }
            
            ta = 255;
            inPixels[index] = (ta << 24) | (tr << 16) | (tg << 8) | tb;
          }
        }
        setRGB(fractalImage, 0, 0, getWidth(), getHeight(), inPixels);
  }
 
}

递归分形树代码如下:

package com.gloomyfish.fractal;
 
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.FontFormatException;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
 
import javax.swing.JComponent;
import javax.swing.JFrame;
 
public class FractalTree extends JComponent {
  
  /**
   * 
   */
  private static final long serialVersionUID = 8812325148970066491L;
 
  private int maxRecursions = 8; //never make this too big or it'll take forever
  private double angle = 0.2 * Math.PI; //angle in radians
  private double shrink = 1.8; //relative size of new branches
  public FractalTree() {
    super();
  }
  protected void paintComponent(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    g2.setPaint(Color.WHITE);
    g2.fillRect(0, 0, 400, 400);
    renderTree(g2);
    g2.setPaint(Color.RED);
    try {
      g2.setFont(loadFont());
    } catch (FontFormatException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    } catch (IOException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }
    g2.drawString("Created by Gloomyfish " + new Date(System.currentTimeMillis()), 10, 320);
  }
  
  /**
   * create fractal tree using recursion
   * @param Graphics2D g2
   */
  private void renderTree(Graphics2D g2) {
    g2.setPaint(new Color(128, 96, 64));
    recursion(400.0d / 2.0d, 400.0d -1.0d, 0.0d, -1.0d, 400.0d / 2.3d, 0, g2);
  }
  
  // http://www.cg.info.hiroshima-cu.ac.jp/~miyazaki/knowledge/teche31.html
  void recursion(double posX, double posY, double dirX, double dirY, double size, int n, Graphics2D g2)
  {
      int x1, x2, y1, y2;
      x1 = (int)posX;
      y1 = (int)posY;
      x2 = (int)(posX + size * dirX);
      y2 = (int)(posY + size * dirY);
      g2.drawLine(x1, y1, x2, y2);
 
      if(n >= maxRecursions) return;
      double posX2, posY2, dirX2, dirY2, size2;
      int n2;
      
      // calculate the new start point coordinate
      posX2 = posX + size * dirX;
      posY2 = posY + size * dirY;
      size2 = size / shrink; // make different length of line.
      n2 = n + 1;
      
      // rotate angle and get the new directX, directY
      // http://www.jimloy.com/geometry/trigz.htm
      // sin(theta + angle) = sin(theta) * cos(angle) + cos(theta) * sin(angle)
      // cos(theta + angle) = -sin(angle) * sin(theta) + cos(theta) * cos(angle)
      dirX2 = Math.cos(angle) * dirX + Math.sin(angle) * dirY;
      dirY2 = -Math.sin(angle) * dirX + Math.cos(angle) * dirY;
      recursion(posX2, posY2, dirX2, dirY2, size2, n2, g2);
      
      dirX2 = Math.cos(-angle) * dirX + Math.sin(-angle) * dirY;
      dirY2 = -Math.sin(-angle) * dirX + Math.cos(-angle) * dirY;
      recursion(posX2, posY2, dirX2, dirY2, size2, n2, g2);
  }
  
  /**
   * http://en.wikipedia.org/wiki/Mandelbrot_set
   * http://www.urbanfonts.com/fonts/sans-serif-fonts.htm
   * @return
   * @throws FontFormatException
   * @throws IOException
   */
  public Font loadFont() throws FontFormatException, IOException{
      String fontFileName = "AMERSN.ttf";
      InputStream is = this.getClass().getResourceAsStream(fontFileName);
      Font actionJson = Font.createFont(Font.TRUETYPE_FONT, is);
      Font actionJsonBase = actionJson.deriveFont(Font.BOLD, 12);
      return actionJsonBase;
  }
  
  public static void main(String[] args) {
    JFrame frame = new JFrame("Fractal Tree UI - GloomyFish");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().setLayout(new BorderLayout());
    
    // Display the window.
    frame.getContentPane().add(new FractalTree(), BorderLayout.CENTER);
    frame.setPreferredSize(new Dimension(450,400));
    frame.pack();
    frame.setVisible(true);
  }
}
相关文章
|
2月前
【数值分析】迭代法求方程的根(附matlab代码)
【数值分析】迭代法求方程的根(附matlab代码)
|
2月前
【数值分析】二分法求方程的根(附matlab代码)
【数值分析】二分法求方程的根(附matlab代码)
|
11月前
|
算法
算法提高:计算几何基础 | 详解凸包问题
点集Q的凸包(convex hull)是指一个最小凸多边形,满足Q中的点或者在多边形边上,或者在其内
115 0
算法提高:计算几何基础 | 详解凸包问题
|
机器学习/深度学习
排列组合、古典概型、几何概型与伯努利概型
排列组合、古典概型、几何概型与伯努利概型
|
算法
进阶指南图论——闇の連鎖 I. 黑暗的锁链(树上差分+LCA)
进阶指南图论——闇の連鎖 I. 黑暗的锁链(树上差分+LCA)
150 0
143.Mandelbrot分形图案
143.Mandelbrot分形图案
69 0
|
算法 Python
递归算法的典型程序,分形树的绘制和汉诺塔的问题解决。
在程序中,程序自身调用自身的这种技巧称为递归。我们来通俗的讲一下递归,从前有座山,山里有座庙,庙里有个和尚,和尚在讲故事,从前有座山,山里有座庙,庙里有个和尚,和尚在讲故事,从前有座山…我们小时候应该都听过这样的故事,大家想想,这个故事如果以 我们程序的思维来看是不是递归?当然,这的确很想递归,因为老和尚在一直讲故事,这就像在调用自身老和尚讲故事这个函数,但我要告诉大家的是,
215 0
递归算法的典型程序,分形树的绘制和汉诺塔的问题解决。
|
算法
什么是A*寻路算法?
A*寻路算法的介绍。
110 0
什么是A*寻路算法?