This is a variant of processing sketch by Giles Whitaker, that he in turn had adapted from "Plasma Fractal" - written January, 2002 by Justin Seyster. I have somewhat revised the code to make it a bit more efficient, the color is set using bit shifting. I have also introduced a (Sierpinksi) carpet variant which can be selected from the menu. Further I have included a save_it button which only be useful when run as application/script.... Graininess is controlled by a slider, a feature I think Giles introduced (although here we use the ruby-processing control panel).
#######################################
# plasma.rb
# A sketch that demonstrates the use of
# bit shifting to create color values
######################################
load_library 'control_panel'
ALPHA = 255
PHI = (1 +Math.sqrt(5)) / 2
attr_reader :control, :grain, :variant, :redraw
def setup
size(500, 500)
@variant = 'plasma'
@grain = 3
draw_plasma width, height
setup_control
end
def setup_control
control_panel do |c|
c.title = "Control Panel"
c.slider :grain, 3...40, 3
c.menu :variant, ['plasma', 'carpet']
c.button :draw_it
c.button :save_it
end
end
def draw
end
def draw_it
draw_plasma width, height
end
def save_it
save_frame("plasma#{frame_count}.png")
end
def calc_color c
# alpha value & int adjustment
r = (c < 0.5)? c : 1.0 - c
gr = (c >= 0.8)? 1.3 - c : (c < 0.3)? 0.3 - c : c - 0.3
b = (c < 0.5)? 0.5 - c : c - 0.5
# r, gr and b are bit shifted by an extra 1 to avoid doubling above values
col = (ALPHA << 24)|((r * ALPHA).round << 17)|((gr * ALPHA).round << 9)| (b * ALPHA).round << 1
end
def displace num
max = num / (width + height) * grain
(rand - 0.5) * max
end
def draw_plasma w, h
#Assign the four corners of the intial grid random color values
#These will end up being the colors of the four corners of the applet.
divide_grid(0.0, 0.0, w, h, rand, rand, rand, rand)
end
def divide_grid(x1, y1, w, h, c1, c2, c3, c4)
new_width = w / 2.0 # NB dividing by 2.0 to ensure float
new_height = h / 2.0
c = (c1 + c2 + c3 + c4) / 4.0
if (w <= 1.0 || h <= 1.0)
#The four corners of the grid piece will be averaged and drawn as a single pixel
set(x1.round, y1.round, calc_color(c))
else
middle = c + displace(new_width + new_height) #Randomly displace the midpoint!
divisor = (variant == 'plasma')? 2.0 : PHI
edge1 = (c1 + c2) / 2.0 #Calculate the edges by averaging the two corners of each edge.
edge2 = (c2 + c3) / divisor
edge3 = (c3 + c4) / divisor
edge4 = (c4 + c1) / 2.0
#Make sure that the midpoint doesn't accidentally "randomly displaced" past the boundaries!
middle = (middle <= 0) ? 0 : (middle < 1.0) ? middle : 1.0
#Do the operation over again for each of the four new grids.
divide_grid(x1, y1, new_width, new_height, c1, edge1, middle, edge4)
divide_grid(x1 + new_width, y1, new_width, new_height, edge1, c2, edge2, middle)
divide_grid(x1 + new_width, y1 + new_height, new_width, new_height, middle, edge2, c3, edge3)
divide_grid(x1, y1 + new_height, new_width, new_height, edge4, middle, edge3, c4)
end
end
Experiments with ruby-processing (processing-2.2.1) and JRubyArt for processing-3.0
Showing posts with label fractal. Show all posts
Showing posts with label fractal. Show all posts
Sunday, 4 April 2010
Plasma fractal (and carpet)
Labels:
bit-shifting color,
fractal,
ruby-processing
Wednesday, 10 February 2010
DavidTour fractal
For the grammar.rb library see my Cesàro fractal (here it was included in the davidtour.rb file which is why it didn't need to be separately loaded, Grammar code omitted for brevity).
########################################################
# A David Tour fractal implemented using a
# Lindenmayer System in ruby-processing by Martin Prout
########################################################
require 'davidtour'
class David_Test < Processing::App
attr_reader :david, :points, :production
def setup
size(800, 900)
@david = DavidTour.new(width * 0.6, height/4)
@production = david.create_grammar(5)
@points = david.translate_rules(production)
no_loop()
end
def draw()
background(0)
stroke(255)
points.each do |tmp|
line(*tmp)
end
end
end
####################################################
# The DavidTour fractal has been used to study the
# Euclidean travelling salesmam problem
####################################################
class DavidTour
attr_reader :draw_length, :xpos, :ypos, :theta, :axiom, :grammar
DELTA = Math::PI/3 # 60 degrees
def initialize xpos, ypos
@axiom = "FX-XFX-XFX-XFX-XFX-XF"
@theta = 0
@grammar = Grammar.new(axiom)
grammar.add_rule("F", "!F!-F-!F!")
grammar.add_rule("X", "!X")
@draw_length = 15
@xpos = xpos
@ypos = ypos
end
def create_grammar(gen)
@draw_length *= @draw_length * 0.5**gen
grammar.generate(gen)
end
def translate_rules(prod)
swap = false
points = [] # An empty array to store lines as an array of points
prod.scan(/./) do |ch|
case(ch)
when 'F'
temp = [xpos, ypos, (@xpos += draw_length * Math.cos(theta)), (@ypos -= draw_length * Math.sin(theta))]
points.push(temp)
when '+'
@theta += (DELTA)
when '-'
@theta += (swap ? DELTA : -DELTA)
when '!'
swap = !swap
when 'X'
else
puts("character '#{ch}' not in grammar")
end
end
return points
end
end
########################################################
# A David Tour fractal implemented using a
# Lindenmayer System in ruby-processing by Martin Prout
########################################################
require 'davidtour'
class David_Test < Processing::App
attr_reader :david, :points, :production
def setup
size(800, 900)
@david = DavidTour.new(width * 0.6, height/4)
@production = david.create_grammar(5)
@points = david.translate_rules(production)
no_loop()
end
def draw()
background(0)
stroke(255)
points.each do |tmp|
line(*tmp)
end
end
end
####################################################
# The DavidTour fractal has been used to study the
# Euclidean travelling salesmam problem
####################################################
class DavidTour
attr_reader :draw_length, :xpos, :ypos, :theta, :axiom, :grammar
DELTA = Math::PI/3 # 60 degrees
def initialize xpos, ypos
@axiom = "FX-XFX-XFX-XFX-XFX-XF"
@theta = 0
@grammar = Grammar.new(axiom)
grammar.add_rule("F", "!F!-F-!F!")
grammar.add_rule("X", "!X")
@draw_length = 15
@xpos = xpos
@ypos = ypos
end
def create_grammar(gen)
@draw_length *= @draw_length * 0.5**gen
grammar.generate(gen)
end
def translate_rules(prod)
swap = false
points = [] # An empty array to store lines as an array of points
prod.scan(/./) do |ch|
case(ch)
when 'F'
temp = [xpos, ypos, (@xpos += draw_length * Math.cos(theta)), (@ypos -= draw_length * Math.sin(theta))]
points.push(temp)
when '+'
@theta += (DELTA)
when '-'
@theta += (swap ? DELTA : -DELTA)
when '!'
swap = !swap
when 'X'
else
puts("character '#{ch}' not in grammar")
end
end
return points
end
end
Labels:
fractal,
LSystems,
travelling salesman
Subscribe to:
Posts (Atom)
Followers
About Me
- monkstone
- I have developed JRubyArt and propane new versions of ruby-processing for JRuby-9.1.5.0 and processing-3.2.2

