1. NodeBox 1
    1. Homepage
    2. NodeBox 3Node-based app for generative design and data visualization
    3. NodeBox OpenGLHardware-accelerated cross-platform graphics library
    4. NodeBox 1Generate 2D visuals using Python code (Mac OS X only)
  2. Gallery
  3. Documentation
  4. Forum
  5. Blog

circular gradients?

Posted by ryan fitz on Sep 02, 2007

hi, I just started playing with nodebox and I'm kind of stumped by this issue. I'm trying to make a function to produce circles or rings with gradient fill, but the result looks really ugly, with a ton of moire lines. I'm not sure what I'm doing wrong. here's the function:

def gradcirc(x=(WIDTH/2),y=(HEIGHT/2),rad=(WIDTH/2),inner=0,c=color(0.5,0,0)):
    colormode(HSB)
    nofill()
    for i in range(rad)[int(rad*inner):rad]:
        c.a = (float(i) / rad)
        stroke(c)
        oval(x-i, y-i, i*2, i*2)
anyone have any insights?


 
Posted by ryan on Sep 02, 2007

oh also the colormode(HSB) should be outside (before) the def block. I changed it and didn't realize that it was a problem until after posting this.



Posted by Tom De Smedt on Sep 05, 2007

You could widen the gap between each circle and at the same time increase the strokewidth. Less steps soften the moire effect.

colormode(HSB)
def gradcirc(x=(WIDTH/2),y=(HEIGHT/2),rad=(WIDTH/2),
             inner=0,c=color(0.5,0,0), step=2):
    nofill()
    for i in range(rad / step)[int(rad*inner):rad]:
        c.a = (float(i) / rad)
        stroke(c)
        strokewidth(step*3)
        oval(x-i*step, y-i*step, i*2*step, i*2*step)
However, I think it is a better idea to use filled circles instead of stroked circles. Some code from Superfolia:
from math import sqrt
n = 280 # adjusts the spread
r = sqrt(WIDTH*WIDTH + HEIGHT*HEIGHT)
for i in range(n):
    dx = (WIDTH-r)/2
    dy = (HEIGHT-r)/2
    fill(0, 0, float(i)/n)
    oval(dx+i, dy+i, r-i*2, r-i*2)
Now, it would also be nice to have a command that interpolates gradient steps from a list of colors. So a more elaborate example would be:
size(400, 400)
 
colors = [color(0.80, 0.80, 0.44),
          color(0.29, 0.27, 0.08),
          color(0.16, 0.16, 0.05),
          color(0, 0, 0),
          ]
colors.reverse()
 
def gradient(colors, i, n):
    
    l = len(colors)-1
    a = int(1.0*i/n*l)
    a = min(a+0, l)
    b = min(a+1, l)
    base = 1.0 * n/l * a
    d = (i-base) / (n/l)
    r = colors[a].r*(1-d) + colors[b].r*d
    g = colors[a].g*(1-d) + colors[b].g*d
    b = colors[a].b*(1-d) + colors[b].b*d
    
    return color(r, g, b)
 
from math import sqrt
n = 280
r = sqrt(WIDTH*WIDTH + HEIGHT*HEIGHT)
for i in range(n):
    dx = (WIDTH-r)/2
    dy = (HEIGHT-r)/2
    fill(gradient(colors, i, n))
    oval(dx+i, dy+i, r-i*2, r-i*2)


Also, the upcoming Colors library has all kinds of easy-to-use support for smooth bitmap gradients, so help is underway.