pendulum_animation.sf 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768
  1. #!/usr/bin/ruby
  2. #
  3. ## https://rosettacode.org/wiki/Animate_a_pendulum
  4. #
  5. require('Tk')
  6. var root = %s<MainWindow>.new('-title' => 'Pendulum Animation')
  7. var canvas = root.Canvas('-width' => 320, '-height' => 200)
  8. canvas.createLine( 0, 25, 320, 25, '-tags' => <plate>, '-width' => 2, '-fill' => :grey50)
  9. canvas.createOval(155, 20, 165, 30, '-tags' => <pivot outline>, '-fill' => :grey50)
  10. canvas.createLine( 1, 1, 1, 1, '-tags' => <rod width>, '-width' => 3, '-fill' => :black)
  11. canvas.createOval( 1, 1, 2, 2, '-tags' => <bob outline>, '-fill' => :yellow)
  12. canvas.raise(:pivot)
  13. canvas.pack('-fill' => :both, '-expand' => 1)
  14. var(θ = 45, Δθ = 0, length = 150, homeX = 160, homeY = 25)
  15. func show_pendulum() {
  16. var angle = θ.deg2rad
  17. var x = (homeX + length*sin(angle))
  18. var y = (homeY + length*cos(angle))
  19. canvas.coords(:rod, homeX, homeY, x, y)
  20. canvas.coords(:bob, x - 15, y - 15, x + 15, y + 15)
  21. }
  22. func recompute_angle() {
  23. var scaling = 3000/(length**2)
  24. # first estimate
  25. var firstΔΔθ = (-sin(θ.deg2rad) * scaling)
  26. var midΔθ = (Δθ + firstΔΔθ)
  27. var midθ = ((Δθ + midΔθ)/2 + θ)
  28. # second estimate
  29. var midΔΔθ = (-sin(midθ.deg2rad) * scaling)
  30. midΔθ = ((firstΔΔθ + midΔΔθ)/2 + Δθ)
  31. midθ = ((Δθ + midΔθ)/2 + θ)
  32. # again, first
  33. midΔΔθ = (-sin(midθ.deg2rad) * scaling)
  34. var lastΔθ = (midΔθ + midΔΔθ)
  35. var lastθ = ((midΔθ + lastΔθ)/2 + midθ)
  36. # again, second
  37. var lastΔΔθ = (-sin(lastθ.deg2rad) * scaling)
  38. lastΔθ = ((midΔΔθ + lastΔΔθ)/2 + midΔθ)
  39. lastθ = ((midΔθ + lastΔθ)/2 + midθ)
  40. # Now put the values back in our globals
  41. Δθ = lastΔθ
  42. θ = lastθ
  43. }
  44. func animate(Ref id) {
  45. recompute_angle()
  46. show_pendulum()
  47. *id = root.after(15 => { animate(id) })
  48. }
  49. show_pendulum()
  50. var after_id = root.after(500 => { animate(\after_id) })
  51. canvas.bind('<Destroy>' => { after_id.cancel })
  52. %S<Tk>.MainLoop()