RosettaCodeData/Task/Animate-a-pendulum/Oz/animate-a-pendulum.oz
Ingy döt Net d066446780 langs a-z
2013-04-10 22:43:41 -07:00

81 lines
2.1 KiB
Text

declare
[QTk] = {Link ['x-oz://system/wp/QTk.ozf']}
Pi = 3.14159265
class PendulumModel
feat
K
attr
angle
velocity
meth init(length:L <= 1.0 %% meters
gravity:G <= 9.81 %% m/s²
initialAngle:A <= Pi/2.) %% radians
self.K = ~G / L
angle := A
velocity := 0.0
end
meth nextAngle(deltaT:DeltaTMS %% milliseconds
?Angle) %% radians
DeltaT = {Int.toFloat DeltaTMS} / 1000.0 %% seconds
Acceleration = self.K * {Sin @angle}
in
velocity := @velocity + Acceleration * DeltaT
angle := @angle + @velocity * DeltaT
Angle = @angle
end
end
%% Animates a pendulum on a given canvas.
class PendulumAnimation from Time.repeat
feat
Pend
Rod
Bob
home:pos(x:160 y:50)
length:140.0
delay
meth init(Pendulum Canvas delay:Delay <= 25) %% milliseconds
self.Pend = Pendulum
self.delay = Delay
%% plate and pivot
{Canvas create(line 0 self.home.y 320 self.home.y width:2 fill:grey50)}
{Canvas create(oval 155 self.home.y-5 165 self.home.y+5 fill:grey50 outline:black)}
%% the pendulum itself
self.Rod = {Canvas create(line 1 1 1 1 width:3 fill:black handle:$)}
self.Bob = {Canvas create(oval 1 1 2 2 fill:yellow outline:black handle:$)}
%%
{self setRepAll(action:Animate delay:Delay)}
end
meth Animate
Theta = {self.Pend nextAngle(deltaT:self.delay $)}
%% calculate x and y from angle
X = self.home.x + {Float.toInt self.length * {Sin Theta}}
Y = self.home.y + {Float.toInt self.length * {Cos Theta}}
in
%% update canvas
try
{self.Rod setCoords(self.home.x self.home.y X Y)}
{self.Bob setCoords(X-15 Y-15 X+15 Y+15)}
catch system(tk(alreadyClosed ...) ...) then skip end
end
end
Pendulum = {New PendulumModel init}
Canvas
GUI = td(title:"Pendulum"
canvas(width:320 height:210 handle:?Canvas)
action:proc {$} {Animation stop} {Window close} end
)
Window = {QTk.build GUI}
Animation = {New PendulumAnimation init(Pendulum Canvas)}
in
{Window show}
{Animation go}