I had the idea for sometime to optimize this application. As before the application uses Lee Byrons library which in turn depends on John Lloyds QuickHull3D library (both can be accessed at the Lee Byron link). One day I might re-write the application to use a 3D mesh library directly. The major optimization here is to use processings built in pixels array functionality. The app will work best if the aspect ratio of the image is the same as the frame size (1:1 is probably optimal?). I have introduced an auto-scale feature that seems to work...
Use the view raw feature (below) if you want to copy the code.
Experiments with ruby-processing (processing-2.2.1) and JRubyArt for processing-3.0
Showing posts with label voronoi mesh. Show all posts
Showing posts with label voronoi mesh. Show all posts
Saturday, 30 October 2010
Revisiting My Voronoi Application
Labels:
portrait application,
voronoi mesh
Monday, 10 May 2010
Op Art using Voronoi Cell, Ruby Processing
load_libraries 'mesh' # http://www.leebyron.com/else/mesh/
import 'megamu.mesh.Voronoi'
require 'set'
attr_reader :voronoi, :points, :left, :right, :top, :bottom
def setup()
size(1000, 1000)
color_mode HSB, 1.0
@points = Set.new
@points.clear
@left = MRect.new 10, height/2, 20, height, 20
@right = MRect.new 990, height/2, 20, height, 20
@top = MRect.new width/2, 10, width, 20, 20
@bottom = MRect.new width/2, 990, width, 20, 20
smooth
# no_loop
end
def draw
@points.clear
shape = MPoly.new width/3, height/3, 8, 150, 4
shape1 = MPoly.new width/2, height/2, 8, 120, 4
shape2 = MPoly.new width*0.667, height*0.667, 8, 150, 4
shape3 = MPoly.new width/3, height*0.667, 3, 150, 4
shape4 = MPoly.new width*0.667, height/3, 3, 150, 4
@points.merge(left.points)
@points.merge(right.points)
@points.merge(top.points)
@points.merge(bottom.points)
@points.merge(shape.points)
@points.merge(shape1.points)
@points.merge(shape2.points)
@points.merge(shape3.points)
@points.merge(shape4.points)
voronoi = Voronoi.new((@points.to_a).to_java(Java::float[]))
regions = voronoi.get_regions
regions.each do |region|
region_coordinates = region.get_coords
fill(rand)
region.draw(self)
end
end
class MRect # border for now
attr_reader :x, :y, :w, :h, :skip, :points
def initialize x, y, w, h, skip
@x = x - w/2
@y = y - h/2
@w = w
@h = h
@skip = skip
@points = calculate_points
end
def calculate_points
mpoints = Array.new
(w/skip).times do
(h/skip).times do
mpoints.push([rand*w + x, rand*h + y])
end
end
return mpoints
end
end
class MPoly # shape
attr_reader :x, :y, :sides, :size, :theta, :delta, :repeats, :len, :points
def initialize x, y, sides, size, density
@delta = -PI/sides
@x = x
@y = y
@sides = sides
@size = size
@theta = 2 * PI/sides
@repeats = density
@len = size/repeats
@points = calculate_points
end
def calculate_points
mpoints = Array.new
repeats.times do |i|
sides.times do |j|
mpoint_x = x + (i + 1) * len * cos(j * theta + delta)
mpoint_y = y - (i + 1) * len * sin(j * theta + delta)
mpoints.push [mpoint_x, mpoint_y]
end
end
return mpoints
end
# def rotate delta
# @delta += delta
# calculate_points
# end
end
Labels:
pop art,
ruby processing,
voronoi mesh
Saturday, 8 May 2010
Voronoi Cells from the Coordinates of A Penrose Tiling
Here's an idea to create 'regular' voronoi cells from fractal dimensions. Well recently I was working on Penrose Tiling created using LSystems, so that's were I started.
#########################################################
# Voronoi cells centered on penrose tiling coordinates
# generated by a Lindenmayer System in ruby-processing
# by Martin Prout
#######################################################
require 'penrose_tiling'
require 'set'
load_libraries 'grammar', 'mesh'
import 'megamu.mesh.Voronoi'
attr_reader :regions
def setup
size 300, 300
stroke 255, 255, 0 # yellow mesh
stroke_weight 3
fill 255, 0, 0 # red regions
smooth
penrose = PenroseTiling.new
penrose.create_grammar 4
set = penrose.get_points
voronoi = Voronoi.new((set.to_a).to_java(Java::float[]))
@regions = voronoi.get_regions
no_loop
end
def draw
background 0
regions.each do |region|
region_coordinates = region.get_coords
region.draw(self)
end
end
#######################################
# penrose_tiling.rb
# #####################################
require 'set'
class PenroseTiling
include Processing::Proxy
attr_reader :axiom, :grammar, :start_length, :theta, :production, :draw_length,
:repeats, :xpos, :ypos
XPOS = 0 # placeholders for turtle array
YPOS = 1
ANGLE = 2
DELTA = PI/5 # radians or 36 degrees
def initialize
@axiom = "[X]2+[X]2+[X]2+[X]2+[X]" # Note use of abbreviated rule
@grammar = Grammar.new axiom # here number equals number of repeats
@grammar.add_rule "F", ""
@grammar.add_rule "X", "+YF2-ZF[3-WF2-XF]+"
@grammar.add_rule "Y", "-WF2+XF[3+YF2+ZF]-"
@grammar.add_rule "Z", "2-YF4+WF[+ZF4+XF]2-XF"
@grammar.add_rule "W", "YF2+ZF4-XF[-YF4-WF]2+"
@start_length = 300.0
@theta = 0
@xpos = width/2
@ypos = height/2
@production = axiom
@draw_length = start_length
end
##############################################################################
# Not strictly in the spirit of either processing in my get_points
# function I have ignored the processing translate/rotate functions in favour
# of the direct calculation of the new x and y positions, thus avoiding such
# affine transformations. Returns a Set of unique [x, y] coordinates.
##############################################################################
def get_points()
points = Set.new
repeats = 1
turtle = [xpos, ypos, theta] # simple array for turtle
points.add([xpos.round, ypos.round])
stack = [] # simple array for stack
production.scan(/./).each do |element|
case element
when 'F'
turtle = next_point(turtle, draw_length)
points.add([turtle[XPOS].round, turtle[YPOS].round]) unless (turtle[XPOS] < 0) || (turtle[YPOS] < 0)
when '+'
turtle[ANGLE] += DELTA * repeats
repeats = 1
when '-'
turtle[ANGLE] -= DELTA * repeats
repeats = 1
when '['
stack.push(turtle.clone) # push a copy current turtle to stack
when ']'
turtle = stack.pop # assign current turtle a instance popped from the stack
when 'W', 'X', 'Y', 'Z'
when '1', '2', '3', '4'
repeats = Integer(element)
else puts "Character '#{element}' not in grammar"
end
end
return points
end
##############################
# create grammar from axiom and # rules (adjust scale)
##############################
def create_grammar(gen)
@draw_length *= 0.5**gen
@production = grammar.generate gen
end
private
######################################################
# uses current turtle and length parameters to calculate
# a turtle corresponding to the new position
######################################################
def next_point(turtle, length)
new_xpos = turtle[XPOS] + length * cos(turtle[ANGLE])
new_ypos = turtle[YPOS] + length * sin(turtle[ANGLE])
return [new_xpos, new_ypos, turtle[ANGLE]]
end
end
For the grammar library see my PenroseTiling post.
#########################################################
# Voronoi cells centered on penrose tiling coordinates
# generated by a Lindenmayer System in ruby-processing
# by Martin Prout
#######################################################
require 'penrose_tiling'
require 'set'
load_libraries 'grammar', 'mesh'
import 'megamu.mesh.Voronoi'
attr_reader :regions
def setup
size 300, 300
stroke 255, 255, 0 # yellow mesh
stroke_weight 3
fill 255, 0, 0 # red regions
smooth
penrose = PenroseTiling.new
penrose.create_grammar 4
set = penrose.get_points
voronoi = Voronoi.new((set.to_a).to_java(Java::float[]))
@regions = voronoi.get_regions
no_loop
end
def draw
background 0
regions.each do |region|
region_coordinates = region.get_coords
region.draw(self)
end
end
#######################################
# penrose_tiling.rb
# #####################################
require 'set'
class PenroseTiling
include Processing::Proxy
attr_reader :axiom, :grammar, :start_length, :theta, :production, :draw_length,
:repeats, :xpos, :ypos
XPOS = 0 # placeholders for turtle array
YPOS = 1
ANGLE = 2
DELTA = PI/5 # radians or 36 degrees
def initialize
@axiom = "[X]2+[X]2+[X]2+[X]2+[X]" # Note use of abbreviated rule
@grammar = Grammar.new axiom # here number equals number of repeats
@grammar.add_rule "F", ""
@grammar.add_rule "X", "+YF2-ZF[3-WF2-XF]+"
@grammar.add_rule "Y", "-WF2+XF[3+YF2+ZF]-"
@grammar.add_rule "Z", "2-YF4+WF[+ZF4+XF]2-XF"
@grammar.add_rule "W", "YF2+ZF4-XF[-YF4-WF]2+"
@start_length = 300.0
@theta = 0
@xpos = width/2
@ypos = height/2
@production = axiom
@draw_length = start_length
end
##############################################################################
# Not strictly in the spirit of either processing in my get_points
# function I have ignored the processing translate/rotate functions in favour
# of the direct calculation of the new x and y positions, thus avoiding such
# affine transformations. Returns a Set of unique [x, y] coordinates.
##############################################################################
def get_points()
points = Set.new
repeats = 1
turtle = [xpos, ypos, theta] # simple array for turtle
points.add([xpos.round, ypos.round])
stack = [] # simple array for stack
production.scan(/./).each do |element|
case element
when 'F'
turtle = next_point(turtle, draw_length)
points.add([turtle[XPOS].round, turtle[YPOS].round]) unless (turtle[XPOS] < 0) || (turtle[YPOS] < 0)
when '+'
turtle[ANGLE] += DELTA * repeats
repeats = 1
when '-'
turtle[ANGLE] -= DELTA * repeats
repeats = 1
when '['
stack.push(turtle.clone) # push a copy current turtle to stack
when ']'
turtle = stack.pop # assign current turtle a instance popped from the stack
when 'W', 'X', 'Y', 'Z'
when '1', '2', '3', '4'
repeats = Integer(element)
else puts "Character '#{element}' not in grammar"
end
end
return points
end
##############################
# create grammar from axiom and # rules (adjust scale)
##############################
def create_grammar(gen)
@draw_length *= 0.5**gen
@production = grammar.generate gen
end
private
######################################################
# uses current turtle and length parameters to calculate
# a turtle corresponding to the new position
######################################################
def next_point(turtle, length)
new_xpos = turtle[XPOS] + length * cos(turtle[ANGLE])
new_ypos = turtle[YPOS] + length * sin(turtle[ANGLE])
return [new_xpos, new_ypos, turtle[ANGLE]]
end
end
For the grammar library see my PenroseTiling post.
Labels:
LSystems,
penrose tiling,
ruby-processing,
voronoi mesh
Random Voronoi Sketch
Here is a simple sketch, that flashes new random voronoi cells, with random fill.
load_libraries 'mesh' # http://www.leebyron.com/else/mesh/
import 'megamu.mesh.Voronoi'
require 'set'
attr_reader :voronoi, :points
def setup()
size(300, 300)
color_mode HSB, 1.0
end
def draw
points = Set.new
10.times do
10.times do
points.add([rand*300, rand*300])
end
end
voronoi = Voronoi.new((points.to_a).to_java(Java::float[]))
regions = voronoi.get_regions
regions.each do |region|
region_coordinates = region.get_coords
fill(rand, rand, rand)
region.draw(self)
end
end
load_libraries 'mesh' # http://www.leebyron.com/else/mesh/
import 'megamu.mesh.Voronoi'
require 'set'
attr_reader :voronoi, :points
def setup()
size(300, 300)
color_mode HSB, 1.0
end
def draw
points = Set.new
10.times do
10.times do
points.add([rand*300, rand*300])
end
end
voronoi = Voronoi.new((points.to_a).to_java(Java::float[]))
regions = voronoi.get_regions
regions.each do |region|
region_coordinates = region.get_coords
fill(rand, rand, rand)
region.draw(self)
end
end
Labels:
ruby processing,
voronoi mesh
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


