Skip to content

Instantly share code, notes, and snippets.

@monkstone
Created September 30, 2011 15:09
Show Gist options
  • Save monkstone/1254029 to your computer and use it in GitHub Desktop.
Save monkstone/1254029 to your computer and use it in GitHub Desktop.
Hilbert Fractal Sketch
############################
# Non-stochastic grammar
# with unique premise/rules
############################
class Grammar
attr_accessor :axiom, :rules
def initialize axiom
@axiom = axiom
@rules = Hash.new
end
def add_rule premise, rule
rules.store(premise, rule)
end
##########################################
# replace each pre char with a unique rule
##########################################
def new_production production
production.gsub!(/./) { |c| (r = @rules[c]) ? r : c }
end
##########################################
# control the number of iterations
# default 0, returns the axiom
##########################################
def generate repeat = 0
prod = axiom
repeat.times do
prod = new_production prod
end
return prod
end
end
############################
# Hilbert Curves
###########################
class Hilbert
include Processing::Proxy
ADJUSTMENT = [0, 0.5, 1.5, 3.5, 7.5, 15]
attr_reader :grammar, :axiom, :production, :premis, :rule,
:theta, :distance, :phi, :gen
def initialize(len)
@axiom = "X"
@grammar = Grammar.new(axiom)
@production = axiom
@premis = "X"
@rule = "^<XF^<XFX-F^>>XFX&F+>>XFX-F>X->"
@distance = len
@theta = Math::PI/180 * 90
@phi = Math::PI/180 * 90
grammar.add_rule(premis, rule)
end
def render()
translate( -distance * ADJUSTMENT[gen], distance * ADJUSTMENT[gen], -distance * ADJUSTMENT[gen])
fill(0, 75, 152)
light_specular(204, 204, 204)
specular(255, 255, 255)
shininess(1.0)
production.scan(/./) do |ch|
case(ch)
when "F"
translate(0, distance/-2, 0)
box(distance/9 , distance, distance/9)
translate(0, distance/-2, 0)
when "+"
rotateX(-theta)
when "-"
rotateX(theta)
when ">"
rotateY(theta)
when "<"
rotateY(-theta)
when "&"
rotateZ(-phi)
when "^"
rotateZ(phi)
when "X"
else
puts("character '#{ch}' not in grammar")
end
end
end
##############################
# create grammar from axiom and
# rules (adjust scale)
##############################
def create_grammar(gen)
@gen = gen # required for depth adjustment
@distance *= 1/(pow(2, gen) - 1)
@production = @grammar.generate gen
end
end
########################################################
# A 3D Hilbert fractal implemented using a
# Lindenmayer System in ruby-processing by Martin Prout
# Best if you've got opengl
########################################################
class Hilbert_Test < Processing::App
full_screen # NB: All distances are relative to screen height
load_libraries 'hilbert', 'peasycam', 'opengl'
import 'peasy'
import "processing.opengl" if library_loaded? "opengl"
attr_reader :hilbert, :cam, :depth
def setup
library_loaded?(:opengl) ? configure_opengl : render_mode(P3D)
@depth = 3
configure_peasycam
@hilbert = Hilbert.new(height/10)
hilbert.create_grammar depth
no_stroke
end
def configure_peasycam
@cam = PeasyCam.new(self, 200)
cam.set_minimum_distance 100
cam.set_maximum_distance 800
end
def configure_opengl
render_mode OPENGL
hint ENABLE_OPENGL_4X_SMOOTH # optional
hint DISABLE_OPENGL_ERROR_REPORT # optional
end
def draw
background 0
lights
hilbert.render
end
def key_pressed()
case(key)
when 'i', '+'
@depth += 1 unless depth > 4
@hilbert = Hilbert.new(height/10)
@hilbert.create_grammar(depth)
when 'd', '-'
@depth -= 1 unless depth < 2
@hilbert = Hilbert.new(height/10)
@hilbert.create_grammar(depth)
end
end
end
@monkstone
Copy link
Author

Don't know whether it is worth updating the PeasyCam library? Now version 0.92 from memory.

@monkstone
Copy link
Author

Just amended to script to use latest version of 'peasycam' from sketchbook libraries folder (vs original 'PeasyCam').

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment