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)

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









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



Followers

About Me

My photo
I have developed JRubyArt and propane new versions of ruby-processing for JRuby-9.1.5.0 and processing-3.2.2