Harmonograph and spirograph

For the cover of Grafia magazine 3/2010 we created these scripts in Nodebox, a harmonograph and a spirograph. Copy the code into a new Nodebox file and experiment with the sliders to create different figures.


# http://en.wikipedia.org/wiki/Harmonograph

from math import sin, cos, exp, pi, radians
from random import seed

def pendulum(t, a, f, p, d):
    return a * sin(t * f + p) * exp(-d * t)

def harmonograph(t, a1, f1, p1, d1, a2, f2, p2, d2,
                    a3, f3, p3, d3, a4, f4, p4, d4):
    x = pendulum(t, a1, f1, p1, d1) + pendulum(t, a2, f2, p2, d2)
    y = pendulum(t, a3, f3, p3, d3) + pendulum(t, a4, f4, p4, d4)
    return x, y

var("a1", NUMBER, 100, 0, 200)
var("f1", NUMBER, 1.8, 1, 2)
var("f1_tweak", NUMBER, 0, 0, 0.05)
var("p1", NUMBER, 0.6, 0, pi)
var("d1", NUMBER, 0.0015, 0, 0.1)

var("a2", NUMBER, 40, 0, 200)
var("f2", NUMBER, 1.8, 1, 2)
var("f2_tweak", NUMBER, 0, 0, 0.05)
var("p2", NUMBER, 0.6, 0, pi)
var("d2", NUMBER, 0.0015, 0, 0.1)

var("a3", NUMBER, 33, 0, 200)
var("f3", NUMBER, 1.8, 1, 2)
var("f3_tweak", NUMBER, 0, 0, 0.05)
var("p3", NUMBER, 2.1, 0, pi)
var("d3", NUMBER, 0.0015, 0, 0.1)

var("a4", NUMBER, 160, 0, 200)
var("f4", NUMBER, 1.2, 1, 2)
var("f4_tweak", NUMBER, 0, 0, 0.05)
var("p4", NUMBER, 2.3, 0, pi)
var("d4", NUMBER, 0.0015, 0, 0.1)

var("revolutions", NUMBER, 100, 1, 250)
var("highres", BOOLEAN, False)

samples = 100.0 if highres else 20.0
f1 += f1_tweak
f2 += f2_tweak
f3 += f3_tweak
f4 += f4_tweak

stroke(0)
nofill()
strokewidth(0.25)
translate(250, 250)
autoclosepath(False)

beginpath()
for i in range(int(revolutions * 2 * pi * samples)):
    x, y = harmonograph(i/samples,
                        a1, f1, p1, d1, a2, f2, p2, d2,
                        a3, f3, p3, d3, a4, f4, p4, d4)
    if i == 0: moveto(x, y)
    else: lineto(x, y)
endpath()


# Spirograph http://en.wikipedia.org/wiki/Spirograph

from math import sin, cos, pi

def spirograph(t, R, r, p):
    x = (R - r) * cos(t) + p * cos((R - r) * t / r)
    y = (R - r) * sin(t) - p * sin((R - r) * t / r)
    return x, y

var("R", NUMBER, 12.0, -25, 25)
var("R_tweak", NUMBER, 0.0, -0.25, 0.25)
var("r", NUMBER, 5.0, -10, 10)
var("r_tweak", NUMBER, 0.0, -0.1, 0.1)
var("p", NUMBER, -2.0, -10, 10)
var("revolutions", NUMBER, 10, 1, 30)
var("highres", BOOLEAN, False)

samples = 250.0 if highres else 25.0
R += R_tweak
r += r_tweak
r = 0.1 if r == 0 else r

stroke(0)
strokewidth(0.25)
nofill()
autoclosepath(False)
translate(250, 250)

beginpath()
for i in range(int(revolutions * 2 * pi * samples)):
    x, y = spirograph(i/samples, R, r, p)
    x, y = x * 7, y * 7
    if i == 0: moveto(x, y)
    else: lineto(x, y)
endpath()
This entry was posted in the Kirstu Blog. Bookmark the permalink.

one comment

  1. Xaime /

    Great sript!
    thanks a lot!

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>