Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Last active November 26, 2016 15:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JoshCheek/88a7e739cb6f4e7ccaed9f4977066236 to your computer and use it in GitHub Desktop.
Save JoshCheek/88a7e739cb6f4e7ccaed9f4977066236 to your computer and use it in GitHub Desktop.
Lissajous Curves
# encoding: utf-8
# Screenshots:
# http://joshcheek.deviantart.com/gallery/61181398/Lissajous-Curves
# Videos:
# https://vimeo.com/193155770
# https://vimeo.com/193155808
# https://vimeo.com/193156077
# https://vimeo.com/193156097
# https://vimeo.com/193156142
# https://vimeo.com/193156237
# https://vimeo.com/193156327
# https://vimeo.com/193156506
# https://vimeo.com/193156596
# https://vimeo.com/193159486 (unedited, useful for finding specific values of an animation)
# Inspired by one of the slides (47) at
# https://acko.net/blog/animate-your-way-to-glory/
# Fun Fact!
# Aphex Twin used these to embed images into his music,
# When you look at the sound waves of some of his music
# on an Oscilloscope in Lissajous mode, it makes images!
require 'graphics'
class Lissajous < Graphics::Simulation
include Math
def π
PI
end
def initialize
super 1440, 850, 24
color.default_proc = -> h, k { k }
end
def draw(n)
return if @pause
# ----- Various Variables -----
# how large the animation is
x_radius = w/2-20
y_radius = h/2-20
# speed, frustratingly, this has an impact on the phase shifts & other features >.<
steps = 250
# higher is rounder, varying it across time (eg n/20.0) gives a cool warbly effect
lines_per_step = 20
# Pause at the end to look at the final result.
@pause = true if n == steps # Note that some variations keep going after n==steps
# ----- The x and y coordinates (how it shifts phases) -----
# # these look nice together, but will never get the resolution on video to appreciate it
# y_numerator, y_denominator = 23, 27
# x_numerator, x_denominator = 28, 29
# y_numerator, y_denominator = 12, 17
# x_numerator, x_denominator = 21, 23
# y_numerator, y_denominator = 7, 8
# x_numerator, x_denominator = 2, 9
y_numerator, y_denominator = 1, 1
x_numerator, x_denominator = 7, 8
# ----- Constants -----
# There's no point in changing these, they either don't command anything useful,
# or they're composed of vars above, which let you change them in more meaningful ways.
y_coefficient = y_numerator/y_denominator.to_f
x_coefficient = x_numerator/x_denominator.to_f
domain = 2*π * x_denominator.lcm(y_denominator)
step_size = domain / steps
# ----- Draw Background -----
# clear colour(2*π*n/steps) # colour the background over time
clear :black # Graphics' default, you'll want to make the lines white or coloured
# clear :white # inverted default,
# ----- Draw the Lines -----
0.step(domain*n/steps, by: step_size/lines_per_step).each_cons(2) do |i_prev, i_crnt|
# ----- Colouring Functions -----
# rgb = [0xFF]*3 # uncoloured (white) put it on a coloured background
# rgb = [0x00]*3 # uncoloured (black)
rgb = colour(i_prev) # colour across the line (like yarn)
# rgb = colour(2*π*n/steps) # colours across time
# ----- Line Location -----
# Makes them migrate over time / show up in nonlocal positions.
# NOTE this behaves very differently based on number of steps!
x_prev, y_prev = xy(i_prev, vary(x_radius/2, x_radius, n/domain), y_radius, x_coefficient, y_coefficient)
x_crnt, y_crnt = xy(i_crnt, x_radius, vary(y_radius/2, y_radius, n/domain), x_coefficient, y_coefficient)
# # This is the normal lissajuous curve
# x_prev, y_prev = xy(i_prev, x_radius, y_radius, x_coefficient, y_coefficient)
# x_crnt, y_crnt = xy(i_crnt, x_radius, y_radius, x_coefficient, y_coefficient)
# ----- Draw Line -----
line x_prev, y_prev, x_crnt, y_crnt, rgb
# line x_prev+1, y_prev, x_crnt+1, y_crnt, rgb # thicken the line
# line x_prev, y_prev+1, x_crnt, y_crnt+1, rgb # thicken the line
# line x_prev-1, y_prev, x_crnt-1, y_crnt, rgb # thicken the line more
# line x_prev, y_prev-1, x_crnt, y_crnt-1, rgb # thicken the line more
# circle x_prev, y_prev, 50, rgb, false # knob on the prev line end
# circle x_crnt, y_crnt, 50, rgb, false # knob on the crnt line end
end
end
def xy(ø, x_radius, y_radius, x_coefficient, y_coefficient)
[ x_radius*sin(x_coefficient*ø) + w/2,
y_radius*sin(y_coefficient*ø) + h/2,
]
end
# A relatively nice traversal of colourspace, given an angle
# (arbitrary quantity, you just don't want it jumping between
# values that are far apart on 0..2π)
# It avoids black and white since they're common background colours
def colour(ø)
blue = (Math.cos(ø) * 127.5).to_i + 128
green = (Math.sin(ø) * 50.5).to_i + 128
red = 255 - blue
[red, green, blue]
end
def vary(min, max, ø)
∆ = (max-min)
min + (1 + sin(2*π*ø))*∆/2
end
end
Lissajous.new.run
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment