# Animate a pendulum

Capture of the Oz version.
Animate a pendulum
You are encouraged to solve this task according to the task description, using any language you may know.

One good way of making an animation is by simulating a physical system and illustrating the variables in that system using a dynamically changing graphical display. The classic such physical system is a simple gravity pendulum.

For this task, create a simple physical model of a pendulum and animate it.

This does not use a GUI, it simply animates the pendulum and prints out the positions. If you want, you can replace the output method with graphical update methods.

X and Y are relative positions of the pendulum to the anchor.

generic   type Float_Type is digits <>;   Gravitation : Float_Type;package Pendulums is   type Pendulum is private;   function New_Pendulum (Length : Float_Type;                          Theta0 : Float_Type) return Pendulum;   function Get_X (From : Pendulum) return Float_Type;   function Get_Y (From : Pendulum) return Float_Type;   procedure Update_Pendulum (Item : in out Pendulum; Time : in Duration);private   type Pendulum is record      Length   : Float_Type;      Theta    : Float_Type;      X        : Float_Type;      Y        : Float_Type;      Velocity : Float_Type;   end record;end Pendulums;

with Ada.Numerics.Generic_Elementary_Functions;package body Pendulums is   package Math is new Ada.Numerics.Generic_Elementary_Functions (Float_Type);    function New_Pendulum (Length : Float_Type;                          Theta0 : Float_Type) return Pendulum is      Result : Pendulum;   begin      Result.Length   := Length;      Result.Theta    := Theta0 / 180.0 * Ada.Numerics.Pi;      Result.X        := Math.Sin (Theta0) * Length;      Result.Y        := Math.Cos (Theta0) * Length;      Result.Velocity := 0.0;      return Result;   end New_Pendulum;    function Get_X (From : Pendulum) return Float_Type is   begin      return From.X;   end Get_X;    function Get_Y (From : Pendulum) return Float_Type is   begin      return From.Y;   end Get_Y;    procedure Update_Pendulum (Item : in out Pendulum; Time : in Duration) is      Acceleration : constant Float_Type := Gravitation / Item.Length *                                            Math.Sin (Item.Theta);   begin         Item.X        := Math.Sin (Item.Theta) * Item.Length;         Item.Y        := Math.Cos (Item.Theta) * Item.Length;         Item.Velocity := Item.Velocity +                          Acceleration  * Float_Type (Time);         Item.Theta    := Item.Theta +                          Item.Velocity * Float_Type (Time);   end Update_Pendulum;end Pendulums;

with Ada.Text_IO;with Ada.Calendar;with Pendulums; procedure Main is   package Float_Pendulum is new Pendulums (Float, -9.81);   use Float_Pendulum;   use type Ada.Calendar.Time;    My_Pendulum : Pendulum := New_Pendulum (10.0, 30.0);   Now, Before : Ada.Calendar.Time;begin   Before := Ada.Calendar.Clock;   loop      Delay 0.1;      Now := Ada.Calendar.Clock;      Update_Pendulum (My_Pendulum, Now - Before);      Before := Now;      -- output positions relative to origin      -- replace with graphical output if wanted      Ada.Text_IO.Put_Line (" X: " & Float'Image (Get_X (My_Pendulum)) &                            " Y: " & Float'Image (Get_Y (My_Pendulum)));   end loop;end Main;
Output:
 X:  5.00000E+00 Y:  8.66025E+00
X:  4.95729E+00 Y:  8.68477E+00
X:  4.87194E+00 Y:  8.73294E+00
X:  4.74396E+00 Y:  8.80312E+00
X:  4.57352E+00 Y:  8.89286E+00
X:  4.36058E+00 Y:  8.99919E+00
X:  4.10657E+00 Y:  9.11790E+00
X:  3.81188E+00 Y:  9.24498E+00
X:  3.47819E+00 Y:  9.37562E+00
X:  3.10714E+00 Y:  9.50504E+00
X:  2.70211E+00 Y:  9.62801E+00
X:  2.26635E+00 Y:  9.73980E+00
X:  1.80411E+00 Y:  9.83591E+00
X:  1.32020E+00 Y:  9.91247E+00
X:  8.20224E-01 Y:  9.96630E+00
X:  3.10107E-01 Y:  9.99519E+00
X: -2.03865E-01 Y:  9.99792E+00
X: -7.15348E-01 Y:  9.97438E+00
X: -1.21816E+00 Y:  9.92553E+00
X: -1.70581E+00 Y:  9.85344E+00
X: -2.17295E+00 Y:  9.76106E+00
X: -2.61452E+00 Y:  9.65216E+00
X: -3.02618E+00 Y:  9.53112E+00
X: -3.40427E+00 Y:  9.40271E+00
X: -3.74591E+00 Y:  9.27190E+00
X: -4.04873E+00 Y:  9.14373E+00
X: -4.31141E+00 Y:  9.02285E+00
X: -4.53271E+00 Y:  8.91373E+00
X: -4.71186E+00 Y:  8.82034E+00
X: -4.84868E+00 Y:  8.74587E+00
X: -4.94297E+00 Y:  8.69293E+00
X: -4.99459E+00 Y:  8.66337E+00
X: -5.00352E+00 Y:  8.65822E+00
...

## AutoHotkey

This version doesn't use an complex physics calculation - I found a faster way.

Library: GDIP
SetBatchlines,-1;settingsSizeGUI:={w:650,h:400} ;Guisizependulum:={length:300,maxangle:90,speed:2,size:30,center:{x:Sizegui.w//2,y:10}} ;pendulum length, size, center, speed and maxangle pendulum.maxangle:=pendulum.maxangle*0.01745329252p_Token:=Gdip_Startup()Gui,+LastFoundGui,show,% "w" SizeGUI.w  " h" SizeGUI.hhwnd:=WinActive()hdc:=GetDC(hwnd)start:=A_TickCount/1000G:=Gdip_GraphicsFromHDC(hdc)pBitmap:=Gdip_CreateBitmap(650, 450)G2:=Gdip_GraphicsFromImage(pBitmap)Gdip_SetSmoothingMode(G2, 4)pBrush := Gdip_BrushCreateSolid(0xff0000FF)pBrush2 := Gdip_BrushCreateSolid(0xFF777700)pPen:=Gdip_CreatePenFromBrush(pBrush2, 10)SetTimer,Update,10 Update:Gdip_GraphicsClear(G2,0xFFFFFFFF)time:=start-(A_TickCount/1000*pendulum.speed)angle:=sin(time)*pendulum.maxanglex2:=sin(angle)*pendulum.length+pendulum.center.xy2:=cos(angle)*pendulum.length+pendulum.center.yGdip_DrawLine(G2,pPen,pendulum.center.x,pendulum.center.y,x2,y2)GDIP_DrawCircle(G2,pBrush,pendulum.center.x,pendulum.center.y,15)GDIP_DrawCircle(G2,pBrush2,x2,y2,pendulum.size)Gdip_DrawImage(G, pBitmap)return GDIP_DrawCircle(g,b,x,y,r){	Gdip_FillEllipse(g, b, x-r//2,y-r//2 , r, r)} GuiClose:ExitApp

## BASIC

### BBC BASIC

      MODE 8      *FLOAT 64      VDU 23,23,4;0;0;0; : REM Set line thickness       theta = RAD(40) : REM initial displacement      g = 9.81 : REM acceleration due to gravity      l = 0.50 : REM length of pendulum in metres       REPEAT        PROCpendulum(theta, l)        WAIT 1        PROCpendulum(theta, l)        accel = - g * SIN(theta) / l / 100        speed += accel / 100        theta += speed      UNTIL FALSE      END       DEF PROCpendulum(a, l)      LOCAL pivotX, pivotY, bobX, bobY      pivotX = 640      pivotY = 800      bobX = pivotX + l * 1000 * SIN(a)      bobY = pivotY - l * 1000 * COS(a)      GCOL 3,6      LINE pivotX, pivotY, bobX, bobY      GCOL 3,11      CIRCLE FILL bobX + 24 * SIN(a), bobY - 24 * COS(a), 24      ENDPROC

### Commodore BASIC

10 GOSUB 100020 THETA = π/230 G = 9.8140 L = 0.550 SPEED = 060 PX = 2070 PY = 180 BX = PX+L*20*SIN(THETA)90 BY = PY-L*20*COS(THETA)100 PRINT CHR$(147);110 FOR X=PX TO BX STEP (BX-PX)/10120 Y=PY+(X-PX)*(BY-PY)/(BX-PX)130 PRINT CHR$(19);LEFT$(X$,X);LEFT$(Y$,Y);"."140 NEXT150 PRINT CHR$(19);LEFT$(X$,BX);LEFT$(Y$,BY);CHR$(113)160 ACCEL=G*SIN(THETA)/L/50170 SPEED=SPEED+ACCEL/10180 THETA=THETA+SPEED190 GOTO 80980 REM ** SETUP STRINGS TO BE USED **990 REM ** FOR CURSOR POSITIONING   **1000 FOR I=0 TO 39: X$= X$+CHR$(29): NEXT1010 FOR I=0 TO 24: Y$ = Y$+CHR$(17): NEXT1020 RETURN

### FreeBASIC

Const PI = 3.141592920Dim As Double theta, g, l, accel, speed, px, py, bx, bytheta = PI/2g = 9.81l = 1speed = 0px = 320py = 10Screen 17 '640x400 graphicDo    bx=px+l*300*Sin(theta)    by=py-l*300*Cos(theta)    Cls    Line (px,py)-(bx,by)    Circle (bx,by),5,,,,,F    accel=g*Sin(theta)/l/100    speed=speed+accel/100    theta=theta+speed    Draw String (0,370), "Pendulum"    Draw String (0,385), "Press any key to quit"    Sleep 10Loop Until Inkey()<>""

### IS-BASIC

100 PROGRAM "Pendulum.bas"110 LET THETA=RAD(50):LET G=9.81:LET L=.5120 CALL INIC130 CALL DRAWING140 CALL ANIMATE150 CALL RESET160 END170 DEF INIC180   CLOSE #102190   OPTION ANGLE RADIANS200   SET STATUS OFF:SET INTERRUPT STOP OFF:SET BORDER 56210   SET VIDEO MODE 1:SET VIDEO COLOR 1:SET VIDEO X 14:SET VIDEO Y 8220   FOR I=1 TO 24230     OPEN #I:"video:"240     SET #I:PALETTE 56,0,255,YELLOW250   NEXT260 END DEF270 DEF DRAWING280   LET SPD=0290   FOR I=1 TO 24300     DISPLAY #I:AT 3 FROM 1 TO 8310     SET #I:INK 2320     PLOT #I:224,280,ELLIPSE 10,10330     PLOT #I:0,280;214,280,234,280;446,280340     SET #I:INK 1350     CALL PENDULUM(THETA,L,I)360     LET ACC=-G*SIN(THETA)/L/100370     LET SPD=SPD+ACC/10.5380     LET THETA=THETA+SPD390   NEXT400 END DEF410 DEF PENDULUM(A,L,CH)420   LET PX=224:LET PY=280430   LET BX=PX+L*460*SIN(A)440   LET BY=PY-L*460*COS(A)450   PLOT #CH:PX,PY;BX,BY460   PLOT #CH:BX+24*SIN(A),BY-24*COS(A),ELLIPSE 20,20,470   SET #CH:INK 3:PLOT #CH:PAINT480 END DEF490 DEF ANIMATE500   DO510     FOR I=1 TO 24520       DISPLAY #I:AT 3 FROM 1 TO 8530     NEXT 540     FOR I=23 TO 2 STEP-1550       DISPLAY #I:AT 3 FROM 1 TO 8560     NEXT 570   LOOP UNTIL INKEY$=CHR$(27)580 END DEF590 DEF RESET600   TEXT 40:SET STATUS ON:SET INTERRUPT STOP ON:SET BORDER 0610   FOR I=24 TO 1 STEP-1620     CLOSE #I630   NEXT640 END DEF

## C

Library: GLUT
#include <stdlib.h>#include <math.h>#include <GL/glut.h>#include <GL/gl.h>#include <sys/time.h> #define length 5#define g 9.8double alpha, accl, omega = 0, E;struct timeval tv; double elappsed() {	struct timeval now;	gettimeofday(&now, 0);	int ret = (now.tv_sec - tv.tv_sec) * 1000000		+ now.tv_usec - tv.tv_usec;	tv = now;	return ret / 1.e6;} void resize(int w, int h){	glViewport(0, 0, w, h);	glMatrixMode(GL_PROJECTION);	glLoadIdentity(); 	glMatrixMode(GL_MODELVIEW);	glLoadIdentity();	glOrtho(0, w, h, 0, -1, 1);} void render(){	double x = 320 + 300 * sin(alpha), y = 300 * cos(alpha);	resize(640, 320); 	glClear(GL_COLOR_BUFFER_BIT); 	glBegin(GL_LINES);	glVertex2d(320, 0);	glVertex2d(x, y);	glEnd();	glFlush(); 	double us = elappsed();	alpha += (omega + us * accl / 2) * us;	omega += accl * us; 	/* don't let precision error go out of hand */	if (length * g * (1 - cos(alpha)) >= E) {		alpha = (alpha < 0 ? -1 : 1) * acos(1 - E / length / g);		omega = 0;	}	accl = -g / length * sin(alpha);} void init_gfx(int *c, char **v){	glutInit(c, v);	glutInitDisplayMode(GLUT_RGB);	glutInitWindowSize(640, 320);	glutIdleFunc(render);	glutCreateWindow("Pendulum");} int main(int c, char **v){	alpha = 4 * atan2(1, 1) / 2.1;	E = length * g * (1 - cos(alpha)); 	accl = -g / length * sin(alpha);	omega = 0; 	gettimeofday(&tv, 0);	init_gfx(&c, v);	glutMainLoop();	return 0;}

## C++

Library: wxWidgets

File wxPendulumDlg.hpp

 #ifndef __wxPendulumDlg_h__#define __wxPendulumDlg_h__ // ---------------------/// @author Martin Ettl/// @date   2013-02-03// --------------------- #ifdef __BORLANDC__#pragma hdrstop#endif #ifndef WX_PRECOMP#include <wx/wx.h>#include <wx/dialog.h>#else#include <wx/wxprec.h>#endif#include <wx/timer.h>#include <wx/dcbuffer.h>#include <cmath> class wxPendulumDlgApp : public wxApp{    public:        bool OnInit();        int OnExit();}; class wxPendulumDlg : public wxDialog{    public:         wxPendulumDlg(wxWindow *parent, wxWindowID id = 1, const wxString &title = wxT("wxPendulum"), 				 const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize, 				 long style = wxSUNKEN_BORDER | wxCAPTION | wxRESIZE_BORDER | wxSYSTEM_MENU | wxDIALOG_NO_PARENT | wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxCLOSE_BOX);         virtual ~wxPendulumDlg(); 		// Event handler        void wxPendulumDlgPaint(wxPaintEvent& event);        void wxPendulumDlgSize(wxSizeEvent& event);        void OnTimer(wxTimerEvent& event);     private: 		// a pointer to a timer object        wxTimer *m_timer; 		unsigned int m_uiLength;		double  	 m_Angle;		double       m_AngleVelocity;         enum wxIDs        {            ID_WXTIMER1 = 1001,            ID_DUMMY_VALUE_         };         void OnClose(wxCloseEvent& event);        void CreateGUIControls();         DECLARE_EVENT_TABLE()}; #endif // __wxPendulumDlg_h__

File wxPendulumDlg.cpp

 // ---------------------/// @author Martin Ettl/// @date   2013-02-03// --------------------- #include "wxPendulumDlg.hpp"#include <wx/pen.h> IMPLEMENT_APP(wxPendulumDlgApp) bool wxPendulumDlgApp::OnInit(){    wxPendulumDlg* dialog = new wxPendulumDlg(NULL);    SetTopWindow(dialog);    dialog->Show(true);    return true;} int wxPendulumDlgApp::OnExit(){    return 0;} BEGIN_EVENT_TABLE(wxPendulumDlg, wxDialog)    EVT_CLOSE(wxPendulumDlg::OnClose)    EVT_SIZE(wxPendulumDlg::wxPendulumDlgSize)    EVT_PAINT(wxPendulumDlg::wxPendulumDlgPaint)    EVT_TIMER(ID_WXTIMER1, wxPendulumDlg::OnTimer)END_EVENT_TABLE() wxPendulumDlg::wxPendulumDlg(wxWindow *parent, wxWindowID id, const wxString &title, const wxPoint &position, const wxSize& size, long style)    : wxDialog(parent, id, title, position, size, style){    CreateGUIControls();} wxPendulumDlg::~wxPendulumDlg(){} void wxPendulumDlg::CreateGUIControls(){    SetIcon(wxNullIcon);    SetSize(8, 8, 509, 412);    Center(); 	m_uiLength = 200;	m_Angle    = M_PI/2.;	m_AngleVelocity = 0;     m_timer = new wxTimer();    m_timer->SetOwner(this, ID_WXTIMER1);    m_timer->Start(20);} void wxPendulumDlg::OnClose(wxCloseEvent& WXUNUSED(event)){    Destroy();} void wxPendulumDlg::wxPendulumDlgPaint(wxPaintEvent& WXUNUSED(event)){    SetBackgroundStyle(wxBG_STYLE_CUSTOM);    wxBufferedPaintDC dc(this);     // Get window dimensions    wxSize sz = GetClientSize();	// determine the center of the canvas    const wxPoint center(wxPoint(sz.x / 2, sz.y / 2));     // create background color    wxColour powderblue = wxColour(176,224,230);     // draw powderblue background    dc.SetPen(powderblue);    dc.SetBrush(powderblue);    dc.DrawRectangle(0, 0, sz.x, sz.y);     // draw lines	wxPen Pen(*wxBLACK_PEN);	Pen.SetWidth(1);    dc.SetPen(Pen);    dc.SetBrush(*wxBLACK_BRUSH);     double angleAccel, dt = 0.15;     angleAccel = (-9.81 / m_uiLength) * sin(m_Angle);    m_AngleVelocity += angleAccel * dt;    m_Angle += m_AngleVelocity * dt;     int anchorX = sz.x / 2, anchorY = sz.y / 4;    int ballX = anchorX + (int)(sin(m_Angle) * m_uiLength);    int ballY = anchorY + (int)(cos(m_Angle) * m_uiLength);    dc.DrawLine(anchorX, anchorY, ballX, ballY);     dc.SetBrush(*wxGREY_BRUSH);    dc.DrawEllipse(anchorX - 3, anchorY - 4, 7, 7);     dc.SetBrush(wxColour(255,255,0)); // yellow    dc.DrawEllipse(ballX - 7, ballY - 7, 20, 20);} void wxPendulumDlg::wxPendulumDlgSize(wxSizeEvent& WXUNUSED(event)){    Refresh();} void wxPendulumDlg::OnTimer(wxTimerEvent& WXUNUSED(event)){	// force refresh	Refresh();}

This program is tested with wxWidgets version 2.8 and 2.9. The whole project, including makefile for compiling on Linux can be download from github.

## C#

Library: Windows Forms
 using System;using System.Drawing;using System.Windows.Forms; class CSharpPendulum{    Form _form;    Timer _timer;     double _angle = Math.PI / 2,            _angleAccel,            _angleVelocity = 0,            _dt = 0.1;     int _length = 50;     [STAThread]    static void Main()    {        var p = new CSharpPendulum();    }     public CSharpPendulum()    {        _form = new Form() { Text = "Pendulum", Width = 200, Height = 200 };        _timer = new Timer() { Interval = 30 };         _timer.Tick += delegate(object sender, EventArgs e)        {            int anchorX = (_form.Width / 2) - 12,                anchorY = _form.Height / 4,                ballX = anchorX + (int)(Math.Sin(_angle) * _length),                ballY = anchorY + (int)(Math.Cos(_angle) * _length);             _angleAccel = -9.81 / _length * Math.Sin(_angle);            _angleVelocity += _angleAccel * _dt;            _angle += _angleVelocity * _dt;             Bitmap dblBuffer = new Bitmap(_form.Width, _form.Height);            Graphics g = Graphics.FromImage(dblBuffer);            Graphics f = Graphics.FromHwnd(_form.Handle);             g.DrawLine(Pens.Black, new Point(anchorX, anchorY), new Point(ballX, ballY));            g.FillEllipse(Brushes.Black, anchorX - 3, anchorY - 4, 7, 7);            g.FillEllipse(Brushes.DarkGoldenrod, ballX - 7, ballY - 7, 14, 14);             f.Clear(Color.White);            f.DrawImage(dblBuffer, new Point(0, 0));            };         _timer.Start();        Application.Run(_form);    }     }

## Clojure

Clojure solution using an atom and a separate rendering thread

Library: Swing
Library: AWT
 (ns pendulum  (:import    (javax.swing JFrame)    (java.awt Canvas Graphics Color))) (def length 200)(def width (* 2 (+ 50 length)))(def height (* 3 (/ length 2)))(def dt 0.1)(def g 9.812)(def k (- (/ g length)))(def anchor-x (/ width 2))(def anchor-y (/ height 8))(def angle (atom (/ (Math/PI) 2))) (defn draw [#^Canvas canvas angle]  (let [buffer  (.getBufferStrategy canvas)        g       (.getDrawGraphics buffer)        ball-x (+ anchor-x (* (Math/sin angle) length))        ball-y (+ anchor-y (* (Math/cos angle) length))]    (try            (doto g        (.setColor Color/BLACK)        (.fillRect 0 0 width height)        (.setColor Color/RED)        (.drawLine anchor-x anchor-y ball-x ball-y)        (.setColor Color/YELLOW)        (.fillOval (- anchor-x 3) (- anchor-y 4) 7 7)        (.fillOval (- ball-x 7) (- ball-y 7) 14 14))            (finally (.dispose g)))    (if-not (.contentsLost buffer)      (.show buffer)) )) (defn start-renderer [canvas]  (->>    (fn [] (draw canvas @angle) (recur))    (new Thread)    (.start))) (defn -main [& args]  (let [frame  (JFrame. "Pendulum")        canvas (Canvas.)]     (doto frame      (.setSize width height)            (.setDefaultCloseOperation JFrame/EXIT_ON_CLOSE)      (.setResizable false)      (.add canvas)      (.setVisible true))     (doto canvas      (.createBufferStrategy 2)            (.setVisible true)      (.requestFocus))     (start-renderer canvas)     (loop [v 0]            (swap! angle #(+ % (* v dt)))      (Thread/sleep 15)      (recur (+ v (* k (Math/sin @angle) dt)))) )) (-main)

## Common Lisp

Pressing the spacebar adds a pendulum.

(defvar *frame-rate* 30)(defvar *damping* 0.99 "Deceleration factor.") (defun make-pendulum (length theta0 x)  "Returns an anonymous function with enclosed state representing a pendulum."  (let* ((theta (* (/ theta0 180) pi))         (acceleration 0))    (if (< length 40) (setf length 40)) ;;avoid a divide-by-zero    (lambda ()      ;;Draws the pendulum, updating its location and speed.      (sdl:draw-line (sdl:point :x x :y 1)                     (sdl:point :x (+ (* (sin theta) length) x)                                :y (* (cos theta) length)))      (sdl:draw-filled-circle (sdl:point :x (+ (* (sin theta) length) x)                                         :y (* (cos theta) length))                              20                              :color sdl:*yellow*                              :stroke-color sdl:*white*)      ;;The magic constant approximates the speed we want for a given frame-rate.      (incf acceleration (* (sin theta) (* *frame-rate* -0.001)))      (incf theta acceleration)      (setf acceleration (* acceleration *damping*)))))  (defun main (&optional (w 640) (h 480))  (sdl:with-init ()    (sdl:window w h :title-caption "Pendulums"                :fps (make-instance 'sdl:fps-fixed))    (setf (sdl:frame-rate) *frame-rate*)    (let ((pendulums nil))      (sdl:with-events ()        (:quit-event () t)        (:idle ()               (sdl:clear-display sdl:*black*)               (mapcar #'funcall pendulums) ;;Draw all the pendulums                (sdl:update-display))        (:key-down-event (:key key)                         (cond ((sdl:key= key :sdl-key-escape)                                (sdl:push-quit-event))                               ((sdl:key= key :sdl-key-space)                                (push (make-pendulum (random (- h 100))                                                     (random 90)                                                     (round w 2))                                      pendulums))))))))

## E

Works with: E-on-Java
(Uses Java Swing for GUI. The animation logic is independent, however.)

The angle ${\displaystyle \theta }$ of a pendulum with length ${\displaystyle L}$ and acceleration due to gravity ${\displaystyle g}$ with all its mass at the end and no friction/air resistance has an acceleration at any given moment of

${\displaystyle {\frac {d^{2}}{dt^{2}}}\theta =-{\frac {g}{L}}\sin \theta }$

This simulation uses this formula directly, updating the velocity from the acceleration and the position from the velocity; inaccuracy results from the finite timestep.

The event flow works like this: The clock object created by the simulation steps the simulation on the specified in the interval. The simulation writes its output to angle, which is a Lamport slot which can notify of updates. The whenever set up by makeDisplayComponent listens for updates and triggers redrawing as long as interest has been expressed, which is done whenever the component actually redraws, which happens only if the component's window is still on screen. When the window is closed, additionally, the simulation itself is stopped and the application allowed to exit. (This logic is more general than necessary; it is designed to be suitable for a larger application as well.)

#!/usr/bin/env runepragma.syntax("0.9") def pi := (-1.0).acos()def makeEPainter := <unsafe:com.zooko.tray.makeEPainter>def makeLamportSlot := <import:org.erights.e.elib.slot.makeLamportSlot>def whenever := <import:org.erights.e.elib.slot.whenever>def colors := <import:java.awt.makeColor> # --------------------------------------------------------------# --- Definitions def makePendulumSim(length_m :float64,                    gravity_mps2 :float64,                    initialAngle_rad :float64,                    timestep_ms :int) {  var velocity := 0  def &angle := makeLamportSlot(initialAngle_rad)  def k := -gravity_mps2/length_m  def timestep_s := timestep_ms / 1000  def clock := timer.every(timestep_ms, fn _ {    def acceleration := k * angle.sin()    velocity += acceleration * timestep_s    angle    += velocity     * timestep_s  })  return [clock, &angle]} def makeDisplayComponent(&angle) {  def c  def updater := whenever([&angle], fn { c.repaint() })   bind c := makeEPainter(def paintCallback {    to paintComponent(g) {      try {        def originX := c.getWidth() // 2        def originY := c.getHeight() // 2        def pendRadius := (originX.min(originY) * 0.95).round()        def ballRadius := (originX.min(originY) * 0.04).round()        def ballX := (originX + angle.sin() * pendRadius).round()        def ballY := (originY + angle.cos() * pendRadius).round()         g.setColor(colors.getWhite())        g.fillRect(0, 0, c.getWidth(), c.getHeight())        g.setColor(colors.getBlack())         g.fillOval(originX - 2, originY - 2, 4, 4)        g.drawLine(originX, originY, ballX, ballY)        g.fillOval(ballX - ballRadius, ballY - ballRadius, ballRadius * 2, ballRadius * 2)         updater[] # provoke interest provided that we did get drawn (window not closed)      } catch p {        stderr.println(In paint callback: $p${p.eStack()})      }    }  })   c.setPreferredSize(<awt:makeDimension>(300, 300))  return c} # --------------------------------------------------------------# --- Application setup def [clock, &angle] := makePendulumSim(1, 9.80665, pi*99/100, 10) # Initialize AWT, move to AWT event threadwhen (currentVat.morphInto("awt")) -> {   # Create the window  def frame := <unsafe:javax.swing.makeJFrame>("Pendulum")  frame.setContentPane(def display := makeDisplayComponent(&angle))  frame.addWindowListener(def mainWindowListener {    to windowClosing(_) {      clock.stop()      interp.continueAtTop()    }    match _ {}  })  frame.setLocation(50, 50)  frame.pack()   # Start and become visible  frame.show()  clock.start()} interp.blockAtTop()

## Elm

import Color exposing (..)import Collage exposing (..)import Element exposing (..)import Html exposing (..)import Time exposing (..)import Html.App exposing (program) dt = 0.01scale = 100 type alias Model =  { angle : Float  , angVel : Float  , length : Float  , gravity : Float  } type Msg     = Tick Time init : (Model,Cmd Msg)init =  ( { angle = 3 * pi / 4    , angVel = 0.0    , length = 2    , gravity = -9.81    }  , Cmd.none) update : Msg -> Model -> (Model, Cmd Msg)update _ model =  let    angAcc = -1.0 * (model.gravity / model.length) * sin (model.angle)    angVel' = model.angVel + angAcc * dt    angle' = model.angle + angVel' * dt  in    ( { model        | angle = angle'        , angVel = angVel'      }    , Cmd.none ) view : Model -> Html Msgview model =  let    endPoint = ( 0, scale * model.length )    pendulum =      group        [ segment ( 0, 0 ) endPoint            |> traced { defaultLine | width = 2, color = red }        , circle 8            |> filled blue        , ngon 3 10            |> filled green            |> rotate (pi/2)            |> move endPoint        ]  in    toHtml <|      collage 700 500        [ pendulum |> rotate model.angle ] subscriptions : Model -> Sub Msgsubscriptions _ =     Time.every (dt * second) Tick main =  program       { init = init      , view = view      , update = update      , subscriptions = subscriptions      }

## ERRE

 PROGRAM PENDULUM !! for rosettacode.org! !$KEY !$INCLUDE="PC.LIB" PROCEDURE PENDULUM(A,L)      PIVOTX=320      PIVOTY=0      BOBX=PIVOTX+L*500*SIN(a)      BOBY=PIVOTY+L*500*COS(a)      LINE(PIVOTX,PIVOTY,BOBX,BOBY,6,FALSE)      CIRCLE(BOBX+24*SIN(A),BOBY+24*COS(A),27,11)      PAUSE(0.01)      LINE(PIVOTX,PIVOTY,BOBX,BOBY,0,FALSE)      CIRCLE(BOBX+24*SIN(A),BOBY+24*COS(A),27,0)END PROCEDURE BEGIN      SCREEN(9)      THETA=40*p/180     ! initial displacement      G=9.81             ! acceleration due to gravity      L=0.5              ! length of pendulum in metres      LINE(0,0,639,0,5,FALSE)      LOOP        PENDULUM(THETA,L)        ACCEL=-G*SIN(THETA)/L/100        SPEED=SPEED+ACCEL/100        THETA=THETA+SPEED      END LOOPEND PROGRAM

PC version: Ctrl+Break to stop.

## Euphoria

### DOS32 version

Works with: Euphoria version 3.1.1
include graphics.einclude misc.e constant dt = 1E-3constant g = 50 sequence vcsequence suspensionatom len procedure draw_pendulum(atom color, atom len, atom alfa)    sequence point    point = (len*{sin(alfa),cos(alfa)} + suspension)    draw_line(color, {suspension, point})    ellipse(color,0,point-{10,10},point+{10,10})end procedure function wait()    atom t0    t0 = time()    while time() = t0 do        if get_key() != -1 then            return 1        end if    end while    return 0end function procedure animation()    atom alfa, omega, epsilon     if graphics_mode(18) then    end if     vc = video_config()    suspension = {vc[VC_XPIXELS]/2,vc[VC_YPIXELS]/2}    len = vc[VC_YPIXELS]/2-20     alfa = PI/2    omega = 0     while 1 do        draw_pendulum(BRIGHT_WHITE,len,alfa)        if wait() then            exit        end if        draw_pendulum(BLACK,len,alfa)        epsilon = -len*sin(alfa)*g        omega += dt*epsilon        alfa += dt*omega    end while     if graphics_mode(-1) then    end ifend procedure animation()

## Euler Math Toolbox

Euler Math Toolbox can determine the exact period of a physical pendulum. The result is then used to animate the pendulum. The following code is ready to be pasted back into Euler notebooks.

>g=gearth$; l=1m; >function f(x,y) := [y[2],-g*sin(y[1])/l] >function h(a) := ode("f",linspace(0,a,100),[0,2])[1,-1] >period=solve("h",2) 2.06071780729 >t=linspace(0,period,30); s=ode("f",t,[0,2])[1]; >function anim (t,s) ...$  setplot(-1,1,-1,1);
$markerstyle("o#");$  repeat
$for i=1 to cols(t)-1;$    clg;
$hold on;$    plot([0,sin(s[i])],[1,1-cos(s[i])]);
$mark([0,sin(s[i])],[1,1-cos(s[i])]);$    hold off;
$wait(t[i+1]-t[i]);$  end;
$until testkey();$  end

## Yabasic

clear screenopen window 400, 300window origin "cc" rodLen = 160gravity = 2damp = .989TWO_PI = pi * 2angle = 90 * 0.01745329251 // convert degree to radian repeat    acceleration = -gravity / rodLen * sin(angle)    angle = angle + velocity : if angle > TWO_PI angle = 0    velocity = velocity + acceleration    velocity = velocity * damp    posX = sin(angle) * rodLen    posY = cos(angle) * rodLen - 70    clear window    text -50, -100, "Press 'q' to quit"    color 250, 0, 250    fill circle 0, -70, 4    line 0, -70, posX, posY    color 250, 100, 20    fill circle posX, posY, 10until(lower$(inkey$(0.02)) = "q") exit

## ZX Spectrum Basic

Translation of: ERRE

In a real Spectrum it is too slow. Use the BasinC emulator/editor at maximum speed for realistic animation.

10 OVER 1: CLS 20 LET theta=130 LET g=9.8140 LET l=0.550 LET speed=0100 LET pivotx=120110 LET pivoty=140120 LET bobx=pivotx+l*100*SIN (theta)130 LET boby=pivoty+l*100*COS (theta)140 GO SUB 1000: PAUSE 1: GO SUB 1000190 LET accel=g*SIN (theta)/l/100200 LET speed=speed+accel/100210 LET theta=theta+speed220 GO TO 1001000 PLOT pivotx,pivoty: DRAW bobx-pivotx,boby-pivoty1010 CIRCLE bobx,boby,31020 RETURN