circles-4
2014. 05. 18.

A little variation of circles-3. Inspired by the work of Kusama Yayoi. Click on the screen to refresh, press enter key to invert the background color.

» launch circles-4

rint = (a, b) -> parseInt random(a, b)
Array::sample  = -> this[rint(0, this.length)]
Object::keys   = -> _(this).keys()
String::sample = -> this.substr(rint(0, this.length), 1)
Object::each   = (f) ->
  for k, v of this
    f(k, v) if this.hasOwnProperty(k)
  null
Array::each    = (f) -> _(this).each(f)

p5       = processing
sizes    = {}
grids    = {}
shapes   = 5
sr       = 0.4
sparsity = 2
opacity  = 20
bg       = 1

pick_slot = (sz) ->
  sz = parseInt sz
  x  = grids[sz].keys().sample()

  if x?
    y = grids[sz][x].keys().sample()
    if y?
      x = parseInt x
      y = parseInt y
      occupy sz, x, y
      return { x: x, y: y }

occupy = (sz, x, y) ->
  sizes.each (s, cnt) ->
    s = parseInt s
    step = parseInt s * sr

    sx = floor((x - s) / step) * step
    sy = floor((y - s) / step) * step

    for xx in [sx...(x + sz)] by step
      for yy in [sy...(y + sz)] by step
        if grids[s][xx]? and xx > sx and yy > sy
          delete grids[s][xx][yy]
          if grids[s][xx].keys().length == 0
            delete grids[s][xx]
  null

setup = ->
  colorMode HSB, 1.0
  ellipseMode CENTER
  noLoop()
  noStroke()
  mousePressed()

drawCircle = (x, y, sz, col, rt) ->
  fill hue(col), saturation(col), brightness(col), opacity / sz
  pushMatrix()
  ns = 0.001
  translate x + sz / 2 - sz + noise(ns * x, ns * y) * 2 * sz,
            y + sz / 2 - sz + noise(ns * x, ns * y) * 2 * sz
  for s in [sz/1.25..sz] by 2
    rotate random TWO_PI
    ellipse(
      random(-1, 1) * 0.03 * s,
      random(-1, 1) * 0.03 * s,
      (random(-1, 1) * 0.05 + rt) * s, (random(-1, 1) * 0.05 + rt) * s)
  popMatrix()

mousePressed = ->
  size       $(window).width(), $(window).height()
  background bg

  colors = for i in [0...rint(5, 10)]
    color(random(1.0), random(0.5, 1.0), random(0.7, 1.0))

  grids  = {}
  sizes  = {}
  sbase  = rint(20, 40)
  srange = [sbase, sbase * 2]
  rt     = random(0.2, 0.7)
  for i in [0...shapes]
    sz = rint(srange[0], srange[1])
    sizes[sz] = parseInt(p5.width * p5.height /
                         (shapes + sparsity) / pow(sz, 2))
  sizes.each (sz, count) ->
    sz = parseInt sz
    step = parseInt sz * sr

    grids[sz] = {}
    for x in [0..p5.width - sz] by step
      grids[sz][x] = {}
      for y in [0..p5.height - sz] by step
        grids[sz][x][y] = 1

  rsizes = _(sizes.keys()).sortBy((e) -> -parseInt(e))
  _(rsizes).each (sz) ->
    sz = parseInt sz
    count = sizes[sz]
    for i in [0...count]
      p = pick_slot sz
      if p?
        drawCircle p.x, p.y, sz, colors.sample(), rt
      else
        break

keyPressed = ->
  if keyCode() == ENTER || keyCode() == RETURN
    bg = if bg == 1 then 0 else 1
    mousePressed()
» capture | close