#!/usr/bin/env ruby
#
#	Copyright (c) 2000 by Mathieu Bouchard
#	Released under the LGPL
#

# N = subbranches per branch
# L = max level
# Q = how many figures to show at once

$N,$L,$Q = 5,2,2
$show_lines = true
$show_dots = true
$spiral_mode = true

$n_nodes = 0
(0..$L).each {|x| $n_nodes += $N ** x }

require "X11/Display"

$wsize = X11::Size[400,400]

PI = Math::PI

$d = X11::Display.new; #$d.conn.log = true
$s = $d.screens[0]
$dp = $s.depths.find {|dp| dp.depth > 1 }
$cmap = $s.default_colormap

$w = X11::Window.new($d)
$w.create_window($dp.depth, $s.root,
	X11::Rectangle[X11::Point[0,0], $wsize],
	4, :InputOutput, :CopyFromParent,
		X11::WindowAttributes.new(
			:background_pixel => $s.black_pixel))
$w.map

$t0=Time.new

$w.change_property(:Replace, $d.atom("WM_NAME"), $d.atom("STRING"), 8,
	"Matju's Iterated Function System")

$g2 = X11::Graphics.new($d)
$gcinfo = X11::GraphicsInfo.new(
#	:function => :Xor,
	:foreground => $s.white_pixel,
	:line_width => 1,
#	:line_style => :DoubleDash,
	:cap_style => :Round,
	:join_style => :Round)
$g2.create($w,$gcinfo)
$g = X11::GraphicsOnDrawable[$w,$g2]

$d.wait_for {
	$cmap.alloc_color(X11::RGB["#fff"]) {|foo,$color_vertex|}
	$cmap.alloc_color(X11::RGB["#04a"]) {|foo,$color_edge|}
	$cmap.alloc_color(X11::RGB["#000"]) {|foo,$color_bg|}
}

def transform(edges)
	ox,oy  = $wsize/2
	xpoint = X11::Point
	xrect  = X11::Rectangle
	size   = X11::Size[3,3]
	e      = nil; ex,ey=nil
	edges.map! {|e| xpoint[e[0].to_i+ox,e[1].to_i+oy] }
	vertices = edges.map {|e| xrect[xpoint[e[0]-1,e[1]-1], size] }
	[edges,vertices]
end

def plot(vertex_color,edge_color,edges)
	$g2.change(X11::GraphicsInfo.new(:foreground => edge_color))
	$g.draw_lines(:Origin, edges[0]) if $show_lines
	$g2.change(X11::GraphicsInfo.new(:foreground => vertex_color))
	$g.fill_rectangles(edges[1]) if $show_dots
#	$g.draw_points(:Origin,edges[0]) if $show_dots
end

$queue = []

def tick(r,s,add)
	p = [[0,0]]
	k = (0...$N).map {|i|
		t=[Math.cos(r*i),Math.sin(r*i)]
		t<<(t[0]-t[1])
		t
	}
	a,axx,axy,ayy,l,oj=nil
	while p.length<$n_nodes
		j=(p.length-(p.length%$N))/$N
		if oj!=j then
			a = p[j]
			axx,axy,ayy = a[0]**2, a[0]*a[1], a[1]**2
			l = s / Math.sqrt(1 + axx + ayy)
			axx*=l; axy*=l; ayy*=l
		end
		bx,by,bz = k[p.length%$N]
		p << [axx*bx + ayy*by + add[0], 2*axy*bz + add[1]]
		oj=j
	end

	p=transform(p)
	plot($color_vertex,$color_edge,p)
	if not $spiral_mode
		$queue.push(p)
		plot($color_bg,$color_bg,$queue.shift) if $queue.length >= $Q
	end
end

a,b,i = 0,0,0
while true
	a += 0.015 ; a -= 2*PI if a>PI
	b -= 0.0346; b += 2*PI if b<-PI
	add = [Math.cos(b)*20,Math.sin(b)*20]
	if $spiral_mode then
		$g.copy_area($w,X11::Point[
				(Math.cos(a)*10).to_i,
				(Math.sin(a)*10).to_i],
			X11::Point[0,0],$wsize)
	end
	tick a, 2, add
	$d.flush
	i+=1
	if (i%50)==0 then puts "#{i}: #{i/(Time.new-$t0)}" end
end
