Created
October 23, 2021 14:58
-
-
Save OndrejSlamecka/6401a6c6747968886204d29142859094 to your computer and use it in GitHub Desktop.
Animation of connected springs
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
using Luxor | |
using Colors | |
const height = 80 | |
const lw = height / 10 | |
mutable struct Spring | |
k::Float64 # spring constant | |
equilibrium_length::Float64 | |
current_length::Float64 | |
turns::Float64 | |
end | |
transparent(c::RGB) = RGBA(c.r, c.g, c.b, 0.5) | |
function draw_front_line(colour, pitch, from) | |
f = Point(from, -height/2) | |
t = Point(from + pitch, height/2) | |
setcolor(colour) | |
setline(lw) | |
line(f, t, :stroke) | |
circle(f, lw/2, :fill) | |
circle(t, lw/2, :fill) | |
end | |
function draw_rear_line(colour, pitch, from) | |
f = Point(from, height/2) | |
t = Point(from + pitch, -height/2) | |
setcolor(transparent(colour)) | |
setline(lw) | |
line(f, t, :stroke) | |
setcolor(colour) | |
circle(f, lw/2, :fill) | |
circle(t, lw/2, :fill) | |
end | |
function draw_spring(colour, turns, width, start) | |
pitch = width / (2 * turns) | |
pos = start | |
for i = 1:turns | |
draw_front_line(colour, pitch, pos) | |
pos += pitch | |
draw_rear_line(colour, pitch, pos) | |
pos += pitch | |
end | |
end | |
function draw_springs(springs) | |
background("black") | |
start = -sum(s.equilibrium_length for s in springs)/2 | |
for (ix, spring) in enumerate(springs) | |
draw_spring(colours[ix], spring.turns, spring.current_length, start) | |
start += spring.current_length | |
end | |
end | |
hooke_F(s::Spring) = s.k * (s.equilibrium_length - s.current_length) | |
function frame(scene::Scene, framenumber::Int64) | |
draw_springs(springs) | |
if framenumber < 30 | |
# stand still in initial position for the first second | |
return | |
end | |
# a pretty arbitrary way to translate force into something that's relative to size | |
scaler = maximum(max(s.equilibrium_length, s.current_length) for s in springs) | |
for s in springs | |
s.current_length += hooke_F(s) / scaler | |
end | |
end | |
springs = [Spring(20, 160, 100, 5), Spring(25, 120, 270, 4), Spring(30, 120, 110, 4), Spring(200, 260, 180, 8)] | |
@assert sum(s.equilibrium_length for s in springs) == sum(s.current_length for s in springs) | |
colours = distinguishable_colors(length(springs), [RGB(1,1,1), RGB(0,0,0)], dropseed=true) | |
mymovie = Movie(sum(s.equilibrium_length for s in springs)+120, height+50, "mymovie") | |
animate(mymovie, [Scene(mymovie, frame, 1:90)], creategif=true, pathname="springs.gif") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment