分形树(Fractal tree)【代码实现】

C

#include <SDL/SDL.h>
#ifdef WITH_CAIRO
#include <cairo.h>
#else
#include <SDL/sge.h>
#endif
#include <cairo.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
 
#ifdef WITH_CAIRO
#define PI 3.1415926535
#endif
 
#define SIZE           800   // determines size of window
#define SCALE          5     // determines how quickly branches shrink (higher value means faster shrinking)
#define BRANCHES       14    // number of branches
#define ROTATION_SCALE 0.75  // determines how slowly the angle between branches shrinks (higher value means slower shrinking)
#define INITIAL_LENGTH 50    // length of first branch
 
double rand_fl(){
  return (double)rand() / (double)RAND_MAX;
}
 
void draw_tree(SDL_Surface * surface, double offsetx, double offsety,
               double directionx, double directiony, double size,
               double rotation, int depth) {
#ifdef WITH_CAIRO
  cairo_surface_t *surf = cairo_image_surface_create_for_data( surface->pixels,
                                                               CAIRO_FORMAT_RGB24,
							       surface->w, surface->h,
							       surface->pitch );
  cairo_t *ct = cairo_create(surf);
 
  cairo_set_line_width(ct, 1);
  cairo_set_source_rgba(ct, 0,0,0,1);
  cairo_move_to(ct, (int)offsetx, (int)offsety);
  cairo_line_to(ct, (int)(offsetx + directionx * size), (int)(offsety + directiony * size));
  cairo_stroke(ct);
#else
  sge_AALine(surface,
      (int)offsetx, (int)offsety,
      (int)(offsetx + directionx * size), (int)(offsety + directiony * size),
      SDL_MapRGB(surface->format, 0, 0, 0));
#endif
  if (depth > 0){
    // draw left branch
    draw_tree(surface,
        offsetx + directionx * size,
        offsety + directiony * size,
        directionx * cos(rotation) + directiony * sin(rotation),
        directionx * -sin(rotation) + directiony * cos(rotation),
        size * rand_fl() / SCALE + size * (SCALE - 1) / SCALE,
        rotation * ROTATION_SCALE,
        depth - 1);
 
    // draw right branch
    draw_tree(surface,
        offsetx + directionx * size,
        offsety + directiony * size,
        directionx * cos(-rotation) + directiony * sin(-rotation),
        directionx * -sin(-rotation) + directiony * cos(-rotation),
        size * rand_fl() / SCALE + size * (SCALE - 1) / SCALE,
        rotation * ROTATION_SCALE,
        depth - 1);
  }
}
 
void render(SDL_Surface * surface){
  SDL_FillRect(surface, NULL, SDL_MapRGB(surface->format, 255, 255, 255));
  draw_tree(surface,
      surface->w / 2.0,
      surface->h - 10.0,
      0.0, -1.0,
      INITIAL_LENGTH,
      PI / 8,
      BRANCHES);
  SDL_UpdateRect(surface, 0, 0, 0, 0);
}
 
int main(){
  SDL_Surface * screen;
  SDL_Event evt;
 
  SDL_Init(SDL_INIT_VIDEO);
 
  srand((unsigned)time(NULL));
 
  screen = SDL_SetVideoMode(SIZE, SIZE, 32, SDL_HWSURFACE);
 
  render(screen);
  while(1){
    if (SDL_PollEvent(&evt)){
      if(evt.type == SDL_QUIT) break;
    }
    SDL_Delay(1);
  }
  SDL_Quit();
  return 0;
}

C++

#include <windows.h>
#include <string>
#include <math.h>
 
//--------------------------------------------------------------------------------------------------
using namespace std;
 
//--------------------------------------------------------------------------------------------------
const float PI = 3.1415926536f;
 
//--------------------------------------------------------------------------------------------------
class myBitmap
{
public:
    myBitmap() : pen( NULL ) {}
    ~myBitmap()
    {
	DeleteObject( pen );
	DeleteDC( hdc );
	DeleteObject( bmp );
    }
 
    bool create( int w, int h )
    {
	BITMAPINFO	bi;
	void		*pBits;
	ZeroMemory( &bi, sizeof( bi ) );
	bi.bmiHeader.biSize	   = sizeof( bi.bmiHeader );
	bi.bmiHeader.biBitCount	   = sizeof( DWORD ) * 8;
	bi.bmiHeader.biCompression = BI_RGB;
	bi.bmiHeader.biPlanes	   = 1;
	bi.bmiHeader.biWidth	   =  w;
	bi.bmiHeader.biHeight	   = -h;
 
	HDC dc = GetDC( GetConsoleWindow() );
	bmp = CreateDIBSection( dc, &bi, DIB_RGB_COLORS, &pBits, NULL, 0 );
	if( !bmp ) return false;
 
	hdc = CreateCompatibleDC( dc );
	SelectObject( hdc, bmp );
	ReleaseDC( GetConsoleWindow(), dc ); 
 
	width = w; height = h;
 
	return true;
    }
 
