Task: Animate a pendulum




Go: package main

import (
	"github.com/google/gxui"
	"github.com/google/gxui/drivers/gl"
	"github.com/google/gxui/math"
	"github.com/google/gxui/themes/dark"
	omath "math"
	"time"
)





const (
	ANIMATION_WIDTH  int     = 480
	ANIMATION_HEIGHT int     = 320
	BALL_RADIUS      float32 = 25.0
	METER_PER_PIXEL  float64 = 1.0 / 20.0
	PHI_ZERO         float64 = omath.Pi * 0.5
)

var (
	l    float64 = float64(ANIMATION_HEIGHT) * 0.5
	freq float64 = omath.Sqrt(9.81 / (l * METER_PER_PIXEL))
)

type Pendulum interface {
	GetPhi() float64
}

type mathematicalPendulum struct {
	start time.Time
}

func (p *mathematicalPendulum) GetPhi() float64 {
	if (p.start == time.Time{}) {
		p.start = time.Now()
	}
	t := float64(time.Since(p.start).Nanoseconds()) / omath.Pow10(9)
	return PHI_ZERO * omath.Cos(t*freq)
}

type numericalPendulum struct {
	currentPhi float64
	angAcc     float64
	angVel     float64
	lastTime   time.Time
}

func (p *numericalPendulum) GetPhi() float64 {
	dt := 0.0
	if (p.lastTime != time.Time{}) {
		dt = float64(time.Since(p.lastTime).Nanoseconds()) / omath.Pow10(9)
	}
	p.lastTime = time.Now()

	p.angAcc = -9.81 / (float64(l) * METER_PER_PIXEL) * omath.Sin(p.currentPhi)
	p.angVel += p.angAcc * dt
	p.currentPhi += p.angVel * dt

	return p.currentPhi
}

func draw(p Pendulum, canvas gxui.Canvas, x, y int) {
	attachment := math.Point{X: ANIMATION_WIDTH/2 + x, Y: y}

	phi := p.GetPhi()
	ball := math.Point{X: x + ANIMATION_WIDTH/2 + math.Round(float32(l*omath.Sin(phi))), Y: y + math.Round(float32(l*omath.Cos(phi)))}

	line := gxui.Polygon{gxui.PolygonVertex{attachment, 0}, gxui.PolygonVertex{ball, 0}}

	canvas.DrawLines(line, gxui.DefaultPen)

	m := math.Point{int(BALL_RADIUS), int(BALL_RADIUS)}
	rect := math.Rect{ball.Sub(m), ball.Add(m)}
	canvas.DrawRoundedRect(rect, BALL_RADIUS, BALL_RADIUS, BALL_RADIUS, BALL_RADIUS, gxui.TransparentPen, gxui.CreateBrush(gxui.Yellow))
}

func appMain(driver gxui.Driver) {
	theme := dark.CreateTheme(driver)

	window := theme.CreateWindow(ANIMATION_WIDTH, 2*ANIMATION_HEIGHT, "Pendulum")
	window.SetBackgroundBrush(gxui.CreateBrush(gxui.Gray50))

	image := theme.CreateImage()

	ticker := time.NewTicker(time.Millisecond * 15)
	pendulum := &mathematicalPendulum{}
	pendulum2 := &numericalPendulum{PHI_ZERO, 0.0, 0.0, time.Time{}}

	go func() {
		for _ = range ticker.C {
			canvas := driver.CreateCanvas(math.Size{ANIMATION_WIDTH, 2 * ANIMATION_HEIGHT})
			canvas.Clear(gxui.White)

			draw(pendulum, canvas, 0, 0)
			draw(pendulum2, canvas, 0, ANIMATION_HEIGHT)

			canvas.Complete()
			driver.Call(func() {
				image.SetCanvas(canvas)
			})
		}
	}()

	window.AddChild(image)

	window.OnClose(ticker.Stop)
	window.OnClose(driver.Terminate)
}

func main() {
	gl.StartDriver(appMain)
}


Java: import java.awt.*;
import javax.swing.*;

public class Pendulum extends JPanel implements Runnable {

    private double angle = Math.PI / 2;
    private int length;

    public Pendulum(int length) {
        this.length = length;
        setDoubleBuffered(true);
    }

    @Override
    public void paint(Graphics g) {
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, getWidth(), getHeight());
        g.setColor(Color.BLACK);
        int anchorX = getWidth() / 2, anchorY = getHeight() / 4;
        int ballX = anchorX + (int) (Math.sin(angle) * length);
        int ballY = anchorY + (int) (Math.cos(angle) * length);
        g.drawLine(anchorX, anchorY, ballX, ballY);
        g.fillOval(anchorX - 3, anchorY - 4, 7, 7);
        g.fillOval(ballX - 7, ballY - 7, 14, 14);
    }

    public void run() {
        double angleAccel, angleVelocity = 0, dt = 0.1;
        while (true) {
            angleAccel = -9.81 / length * Math.sin(angle);
            angleVelocity += angleAccel * dt;
            angle += angleVelocity * dt;
            repaint();
            try { Thread.sleep(15); } catch (InterruptedException ex) {}
        }
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(2 * length + 50, length / 2 * 3);
    }

    public static void main(String[] args) {
        JFrame f = new JFrame("Pendulum");
        Pendulum p = new Pendulum(200);
        f.add(p);
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.pack();
        f.setVisible(true);
        new Thread(p).start();
    }
}