Xiaohan Zhang Sketch in JRubyArt
Xiaohan Zhang has created interesting stuff in processing
Here is a processing sketch by Xiaohan Zhang aka hellochar roughly translated for JRubyArt by Martin Prout
# After an original by Xiaohan Zhang aka hellochar
load_library :particle
PX_PER_BUCKET = 40
attr_reader :scalar, :g, :t, :particles
def setup
sketch_title 'March 15'
@t = 0
@particles = (0..500).map { |i| Particle.new(i, rand * width, rand * height) }
background(255)
end
def draw
noStroke
fill(12, 6, 19, 155)
rect(0, 0, width, height)
stroke_cap(SQUARE)
5.times do
dt = mouse_pressed? ? -0.02 : 0.02
@scalar = 2**map1d(mouse_x, 0..width, -5..5.0) / 32 * 1_000
@g = map1d(mouse_y, 0..height, 1..10.0)**3
particles.each(&:compute_force)
particles.each { |p| p.update(dt) }
@t += dt
end
particles.each(&:draw)
end
def settings
size(800, 800, P2D)
end
The library (library/particle/particle.rb)
# The Particle class
class Particle
include Processing::Proxy
attr_accessor :fx, :fy
attr_reader :idx, :x, :y, :vx, :vy
def initialize(idx, x, y)
@idx = idx
@x = x
@y = y
@vx = 0
@vy = 0
@fx = 0
@fy = 0
end
def compute_force_single(pa)
g = Processing.app.g
scalar = Processing.app.scalar
return if pa == self || idx > pa.idx
dfx = 0
dfy = 0
ox = pa.x - x
oy = pa.y - y
dist2 = ox * ox + oy * oy
# if (dist2 < 5 * 5) return
dist = Math.sqrt(dist2)
dist_factor = g * Math.sin(dist / scalar) / dist2
# dist_factor = min(100, 1 / (dist * dist))
unless dist_factor.nan?
dfx += ox * dist_factor
dfy += oy * dist_factor
end
# repel force when very close by
repel_factor = -1000 / (dist2 * dist)
unless repel_factor.nan?
dfx += ox * repel_factor
dfy += oy * repel_factor
end
@fx += dfx
@fy += dfy
pa.fx -= dfx
pa.fy -= dfy
end
def compute_force
Processing.app.particles.each { |p| compute_force_single(p) }
end
def update(dt)
@vx += fx * dt
@vy += fy * dt
@vx *= 0.99
@vy *= 0.99
px = x
py = y
@x += fx * dt
@y += fy * dt
out_of_bounds = reset_bounds
speed = dist(px, py, x, y)
if !out_of_bounds && speed < 20
c = lerp_color(color('#2D728F'), color('#F49E4C'), speed / 3)
stroke(c, 40)
stroke_weight(6)
line(px, py, x, y)
no_stroke
fill(c)
# fill(255, 128)
# rad = Math.sqrt(2 + speed / 3)
rad = 3
ellipse(x, y, rad * 2, rad * 2)
end
@fx = 0
@fy = 0
end
def reset_bounds
return false if (0..width).cover?(x) && (0..height).cover?(y)
@x = rand * width
@y = rand * height
@vx = 0
@vy = 0
true
end
def draw
ellipse(x, y, 14, 14)
end
end
A snapshot of running sketch