    void setPenColor( DWORD clr )
    {
	if( pen ) DeleteObject( pen );
	pen = CreatePen( PS_SOLID, 1, clr );
	SelectObject( hdc, pen );
    }
 
    void saveBitmap( string path )
    {
	BITMAPFILEHEADER	fileheader;
	BITMAPINFO			infoheader;
	BITMAP				bitmap;
	DWORD*				dwpBits;
	DWORD				wb;
	HANDLE				file;
 
	GetObject( bmp, sizeof( bitmap ), &bitmap );
 
	dwpBits = new DWORD[bitmap.bmWidth * bitmap.bmHeight];
	ZeroMemory( dwpBits, bitmap.bmWidth * bitmap.bmHeight * sizeof( DWORD ) );
	ZeroMemory( &infoheader, sizeof( BITMAPINFO ) );
	ZeroMemory( &fileheader, sizeof( BITMAPFILEHEADER ) );
 
	infoheader.bmiHeader.biBitCount = sizeof( DWORD ) * 8;
	infoheader.bmiHeader.biCompression = BI_RGB;
	infoheader.bmiHeader.biPlanes = 1;
	infoheader.bmiHeader.biSize = sizeof( infoheader.bmiHeader );
	infoheader.bmiHeader.biHeight = bitmap.bmHeight;
	infoheader.bmiHeader.biWidth = bitmap.bmWidth;
	infoheader.bmiHeader.biSizeImage = bitmap.bmWidth * bitmap.bmHeight * sizeof( DWORD );
 
	fileheader.bfType    = 0x4D42;
	fileheader.bfOffBits = sizeof( infoheader.bmiHeader ) + sizeof( BITMAPFILEHEADER );
	fileheader.bfSize    = fileheader.bfOffBits + infoheader.bmiHeader.biSizeImage;
 
	GetDIBits( hdc, bmp, 0, height, ( LPVOID )dwpBits, &infoheader, DIB_RGB_COLORS );
 
	file = CreateFile( path.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL );
	WriteFile( file, &fileheader, sizeof( BITMAPFILEHEADER ), &wb, NULL );
	WriteFile( file, &infoheader.bmiHeader, sizeof( infoheader.bmiHeader ), &wb, NULL );
	WriteFile( file, dwpBits, bitmap.bmWidth * bitmap.bmHeight * 4, &wb, NULL );
	CloseHandle( file );
 
	delete [] dwpBits;
    }
 
    HDC getDC()     { return hdc; }
    int getWidth()  { return width; }
    int getHeight() { return height; }
 
private:
    HBITMAP bmp;
    HDC	    hdc;
    HPEN    pen;
    int     width, height;
};
//--------------------------------------------------------------------------------------------------
class vector2
{
public:
    vector2() { x = y = 0; }
    vector2( int a, int b ) { x = a; y = b; }
    void set( int a, int b ) { x = a; y = b; }
    void rotate( float angle_r )
    {
	float _x = static_cast<float>( x ),
	      _y = static_cast<float>( y ),
	       s = sinf( angle_r ), 
	       c = cosf( angle_r ),
	       a = _x * c - _y * s, 
	       b = _x * s + _y * c;
 
	x = static_cast<int>( a ); 
	y = static_cast<int>( b );
    }
 
    int x, y;
};
//--------------------------------------------------------------------------------------------------
class fractalTree
{
public:
    fractalTree()		      { _ang = DegToRadian( 24.0f ); }
    float DegToRadian( float degree ) { return degree * ( PI / 180.0f ); }
 
    void create( myBitmap* bmp )
    {
	_bmp = bmp;
	float line_len = 130.0f;
 
	vector2 sp( _bmp->getWidth() / 2, _bmp->getHeight() - 1 );
	MoveToEx( _bmp->getDC(), sp.x, sp.y, NULL );
	sp.y -= static_cast<int>( line_len );
	LineTo( _bmp->getDC(), sp.x, sp.y);
 
	drawRL( &sp, line_len, 0, true );
	drawRL( &sp, line_len, 0, false );
    }
 
private:
    void drawRL( vector2* sp, float line_len, float a, bool rg )
    {
	line_len *= .75f;
	if( line_len < 2.0f ) return;
 
	MoveToEx( _bmp->getDC(), sp->x, sp->y, NULL );
	vector2 r( 0, static_cast<int>( line_len ) );
 
        if( rg ) a -= _ang;
        else a += _ang; 
 
	r.rotate( a );
	r.x += sp->x; r.y = sp->y - r.y;
 
	LineTo( _bmp->getDC(), r.x, r.y );
 
	drawRL( &r, line_len, a, true );
	drawRL( &r, line_len, a, false );
    }
 
    myBitmap* _bmp;
    float     _ang;
};
//--------------------------------------------------------------------------------------------------
int main( int argc, char* argv[] )
{
    ShowWindow( GetConsoleWindow(), SW_MAXIMIZE );
 
    myBitmap bmp;
    bmp.create( 640, 512 );
    bmp.setPenColor( RGB( 255, 255, 0 ) );
 
    fractalTree tree;
    tree.create( &bmp );
 
    BitBlt( GetDC( GetConsoleWindow() ), 0, 20, 648, 512, bmp.getDC(), 0, 0, SRCCOPY );
 
    bmp.saveBitmap( "f://rc//fracTree.bmp" );
 
    system( "pause" );
 
    return 0;
}

Go

package main
 
// Files required to build supporting package raster are found in:
// * Bitmap
// * Grayscale image
// * Xiaolin Wu's line algorithm
// * Write a PPM file
 
import (
    "math"
    "raster"
)
 
const (
    width  = 400
    height = 300
    depth  = 8
    angle  = 12
    length = 50
    frac   = .8
)
 
func main() {
    g := raster.NewGrmap(width, height)
    ftree(g, width/2, height*9/10, length, 0, depth)
    g.Bitmap().WritePpmFile("ftree.ppm")
}
 
func ftree(g *raster.Grmap, x, y, distance, direction float64, depth int) {
    x2 := x + distance*math.Sin(direction*math.Pi/180)
    y2 := y - distance*math.Cos(direction*math.Pi/180)
    g.AaLine(x, y, x2, y2)
    if depth > 0 {
        ftree(g, x2, y2, distance*frac, direction-angle, depth-1)
        ftree(g, x2, y2, distance*frac, direction+angle, depth-1)
    }
}

Java

import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
 
public class FractalTree extends JFrame {
 
    public FractalTree() {
        super("Fractal Tree");
        setBounds(100, 100, 800, 600);
        setResizable(false);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }
 
    private void drawTree(Graphics g, int x1, int y1, double angle, int depth) {
        if (depth == 0) return;
        int x2 = x1 + (int) (Math.cos(Math.toRadians(angle)) * depth * 10.0);
        int y2 = y1 + (int) (Math.sin(Math.toRadians(angle)) * depth * 10.0);
        g.drawLine(x1, y1, x2, y2);
        drawTree(g, x2, y2, angle - 20, depth - 1);
        drawTree(g, x2, y2, angle + 20, depth - 1);
    }
 
    @Override
    public void paint(Graphics g) {
        g.setColor(Color.BLACK);
        drawTree(g, 400, 500, -90, 9);
    }
 
    public static void main(String[] args) {
        new FractalTree().setVisible(true);
    }
}

JavaScript

html>
<body>
<canvas id="canvas" width="600" height="500"></canvas>
 
<script type="text/javascript">
var elem = document.getElementById('canvas');
var context = elem.getContext('2d');
 
context.fillStyle = '#C0C0C0';
context.lineWidth = 1;
 
var deg_to_rad = Math.PI / 180.0;
var depth = 9;
 
function drawLine(x1, y1, x2, y2, brightness){
  context.moveTo(x1, y1);
  context.lineTo(x2, y2);
}
 
function drawTree(x1, y1, angle, depth){
  if (depth !== 0){
    var x2 = x1 + (Math.cos(angle * deg_to_rad) * depth * 10.0);
    var y2 = y1 + (Math.sin(angle * deg_to_rad) * depth * 10.0);
    drawLine(x1, y1, x2, y2, depth);
    drawTree(x2, y2, angle - 20, depth - 1);
    drawTree(x2, y2, angle + 20, depth - 1);
  }
}
 
context.beginPath();
drawTree(300, 500, -90, depth);
context.closePath();
context.stroke();
</script>
 
</body>
</html>

Kotlin

// version 1.1.2
 
import java.awt.Color
import java.awt.Graphics
import javax.swing.JFrame
 
class FractalTree : JFrame("Fractal Tree") {
    init {
        background = Color.black
        setBounds(100, 100, 800, 600)
        isResizable = false
        defaultCloseOperation = EXIT_ON_CLOSE
    }
 
    private fun drawTree(g: Graphics, x1: Int, y1: Int, angle: Double, depth: Int) {
        if (depth == 0) return
        val x2 = x1 + (Math.cos(Math.toRadians(angle)) * depth * 10.0).toInt()
        val y2 = y1 + (Math.sin(Math.toRadians(angle)) * depth * 10.0).toInt()
        g.drawLine(x1, y1, x2, y2)
        drawTree(g, x2, y2, angle - 20, depth - 1)
        drawTree(g, x2, y2, angle + 20, depth - 1)
    }
 
