Last active
November 26, 2016 15:32
-
-
Save JoshCheek/88a7e739cb6f4e7ccaed9f4977066236 to your computer and use it in GitHub Desktop.
Lissajous Curves
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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