orbit-1
2012. 06. 10.

orbit series can be said to be "circular"-variation of the previous tiles projects. The idea is to place circles, instead of rectangles, densely onto the circular grid without each overlapping each other.

Four sketches shown here are mostly identical, only differ in their presentation. Click on the screen to regenerate the pattern.

» launch orbit-1-solid
» launch orbit-1-space
```rint    = (a, b) -> parseInt random(a, b)
fuzzy   = (m, p) -> m * p * random(-0.01, 0.01)
quintic = (t) -> 6 * pow(t, 5) - 15 * pow(t, 4) + 10 * pow(t, 3)
Array::sample = -> this[rint(0, this.length)]

class Planet
constructor: (@rad, @theta, @r, @R, @c, @o) ->
@h = hue @c
@s = saturation @c
@b = brightness @c
@diameter = @r * 2
@attrs = {}
mind = parseInt(0)
maxd = parseInt(@diameter)
for s in [maxd..mind] by -1
@attrs[s] = {
rx: @diameter * random(-0.03, 0.03)
ry: @diameter * random(-0.03, 0.03)
sx: random(1, s * 3)
}
null

draw: ->
pushMatrix()
translate @x, @y
mind = parseInt(0)
maxd = parseInt(@diameter)
for s in [maxd..mind] by -1
r = (s - mind) / (maxd - mind)
r2 = if @R == 0 then 1 else @R / max_R
fill @h, pow(r, 3), 1, r2 * (1 - r) * @o / @diameter

pushMatrix()
translate @attrs[s].rx, @attrs[s].ry
ellipse(
0, 0,
@attrs[s].sx,
pow(pow(@r / max_R, 0.15), 4) * s * s / @attrs[s].sx
)
popMatrix()
popMatrix()

p5      = processing
min_r   = undefined
step    = undefined
min_R   = undefined
max_R   = undefined
colors  = undefined
suncol  = undefined
density = undefined
rings   = {}
opacity = 4
bg      = 0

setup = ->
size \$(window).width(), \$(window).height()
max_R = sqrt(pow(p5.width / 2, 2) + pow(p5.height / 2, 2))
colorMode HSB, 1.0
ellipseMode CENTER
noLoop()
noStroke()
mousePressed()

draw = ->
background bg

# for i in [0...1000]
#   [rx, ry] = [random(p5.width), random(p5.height)]
#   fill 1, random(0.05, 0.1)
#   ellipse rx, ry, 3, 3
#   ellipse rx, ry, 2, 2
#   ellipse rx, ry, 1, 1

pushMatrix()
translate p5.width / 2, p5.height / 2
fill hue(suncol), saturation(suncol), brightness(suncol), 0.01
for R in [min_R..min_R * 2] by 4
ellipse random(-step, step) / 5, random(-step, step) / 5,
R * random(0.7, 1.5), R * random(0.9, 1.1)
_(rings).each (ps, R) ->
_(ps).each (p) -> p.draw()
popMatrix()

mousePressed = ->
size \$(window).width(), \$(window).height()
rings = {}

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

density = random(0.1, 0.5)
min_r = rint(10, 20)
step  = rint(min_r * 3, 120)
min_R = rint(step, max(step * 2, min(p5.width / 2, p5.height / 2)))
center_r = min_R

rings[0] = [new Planet(0, 0, center_r, 0, colors.sample(), opacity * 3)]

for R in [min_R..max_R] by step
rings[R] = []

for R in [min_R..max_R] by step
pring = rings[R - step]
ring = rings[R]

# Calculate thetas according to mininum and maximum radius
min_theta = 2 * asin(min_r / (2 * R))
max_theta = 2 * asin(step / (2 * R))
max_margin = max( max_theta / density - max_theta, 0 )

idx = 0
while true
prev  = _(ring).last() or { rad: srad, theta: 0, r: 0 }
first = _(ring).first() or { rad: srad, theta: 0, r: 0 }

# No more space
break if avail_theta < min_theta

theta = random(min_theta, min(avail_theta, max_theta))
random(min(max_margin, avail_theta - theta))

if pring
safed = 2.5 * step
closest = _(_(pring).filter((p) ->
abs(p.x - x) <= safed and abs(p.y - y) <= safed
)).sortBy((p) -> dist(p.x, p.y, x, y) - p.r)[0]
max_r =
if closest?
dist(closest.x, closest.y, x, y) - closest.r
else
step
else
closest = null
max_r = step

# (r + r')^2 = R^2 + R^2 - 2R^2cos(t)
max_r =
min([
step,
max_r,
sqrt(2 * pow(R, 2) * (1 - cos(prev.theta + theta))) - prev.r,
sqrt(2 * pow(R, 2) * (1 - cos(first.theta + theta))) - first.r
else
step
])

d = max_r - min_r
r = min_r + random() * d

p = new Planet(rad, theta, r, R, colors.sample(), opacity)
ring.push p
rings[R] = for p in ring when p.r >= min_r
p
draw()```
» capture | close