    override fun paint(g: Graphics) {
        g.color = Color.white
        drawTree(g, 400, 500, -90.0, 9)
    }
}
 
fun main(args: Array<String>) {
    FractalTree().isVisible = true
}

PHP

<?php
header("Content-type: image/png");
 
$width = 512;
$height = 512;
$img = imagecreatetruecolor($width,$height);
$bg = imagecolorallocate($img,255,255,255);
imagefilledrectangle($img, 0, 0, $width, $width, $bg);
 
$depth = 8;
function drawTree($x1, $y1, $angle, $depth){
 
    global $img;
 
    if ($depth != 0){
        $x2 = $x1 + (int)(cos(deg2rad($angle)) * $depth * 10.0);
        $y2 = $y1 + (int)(sin(deg2rad($angle)) * $depth * 10.0);
 
        imageline($img, $x1, $y1, $x2, $y2, imagecolorallocate($img,0,0,0));
 
        drawTree($x2, $y2, $angle - 20, $depth - 1);
        drawTree($x2, $y2, $angle + 20, $depth - 1);
    }
}
 
drawTree($width/2, $height, -90, $depth);
 
imagepng($img);
imagedestroy($img);
?>

Python

import pygame, math
 
pygame.init()
window = pygame.display.set_mode((600, 600))
pygame.display.set_caption("Fractal Tree")
screen = pygame.display.get_surface()
 
def drawTree(x1, y1, angle, depth):
    if depth:
        x2 = x1 + int(math.cos(math.radians(angle)) * depth * 10.0)
        y2 = y1 + int(math.sin(math.radians(angle)) * depth * 10.0)
        pygame.draw.line(screen, (255,255,255), (x1, y1), (x2, y2), 2)
        drawTree(x2, y2, angle - 20, depth - 1)
        drawTree(x2, y2, angle + 20, depth - 1)
 
def input(event):
    if event.type == pygame.QUIT:
        exit(0)
 
drawTree(300, 550, -90, 9)
pygame.display.flip()
while True:
    input(pygame.event.wait())

Ruby

Shoes.app(:title => "Fractal Tree", :width => 600, :height => 600) do
  background "#fff"
  stroke "#000"
  @deg_to_rad = Math::PI / 180.0
 
  def drawTree(x1, y1, angle, depth)
    if depth != 0
      x2 = x1 + (Math.cos(angle * @deg_to_rad) * depth * 10.0).to_i
      y2 = y1 + (Math.sin(angle * @deg_to_rad) * depth * 10.0).to_i
 
      line x1, y1, x2, y2
 
      drawTree(x2, y2, angle - 20, depth - 1)
      drawTree(x2, y2, angle + 20, depth - 1)      
    end
  end
 
  drawTree(300,550,-90,9)
end

Swift

extension CGFloat {
  func degrees_to_radians() -> CGFloat {
    return CGFloat(M_PI) * self / 180.0
  }
}
 
extension Double {
  func degrees_to_radians() -> Double {
    return Double(M_PI) * self / 180.0
  }
}
 
 
class Tree: UIView {
 
 
  func drawTree(x1: CGFloat, y1: CGFloat, angle: CGFloat, depth:Int){
    if depth == 0 {
      return
    }
    let ang = angle.degrees_to_radians()
    let x2:CGFloat = x1 + ( cos(ang) as CGFloat) * CGFloat(depth) * (self.frame.width / 60)
    let y2:CGFloat = y1 + ( sin(ang) as CGFloat) * CGFloat(depth) * (self.frame.width / 60)
 
    let line = drawLine(x1, y1: y1, x2: x2, y2: y2)
 
    line.stroke()
    drawTree(x2, y1: y2, angle: angle - 20, depth: depth - 1)
    drawTree(x2, y1: y2, angle: angle + 20, depth: depth - 1)
  }
 
  func drawLine(x1:CGFloat, y1:CGFloat, x2:CGFloat, y2:CGFloat) -> UIBezierPath
  {
 
    let path = UIBezierPath()
    path.moveToPoint(CGPoint(x: x1,y: y1))
    path.addLineToPoint(CGPoint(x: x2,y: y2))
    path.lineWidth = 1
    return path
  }
 
  override func drawRect(rect: CGRect) {
 
    let color = UIColor(red: 1.0, green: 0.0, blue: 0.0, alpha: 1.0)
    color.set()
    drawTree(self.frame.width / 2 , y1: self.frame.height * 0.8, angle: -90 , depth: 9 )
  }
}
 
 
let tree = Tree(frame: CGRectMake(0, 0, 300, 300))
tree
上一篇:大整数类 BigInt


下一篇:带你剖析WebGis的世界奥秘----点和线的世界